Finish issue #57 with more support for showing locked status.
* lib/vclib/__init__.py (Repository.dirlogs): Update comment. (Revision.__init__): Add 'lockinfo' parameter, used to populate similarly named class member. * lib/vclib/svn/svn_repos.py (Revision.__init__): Add 'lockinfo' parameter, and update call to vclib.Revision(). (_log_helper): Update call to Revision(), and lose custom lockinfo handling. (LocalSubversionRepository.dirlogs): Populate entry lockinfo with a call to svn_fs_get_lock() for each entry. * lib/vclib/svn/svn_ra.py (LogCollector.__init__): Add 'lockinfo' parameter, used to populate similarly named class member. (LogCollector.add_log): Pass self.lockinfo to updated call to Revision(). (RemoteSubversionRepository.itemlog): Pass lock info to LogCollector(), and lose custom lockinfo handling. (RemoteSubversionRepository.itemtype, RemoteSubversionRepository.listdir): Update expected return value from _get_dirents(). (RemoteSubversionRepository.dirlogs): Populate entry lockinfo from updated return value from _get_dirents(). (RemoteSubversionRepository._get_dirents): Rework to trade in dirents and locks instead of only dirents. * lib/vclib/ccvs/bincvs.py (Revision.__init__): Update call to vclib.Revision(). (_get_logs): Add 'lockinfo' member to DirEntry() items. * lib/vclib/ccvs/ccvs.py (InfoSink.__init__): Init lockinfo dictionary. (InfoSink.set_locker): New. (InfoSink.define_revision): Set lockinfo on Revision item. (InfoSink.set_revision_info): Populate DirEntry lockinfo from Revision lockinfo data. * lib/viewvc.py (view_directory): Populate entry lockinfo. (common_template_data): Populate the 'lockinfo' data dictionary item. * templates/directory.ezt, * templates/dir_new.ezt * templates/annotate.ezt, * templates/markup.ezt Tweak to show lock status. * docs/template-authoring-guide.html Note new data dictionary items. git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1787 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/merged-file-views
parent
d620498e9e
commit
3cbf07551b
|
@ -159,6 +159,11 @@ td {
|
|||
<var>labels</var> section of the key/value file whose configured
|
||||
abstract name is <var>l10n</var>.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">lockinfo</td>
|
||||
<td>String</td>
|
||||
<td>Information about the lock status of the current resource.</td>
|
||||
</tr>
|
||||
<tr class="varlevel1">
|
||||
<td class="varname">log_href</td>
|
||||
<td>String</td>
|
||||
|
@ -928,6 +933,11 @@ td {
|
|||
<td>URL of the ViewVC revision graph view for the directory
|
||||
entry.</td>
|
||||
</tr>
|
||||
<tr class="varlevel2">
|
||||
<td class="varname">entries.lockinfo</td>
|
||||
<td>String</td>
|
||||
<td>Information about the lock status of the directory entry.</td>
|
||||
</tr>
|
||||
<tr class="varlevel2">
|
||||
<td class="varname">entries.log</td>
|
||||
<td>String</td>
|
||||
|
|
|
@ -101,7 +101,7 @@ class Repository:
|
|||
New properties will be set on all of the DirEntry objects in the entries
|
||||
list. At the very least, a "rev" property will be set to a revision
|
||||
number or None if the entry doesn't have a number. Other properties that
|
||||
may be set include "date", "author", and "log".
|
||||
may be set include "date", "author", "log", "size", and "lockinfo".
|
||||
|
||||
The path is specified as a list of components, relative to the root
|
||||
of the repository. e.g. ["subdir1", "subdir2", "filename"]
|
||||
|
@ -180,7 +180,7 @@ class DirEntry:
|
|||
class Revision:
|
||||
"""Instances holds information about revisions of versioned resources"""
|
||||
|
||||
def __init__(self, number, string, date, author, changed, log, size):
|
||||
def __init__(self, number, string, date, author, changed, log, size, lockinfo):
|
||||
"""Create a new Revision() item:
|
||||
NUMBER: Revision in an integer-based, sortable format
|
||||
STRING: Revision as a string
|
||||
|
@ -189,6 +189,7 @@ class Revision:
|
|||
CHANGED: Lines-changed (contextual diff) information
|
||||
LOG: Log message associated with the creation of this revision
|
||||
SIZE: Size (in bytes) of this revision's fulltext (files only)
|
||||
LOCKINFO: Information about locks held on this revision
|
||||
"""
|
||||
self.number = number
|
||||
self.string = string
|
||||
|
@ -197,6 +198,7 @@ class Revision:
|
|||
self.changed = changed
|
||||
self.log = log
|
||||
self.size = size
|
||||
self.lockinfo = lockinfo
|
||||
|
||||
def __cmp__(self, other):
|
||||
return cmp(self.number, other.number)
|
||||
|
|
|
@ -346,7 +346,7 @@ class Revision(vclib.Revision):
|
|||
def __init__(self, revstr, date=None, author=None, dead=None,
|
||||
changed=None, log=None):
|
||||
vclib.Revision.__init__(self, _revision_tuple(revstr), revstr,
|
||||
date, author, changed, log, None)
|
||||
date, author, changed, log, None, None)
|
||||
self.dead = dead
|
||||
|
||||
class Tag:
|
||||
|
@ -1042,6 +1042,7 @@ def _get_logs(repos, dir_path_parts, entries, view_tag, get_dirs):
|
|||
file.author = wanted_entry.author
|
||||
file.dead = file.kind == vclib.FILE and wanted_entry.dead
|
||||
file.log = wanted_entry.log
|
||||
file.lockinfo = lockinfo.get(file.rev)
|
||||
# suppress rlog errors if we find a usable revision in the end
|
||||
del file.errors[:]
|
||||
elif file.kind == vclib.FILE:
|
||||
|
|
|
@ -164,6 +164,7 @@ class InfoSink(MatchingSink):
|
|||
self.alltags = alltags
|
||||
self.matching_rev = None
|
||||
self.perfect_match = 0
|
||||
self.lockinfo = { }
|
||||
|
||||
def define_tag(self, name, revision):
|
||||
MatchingSink.define_tag(self, name, revision)
|
||||
|
@ -175,13 +176,17 @@ class InfoSink(MatchingSink):
|
|||
# tag we're looking for doesn't exist
|
||||
raise rcsparse.RCSStopParser
|
||||
|
||||
def set_locker(self, rev, locker):
|
||||
self.lockinfo[rev] = locker
|
||||
|
||||
def define_revision(self, revision, date, author, state, branches, next):
|
||||
if self.perfect_match:
|
||||
return
|
||||
|
||||
tag = self.find_tag
|
||||
rev = Revision(revision, date, author, state == "dead")
|
||||
|
||||
rev.lockinfo = self.lockinfo.get(revision)
|
||||
|
||||
# perfect match if revision number matches tag number or if revision is on
|
||||
# trunk and tag points to trunk. imperfect match if tag refers to a branch
|
||||
# and this revision is the highest revision so far found on that branch
|
||||
|
@ -200,6 +205,7 @@ class InfoSink(MatchingSink):
|
|||
self.entry.date = self.matching_rev.date
|
||||
self.entry.author = self.matching_rev.author
|
||||
self.entry.dead = self.matching_rev.dead
|
||||
self.entry.lockinfo = self.matching_rev.lockinfo
|
||||
self.entry.log = log
|
||||
raise rcsparse.RCSStopParser
|
||||
else:
|
||||
|
|
|
@ -91,7 +91,7 @@ def _get_rev_details(svnrepos, rev):
|
|||
|
||||
|
||||
class LogCollector:
|
||||
def __init__(self, path, show_all_logs):
|
||||
def __init__(self, path, show_all_logs, lockinfo):
|
||||
# This class uses leading slashes for paths internally
|
||||
if not path:
|
||||
self.path = '/'
|
||||
|
@ -99,6 +99,7 @@ class LogCollector:
|
|||
self.path = path[0] == '/' and path or '/' + path
|
||||
self.logs = []
|
||||
self.show_all_logs = show_all_logs
|
||||
self.lockinfo = lockinfo
|
||||
|
||||
def add_log(self, paths, revision, author, date, message, pool):
|
||||
# Changed paths have leading slashes
|
||||
|
@ -121,7 +122,7 @@ class LogCollector:
|
|||
this_path = change.copyfrom_path + self.path[len(changed_path):]
|
||||
if self.show_all_logs or this_path:
|
||||
entry = Revision(revision, _datestr_to_date(date), author, message, None,
|
||||
self.path[1:], None, None)
|
||||
self.lockinfo, self.path[1:], None, None)
|
||||
self.logs.append(entry)
|
||||
if this_path:
|
||||
self.path = this_path
|
||||
|
@ -217,7 +218,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
rev = self._getrev(rev)
|
||||
if not len(path_parts):
|
||||
return vclib.DIR
|
||||
dirents = self._get_dirents(path, rev)
|
||||
dirents, locks = self._get_dirents(path, rev)
|
||||
try:
|
||||
entry = dirents[path_parts[-1]]
|
||||
if entry.kind == core.svn_node_dir:
|
||||
|
@ -243,7 +244,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
path = self._getpath(path_parts)
|
||||
rev = self._getrev(rev)
|
||||
entries = [ ]
|
||||
dirents = self._get_dirents(path, rev)
|
||||
dirents, locks = self._get_dirents(path, rev)
|
||||
for name in dirents.keys():
|
||||
entry = dirents[name]
|
||||
if entry.kind == core.svn_node_dir:
|
||||
|
@ -255,7 +256,8 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
|
||||
def dirlogs(self, path_parts, rev, entries, options):
|
||||
rev_info_cache = { }
|
||||
dirents = self._get_dirents(self._getpath(path_parts), self._getrev(rev))
|
||||
dirents, locks = self._get_dirents(self._getpath(path_parts),
|
||||
self._getrev(rev))
|
||||
for entry in entries:
|
||||
dirent = dirents[entry.name]
|
||||
if rev_info_cache.has_key(dirent.created_rev):
|
||||
|
@ -270,23 +272,28 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
entry.date = _datestr_to_date(date)
|
||||
entry.log = log
|
||||
entry.size = dirent.size
|
||||
entry.lockinfo = None
|
||||
if locks.has_key(entry.name):
|
||||
entry.lockinfo = locks[entry.name].owner
|
||||
|
||||
def itemlog(self, path_parts, rev, options):
|
||||
full_name = self._getpath(path_parts)
|
||||
rev = self._getrev(rev)
|
||||
|
||||
# It's okay if we're told to not show all logs on a file -- all
|
||||
# the revisions should match correctly anyway.
|
||||
lc = LogCollector(full_name, options.get('svn_show_all_dir_logs', 0))
|
||||
dir_url = self.rootpath
|
||||
if full_name:
|
||||
dir_url = dir_url + '/' + full_name
|
||||
|
||||
# Use ls3 to fetch the lock status for this item.
|
||||
lockinfo = None
|
||||
dirents, locks = client.svn_client_ls3(dir_url, _rev2optrev(rev),
|
||||
_rev2optrev(rev), 0, self.ctx)
|
||||
locker = locks.has_key(path_parts[-1]) \
|
||||
and locks[path_parts[-1]].owner or ''
|
||||
if locks.has_key(path_parts[-1]):
|
||||
lockinfo = locks[path_parts[-1]].owner
|
||||
|
||||
# It's okay if we're told to not show all logs on a file -- all
|
||||
# the revisions should match correctly anyway.
|
||||
lc = LogCollector(full_name, options.get('svn_show_all_dir_logs', 0),
|
||||
lockinfo)
|
||||
|
||||
cross_copies = options.get('svn_cross_copies', 0)
|
||||
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
|
||||
|
@ -295,7 +302,6 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
revs.sort()
|
||||
prev = None
|
||||
for rev in revs:
|
||||
rev.lockinfo = locker
|
||||
rev.prev = prev
|
||||
prev = rev
|
||||
|
||||
|
@ -358,18 +364,22 @@ class RemoteSubversionRepository(vclib.Repository):
|
|||
return rev
|
||||
|
||||
def _get_dirents(self, path, rev):
|
||||
"""Return a 2-type of dirents and locks, possibly reading/writing
|
||||
from a local cache of that information."""
|
||||
|
||||
if path:
|
||||
key = str(rev) + '/' + path
|
||||
dir_url = self.rootpath + '/' + path
|
||||
else:
|
||||
key = str(rev)
|
||||
dir_url = self.rootpath
|
||||
dirents = self._dirent_cache.get(key)
|
||||
if dirents:
|
||||
return dirents
|
||||
dirents = client.svn_client_ls(dir_url, _rev2optrev(rev), 0, self.ctx)
|
||||
self._dirent_cache[key] = dirents
|
||||
return dirents
|
||||
dirents_locks = self._dirent_cache.get(key)
|
||||
if not dirents_locks:
|
||||
dirents, locks = client.svn_client_ls3(dir_url, _rev2optrev(rev),
|
||||
_rev2optrev(rev), 0, self.ctx)
|
||||
dirents_locks = [dirents, locks]
|
||||
self._dirent_cache[key] = dirents_locks
|
||||
return dirents_locks[0], dirents_locks[1]
|
||||
|
||||
##--- custom --##
|
||||
|
||||
|
|
|
@ -110,9 +110,10 @@ def _datestr_to_date(datestr):
|
|||
|
||||
class Revision(vclib.Revision):
|
||||
"Hold state for each revision's log entry."
|
||||
def __init__(self, rev, date, author, msg, size,
|
||||
def __init__(self, rev, date, author, msg, size, lockinfo,
|
||||
filename, copy_path, copy_rev):
|
||||
vclib.Revision.__init__(self, rev, str(rev), date, author, None, msg, size)
|
||||
vclib.Revision.__init__(self, rev, str(rev), date, author, None,
|
||||
msg, size, lockinfo)
|
||||
self.filename = filename
|
||||
self.copy_path = copy_path
|
||||
self.copy_rev = copy_rev
|
||||
|
@ -186,10 +187,9 @@ def _log_helper(svnrepos, rev, path, lockinfo):
|
|||
size = fs.file_length(rev_root, path)
|
||||
else:
|
||||
size = None
|
||||
entry = Revision(rev, date, author, msg, size, path,
|
||||
entry = Revision(rev, date, author, msg, size, lockinfo, path,
|
||||
copyfrom_path and _cleanup_path(copyfrom_path),
|
||||
copyfrom_rev)
|
||||
entry.lockinfo = lockinfo
|
||||
return entry
|
||||
|
||||
|
||||
|
@ -462,6 +462,8 @@ class LocalSubversionRepository(vclib.Repository):
|
|||
entry.log = msg
|
||||
if entry.kind == vclib.FILE:
|
||||
entry.size = fs.file_length(fsroot, path)
|
||||
lock = fs.get_lock(self.fs_ptr, path)
|
||||
entry.lockinfo = lock and lock.owner or None
|
||||
|
||||
def itemlog(self, path_parts, rev, options):
|
||||
"""see vclib.Repository.itemlog docstring
|
||||
|
|
|
@ -1099,6 +1099,7 @@ def common_template_data(request):
|
|||
'nav_path' : nav_path(request),
|
||||
'view' : _view_codes[request.view_func],
|
||||
'rev' : None,
|
||||
'lockinfo' : None,
|
||||
'view_href' : None,
|
||||
'annotate_href' : None,
|
||||
'download_href' : None,
|
||||
|
@ -1172,6 +1173,15 @@ def common_template_data(request):
|
|||
if request.roottype == 'cvs' and cfg.options.use_cvsgraph:
|
||||
data['graph_href'] = request.get_url(view_func=view_cvsgraph,
|
||||
params={}, escape=1)
|
||||
file_data = request.repos.listdir(request.path_parts[:-1],
|
||||
request.pathrev, {})
|
||||
def _only_this_file(item):
|
||||
return item.name == request.path_parts[-1]
|
||||
entries = filter(_only_this_file, file_data)
|
||||
if len(entries) == 1:
|
||||
request.repos.dirlogs(request.path_parts[:-1], request.pathrev,
|
||||
entries, {})
|
||||
data['lockinfo'] = entries[0].lockinfo
|
||||
elif request.pathtype == vclib.DIR:
|
||||
data['view_href'] = request.get_url(view_func=view_directory,
|
||||
params={}, escape=1)
|
||||
|
@ -1725,7 +1735,7 @@ def view_directory(request):
|
|||
if cfg.options.show_logs:
|
||||
row.short_log = format_log(file.log, cfg)
|
||||
row.log = htmlify(file.log, cfg.options.mangle_email_addresses)
|
||||
|
||||
row.lockinfo = file.lockinfo
|
||||
row.anchor = request.server.escape(file.name)
|
||||
row.name = request.server.escape(file.name)
|
||||
row.pathtype = (file.kind == vclib.FILE and 'file') or \
|
||||
|
|
|
@ -37,6 +37,9 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
|
|||
[is roottype "svn"][if-any size]
|
||||
<br />File size: [size] byte(s)
|
||||
[end][end]
|
||||
[if-any lockinfo]
|
||||
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]
|
||||
[end]
|
||||
[is state "dead"]
|
||||
<br /><strong><em>FILE REMOVED</em></strong>
|
||||
[end]
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
<a name="[entries.anchor]" href="[is entries.pathtype "dir"][entries.view_href][else][if-any entries.prefer_markup][entries.view_href][else][entries.download_href][end][end]" title="[is entries.pathtype "dir"]View Directory Contents[else][if-any entries.prefer_markup]View[else]Download[end] File Contents[end]">
|
||||
<img src="[docroot]/images/[is entries.pathtype "dir"]dir[else][is entries.state "dead"]broken[else]text[end][end].png" alt="" class="vc_icon" />
|
||||
[entries.name][is entries.pathtype "dir"]/[end]</a>
|
||||
[if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
|
||||
[is entries.state "dead"](dead)[end]
|
||||
</td>
|
||||
|
||||
|
|
|
@ -97,7 +97,9 @@
|
|||
<td> [if-any entries.rev]<a href="[entries.log_href]" title="View directory revision log"><strong>[entries.rev]</strong></a>[end]</td>
|
||||
[else]
|
||||
[define rev_href][if-any entries.prefer_markup][entries.view_href][else][if-any entries.download_href][entries.download_href][end][end][end]
|
||||
<td> [if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]</td>
|
||||
<td style="white-space: nowrap;"> [if-any entries.rev][if-any rev_href]<a href="[rev_href]" title="[if-any entries.prefer_markup]View[else]Download[end] file contents">[end]<strong>[entries.rev]</strong>[if-any rev_href]</a>[end][end]
|
||||
[if-any entries.lockinfo]<img src="[docroot]/images/lock.png" alt="locked" class="vc_icon" title="Locked by [entries.lockinfo]" />[end]
|
||||
</td>
|
||||
[end]
|
||||
<td> [entries.ago]</td>
|
||||
<td> [entries.author]</td>
|
||||
|
|
|
@ -37,6 +37,9 @@ Revision [if-any revision_href]<a href="[revision_href]"><strong>[rev]</strong><
|
|||
[is roottype "svn"][if-any size]
|
||||
<br />File size: [size] byte(s)
|
||||
[end][end]
|
||||
[if-any lockinfo]
|
||||
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [lockinfo]
|
||||
[end]
|
||||
[is state "dead"]
|
||||
<br /><strong><em>FILE REMOVED</em></strong>
|
||||
[end]
|
||||
|
|
Loading…
Reference in New Issue