##// END OF EJS Templates
scm: mercurial: add new "rhlog()" function in helper extension (#7246, #4455)....
Toshi MARUYAMA -
r4981:2e2055c05114
parent child
Show More
@@ -1,183 +1,215
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
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 return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
123 return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
124
124
125 def rhcat(ui, repo, file1, *pats, **opts):
125 def rhcat(ui, repo, file1, *pats, **opts):
126 return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
126 return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
127
127
128 def rhdiff(ui, repo, *pats, **opts):
128 def rhdiff(ui, repo, *pats, **opts):
129 """diff repository (or selected files)"""
129 """diff repository (or selected files)"""
130 change = opts.pop('change', None)
130 change = opts.pop('change', None)
131 if change: # add -c option for Mercurial<1.1
131 if change: # add -c option for Mercurial<1.1
132 base = repo.changectx(change).parents()[0].rev()
132 base = repo.changectx(change).parents()[0].rev()
133 opts['rev'] = [str(base), change]
133 opts['rev'] = [str(base), change]
134 opts['nodates'] = True
134 opts['nodates'] = True
135 return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
135 return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
136
136
137 def rhlog(ui, repo, *pats, **opts):
138 rev = opts.pop('rev')
139 bra0 = opts.pop('branch')
140 from_rev = urllib.unquote_plus(opts.pop('from', None))
141 to_rev = urllib.unquote_plus(opts.pop('to' , None))
142 bra = urllib.unquote_plus(opts.pop('rhbranch', None))
143 from_rev = from_rev.replace('"', '\\"')
144 to_rev = to_rev.replace('"', '\\"')
145 opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
146 opts['branch'] = [bra]
147 return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
148
137 def rhmanifest(ui, repo, path='', **opts):
149 def rhmanifest(ui, repo, path='', **opts):
138 """output the sub-manifest of the specified directory"""
150 """output the sub-manifest of the specified directory"""
139 ui.write('<?xml version="1.0"?>\n')
151 ui.write('<?xml version="1.0"?>\n')
140 ui.write('<rhmanifest>\n')
152 ui.write('<rhmanifest>\n')
141 ui.write('<repository root="%s">\n' % _u(repo.root))
153 ui.write('<repository root="%s">\n' % _u(repo.root))
142 try:
154 try:
143 _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
155 _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
144 finally:
156 finally:
145 ui.write('</repository>\n')
157 ui.write('</repository>\n')
146 ui.write('</rhmanifest>\n')
158 ui.write('</rhmanifest>\n')
147
159
148 def rhsummary(ui, repo, **opts):
160 def rhsummary(ui, repo, **opts):
149 """output the summary of the repository"""
161 """output the summary of the repository"""
150 ui.write('<?xml version="1.0"?>\n')
162 ui.write('<?xml version="1.0"?>\n')
151 ui.write('<rhsummary>\n')
163 ui.write('<rhsummary>\n')
152 ui.write('<repository root="%s">\n' % _u(repo.root))
164 ui.write('<repository root="%s">\n' % _u(repo.root))
153 try:
165 try:
154 _tip(ui, repo)
166 _tip(ui, repo)
155 _tags(ui, repo)
167 _tags(ui, repo)
156 _branches(ui, repo)
168 _branches(ui, repo)
157 # TODO: bookmarks in core (Mercurial>=1.8)
169 # TODO: bookmarks in core (Mercurial>=1.8)
158 finally:
170 finally:
159 ui.write('</repository>\n')
171 ui.write('</repository>\n')
160 ui.write('</rhsummary>\n')
172 ui.write('</rhsummary>\n')
161
173
162 # This extension should be compatible with Mercurial 0.9.5.
174 # This extension should be compatible with Mercurial 0.9.5.
163 # Note that Mercurial 0.9.5 doesn't have extensions.wrapfunction().
175 # Note that Mercurial 0.9.5 doesn't have extensions.wrapfunction().
164 cmdtable = {
176 cmdtable = {
165 'rhannotate': (rhannotate,
177 'rhannotate': (rhannotate,
166 [('r', 'rev', '', 'revision'),
178 [('r', 'rev', '', 'revision'),
167 ('u', 'user', None, 'list the author (long with -v)'),
179 ('u', 'user', None, 'list the author (long with -v)'),
168 ('n', 'number', None, 'list the revision number (default)'),
180 ('n', 'number', None, 'list the revision number (default)'),
169 ('c', 'changeset', None, 'list the changeset'),
181 ('c', 'changeset', None, 'list the changeset'),
170 ],
182 ],
171 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
183 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
172 'rhcat': (rhcat,
184 'rhcat': (rhcat,
173 [('r', 'rev', '', 'revision')],
185 [('r', 'rev', '', 'revision')],
174 'hg rhcat ([-r REV] ...) FILE...'),
186 'hg rhcat ([-r REV] ...) FILE...'),
175 'rhdiff': (rhdiff,
187 'rhdiff': (rhdiff,
176 [('r', 'rev', [], 'revision'),
188 [('r', 'rev', [], 'revision'),
177 ('c', 'change', '', 'change made by revision')],
189 ('c', 'change', '', 'change made by revision')],
178 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
190 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
191 'rhlog': (rhlog,
192 [
193 ('r', 'rev', [], 'show the specified revision'),
194 ('b', 'branch', [],
195 'show changesets within the given named branch', 'BRANCH'),
196 ('l', 'limit', '',
197 'limit number of changes displayed', 'NUM'),
198 ('d', 'date', '',
199 'show revisions matching date spec', 'DATE'),
200 ('u', 'user', [],
201 'revisions committed by user', 'USER'),
202 ('', 'from', '',
203 '', ''),
204 ('', 'to', '',
205 '', ''),
206 ('', 'rhbranch', '',
207 '', ''),
208 ('', 'template', '',
209 'display with template', 'TEMPLATE')],
210 'hg rhlog [OPTION]... [FILE]'),
179 'rhmanifest': (rhmanifest,
211 'rhmanifest': (rhmanifest,
180 [('r', 'rev', '', 'show the specified revision')],
212 [('r', 'rev', '', 'show the specified revision')],
181 'hg rhmanifest [-r REV] [PATH]'),
213 'hg rhmanifest [-r REV] [PATH]'),
182 'rhsummary': (rhsummary, [], 'hg rhsummary'),
214 'rhsummary': (rhsummary, [], 'hg rhsummary'),
183 }
215 }
General Comments 0
You need to be logged in to leave comments. Login now