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