To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / .svn / pristine / 9d / 9dc877e22163cfba0e0ecab2db123574b64de75c.svn-base @ 1297:0a574315af3e
History | View | Annotate | Download (7.72 KB)
| 1 |
# redminehelper: Redmine helper extension for Mercurial |
|---|---|
| 2 |
# |
| 3 |
# Copyright 2010 Alessio Franceschelli (alefranz.net) |
| 4 |
# Copyright 2010-2011 Yuya Nishihara <yuya@tcha.org> |
| 5 |
# |
| 6 |
# This software may be used and distributed according to the terms of the |
| 7 |
# GNU General Public License version 2 or any later version. |
| 8 |
"""helper commands for Redmine to reduce the number of hg calls |
| 9 |
|
| 10 |
To test this extension, please try:: |
| 11 |
|
| 12 |
$ hg --config extensions.redminehelper=redminehelper.py rhsummary |
| 13 |
|
| 14 |
I/O encoding: |
| 15 |
|
| 16 |
:file path: urlencoded, raw string |
| 17 |
:tag name: utf-8 |
| 18 |
:branch name: utf-8 |
| 19 |
:node: 12-digits (short) hex string |
| 20 |
|
| 21 |
Output example of rhsummary:: |
| 22 |
|
| 23 |
<?xml version="1.0"?> |
| 24 |
<rhsummary> |
| 25 |
<repository root="/foo/bar"> |
| 26 |
<tip revision="1234" node="abcdef0123..."/> |
| 27 |
<tag revision="123" node="34567abc..." name="1.1.1"/> |
| 28 |
<branch .../> |
| 29 |
... |
| 30 |
</repository> |
| 31 |
</rhsummary> |
| 32 |
|
| 33 |
Output example of rhmanifest:: |
| 34 |
|
| 35 |
<?xml version="1.0"?> |
| 36 |
<rhmanifest> |
| 37 |
<repository root="/foo/bar"> |
| 38 |
<manifest revision="1234" path="lib"> |
| 39 |
<file name="diff.rb" revision="123" node="34567abc..." time="12345" |
| 40 |
size="100"/> |
| 41 |
... |
| 42 |
<dir name="redmine"/> |
| 43 |
... |
| 44 |
</manifest> |
| 45 |
</repository> |
| 46 |
</rhmanifest> |
| 47 |
""" |
| 48 |
import re, time, cgi, urllib |
| 49 |
from mercurial import cmdutil, commands, node, error, hg |
| 50 |
|
| 51 |
_x = cgi.escape |
| 52 |
_u = lambda s: cgi.escape(urllib.quote(s)) |
| 53 |
|
| 54 |
def _tip(ui, repo): |
| 55 |
# see mercurial/commands.py:tip |
| 56 |
def tiprev(): |
| 57 |
try: |
| 58 |
return len(repo) - 1 |
| 59 |
except TypeError: # Mercurial < 1.1 |
| 60 |
return repo.changelog.count() - 1 |
| 61 |
tipctx = repo.changectx(tiprev()) |
| 62 |
ui.write('<tip revision="%d" node="%s"/>\n'
|
| 63 |
% (tipctx.rev(), _x(node.short(tipctx.node())))) |
| 64 |
|
| 65 |
_SPECIAL_TAGS = ('tip',)
|
| 66 |
|
| 67 |
def _tags(ui, repo): |
| 68 |
# see mercurial/commands.py:tags |
| 69 |
for t, n in reversed(repo.tagslist()): |
| 70 |
if t in _SPECIAL_TAGS: |
| 71 |
continue |
| 72 |
try: |
| 73 |
r = repo.changelog.rev(n) |
| 74 |
except error.LookupError: |
| 75 |
continue |
| 76 |
ui.write('<tag revision="%d" node="%s" name="%s"/>\n'
|
| 77 |
% (r, _x(node.short(n)), _x(t))) |
| 78 |
|
| 79 |
def _branches(ui, repo): |
| 80 |
# see mercurial/commands.py:branches |
| 81 |
def iterbranches(): |
| 82 |
for t, n in repo.branchtags().iteritems(): |
| 83 |
yield t, n, repo.changelog.rev(n) |
| 84 |
def branchheads(branch): |
| 85 |
try: |
| 86 |
return repo.branchheads(branch, closed=False) |
| 87 |
except TypeError: # Mercurial < 1.2 |
| 88 |
return repo.branchheads(branch) |
| 89 |
for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True): |
| 90 |
if repo.lookup(r) in branchheads(t): |
| 91 |
ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
|
| 92 |
% (r, _x(node.short(n)), _x(t))) |
| 93 |
|
| 94 |
def _manifest(ui, repo, path, rev): |
| 95 |
ctx = repo.changectx(rev) |
| 96 |
ui.write('<manifest revision="%d" path="%s">\n'
|
| 97 |
% (ctx.rev(), _u(path))) |
| 98 |
|
| 99 |
known = set() |
| 100 |
pathprefix = (path.rstrip('/') + '/').lstrip('/')
|
| 101 |
for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]): |
| 102 |
if not f.startswith(pathprefix): |
| 103 |
continue |
| 104 |
name = re.sub(r'/.*', '/', f[len(pathprefix):]) |
| 105 |
if name in known: |
| 106 |
continue |
| 107 |
known.add(name) |
| 108 |
|
| 109 |
if name.endswith('/'):
|
| 110 |
ui.write('<dir name="%s"/>\n'
|
| 111 |
% _x(urllib.quote(name[:-1]))) |
| 112 |
else: |
| 113 |
fctx = repo.filectx(f, fileid=n) |
| 114 |
tm, tzoffset = fctx.date() |
| 115 |
ui.write('<file name="%s" revision="%d" node="%s" '
|
| 116 |
'time="%d" size="%d"/>\n' |
| 117 |
% (_u(name), fctx.rev(), _x(node.short(fctx.node())), |
| 118 |
tm, fctx.size(), )) |
| 119 |
|
| 120 |
ui.write('</manifest>\n')
|
| 121 |
|
| 122 |
def rhannotate(ui, repo, *pats, **opts): |
| 123 |
rev = urllib.unquote_plus(opts.pop('rev', None))
|
| 124 |
opts['rev'] = rev |
| 125 |
return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts) |
| 126 |
|
| 127 |
def rhcat(ui, repo, file1, *pats, **opts): |
| 128 |
rev = urllib.unquote_plus(opts.pop('rev', None))
|
| 129 |
opts['rev'] = rev |
| 130 |
return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts) |
| 131 |
|
| 132 |
def rhdiff(ui, repo, *pats, **opts): |
| 133 |
"""diff repository (or selected files)""" |
| 134 |
change = opts.pop('change', None)
|
| 135 |
if change: # add -c option for Mercurial<1.1 |
| 136 |
base = repo.changectx(change).parents()[0].rev() |
| 137 |
opts['rev'] = [str(base), change] |
| 138 |
opts['nodates'] = True |
| 139 |
return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts) |
| 140 |
|
| 141 |
def rhlog(ui, repo, *pats, **opts): |
| 142 |
rev = opts.pop('rev')
|
| 143 |
bra0 = opts.pop('branch')
|
| 144 |
from_rev = urllib.unquote_plus(opts.pop('from', None))
|
| 145 |
to_rev = urllib.unquote_plus(opts.pop('to' , None))
|
| 146 |
bra = urllib.unquote_plus(opts.pop('rhbranch', None))
|
| 147 |
from_rev = from_rev.replace('"', '\\"')
|
| 148 |
to_rev = to_rev.replace('"', '\\"')
|
| 149 |
if hg.util.version() >= '1.6': |
| 150 |
opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)] |
| 151 |
else: |
| 152 |
opts['rev'] = ['%s:%s' % (from_rev, to_rev)] |
| 153 |
opts['branch'] = [bra] |
| 154 |
return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts) |
| 155 |
|
| 156 |
def rhmanifest(ui, repo, path='', **opts): |
| 157 |
"""output the sub-manifest of the specified directory""" |
| 158 |
ui.write('<?xml version="1.0"?>\n')
|
| 159 |
ui.write('<rhmanifest>\n')
|
| 160 |
ui.write('<repository root="%s">\n' % _u(repo.root))
|
| 161 |
try: |
| 162 |
_manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
|
| 163 |
finally: |
| 164 |
ui.write('</repository>\n')
|
| 165 |
ui.write('</rhmanifest>\n')
|
| 166 |
|
| 167 |
def rhsummary(ui, repo, **opts): |
| 168 |
"""output the summary of the repository""" |
| 169 |
ui.write('<?xml version="1.0"?>\n')
|
| 170 |
ui.write('<rhsummary>\n')
|
| 171 |
ui.write('<repository root="%s">\n' % _u(repo.root))
|
| 172 |
try: |
| 173 |
_tip(ui, repo) |
| 174 |
_tags(ui, repo) |
| 175 |
_branches(ui, repo) |
| 176 |
# TODO: bookmarks in core (Mercurial>=1.8) |
| 177 |
finally: |
| 178 |
ui.write('</repository>\n')
|
| 179 |
ui.write('</rhsummary>\n')
|
| 180 |
|
| 181 |
# This extension should be compatible with Mercurial 0.9.5. |
| 182 |
# Note that Mercurial 0.9.5 doesn't have extensions.wrapfunction(). |
| 183 |
cmdtable = {
|
| 184 |
'rhannotate': (rhannotate, |
| 185 |
[('r', 'rev', '', 'revision'),
|
| 186 |
('u', 'user', None, 'list the author (long with -v)'),
|
| 187 |
('n', 'number', None, 'list the revision number (default)'),
|
| 188 |
('c', 'changeset', None, 'list the changeset'),
|
| 189 |
], |
| 190 |
'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'), |
| 191 |
'rhcat': (rhcat, |
| 192 |
[('r', 'rev', '', 'revision')],
|
| 193 |
'hg rhcat ([-r REV] ...) FILE...'), |
| 194 |
'rhdiff': (rhdiff, |
| 195 |
[('r', 'rev', [], 'revision'),
|
| 196 |
('c', 'change', '', 'change made by revision')],
|
| 197 |
'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'), |
| 198 |
'rhlog': (rhlog, |
| 199 |
[ |
| 200 |
('r', 'rev', [], 'show the specified revision'),
|
| 201 |
('b', 'branch', [],
|
| 202 |
'show changesets within the given named branch'), |
| 203 |
('l', 'limit', '',
|
| 204 |
'limit number of changes displayed'), |
| 205 |
('d', 'date', '',
|
| 206 |
'show revisions matching date spec'), |
| 207 |
('u', 'user', [],
|
| 208 |
'revisions committed by user'), |
| 209 |
('', 'from', '',
|
| 210 |
''), |
| 211 |
('', 'to', '',
|
| 212 |
''), |
| 213 |
('', 'rhbranch', '',
|
| 214 |
''), |
| 215 |
('', 'template', '',
|
| 216 |
'display with template')], |
| 217 |
'hg rhlog [OPTION]... [FILE]'), |
| 218 |
'rhmanifest': (rhmanifest, |
| 219 |
[('r', 'rev', '', 'show the specified revision')],
|
| 220 |
'hg rhmanifest [-r REV] [PATH]'), |
| 221 |
'rhsummary': (rhsummary, [], 'hg rhsummary'), |
| 222 |
} |