##// END OF EJS Templates
i18n, hgk: mark command line options for translation
Martin Geisler -
r7000:af694c6a default
parent child Browse files
Show More
@@ -1,356 +1,356
1 1 # Minimal support for git commands on an hg repository
2 2 #
3 3 # Copyright 2005, 2006 Chris Mason <mason@suse.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7 '''browsing the repository in a graphical way
8 8
9 9 The hgk extension allows browsing the history of a repository in a
10 10 graphical way. It requires Tcl/Tk version 8.4 or later. (Tcl/Tk is
11 11 not distributed with Mercurial.)
12 12
13 13 hgk consists of two parts: a Tcl script that does the displaying and
14 14 querying of information, and an extension to mercurial named hgk.py,
15 15 which provides hooks for hgk to get information. hgk can be found in
16 16 the contrib directory, and hgk.py can be found in the hgext directory.
17 17
18 18 To load the hgext.py extension, add it to your .hgrc file (you have
19 19 to use your global $HOME/.hgrc file, not one in a repository). You
20 20 can specify an absolute path:
21 21
22 22 [extensions]
23 23 hgk=/usr/local/lib/hgk.py
24 24
25 25 Mercurial can also scan the default python library path for a file
26 26 named 'hgk.py' if you set hgk empty:
27 27
28 28 [extensions]
29 29 hgk=
30 30
31 31 The hg view command will launch the hgk Tcl script. For this command
32 32 to work, hgk must be in your search path. Alternately, you can
33 33 specify the path to hgk in your .hgrc file:
34 34
35 35 [hgk]
36 36 path=/location/of/hgk
37 37
38 38 hgk can make use of the extdiff extension to visualize revisions.
39 39 Assuming you had already configured extdiff vdiff command, just add:
40 40
41 41 [hgk]
42 42 vdiff=vdiff
43 43
44 44 Revisions context menu will now display additional entries to fire
45 45 vdiff on hovered and selected revisions.'''
46 46
47 47 import os
48 48 from mercurial import commands, util, patch, revlog, cmdutil
49 49 from mercurial.node import nullid, nullrev, short
50 50 from mercurial.i18n import _
51 51
52 52 def difftree(ui, repo, node1=None, node2=None, *files, **opts):
53 53 """diff trees from two commits"""
54 54 def __difftree(repo, node1, node2, files=[]):
55 55 assert node2 is not None
56 56 mmap = repo[node1].manifest()
57 57 mmap2 = repo[node2].manifest()
58 58 m = cmdutil.match(repo, files)
59 59 modified, added, removed = repo.status(node1, node2, m)[:3]
60 60 empty = short(nullid)
61 61
62 62 for f in modified:
63 63 # TODO get file permissions
64 64 ui.write(":100664 100664 %s %s M\t%s\t%s\n" %
65 65 (short(mmap[f]), short(mmap2[f]), f, f))
66 66 for f in added:
67 67 ui.write(":000000 100664 %s %s N\t%s\t%s\n" %
68 68 (empty, short(mmap2[f]), f, f))
69 69 for f in removed:
70 70 ui.write(":100664 000000 %s %s D\t%s\t%s\n" %
71 71 (short(mmap[f]), empty, f, f))
72 72 ##
73 73
74 74 while True:
75 75 if opts['stdin']:
76 76 try:
77 77 line = raw_input().split(' ')
78 78 node1 = line[0]
79 79 if len(line) > 1:
80 80 node2 = line[1]
81 81 else:
82 82 node2 = None
83 83 except EOFError:
84 84 break
85 85 node1 = repo.lookup(node1)
86 86 if node2:
87 87 node2 = repo.lookup(node2)
88 88 else:
89 89 node2 = node1
90 90 node1 = repo.changelog.parents(node1)[0]
91 91 if opts['patch']:
92 92 if opts['pretty']:
93 93 catcommit(ui, repo, node2, "")
94 94 m = cmdutil.match(repo, files)
95 95 patch.diff(repo, node1, node2, match=m,
96 96 opts=patch.diffopts(ui, {'git': True}))
97 97 else:
98 98 __difftree(repo, node1, node2, files=files)
99 99 if not opts['stdin']:
100 100 break
101 101
102 102 def catcommit(ui, repo, n, prefix, ctx=None):
103 103 nlprefix = '\n' + prefix;
104 104 if ctx is None:
105 105 ctx = repo[n]
106 106 ui.write("tree %s\n" % short(ctx.changeset()[0])) # use ctx.node() instead ??
107 107 for p in ctx.parents():
108 108 ui.write("parent %s\n" % p)
109 109
110 110 date = ctx.date()
111 111 description = ctx.description().replace("\0", "")
112 112 lines = description.splitlines()
113 113 if lines and lines[-1].startswith('committer:'):
114 114 committer = lines[-1].split(': ')[1].rstrip()
115 115 else:
116 116 committer = ctx.user()
117 117
118 118 ui.write("author %s %s %s\n" % (ctx.user(), int(date[0]), date[1]))
119 119 ui.write("committer %s %s %s\n" % (committer, int(date[0]), date[1]))
120 120 ui.write("revision %d\n" % ctx.rev())
121 121 ui.write("branch %s\n\n" % ctx.branch())
122 122
123 123 if prefix != "":
124 124 ui.write("%s%s\n" % (prefix, description.replace('\n', nlprefix).strip()))
125 125 else:
126 126 ui.write(description + "\n")
127 127 if prefix:
128 128 ui.write('\0')
129 129
130 130 def base(ui, repo, node1, node2):
131 131 """Output common ancestor information"""
132 132 node1 = repo.lookup(node1)
133 133 node2 = repo.lookup(node2)
134 134 n = repo.changelog.ancestor(node1, node2)
135 135 ui.write(short(n) + "\n")
136 136
137 137 def catfile(ui, repo, type=None, r=None, **opts):
138 138 """cat a specific revision"""
139 139 # in stdin mode, every line except the commit is prefixed with two
140 140 # spaces. This way the our caller can find the commit without magic
141 141 # strings
142 142 #
143 143 prefix = ""
144 144 if opts['stdin']:
145 145 try:
146 146 (type, r) = raw_input().split(' ');
147 147 prefix = " "
148 148 except EOFError:
149 149 return
150 150
151 151 else:
152 152 if not type or not r:
153 153 ui.warn(_("cat-file: type or revision not supplied\n"))
154 154 commands.help_(ui, 'cat-file')
155 155
156 156 while r:
157 157 if type != "commit":
158 158 ui.warn(_("aborting hg cat-file only understands commits\n"))
159 159 return 1;
160 160 n = repo.lookup(r)
161 161 catcommit(ui, repo, n, prefix)
162 162 if opts['stdin']:
163 163 try:
164 164 (type, r) = raw_input().split(' ');
165 165 except EOFError:
166 166 break
167 167 else:
168 168 break
169 169
170 170 # git rev-tree is a confusing thing. You can supply a number of
171 171 # commit sha1s on the command line, and it walks the commit history
172 172 # telling you which commits are reachable from the supplied ones via
173 173 # a bitmask based on arg position.
174 174 # you can specify a commit to stop at by starting the sha1 with ^
175 175 def revtree(ui, args, repo, full="tree", maxnr=0, parents=False):
176 176 def chlogwalk():
177 177 count = len(repo)
178 178 i = count
179 179 l = [0] * 100
180 180 chunk = 100
181 181 while True:
182 182 if chunk > i:
183 183 chunk = i
184 184 i = 0
185 185 else:
186 186 i -= chunk
187 187
188 188 for x in xrange(0, chunk):
189 189 if i + x >= count:
190 190 l[chunk - x:] = [0] * (chunk - x)
191 191 break
192 192 if full != None:
193 193 l[x] = repo[i + x]
194 194 l[x].changeset() # force reading
195 195 else:
196 196 l[x] = 1
197 197 for x in xrange(chunk-1, -1, -1):
198 198 if l[x] != 0:
199 199 yield (i + x, full != None and l[x] or None)
200 200 if i == 0:
201 201 break
202 202
203 203 # calculate and return the reachability bitmask for sha
204 204 def is_reachable(ar, reachable, sha):
205 205 if len(ar) == 0:
206 206 return 1
207 207 mask = 0
208 208 for i in xrange(len(ar)):
209 209 if sha in reachable[i]:
210 210 mask |= 1 << i
211 211
212 212 return mask
213 213
214 214 reachable = []
215 215 stop_sha1 = []
216 216 want_sha1 = []
217 217 count = 0
218 218
219 219 # figure out which commits they are asking for and which ones they
220 220 # want us to stop on
221 221 for i in xrange(len(args)):
222 222 if args[i].startswith('^'):
223 223 s = repo.lookup(args[i][1:])
224 224 stop_sha1.append(s)
225 225 want_sha1.append(s)
226 226 elif args[i] != 'HEAD':
227 227 want_sha1.append(repo.lookup(args[i]))
228 228
229 229 # calculate the graph for the supplied commits
230 230 for i in xrange(len(want_sha1)):
231 231 reachable.append({});
232 232 n = want_sha1[i];
233 233 visit = [n];
234 234 reachable[i][n] = 1
235 235 while visit:
236 236 n = visit.pop(0)
237 237 if n in stop_sha1:
238 238 continue
239 239 for p in repo.changelog.parents(n):
240 240 if p not in reachable[i]:
241 241 reachable[i][p] = 1
242 242 visit.append(p)
243 243 if p in stop_sha1:
244 244 continue
245 245
246 246 # walk the repository looking for commits that are in our
247 247 # reachability graph
248 248 for i, ctx in chlogwalk():
249 249 n = repo.changelog.node(i)
250 250 mask = is_reachable(want_sha1, reachable, n)
251 251 if mask:
252 252 parentstr = ""
253 253 if parents:
254 254 pp = repo.changelog.parents(n)
255 255 if pp[0] != nullid:
256 256 parentstr += " " + short(pp[0])
257 257 if pp[1] != nullid:
258 258 parentstr += " " + short(pp[1])
259 259 if not full:
260 260 ui.write("%s%s\n" % (short(n), parentstr))
261 261 elif full == "commit":
262 262 ui.write("%s%s\n" % (short(n), parentstr))
263 263 catcommit(ui, repo, n, ' ', ctx)
264 264 else:
265 265 (p1, p2) = repo.changelog.parents(n)
266 266 (h, h1, h2) = map(short, (n, p1, p2))
267 267 (i1, i2) = map(repo.changelog.rev, (p1, p2))
268 268
269 269 date = ctx.date()[0]
270 270 ui.write("%s %s:%s" % (date, h, mask))
271 271 mask = is_reachable(want_sha1, reachable, p1)
272 272 if i1 != nullrev and mask > 0:
273 273 ui.write("%s:%s " % (h1, mask)),
274 274 mask = is_reachable(want_sha1, reachable, p2)
275 275 if i2 != nullrev and mask > 0:
276 276 ui.write("%s:%s " % (h2, mask))
277 277 ui.write("\n")
278 278 if maxnr and count >= maxnr:
279 279 break
280 280 count += 1
281 281
282 282 def revparse(ui, repo, *revs, **opts):
283 283 """Parse given revisions"""
284 284 def revstr(rev):
285 285 if rev == 'HEAD':
286 286 rev = 'tip'
287 287 return revlog.hex(repo.lookup(rev))
288 288
289 289 for r in revs:
290 290 revrange = r.split(':', 1)
291 291 ui.write('%s\n' % revstr(revrange[0]))
292 292 if len(revrange) == 2:
293 293 ui.write('^%s\n' % revstr(revrange[1]))
294 294
295 295 # git rev-list tries to order things by date, and has the ability to stop
296 296 # at a given commit without walking the whole repo. TODO add the stop
297 297 # parameter
298 298 def revlist(ui, repo, *revs, **opts):
299 299 """print revisions"""
300 300 if opts['header']:
301 301 full = "commit"
302 302 else:
303 303 full = None
304 304 copy = [x for x in revs]
305 305 revtree(ui, copy, repo, full, opts['max_count'], opts['parents'])
306 306
307 307 def config(ui, repo, **opts):
308 308 """print extension options"""
309 309 def writeopt(name, value):
310 310 ui.write('k=%s\nv=%s\n' % (name, value))
311 311
312 312 writeopt('vdiff', ui.config('hgk', 'vdiff', ''))
313 313
314 314
315 315 def view(ui, repo, *etc, **opts):
316 316 "start interactive history viewer"
317 317 os.chdir(repo.root)
318 318 optstr = ' '.join(['--%s %s' % (k, v) for k, v in opts.iteritems() if v])
319 319 cmd = ui.config("hgk", "path", "hgk") + " %s %s" % (optstr, " ".join(etc))
320 320 ui.debug(_("running %s\n") % cmd)
321 321 util.system(cmd)
322 322
323 323 cmdtable = {
324 324 "^view":
325 325 (view,
326 [('l', 'limit', '', 'limit number of changes displayed')],
327 'hg view [-l LIMIT] [REVRANGE]'),
326 [('l', 'limit', '', _('limit number of changes displayed'))],
327 _('hg view [-l LIMIT] [REVRANGE]')),
328 328 "debug-diff-tree":
329 329 (difftree,
330 [('p', 'patch', None, 'generate patch'),
331 ('r', 'recursive', None, 'recursive'),
332 ('P', 'pretty', None, 'pretty'),
333 ('s', 'stdin', None, 'stdin'),
334 ('C', 'copy', None, 'detect copies'),
335 ('S', 'search', "", 'search')],
336 'hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...'),
330 [('p', 'patch', None, _('generate patch')),
331 ('r', 'recursive', None, _('recursive')),
332 ('P', 'pretty', None, _('pretty')),
333 ('s', 'stdin', None, _('stdin')),
334 ('C', 'copy', None, _('detect copies')),
335 ('S', 'search', "", _('search'))],
336 _('hg git-diff-tree [OPTION]... NODE1 NODE2 [FILE]...')),
337 337 "debug-cat-file":
338 338 (catfile,
339 [('s', 'stdin', None, 'stdin')],
340 'hg debug-cat-file [OPTION]... TYPE FILE'),
339 [('s', 'stdin', None, _('stdin'))],
340 _('hg debug-cat-file [OPTION]... TYPE FILE')),
341 341 "debug-config":
342 (config, [], 'hg debug-config'),
342 (config, [], _('hg debug-config')),
343 343 "debug-merge-base":
344 (base, [], 'hg debug-merge-base node node'),
344 (base, [], _('hg debug-merge-base node node')),
345 345 "debug-rev-parse":
346 346 (revparse,
347 [('', 'default', '', 'ignored')],
348 'hg debug-rev-parse REV'),
347 [('', 'default', '', _('ignored'))],
348 _('hg debug-rev-parse REV')),
349 349 "debug-rev-list":
350 350 (revlist,
351 [('H', 'header', None, 'header'),
352 ('t', 'topo-order', None, 'topo-order'),
353 ('p', 'parents', None, 'parents'),
354 ('n', 'max-count', 0, 'max-count')],
355 'hg debug-rev-list [options] revs'),
351 [('H', 'header', None, _('header')),
352 ('t', 'topo-order', None, _('topo-order')),
353 ('p', 'parents', None, _('parents')),
354 ('n', 'max-count', 0, _('max-count'))],
355 _('hg debug-rev-list [options] revs')),
356 356 }
General Comments 0
You need to be logged in to leave comments. Login now