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