diff --git a/lib/config.py b/lib/config.py
index 55248cd4..60d01c82 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -157,6 +157,7 @@ class Config:
else:
self.general.cvsnt_exe_path = None
self.general.use_rcsparse = 0
+ self.general.svn_path = ''
self.general.mime_types_file = ''
self.general.address = 'No admin address has been configured'
self.general.forbidden = ()
diff --git a/lib/vclib/svn/__init__.py b/lib/vclib/svn/__init__.py
index 31563668..199225a2 100644
--- a/lib/vclib/svn/__init__.py
+++ b/lib/vclib/svn/__init__.py
@@ -24,6 +24,7 @@ import string
import cStringIO
import signal
import time
+import popen
from svn import fs, repos, core, delta
@@ -346,9 +347,46 @@ class FileContentsPipe:
def eof(self):
return self._eof
+
+class BlameSource:
+ def __init__(self, svn_client_path, rootpath, fs_path, rev):
+ self.idx = -1
+ self.line_number = 1
+ self.last = None
+
+ rootpath = os.path.abspath(rootpath)
+ url = 'file://' + string.join([rootpath, fs_path], "/")
+ self.fp = popen.popen(svn_client_path,
+ ('blame', "%s@%d" % (url, int(rev))), 'rb', 1)
+
+ def __getitem__(self, idx):
+ if idx == self.idx:
+ return self.last
+ if self.fp.eof():
+ raise IndexError("No more annotations")
+ if idx != self.idx + 1:
+ raise BlameSequencingError()
+ line = self.fp.readline()
+ if not line:
+ raise IndexError("No more annotations")
+ rev, author = line[:17].split(None, 1)
+ text = line[18:]
+ rev = int(rev)
+ if rev > 1:
+ prev_rev = rev - 1
+ item = _item(text=text, line_number=idx+1, rev=rev,
+ prev_rev=prev_rev, author=author, date=None)
+ self.last = item
+ self.idx = idx
+ return item
+
+
+class BlameSequencingError(Exception):
+ pass
+
class SubversionRepository(vclib.Repository):
- def __init__(self, name, rootpath, rev=None):
+ def __init__(self, name, rootpath, svn_path, rev=None):
if not os.path.isdir(rootpath):
raise vclib.ReposNotFound(name)
@@ -358,6 +396,7 @@ class SubversionRepository(vclib.Repository):
self.rootpath = rootpath
self.name = name
self.rev = rev
+ self.svn_client_path = os.path.normpath(os.path.join(svn_path, 'svn'))
# Register a handler for SIGTERM so we can have a chance to
# cleanup. If ViewCVS takes too long to start generating CGI
@@ -464,8 +503,12 @@ class SubversionRepository(vclib.Repository):
return revs
def annotate(self, path_parts, rev=None):
- raise NotImplementedError, \
- "No support for Subversion annotation yet"
+ if not rev:
+ rev = self.rev
+ path = self._getpath(path_parts)
+ revision = str(_get_last_history_rev(self, path, self.scratch_pool))
+ source = BlameSource(self.svn_client_path, self.rootpath, path, rev)
+ return source, revision
def rawdiff(self, path1, rev1, path2, rev2, type, options={}):
"""see vclib.Repository.rawdiff docstring
@@ -493,3 +536,7 @@ class SubversionRepository(vclib.Repository):
def _getpath(self, path_parts):
return string.join(path_parts, '/')
+
+class _item:
+ def __init__(self, **kw):
+ vars(self).update(kw)
diff --git a/lib/viewcvs.py b/lib/viewcvs.py
index 2210f0d2..dc4e9fd0 100644
--- a/lib/viewcvs.py
+++ b/lib/viewcvs.py
@@ -245,20 +245,25 @@ class Request:
elif cfg.general.svn_roots.has_key(self.rootname):
self.rootpath = cfg.general.svn_roots[self.rootname]
try:
+ rev = None
+ if self.query_dict.has_key('rev') \
+ and self.query_dict['rev'] != 'HEAD':
+ rev = int(self.query_dict['rev'])
if re.match(_re_rewrite_url, self.rootpath):
# If the rootpath is a URL, we'll use the svn_ra module, but
# lie about its name.
import vclib.svn_ra
vclib.svn = vclib.svn_ra
+ self.repos = vclib.svn.SubversionRepository(self.rootname,
+ self.rootpath,
+ rev)
else:
self.rootpath = os.path.normpath(self.rootpath)
import vclib.svn
- rev = None
- if self.query_dict.has_key('rev') \
- and self.query_dict['rev'] != 'HEAD':
- rev = int(self.query_dict['rev'])
- self.repos = vclib.svn.SubversionRepository(self.rootname,
- self.rootpath, rev)
+ self.repos = vclib.svn.SubversionRepository(self.rootname,
+ self.rootpath,
+ cfg.general.svn_path,
+ rev)
self.roottype = 'svn'
except vclib.ReposNotFound:
raise debug.ViewCVSException(
diff --git a/templates/log.ezt b/templates/log.ezt
index ed2129b9..2c712ea5 100644
--- a/templates/log.ezt
+++ b/templates/log.ezt
@@ -34,7 +34,7 @@
(download)
[if-any entries.download_text_href](as text)[end]
[# if you don't want to allow annotation, then remove this line]
- [is roottype "svn"][else](annotate)[end]
+ (annotate)
[# if you don't want to allow select for diffs then remove this section]
[is entries.rev rev_selected]
diff --git a/templates/log_table.ezt b/templates/log_table.ezt
index a5b22723..cb1a1cec 100644
--- a/templates/log_table.ezt
+++ b/templates/log_table.ezt
@@ -46,7 +46,7 @@
[if-any entries.download_text_href]As text
[end]
[# if you don't want to allow annotation, then remove this line]
- [is roottype "svn"][else]Annotate
[end]
+ Annotate