##// END OF EJS Templates
use Python getattr instead of hasattr (#16177)...
Toshi MARUYAMA -
r12660:0cf7a27b503d
parent child
Show More
@@ -1,225 +1,225
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: hex string
19 :node: 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, hg
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.hex(tipctx.node()))))
63 % (tipctx.rev(), _x(node.hex(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.hex(n)), _x(t)))
77 % (r, _x(node.hex(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 if hasattr(repo, 'branchtags'):
82 if getattr(repo, 'branchtags', None) is not None:
83 # Mercurial < 2.9
83 # Mercurial < 2.9
84 for t, n in repo.branchtags().iteritems():
84 for t, n in repo.branchtags().iteritems():
85 yield t, n, repo.changelog.rev(n)
85 yield t, n, repo.changelog.rev(n)
86 else:
86 else:
87 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
87 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
88 yield tag, tip, repo.changelog.rev(tip)
88 yield tag, tip, repo.changelog.rev(tip)
89 def branchheads(branch):
89 def branchheads(branch):
90 try:
90 try:
91 return repo.branchheads(branch, closed=False)
91 return repo.branchheads(branch, closed=False)
92 except TypeError: # Mercurial < 1.2
92 except TypeError: # Mercurial < 1.2
93 return repo.branchheads(branch)
93 return repo.branchheads(branch)
94 for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
94 for t, n, r in sorted(iterbranches(), key=lambda e: e[2], reverse=True):
95 if repo.lookup(r) in branchheads(t):
95 if repo.lookup(r) in branchheads(t):
96 ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
96 ui.write('<branch revision="%d" node="%s" name="%s"/>\n'
97 % (r, _x(node.hex(n)), _x(t)))
97 % (r, _x(node.hex(n)), _x(t)))
98
98
99 def _manifest(ui, repo, path, rev):
99 def _manifest(ui, repo, path, rev):
100 ctx = repo.changectx(rev)
100 ctx = repo.changectx(rev)
101 ui.write('<manifest revision="%d" path="%s">\n'
101 ui.write('<manifest revision="%d" path="%s">\n'
102 % (ctx.rev(), _u(path)))
102 % (ctx.rev(), _u(path)))
103
103
104 known = set()
104 known = set()
105 pathprefix = (path.rstrip('/') + '/').lstrip('/')
105 pathprefix = (path.rstrip('/') + '/').lstrip('/')
106 for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
106 for f, n in sorted(ctx.manifest().iteritems(), key=lambda e: e[0]):
107 if not f.startswith(pathprefix):
107 if not f.startswith(pathprefix):
108 continue
108 continue
109 name = re.sub(r'/.*', '/', f[len(pathprefix):])
109 name = re.sub(r'/.*', '/', f[len(pathprefix):])
110 if name in known:
110 if name in known:
111 continue
111 continue
112 known.add(name)
112 known.add(name)
113
113
114 if name.endswith('/'):
114 if name.endswith('/'):
115 ui.write('<dir name="%s"/>\n'
115 ui.write('<dir name="%s"/>\n'
116 % _x(urllib.quote(name[:-1])))
116 % _x(urllib.quote(name[:-1])))
117 else:
117 else:
118 fctx = repo.filectx(f, fileid=n)
118 fctx = repo.filectx(f, fileid=n)
119 tm, tzoffset = fctx.date()
119 tm, tzoffset = fctx.date()
120 ui.write('<file name="%s" revision="%d" node="%s" '
120 ui.write('<file name="%s" revision="%d" node="%s" '
121 'time="%d" size="%d"/>\n'
121 'time="%d" size="%d"/>\n'
122 % (_u(name), fctx.rev(), _x(node.hex(fctx.node())),
122 % (_u(name), fctx.rev(), _x(node.hex(fctx.node())),
123 tm, fctx.size(), ))
123 tm, fctx.size(), ))
124
124
125 ui.write('</manifest>\n')
125 ui.write('</manifest>\n')
126
126
127 def rhannotate(ui, repo, *pats, **opts):
127 def rhannotate(ui, repo, *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.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
130 return commands.annotate(ui, repo, *map(urllib.unquote_plus, pats), **opts)
131
131
132 def rhcat(ui, repo, file1, *pats, **opts):
132 def rhcat(ui, repo, file1, *pats, **opts):
133 rev = urllib.unquote_plus(opts.pop('rev', None))
133 rev = urllib.unquote_plus(opts.pop('rev', None))
134 opts['rev'] = rev
134 opts['rev'] = rev
135 return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
135 return commands.cat(ui, repo, urllib.unquote_plus(file1), *map(urllib.unquote_plus, pats), **opts)
136
136
137 def rhdiff(ui, repo, *pats, **opts):
137 def rhdiff(ui, repo, *pats, **opts):
138 """diff repository (or selected files)"""
138 """diff repository (or selected files)"""
139 change = opts.pop('change', None)
139 change = opts.pop('change', None)
140 if change: # add -c option for Mercurial<1.1
140 if change: # add -c option for Mercurial<1.1
141 base = repo.changectx(change).parents()[0].rev()
141 base = repo.changectx(change).parents()[0].rev()
142 opts['rev'] = [str(base), change]
142 opts['rev'] = [str(base), change]
143 opts['nodates'] = True
143 opts['nodates'] = True
144 return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
144 return commands.diff(ui, repo, *map(urllib.unquote_plus, pats), **opts)
145
145
146 def rhlog(ui, repo, *pats, **opts):
146 def rhlog(ui, repo, *pats, **opts):
147 rev = opts.pop('rev')
147 rev = opts.pop('rev')
148 bra0 = opts.pop('branch')
148 bra0 = opts.pop('branch')
149 from_rev = urllib.unquote_plus(opts.pop('from', None))
149 from_rev = urllib.unquote_plus(opts.pop('from', None))
150 to_rev = urllib.unquote_plus(opts.pop('to' , None))
150 to_rev = urllib.unquote_plus(opts.pop('to' , None))
151 bra = urllib.unquote_plus(opts.pop('rhbranch', None))
151 bra = urllib.unquote_plus(opts.pop('rhbranch', None))
152 from_rev = from_rev.replace('"', '\\"')
152 from_rev = from_rev.replace('"', '\\"')
153 to_rev = to_rev.replace('"', '\\"')
153 to_rev = to_rev.replace('"', '\\"')
154 if hg.util.version() >= '1.6':
154 if hg.util.version() >= '1.6':
155 opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
155 opts['rev'] = ['"%s":"%s"' % (from_rev, to_rev)]
156 else:
156 else:
157 opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
157 opts['rev'] = ['%s:%s' % (from_rev, to_rev)]
158 opts['branch'] = [bra]
158 opts['branch'] = [bra]
159 return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
159 return commands.log(ui, repo, *map(urllib.unquote_plus, pats), **opts)
160
160
161 def rhmanifest(ui, repo, path='', **opts):
161 def rhmanifest(ui, repo, path='', **opts):
162 """output the sub-manifest of the specified directory"""
162 """output the sub-manifest of the specified directory"""
163 ui.write('<?xml version="1.0"?>\n')
163 ui.write('<?xml version="1.0"?>\n')
164 ui.write('<rhmanifest>\n')
164 ui.write('<rhmanifest>\n')
165 ui.write('<repository root="%s">\n' % _u(repo.root))
165 ui.write('<repository root="%s">\n' % _u(repo.root))
166 try:
166 try:
167 _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
167 _manifest(ui, repo, urllib.unquote_plus(path), urllib.unquote_plus(opts.get('rev')))
168 finally:
168 finally:
169 ui.write('</repository>\n')
169 ui.write('</repository>\n')
170 ui.write('</rhmanifest>\n')
170 ui.write('</rhmanifest>\n')
171
171
172 def rhsummary(ui, repo, **opts):
172 def rhsummary(ui, repo, **opts):
173 """output the summary of the repository"""
173 """output the summary of the repository"""
174 ui.write('<?xml version="1.0"?>\n')
174 ui.write('<?xml version="1.0"?>\n')
175 ui.write('<rhsummary>\n')
175 ui.write('<rhsummary>\n')
176 ui.write('<repository root="%s">\n' % _u(repo.root))
176 ui.write('<repository root="%s">\n' % _u(repo.root))
177 try:
177 try:
178 _tip(ui, repo)
178 _tip(ui, repo)
179 _tags(ui, repo)
179 _tags(ui, repo)
180 _branches(ui, repo)
180 _branches(ui, repo)
181 # TODO: bookmarks in core (Mercurial>=1.8)
181 # TODO: bookmarks in core (Mercurial>=1.8)
182 finally:
182 finally:
183 ui.write('</repository>\n')
183 ui.write('</repository>\n')
184 ui.write('</rhsummary>\n')
184 ui.write('</rhsummary>\n')
185
185
186 cmdtable = {
186 cmdtable = {
187 'rhannotate': (rhannotate,
187 'rhannotate': (rhannotate,
188 [('r', 'rev', '', 'revision'),
188 [('r', 'rev', '', 'revision'),
189 ('u', 'user', None, 'list the author (long with -v)'),
189 ('u', 'user', None, 'list the author (long with -v)'),
190 ('n', 'number', None, 'list the revision number (default)'),
190 ('n', 'number', None, 'list the revision number (default)'),
191 ('c', 'changeset', None, 'list the changeset'),
191 ('c', 'changeset', None, 'list the changeset'),
192 ],
192 ],
193 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
193 'hg rhannotate [-r REV] [-u] [-n] [-c] FILE...'),
194 'rhcat': (rhcat,
194 'rhcat': (rhcat,
195 [('r', 'rev', '', 'revision')],
195 [('r', 'rev', '', 'revision')],
196 'hg rhcat ([-r REV] ...) FILE...'),
196 'hg rhcat ([-r REV] ...) FILE...'),
197 'rhdiff': (rhdiff,
197 'rhdiff': (rhdiff,
198 [('r', 'rev', [], 'revision'),
198 [('r', 'rev', [], 'revision'),
199 ('c', 'change', '', 'change made by revision')],
199 ('c', 'change', '', 'change made by revision')],
200 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
200 'hg rhdiff ([-c REV] | [-r REV] ...) [FILE]...'),
201 'rhlog': (rhlog,
201 'rhlog': (rhlog,
202 [
202 [
203 ('r', 'rev', [], 'show the specified revision'),
203 ('r', 'rev', [], 'show the specified revision'),
204 ('b', 'branch', [],
204 ('b', 'branch', [],
205 'show changesets within the given named branch'),
205 'show changesets within the given named branch'),
206 ('l', 'limit', '',
206 ('l', 'limit', '',
207 'limit number of changes displayed'),
207 'limit number of changes displayed'),
208 ('d', 'date', '',
208 ('d', 'date', '',
209 'show revisions matching date spec'),
209 'show revisions matching date spec'),
210 ('u', 'user', [],
210 ('u', 'user', [],
211 'revisions committed by user'),
211 'revisions committed by user'),
212 ('', 'from', '',
212 ('', 'from', '',
213 ''),
213 ''),
214 ('', 'to', '',
214 ('', 'to', '',
215 ''),
215 ''),
216 ('', 'rhbranch', '',
216 ('', 'rhbranch', '',
217 ''),
217 ''),
218 ('', 'template', '',
218 ('', 'template', '',
219 'display with template')],
219 'display with template')],
220 'hg rhlog [OPTION]... [FILE]'),
220 'hg rhlog [OPTION]... [FILE]'),
221 'rhmanifest': (rhmanifest,
221 'rhmanifest': (rhmanifest,
222 [('r', 'rev', '', 'show the specified revision')],
222 [('r', 'rev', '', 'show the specified revision')],
223 'hg rhmanifest [-r REV] [PATH]'),
223 'hg rhmanifest [-r REV] [PATH]'),
224 'rhsummary': (rhsummary, [], 'hg rhsummary'),
224 'rhsummary': (rhsummary, [], 'hg rhsummary'),
225 }
225 }
General Comments 0
You need to be logged in to leave comments. Login now