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