forked from edavis10/redmine
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
scm: mercurial: add Mercurial helper extension (#4455).
* 'rhsummary' and 'rhmanifest' for reducing the number of hg command calls. * 'rhdiff' for compatibility with Mercurial < 1.1. Also renamed TEMPLATES_DIR to HELPERS_DIR because the directory now contains templates and a helper extension. Original version was written by Alessio Franceschelli, downloaded from http://www.redmine.org/attachments/3395/overhaul.py Contributed by Alessio Franceschelli and Yuya Nishihara. git-svn-id: svn+ssh://rubyforge.org/var/svn/redmine/trunk@4833 e93f8b46-1217-0410-a6f0-8f06a7374b81
- Loading branch information
Showing
3 changed files
with
172 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
# redminehelper: Redmine helper extension for Mercurial | ||
# | ||
# Copyright 2010 Alessio Franceschelli (alefranz.net) | ||
# Copyright 2010-2011 Yuya Nishihara <yuya@tcha.org> | ||
# | ||
# This software may be used and distributed according to the terms of the | ||
# GNU General Public License version 2 or any later version. | ||
"""helper commands for Redmine to reduce the number of hg calls | ||
To test this extension, please try:: | ||
$ hg --config extensions.redminehelper=redminehelper.py rhsummary | ||
I/O encoding: | ||
:file path: urlencoded, raw string | ||
:tag name: utf-8 | ||
:branch name: utf-8 | ||
:node: 12-digits (short) hex string | ||
Output example of rhsummary:: | ||
<?xml version="1.0"?> | ||
<rhsummary> | ||
<repository root="/foo/bar"> | ||
<tip revision="1234" node="abcdef0123..."/> | ||
<tag revision="123" node="34567abc..." name="1.1.1"/> | ||
<branch .../> | ||
... | ||
</repository> | ||
</rhsummary> | ||
Output example of rhmanifest:: | ||
<?xml version="1.0"?> | ||
<rhmanifest> | ||
<repository root="/foo/bar"> | ||
<manifest revision="1234" path="lib"> | ||
<file name="diff.rb" revision="123" node="34567abc..." time="12345" | ||
size="100"/> | ||
... | ||
<dir name="redmine"/> | ||
... | ||
</manifest> | ||
</repository> | ||
</rhmanifest> | ||
""" | ||
import re, time, cgi, urllib | ||
from mercurial import cmdutil, commands, node, error | ||
|
||
_x = cgi.escape | ||
_u = lambda s: cgi.escape(urllib.quote(s)) | ||
|
||
def _tip(ui, repo): | ||
# see mercurial/commands.py:tip | ||
def tiprev(): | ||
try: | ||
return len(repo) - 1 | ||
except TypeError: # Mercurial < 1.1 | ||
return repo.changelog.count() - 1 | ||
tipctx = repo.changectx(tiprev()) | ||
ui.write('<tip revision="%d" node="%s"/>\n' | ||
% (tipctx.rev(), _x(node.short(tipctx.node())))) | ||
|
||
_SPECIAL_TAGS = ('tip',) | ||
|
||
def _tags(ui, repo): | ||
# see mercurial/commands.py:tags | ||
for t, n in reversed(repo.tagslist()): | ||
if t in _SPECIAL_TAGS: | ||
continue | ||
try: | ||
r = repo.changelog.rev(n) | ||
except error.LookupError: | ||
continue | ||
ui.write('<tag revision="%d" node="%s" name="%s"/>\n' | ||
% (r, _x(node.short(n)), _x(t))) | ||
|
||
def _branches(ui, repo): | ||
# see mercurial/commands.py:branches | ||
def iterbranches(): | ||
for t, n in repo.branchtags().iteritems(): | ||
yield t, n, repo.changelog.rev(n) | ||
def branchheads(branch): | ||
try: | ||
return repo.branchheads(branch, closed=False) | ||
except TypeError: # Mercurial < 1.2 | ||
return repo.branchheads(branch) | ||
for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True): | ||
if repo.lookup(r) in branchheads(t): | ||
ui.write('<branch revision="%d" node="%s" name="%s"/>\n' | ||
% (r, _x(node.short(n)), _x(t))) | ||
|
||
def _manifest(ui, repo, path, rev): | ||
ctx = repo.changectx(rev) | ||
ui.write('<manifest revision="%d" path="%s">\n' | ||
% (ctx.rev(), _u(path))) | ||
|
||
known = set() | ||
pathprefix = (path.rstrip('/') + '/').lstrip('/') | ||
for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]): | ||
if not f.startswith(pathprefix): | ||
continue | ||
name = re.sub(r'/.*', '/', f[len(pathprefix):]) | ||
if name in known: | ||
continue | ||
known.add(name) | ||
|
||
if name.endswith('/'): | ||
ui.write('<dir name="%s"/>\n' | ||
% _x(urllib.quote(name[:-1]))) | ||
else: | ||
fctx = repo.filectx(f, fileid=n) | ||
tm, tzoffset = fctx.date() | ||
ui.write('<file name="%s" revision="%d" node="%s" ' | ||
'time="%d" size="%d"/>\n' | ||
% (_u(name), fctx.rev(), _x(node.short(fctx.node())), | ||
tm, fctx.size(), )) | ||
|
||
ui.write('</manifest>\n') | ||
|
||
def rhdiff(ui, repo, *pats, **opts): | ||
"""diff repository (or selected files)""" | ||
change = opts.pop('change', None) | ||
if change: # add -c option for Mercurial<1.1 | ||
base = repo.changectx(change).parents()[0].rev() | ||
opts['rev'] = [str(base), change] | ||
opts['nodates'] = True | ||
return commands.diff(ui, repo, *map(urllib.unquote, pats), **opts) | ||
|
||
def rhmanifest(ui, repo, path='', **opts): | ||
"""output the sub-manifest of the specified directory""" | ||
ui.write('<?xml version="1.0"?>\n') | ||
ui.write('<rhmanifest>\n') | ||
ui.write('<repository root="%s">\n' % _u(repo.root)) | ||
try: | ||
_manifest(ui, repo, urllib.unquote(path), opts.get('rev')) | ||
finally: | ||
ui.write('</repository>\n') | ||
ui.write('</rhmanifest>\n') | ||
|
||
def rhsummary(ui, repo, **opts): | ||
"""output the summary of the repository""" | ||
ui.write('<?xml version="1.0"?>\n') | ||
ui.write('<rhsummary>\n') | ||
ui.write('<repository root="%s">\n' % _u(repo.root)) | ||
try: | ||
_tip(ui, repo) | ||
_tags(ui, repo) | ||
_branches(ui, repo) | ||
# TODO: bookmarks in core (Mercurial>=1.8) | ||
finally: | ||
ui.write('</repository>\n') | ||
ui.write('</rhsummary>\n') | ||
|
||
# This extension should be compatible with Mercurial 0.9.5. | ||
# Note that Mercurial 0.9.5 doesn't have extensions.wrapfunction(). | ||
cmdtable = { | ||
'rhdiff': (rhdiff, | ||
[('r', 'rev', [], 'revision'), | ||
('c', 'change', '', 'change made by revision')], | ||
'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'), | ||
'rhmanifest': (rhmanifest, | ||
[('r', 'rev', '', 'show the specified revision')], | ||
'hg rhmanifest [-r REV] [PATH]'), | ||
'rhsummary': (rhsummary, [], 'hg rhsummary'), | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters