Expose annotation support for local Subversion repositories. Patch
largely by Stefan Haller <haller@ableton.com>, at least in the approach used. * viewcvs/viewcvs.conf.dist (svn_path): New configuration variable. * viewcvs/lib/config.py (Config.set_defaults): Populate a new svn_path config member. * viewcvs/lib/viewcvs.py (Request.__init__): Tweak the way Subversion's vclib.Repository objects are opened to have different codepaths for the 'svn' and 'svn_ra' modules, and pass the new cfg.general.svn_path option to the 'svn' module's SubversionRepository. * viewcvs/lib/vclib/svn/__init__.py (BlameSource, BlameSequencingError, _item): New. (SubversionRepository.__init__): Add 'svn_path' parameter. Calculate and store a path for the 'svn' command-line client binary. (SubversionRepository.annotate): Really implement annotation. * viewcvs/templates/log.ezt, * viewcvs/templates/log_table.ezt Enable annotate links for Subversion, too! git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1100 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/tags/1.0.0-rc1
parent
a5ad1e5f41
commit
ac88e349ca
|
@ -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 = '<a href="mailto:user@insert.your.domain.here">No admin address has been configured</a>'
|
||||
self.general.forbidden = ()
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
(<a href="[entries.download_href]">download</a>)
|
||||
[if-any entries.download_text_href](<a href="[entries.download_text_href]">as text</a>)[end]
|
||||
[# if you don't want to allow annotation, then remove this line]
|
||||
[is roottype "svn"][else](<a href="[entries.annotate_href]">annotate</a>)[end]
|
||||
(<a href="[entries.annotate_href]">annotate</a>)
|
||||
|
||||
[# if you don't want to allow select for diffs then remove this section]
|
||||
[is entries.rev rev_selected]
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
[if-any entries.download_text_href]<a href="[entries.download_text_href]"><b>As text</b></a><br>[end]
|
||||
|
||||
[# if you don't want to allow annotation, then remove this line]
|
||||
[is roottype "svn"][else]<a href="[entries.annotate_href]"><b>Annotate</b></a><br>[end]
|
||||
<a href="[entries.annotate_href]"><b>Annotate</b></a><br>
|
||||
</td>
|
||||
<td>
|
||||
[is entries.state "dead"]
|
||||
|
|
|
@ -124,6 +124,9 @@ default_root = cvs
|
|||
# of invoking rcs utilities. this feature is experimental
|
||||
use_rcsparse = 0
|
||||
|
||||
# uncomment if the svn command-line utilities are not on the standard path
|
||||
#svn_path = /usr/bin/
|
||||
|
||||
#
|
||||
# This is a pathname to a MIME types file to help viewcvs to guess the
|
||||
# correct MIME type on checkout.
|
||||
|
|
Loading…
Reference in New Issue