Add support for display of locked status.
* docs/template-authoring-guide.html Document the new appearances of the lockinfo data. * templates/log.ezt, * templates/log_table.ezt Show lock status information. * templates/docroot/images/lock.png New icon. * lib/viewvc.py (view_log): Populate the log revision entry's new "lockinfo" member. * lib/vclib/svn/svn_repos.py (_log_helper): Accept 'lockinfo' parameter, used to populate the similarly named member of the Revision() object. (_fetch_log): Query the lock status of the input path, and update calls to _log_helper(). * lib/vclib/ccvs/ccvs.py (CCVSRepository.itemlog): Update call to _file_log(), passing lockinfo. (TreeSink.__init__): Init new lockinfo dictionary. (TreeSink.set_locker): New. * lib/vclib/ccvs/bincvs.py (_parse_log_header): Now parse and return lock information, too. (_file_log): Add 'lockinfo' parameter, used to populate the similarly named Revision() object members. (BinCVSRepository._get_tip_revision, BinCVSRepository.itemlog): Expect lockinfo back from _parse_log_header(), and pass to updated calls to _file_log(). (_get_logs): Expect lockinfo back from _parse_log_header(). * lib/vclib/svn/svn_ra.py (RemoteSubversionRepository.itemlog): Use svn_client_ls3() to fetch lock information. git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@1783 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/merged-file-views
parent
2a9584a0fb
commit
d620498e9e
|
@ -1362,6 +1362,11 @@ td {
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
<td>URL to download the file revision as <tt>text/plain</tt>.</td>
|
<td>URL to download the file revision as <tt>text/plain</tt>.</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr class="varlevel2">
|
||||||
|
<td class="varname">entries.lockinfo</td>
|
||||||
|
<td>String</td>
|
||||||
|
<td>Information about the lock status of this revision.</td>
|
||||||
|
</tr>
|
||||||
<tr class="varlevel2">
|
<tr class="varlevel2">
|
||||||
<td class="varname">entries.log</td>
|
<td class="varname">entries.log</td>
|
||||||
<td>String</td>
|
<td>String</td>
|
||||||
|
|
|
@ -139,13 +139,13 @@ class BinCVSRepository(BaseCVSRepository):
|
||||||
"""Get the (basically) youngest revision (filtered by REV)."""
|
"""Get the (basically) youngest revision (filtered by REV)."""
|
||||||
args = rcs_file,
|
args = rcs_file,
|
||||||
fp = self.rcs_popen('rlog', args, 'rt', 0)
|
fp = self.rcs_popen('rlog', args, 'rt', 0)
|
||||||
filename, default_branch, tags, msg, eof = _parse_log_header(fp)
|
filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
|
||||||
revs = []
|
revs = []
|
||||||
while not eof:
|
while not eof:
|
||||||
revision, eof = _parse_log_entry(fp)
|
revision, eof = _parse_log_entry(fp)
|
||||||
if revision:
|
if revision:
|
||||||
revs.append(revision)
|
revs.append(revision)
|
||||||
revs = _file_log(revs, tags, default_branch, rev)
|
revs = _file_log(revs, tags, lockinfo, default_branch, rev)
|
||||||
if revs:
|
if revs:
|
||||||
return revs[-1]
|
return revs[-1]
|
||||||
return None
|
return None
|
||||||
|
@ -272,7 +272,7 @@ class BinCVSRepository(BaseCVSRepository):
|
||||||
args = rcsfile,
|
args = rcsfile,
|
||||||
|
|
||||||
fp = self.rcs_popen('rlog', args, 'rt', 0)
|
fp = self.rcs_popen('rlog', args, 'rt', 0)
|
||||||
filename, default_branch, tags, msg, eof = _parse_log_header(fp)
|
filename, default_branch, tags, lockinfo, msg, eof = _parse_log_header(fp)
|
||||||
|
|
||||||
# Retrieve revision objects
|
# Retrieve revision objects
|
||||||
revs = []
|
revs = []
|
||||||
|
@ -281,7 +281,7 @@ class BinCVSRepository(BaseCVSRepository):
|
||||||
if revision:
|
if revision:
|
||||||
revs.append(revision)
|
revs.append(revision)
|
||||||
|
|
||||||
filtered_revs = _file_log(revs, tags, default_branch, rev)
|
filtered_revs = _file_log(revs, tags, lockinfo, default_branch, rev)
|
||||||
|
|
||||||
options['cvs_tags'] = tags
|
options['cvs_tags'] = tags
|
||||||
return filtered_revs
|
return filtered_revs
|
||||||
|
@ -655,13 +655,14 @@ def _parse_log_header(fp):
|
||||||
If there is no revision information (e.g. the "-h" switch was passed to
|
If there is no revision information (e.g. the "-h" switch was passed to
|
||||||
rlog), then fp will consumed the file separator line on exit.
|
rlog), then fp will consumed the file separator line on exit.
|
||||||
|
|
||||||
Returns: filename, default branch, tag dictionary, rlog error message,
|
Returns: filename, default branch, tag dictionary, lock dictionary,
|
||||||
and eof flag
|
rlog error message, and eof flag
|
||||||
"""
|
"""
|
||||||
|
|
||||||
filename = head = branch = msg = ""
|
filename = head = branch = msg = ""
|
||||||
taginfo = { } # tag name => number
|
taginfo = { } # tag name => number
|
||||||
|
lockinfo = { } # revision => locker
|
||||||
parsing_tags = 0
|
state = 0 # 0 = base, 1 = parsing symbols, 2 = parsing locks
|
||||||
eof = None
|
eof = None
|
||||||
|
|
||||||
while 1:
|
while 1:
|
||||||
|
@ -671,24 +672,35 @@ def _parse_log_header(fp):
|
||||||
eof = _EOF_LOG
|
eof = _EOF_LOG
|
||||||
break
|
break
|
||||||
|
|
||||||
if parsing_tags:
|
if state == 1:
|
||||||
if line[0] == '\t':
|
if line[0] == '\t':
|
||||||
[ tag, rev ] = map(string.strip, string.split(line, ':'))
|
[ tag, rev ] = map(string.strip, string.split(line, ':'))
|
||||||
taginfo[tag] = rev
|
taginfo[tag] = rev
|
||||||
else:
|
else:
|
||||||
# oops. this line isn't tag info. stop parsing tags.
|
# oops. this line isn't tag info. stop parsing tags.
|
||||||
parsing_tags = 0
|
state = 0
|
||||||
|
|
||||||
if not parsing_tags:
|
if state == 2:
|
||||||
|
if line[0] == '\t':
|
||||||
|
[ locker, rev ] = map(string.strip, string.split(line, ':'))
|
||||||
|
lockinfo[rev] = locker
|
||||||
|
else:
|
||||||
|
# oops. this line isn't lock info. stop parsing tags.
|
||||||
|
state = 0
|
||||||
|
|
||||||
|
if state == 0:
|
||||||
if line[:9] == 'RCS file:':
|
if line[:9] == 'RCS file:':
|
||||||
filename = line[10:-1]
|
filename = line[10:-1]
|
||||||
elif line[:5] == 'head:':
|
elif line[:5] == 'head:':
|
||||||
head = line[6:-1]
|
head = line[6:-1]
|
||||||
elif line[:7] == 'branch:':
|
elif line[:7] == 'branch:':
|
||||||
branch = line[8:-1]
|
branch = line[8:-1]
|
||||||
|
elif line[:6] == 'locks:':
|
||||||
|
# start parsing the lock information
|
||||||
|
state = 2
|
||||||
elif line[:14] == 'symbolic names':
|
elif line[:14] == 'symbolic names':
|
||||||
# start parsing the tag information
|
# start parsing the tag information
|
||||||
parsing_tags = 1
|
state = 1
|
||||||
elif line == ENTRY_END_MARKER:
|
elif line == ENTRY_END_MARKER:
|
||||||
# end of the headers
|
# end of the headers
|
||||||
break
|
break
|
||||||
|
@ -717,7 +729,7 @@ def _parse_log_header(fp):
|
||||||
eof = _EOF_ERROR
|
eof = _EOF_ERROR
|
||||||
break
|
break
|
||||||
|
|
||||||
return filename, branch, taginfo, msg, eof
|
return filename, branch, taginfo, lockinfo, msg, eof
|
||||||
|
|
||||||
_re_log_info = re.compile(r'^date:\s+([^;]+);'
|
_re_log_info = re.compile(r'^date:\s+([^;]+);'
|
||||||
r'\s+author:\s+([^;]+);'
|
r'\s+author:\s+([^;]+);'
|
||||||
|
@ -817,7 +829,7 @@ def _paths_eq(path1, path2):
|
||||||
# ======================================================================
|
# ======================================================================
|
||||||
# Functions for interpreting and manipulating log information
|
# Functions for interpreting and manipulating log information
|
||||||
|
|
||||||
def _file_log(revs, taginfo, cur_branch, filter):
|
def _file_log(revs, taginfo, lockinfo, cur_branch, filter):
|
||||||
"""Augment list of Revisions and a dictionary of Tags"""
|
"""Augment list of Revisions and a dictionary of Tags"""
|
||||||
|
|
||||||
# Add artificial ViewVC tag MAIN. If the file has a default branch, then
|
# Add artificial ViewVC tag MAIN. If the file has a default branch, then
|
||||||
|
@ -848,6 +860,10 @@ def _file_log(revs, taginfo, cur_branch, filter):
|
||||||
# Match up tags and revisions
|
# Match up tags and revisions
|
||||||
_match_revs_tags(revs, tags)
|
_match_revs_tags(revs, tags)
|
||||||
|
|
||||||
|
# Match up lockinfo and revision
|
||||||
|
for rev in revs:
|
||||||
|
rev.lockinfo = lockinfo.get(rev.string)
|
||||||
|
|
||||||
# Add artificial ViewVC tag HEAD, which acts like a non-branch tag pointing
|
# Add artificial ViewVC tag HEAD, which acts like a non-branch tag pointing
|
||||||
# at the latest revision on the MAIN branch. The HEAD revision doesn't have
|
# at the latest revision on the MAIN branch. The HEAD revision doesn't have
|
||||||
# anything to do with the "head" revision number specified in the RCS file
|
# anything to do with the "head" revision number specified in the RCS file
|
||||||
|
@ -936,7 +952,8 @@ def _get_logs(repos, dir_path_parts, entries, view_tag, get_dirs):
|
||||||
chunk_idx = 0
|
chunk_idx = 0
|
||||||
while chunk_idx < len(chunk):
|
while chunk_idx < len(chunk):
|
||||||
file = chunk[chunk_idx]
|
file = chunk[chunk_idx]
|
||||||
filename, default_branch, taginfo, msg, eof = _parse_log_header(rlog)
|
filename, default_branch, taginfo, lockinfo, msg, eof \
|
||||||
|
= _parse_log_header(rlog)
|
||||||
|
|
||||||
if eof == _EOF_LOG:
|
if eof == _EOF_LOG:
|
||||||
# the rlog output ended early. this can happen on errors that rlog
|
# the rlog output ended early. this can happen on errors that rlog
|
||||||
|
|
|
@ -87,7 +87,7 @@ class CCVSRepository(BaseCVSRepository):
|
||||||
path = self.rcsfile(path_parts, 1)
|
path = self.rcsfile(path_parts, 1)
|
||||||
sink = TreeSink()
|
sink = TreeSink()
|
||||||
rcsparse.parse(open(path, 'rb'), sink)
|
rcsparse.parse(open(path, 'rb'), sink)
|
||||||
filtered_revs = _file_log(sink.revs.values(), sink.tags,
|
filtered_revs = _file_log(sink.revs.values(), sink.tags, sink.lockinfo,
|
||||||
sink.default_branch, rev)
|
sink.default_branch, rev)
|
||||||
for rev in filtered_revs:
|
for rev in filtered_revs:
|
||||||
if rev.prev and len(rev.number) == 2:
|
if rev.prev and len(rev.number) == 2:
|
||||||
|
@ -214,13 +214,17 @@ class TreeSink(rcsparse.Sink):
|
||||||
self.tags = { }
|
self.tags = { }
|
||||||
self.head = None
|
self.head = None
|
||||||
self.default_branch = None
|
self.default_branch = None
|
||||||
|
self.lockinfo = { }
|
||||||
|
|
||||||
def set_head_revision(self, revision):
|
def set_head_revision(self, revision):
|
||||||
self.head = revision
|
self.head = revision
|
||||||
|
|
||||||
def set_principal_branch(self, branch_number):
|
def set_principal_branch(self, branch_number):
|
||||||
self.default_branch = branch_number
|
self.default_branch = branch_number
|
||||||
|
|
||||||
|
def set_locker(self, rev, locker):
|
||||||
|
self.lockinfo[rev] = locker
|
||||||
|
|
||||||
def define_tag(self, name, revision):
|
def define_tag(self, name, revision):
|
||||||
# check !tags.has_key(tag_name)
|
# check !tags.has_key(tag_name)
|
||||||
self.tags[name] = revision
|
self.tags[name] = revision
|
||||||
|
|
|
@ -282,6 +282,12 @@ class RemoteSubversionRepository(vclib.Repository):
|
||||||
if full_name:
|
if full_name:
|
||||||
dir_url = dir_url + '/' + full_name
|
dir_url = dir_url + '/' + full_name
|
||||||
|
|
||||||
|
# Use ls3 to fetch the lock status for this item.
|
||||||
|
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 ''
|
||||||
|
|
||||||
cross_copies = options.get('svn_cross_copies', 0)
|
cross_copies = options.get('svn_cross_copies', 0)
|
||||||
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
|
client.svn_client_log([dir_url], _rev2optrev(rev), _rev2optrev(1),
|
||||||
1, not cross_copies, lc.add_log, self.ctx)
|
1, not cross_copies, lc.add_log, self.ctx)
|
||||||
|
@ -289,6 +295,7 @@ class RemoteSubversionRepository(vclib.Repository):
|
||||||
revs.sort()
|
revs.sort()
|
||||||
prev = None
|
prev = None
|
||||||
for rev in revs:
|
for rev in revs:
|
||||||
|
rev.lockinfo = locker
|
||||||
rev.prev = prev
|
rev.prev = prev
|
||||||
prev = rev
|
prev = rev
|
||||||
|
|
||||||
|
|
|
@ -174,7 +174,7 @@ def _get_history(svnrepos, full_name, rev, options={}):
|
||||||
return history.histories
|
return history.histories
|
||||||
|
|
||||||
|
|
||||||
def _log_helper(svnrepos, rev, path):
|
def _log_helper(svnrepos, rev, path, lockinfo):
|
||||||
rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
|
rev_root = fs.revision_root(svnrepos.fs_ptr, rev)
|
||||||
|
|
||||||
# Was this path@rev the target of a copy?
|
# Was this path@rev the target of a copy?
|
||||||
|
@ -189,14 +189,24 @@ def _log_helper(svnrepos, rev, path):
|
||||||
entry = Revision(rev, date, author, msg, size, path,
|
entry = Revision(rev, date, author, msg, size, path,
|
||||||
copyfrom_path and _cleanup_path(copyfrom_path),
|
copyfrom_path and _cleanup_path(copyfrom_path),
|
||||||
copyfrom_rev)
|
copyfrom_rev)
|
||||||
|
entry.lockinfo = lockinfo
|
||||||
return entry
|
return entry
|
||||||
|
|
||||||
|
|
||||||
def _fetch_log(svnrepos, full_name, which_rev, options):
|
def _fetch_log(svnrepos, full_name, which_rev, options):
|
||||||
revs = []
|
revs = []
|
||||||
|
lockinfo = None
|
||||||
|
|
||||||
|
# See is this path is locked.
|
||||||
|
try:
|
||||||
|
lock = fs.get_lock(svnrepos.fs_ptr, full_name)
|
||||||
|
if lock:
|
||||||
|
lockinfo = lock.owner
|
||||||
|
except NameError:
|
||||||
|
pass
|
||||||
|
|
||||||
if options.get('svn_latest_log', 0):
|
if options.get('svn_latest_log', 0):
|
||||||
rev = _log_helper(svnrepos, which_rev, full_name)
|
rev = _log_helper(svnrepos, which_rev, full_name, lockinfo)
|
||||||
if rev:
|
if rev:
|
||||||
revs.append(rev)
|
revs.append(rev)
|
||||||
else:
|
else:
|
||||||
|
@ -205,7 +215,8 @@ def _fetch_log(svnrepos, full_name, which_rev, options):
|
||||||
history_revs.sort()
|
history_revs.sort()
|
||||||
history_revs.reverse()
|
history_revs.reverse()
|
||||||
for history_rev in history_revs:
|
for history_rev in history_revs:
|
||||||
rev = _log_helper(svnrepos, history_rev, history_set[history_rev])
|
rev = _log_helper(svnrepos, history_rev, history_set[history_rev],
|
||||||
|
lockinfo)
|
||||||
if rev:
|
if rev:
|
||||||
revs.append(rev)
|
revs.append(rev)
|
||||||
return revs
|
return revs
|
||||||
|
|
|
@ -2034,6 +2034,7 @@ def view_log(request):
|
||||||
entry.ago = html_time(request, rev.date, 1)
|
entry.ago = html_time(request, rev.date, 1)
|
||||||
entry.log = htmlify(rev.log or "", cfg.options.mangle_email_addresses)
|
entry.log = htmlify(rev.log or "", cfg.options.mangle_email_addresses)
|
||||||
entry.size = rev.size
|
entry.size = rev.size
|
||||||
|
entry.lockinfo = rev.lockinfo
|
||||||
entry.branch_point = None
|
entry.branch_point = None
|
||||||
entry.next_main = None
|
entry.next_main = None
|
||||||
entry.orig_path = None
|
entry.orig_path = None
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 303 B |
|
@ -6,6 +6,7 @@
|
||||||
[for entries]
|
[for entries]
|
||||||
[if-index entries first][define first_revision][entries.rev][end][end]
|
[if-index entries first][define first_revision][entries.rev][end][end]
|
||||||
[if-index entries last][define last_revision][entries.rev][end][end]
|
[if-index entries last][define last_revision][entries.rev][end][end]
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
@ -97,6 +98,10 @@
|
||||||
[end]
|
[end]
|
||||||
[end]
|
[end]
|
||||||
|
|
||||||
|
[if-any entries.lockinfo]
|
||||||
|
<br />Lock status: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]
|
||||||
|
[end]
|
||||||
|
|
||||||
[is entries.state "dead"]
|
[is entries.state "dead"]
|
||||||
<br /><strong><em>FILE REMOVED</em></strong>
|
<br /><strong><em>FILE REMOVED</em></strong>
|
||||||
[else]
|
[else]
|
||||||
|
|
|
@ -147,9 +147,14 @@
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="vc_row_[if-index entries even]even[else]odd[end]">
|
<tr class="vc_row_[if-index entries even]even[else]odd[end]">
|
||||||
<td colspan=5>
|
<td colspan=5>
|
||||||
|
|
||||||
|
[if-any entries.lockinfo]
|
||||||
|
<strong>Lock status</strong>: <img src="[docroot]/images/lock.png" alt="Locked" width="16" height="16" /> [entries.lockinfo]<br />
|
||||||
|
[end]
|
||||||
|
|
||||||
[is roottype "svn"]
|
[is roottype "svn"]
|
||||||
[if-any entries.orig_path]
|
[if-any entries.orig_path]
|
||||||
Original Path: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
|
<strong>Original Path</strong>: <a href="[entries.orig_href]"><em>[entries.orig_path]</em></a><br />
|
||||||
[end]
|
[end]
|
||||||
|
|
||||||
[if-any entries.size]
|
[if-any entries.size]
|
||||||
|
|
Loading…
Reference in New Issue