##// END OF EJS Templates
py3: format revision number as '%d' in debugrevspec...
Yuya Nishihara -
r35920:2da4144e default
parent child Browse files
Show More
@@ -1,2478 +1,2478 b''
1 1 # debugcommands.py - command processing for debug* commands
2 2 #
3 3 # Copyright 2005-2016 Matt Mackall <mpm@selenic.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 from __future__ import absolute_import
9 9
10 10 import codecs
11 11 import collections
12 12 import difflib
13 13 import errno
14 14 import operator
15 15 import os
16 16 import random
17 17 import socket
18 18 import ssl
19 19 import string
20 20 import sys
21 21 import tempfile
22 22 import time
23 23
24 24 from .i18n import _
25 25 from .node import (
26 26 bin,
27 27 hex,
28 28 nullhex,
29 29 nullid,
30 30 nullrev,
31 31 short,
32 32 )
33 33 from . import (
34 34 bundle2,
35 35 changegroup,
36 36 cmdutil,
37 37 color,
38 38 context,
39 39 dagparser,
40 40 dagutil,
41 41 encoding,
42 42 error,
43 43 exchange,
44 44 extensions,
45 45 filemerge,
46 46 fileset,
47 47 formatter,
48 48 hg,
49 49 localrepo,
50 50 lock as lockmod,
51 51 logcmdutil,
52 52 merge as mergemod,
53 53 obsolete,
54 54 obsutil,
55 55 phases,
56 56 policy,
57 57 pvec,
58 58 pycompat,
59 59 registrar,
60 60 repair,
61 61 revlog,
62 62 revset,
63 63 revsetlang,
64 64 scmutil,
65 65 setdiscovery,
66 66 simplemerge,
67 67 smartset,
68 68 sslutil,
69 69 streamclone,
70 70 templater,
71 71 treediscovery,
72 72 upgrade,
73 73 url as urlmod,
74 74 util,
75 75 vfs as vfsmod,
76 76 )
77 77
78 78 release = lockmod.release
79 79
80 80 command = registrar.command()
81 81
82 82 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
83 83 def debugancestor(ui, repo, *args):
84 84 """find the ancestor revision of two revisions in a given index"""
85 85 if len(args) == 3:
86 86 index, rev1, rev2 = args
87 87 r = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False), index)
88 88 lookup = r.lookup
89 89 elif len(args) == 2:
90 90 if not repo:
91 91 raise error.Abort(_('there is no Mercurial repository here '
92 92 '(.hg not found)'))
93 93 rev1, rev2 = args
94 94 r = repo.changelog
95 95 lookup = repo.lookup
96 96 else:
97 97 raise error.Abort(_('either two or three arguments required'))
98 98 a = r.ancestor(lookup(rev1), lookup(rev2))
99 99 ui.write('%d:%s\n' % (r.rev(a), hex(a)))
100 100
101 101 @command('debugapplystreamclonebundle', [], 'FILE')
102 102 def debugapplystreamclonebundle(ui, repo, fname):
103 103 """apply a stream clone bundle file"""
104 104 f = hg.openpath(ui, fname)
105 105 gen = exchange.readbundle(ui, f, fname)
106 106 gen.apply(repo)
107 107
108 108 @command('debugbuilddag',
109 109 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
110 110 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
111 111 ('n', 'new-file', None, _('add new file at each rev'))],
112 112 _('[OPTION]... [TEXT]'))
113 113 def debugbuilddag(ui, repo, text=None,
114 114 mergeable_file=False,
115 115 overwritten_file=False,
116 116 new_file=False):
117 117 """builds a repo with a given DAG from scratch in the current empty repo
118 118
119 119 The description of the DAG is read from stdin if not given on the
120 120 command line.
121 121
122 122 Elements:
123 123
124 124 - "+n" is a linear run of n nodes based on the current default parent
125 125 - "." is a single node based on the current default parent
126 126 - "$" resets the default parent to null (implied at the start);
127 127 otherwise the default parent is always the last node created
128 128 - "<p" sets the default parent to the backref p
129 129 - "*p" is a fork at parent p, which is a backref
130 130 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
131 131 - "/p2" is a merge of the preceding node and p2
132 132 - ":tag" defines a local tag for the preceding node
133 133 - "@branch" sets the named branch for subsequent nodes
134 134 - "#...\\n" is a comment up to the end of the line
135 135
136 136 Whitespace between the above elements is ignored.
137 137
138 138 A backref is either
139 139
140 140 - a number n, which references the node curr-n, where curr is the current
141 141 node, or
142 142 - the name of a local tag you placed earlier using ":tag", or
143 143 - empty to denote the default parent.
144 144
145 145 All string valued-elements are either strictly alphanumeric, or must
146 146 be enclosed in double quotes ("..."), with "\\" as escape character.
147 147 """
148 148
149 149 if text is None:
150 150 ui.status(_("reading DAG from stdin\n"))
151 151 text = ui.fin.read()
152 152
153 153 cl = repo.changelog
154 154 if len(cl) > 0:
155 155 raise error.Abort(_('repository is not empty'))
156 156
157 157 # determine number of revs in DAG
158 158 total = 0
159 159 for type, data in dagparser.parsedag(text):
160 160 if type == 'n':
161 161 total += 1
162 162
163 163 if mergeable_file:
164 164 linesperrev = 2
165 165 # make a file with k lines per rev
166 166 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
167 167 initialmergedlines.append("")
168 168
169 169 tags = []
170 170
171 171 wlock = lock = tr = None
172 172 try:
173 173 wlock = repo.wlock()
174 174 lock = repo.lock()
175 175 tr = repo.transaction("builddag")
176 176
177 177 at = -1
178 178 atbranch = 'default'
179 179 nodeids = []
180 180 id = 0
181 181 ui.progress(_('building'), id, unit=_('revisions'), total=total)
182 182 for type, data in dagparser.parsedag(text):
183 183 if type == 'n':
184 184 ui.note(('node %s\n' % pycompat.bytestr(data)))
185 185 id, ps = data
186 186
187 187 files = []
188 188 filecontent = {}
189 189
190 190 p2 = None
191 191 if mergeable_file:
192 192 fn = "mf"
193 193 p1 = repo[ps[0]]
194 194 if len(ps) > 1:
195 195 p2 = repo[ps[1]]
196 196 pa = p1.ancestor(p2)
197 197 base, local, other = [x[fn].data() for x in (pa, p1,
198 198 p2)]
199 199 m3 = simplemerge.Merge3Text(base, local, other)
200 200 ml = [l.strip() for l in m3.merge_lines()]
201 201 ml.append("")
202 202 elif at > 0:
203 203 ml = p1[fn].data().split("\n")
204 204 else:
205 205 ml = initialmergedlines
206 206 ml[id * linesperrev] += " r%i" % id
207 207 mergedtext = "\n".join(ml)
208 208 files.append(fn)
209 209 filecontent[fn] = mergedtext
210 210
211 211 if overwritten_file:
212 212 fn = "of"
213 213 files.append(fn)
214 214 filecontent[fn] = "r%i\n" % id
215 215
216 216 if new_file:
217 217 fn = "nf%i" % id
218 218 files.append(fn)
219 219 filecontent[fn] = "r%i\n" % id
220 220 if len(ps) > 1:
221 221 if not p2:
222 222 p2 = repo[ps[1]]
223 223 for fn in p2:
224 224 if fn.startswith("nf"):
225 225 files.append(fn)
226 226 filecontent[fn] = p2[fn].data()
227 227
228 228 def fctxfn(repo, cx, path):
229 229 if path in filecontent:
230 230 return context.memfilectx(repo, cx, path,
231 231 filecontent[path])
232 232 return None
233 233
234 234 if len(ps) == 0 or ps[0] < 0:
235 235 pars = [None, None]
236 236 elif len(ps) == 1:
237 237 pars = [nodeids[ps[0]], None]
238 238 else:
239 239 pars = [nodeids[p] for p in ps]
240 240 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
241 241 date=(id, 0),
242 242 user="debugbuilddag",
243 243 extra={'branch': atbranch})
244 244 nodeid = repo.commitctx(cx)
245 245 nodeids.append(nodeid)
246 246 at = id
247 247 elif type == 'l':
248 248 id, name = data
249 249 ui.note(('tag %s\n' % name))
250 250 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
251 251 elif type == 'a':
252 252 ui.note(('branch %s\n' % data))
253 253 atbranch = data
254 254 ui.progress(_('building'), id, unit=_('revisions'), total=total)
255 255 tr.close()
256 256
257 257 if tags:
258 258 repo.vfs.write("localtags", "".join(tags))
259 259 finally:
260 260 ui.progress(_('building'), None)
261 261 release(tr, lock, wlock)
262 262
263 263 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
264 264 indent_string = ' ' * indent
265 265 if all:
266 266 ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
267 267 % indent_string)
268 268
269 269 def showchunks(named):
270 270 ui.write("\n%s%s\n" % (indent_string, named))
271 271 for deltadata in gen.deltaiter():
272 272 node, p1, p2, cs, deltabase, delta, flags = deltadata
273 273 ui.write("%s%s %s %s %s %s %s\n" %
274 274 (indent_string, hex(node), hex(p1), hex(p2),
275 275 hex(cs), hex(deltabase), len(delta)))
276 276
277 277 chunkdata = gen.changelogheader()
278 278 showchunks("changelog")
279 279 chunkdata = gen.manifestheader()
280 280 showchunks("manifest")
281 281 for chunkdata in iter(gen.filelogheader, {}):
282 282 fname = chunkdata['filename']
283 283 showchunks(fname)
284 284 else:
285 285 if isinstance(gen, bundle2.unbundle20):
286 286 raise error.Abort(_('use debugbundle2 for this file'))
287 287 chunkdata = gen.changelogheader()
288 288 for deltadata in gen.deltaiter():
289 289 node, p1, p2, cs, deltabase, delta, flags = deltadata
290 290 ui.write("%s%s\n" % (indent_string, hex(node)))
291 291
292 292 def _debugobsmarkers(ui, part, indent=0, **opts):
293 293 """display version and markers contained in 'data'"""
294 294 opts = pycompat.byteskwargs(opts)
295 295 data = part.read()
296 296 indent_string = ' ' * indent
297 297 try:
298 298 version, markers = obsolete._readmarkers(data)
299 299 except error.UnknownVersion as exc:
300 300 msg = "%sunsupported version: %s (%d bytes)\n"
301 301 msg %= indent_string, exc.version, len(data)
302 302 ui.write(msg)
303 303 else:
304 304 msg = "%sversion: %d (%d bytes)\n"
305 305 msg %= indent_string, version, len(data)
306 306 ui.write(msg)
307 307 fm = ui.formatter('debugobsolete', opts)
308 308 for rawmarker in sorted(markers):
309 309 m = obsutil.marker(None, rawmarker)
310 310 fm.startitem()
311 311 fm.plain(indent_string)
312 312 cmdutil.showmarker(fm, m)
313 313 fm.end()
314 314
315 315 def _debugphaseheads(ui, data, indent=0):
316 316 """display version and markers contained in 'data'"""
317 317 indent_string = ' ' * indent
318 318 headsbyphase = phases.binarydecode(data)
319 319 for phase in phases.allphases:
320 320 for head in headsbyphase[phase]:
321 321 ui.write(indent_string)
322 322 ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
323 323
324 324 def _quasirepr(thing):
325 325 if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
326 326 return '{%s}' % (
327 327 b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
328 328 return pycompat.bytestr(repr(thing))
329 329
330 330 def _debugbundle2(ui, gen, all=None, **opts):
331 331 """lists the contents of a bundle2"""
332 332 if not isinstance(gen, bundle2.unbundle20):
333 333 raise error.Abort(_('not a bundle2 file'))
334 334 ui.write(('Stream params: %s\n' % _quasirepr(gen.params)))
335 335 parttypes = opts.get(r'part_type', [])
336 336 for part in gen.iterparts():
337 337 if parttypes and part.type not in parttypes:
338 338 continue
339 339 ui.write('%s -- %s\n' % (part.type, _quasirepr(part.params)))
340 340 if part.type == 'changegroup':
341 341 version = part.params.get('version', '01')
342 342 cg = changegroup.getunbundler(version, part, 'UN')
343 343 _debugchangegroup(ui, cg, all=all, indent=4, **opts)
344 344 if part.type == 'obsmarkers':
345 345 _debugobsmarkers(ui, part, indent=4, **opts)
346 346 if part.type == 'phase-heads':
347 347 _debugphaseheads(ui, part, indent=4)
348 348
349 349 @command('debugbundle',
350 350 [('a', 'all', None, _('show all details')),
351 351 ('', 'part-type', [], _('show only the named part type')),
352 352 ('', 'spec', None, _('print the bundlespec of the bundle'))],
353 353 _('FILE'),
354 354 norepo=True)
355 355 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
356 356 """lists the contents of a bundle"""
357 357 with hg.openpath(ui, bundlepath) as f:
358 358 if spec:
359 359 spec = exchange.getbundlespec(ui, f)
360 360 ui.write('%s\n' % spec)
361 361 return
362 362
363 363 gen = exchange.readbundle(ui, f, bundlepath)
364 364 if isinstance(gen, bundle2.unbundle20):
365 365 return _debugbundle2(ui, gen, all=all, **opts)
366 366 _debugchangegroup(ui, gen, all=all, **opts)
367 367
368 368 @command('debugcapabilities',
369 369 [], _('PATH'),
370 370 norepo=True)
371 371 def debugcapabilities(ui, path, **opts):
372 372 """lists the capabilities of a remote peer"""
373 373 opts = pycompat.byteskwargs(opts)
374 374 peer = hg.peer(ui, opts, path)
375 375 caps = peer.capabilities()
376 376 ui.write(('Main capabilities:\n'))
377 377 for c in sorted(caps):
378 378 ui.write((' %s\n') % c)
379 379 b2caps = bundle2.bundle2caps(peer)
380 380 if b2caps:
381 381 ui.write(('Bundle2 capabilities:\n'))
382 382 for key, values in sorted(b2caps.iteritems()):
383 383 ui.write((' %s\n') % key)
384 384 for v in values:
385 385 ui.write((' %s\n') % v)
386 386
387 387 @command('debugcheckstate', [], '')
388 388 def debugcheckstate(ui, repo):
389 389 """validate the correctness of the current dirstate"""
390 390 parent1, parent2 = repo.dirstate.parents()
391 391 m1 = repo[parent1].manifest()
392 392 m2 = repo[parent2].manifest()
393 393 errors = 0
394 394 for f in repo.dirstate:
395 395 state = repo.dirstate[f]
396 396 if state in "nr" and f not in m1:
397 397 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
398 398 errors += 1
399 399 if state in "a" and f in m1:
400 400 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
401 401 errors += 1
402 402 if state in "m" and f not in m1 and f not in m2:
403 403 ui.warn(_("%s in state %s, but not in either manifest\n") %
404 404 (f, state))
405 405 errors += 1
406 406 for f in m1:
407 407 state = repo.dirstate[f]
408 408 if state not in "nrm":
409 409 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
410 410 errors += 1
411 411 if errors:
412 412 error = _(".hg/dirstate inconsistent with current parent's manifest")
413 413 raise error.Abort(error)
414 414
415 415 @command('debugcolor',
416 416 [('', 'style', None, _('show all configured styles'))],
417 417 'hg debugcolor')
418 418 def debugcolor(ui, repo, **opts):
419 419 """show available color, effects or style"""
420 420 ui.write(('color mode: %s\n') % ui._colormode)
421 421 if opts.get(r'style'):
422 422 return _debugdisplaystyle(ui)
423 423 else:
424 424 return _debugdisplaycolor(ui)
425 425
426 426 def _debugdisplaycolor(ui):
427 427 ui = ui.copy()
428 428 ui._styles.clear()
429 429 for effect in color._activeeffects(ui).keys():
430 430 ui._styles[effect] = effect
431 431 if ui._terminfoparams:
432 432 for k, v in ui.configitems('color'):
433 433 if k.startswith('color.'):
434 434 ui._styles[k] = k[6:]
435 435 elif k.startswith('terminfo.'):
436 436 ui._styles[k] = k[9:]
437 437 ui.write(_('available colors:\n'))
438 438 # sort label with a '_' after the other to group '_background' entry.
439 439 items = sorted(ui._styles.items(),
440 440 key=lambda i: ('_' in i[0], i[0], i[1]))
441 441 for colorname, label in items:
442 442 ui.write(('%s\n') % colorname, label=label)
443 443
444 444 def _debugdisplaystyle(ui):
445 445 ui.write(_('available style:\n'))
446 446 width = max(len(s) for s in ui._styles)
447 447 for label, effects in sorted(ui._styles.items()):
448 448 ui.write('%s' % label, label=label)
449 449 if effects:
450 450 # 50
451 451 ui.write(': ')
452 452 ui.write(' ' * (max(0, width - len(label))))
453 453 ui.write(', '.join(ui.label(e, e) for e in effects.split()))
454 454 ui.write('\n')
455 455
456 456 @command('debugcreatestreamclonebundle', [], 'FILE')
457 457 def debugcreatestreamclonebundle(ui, repo, fname):
458 458 """create a stream clone bundle file
459 459
460 460 Stream bundles are special bundles that are essentially archives of
461 461 revlog files. They are commonly used for cloning very quickly.
462 462 """
463 463 # TODO we may want to turn this into an abort when this functionality
464 464 # is moved into `hg bundle`.
465 465 if phases.hassecret(repo):
466 466 ui.warn(_('(warning: stream clone bundle will contain secret '
467 467 'revisions)\n'))
468 468
469 469 requirements, gen = streamclone.generatebundlev1(repo)
470 470 changegroup.writechunks(ui, gen, fname)
471 471
472 472 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
473 473
474 474 @command('debugdag',
475 475 [('t', 'tags', None, _('use tags as labels')),
476 476 ('b', 'branches', None, _('annotate with branch names')),
477 477 ('', 'dots', None, _('use dots for runs')),
478 478 ('s', 'spaces', None, _('separate elements by spaces'))],
479 479 _('[OPTION]... [FILE [REV]...]'),
480 480 optionalrepo=True)
481 481 def debugdag(ui, repo, file_=None, *revs, **opts):
482 482 """format the changelog or an index DAG as a concise textual description
483 483
484 484 If you pass a revlog index, the revlog's DAG is emitted. If you list
485 485 revision numbers, they get labeled in the output as rN.
486 486
487 487 Otherwise, the changelog DAG of the current repo is emitted.
488 488 """
489 489 spaces = opts.get(r'spaces')
490 490 dots = opts.get(r'dots')
491 491 if file_:
492 492 rlog = revlog.revlog(vfsmod.vfs(pycompat.getcwd(), audit=False),
493 493 file_)
494 494 revs = set((int(r) for r in revs))
495 495 def events():
496 496 for r in rlog:
497 497 yield 'n', (r, list(p for p in rlog.parentrevs(r)
498 498 if p != -1))
499 499 if r in revs:
500 500 yield 'l', (r, "r%i" % r)
501 501 elif repo:
502 502 cl = repo.changelog
503 503 tags = opts.get(r'tags')
504 504 branches = opts.get(r'branches')
505 505 if tags:
506 506 labels = {}
507 507 for l, n in repo.tags().items():
508 508 labels.setdefault(cl.rev(n), []).append(l)
509 509 def events():
510 510 b = "default"
511 511 for r in cl:
512 512 if branches:
513 513 newb = cl.read(cl.node(r))[5]['branch']
514 514 if newb != b:
515 515 yield 'a', newb
516 516 b = newb
517 517 yield 'n', (r, list(p for p in cl.parentrevs(r)
518 518 if p != -1))
519 519 if tags:
520 520 ls = labels.get(r)
521 521 if ls:
522 522 for l in ls:
523 523 yield 'l', (r, l)
524 524 else:
525 525 raise error.Abort(_('need repo for changelog dag'))
526 526
527 527 for line in dagparser.dagtextlines(events(),
528 528 addspaces=spaces,
529 529 wraplabels=True,
530 530 wrapannotations=True,
531 531 wrapnonlinear=dots,
532 532 usedots=dots,
533 533 maxlinewidth=70):
534 534 ui.write(line)
535 535 ui.write("\n")
536 536
537 537 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
538 538 def debugdata(ui, repo, file_, rev=None, **opts):
539 539 """dump the contents of a data file revision"""
540 540 opts = pycompat.byteskwargs(opts)
541 541 if opts.get('changelog') or opts.get('manifest') or opts.get('dir'):
542 542 if rev is not None:
543 543 raise error.CommandError('debugdata', _('invalid arguments'))
544 544 file_, rev = None, file_
545 545 elif rev is None:
546 546 raise error.CommandError('debugdata', _('invalid arguments'))
547 547 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
548 548 try:
549 549 ui.write(r.revision(r.lookup(rev), raw=True))
550 550 except KeyError:
551 551 raise error.Abort(_('invalid revision identifier %s') % rev)
552 552
553 553 @command('debugdate',
554 554 [('e', 'extended', None, _('try extended date formats'))],
555 555 _('[-e] DATE [RANGE]'),
556 556 norepo=True, optionalrepo=True)
557 557 def debugdate(ui, date, range=None, **opts):
558 558 """parse and display a date"""
559 559 if opts[r"extended"]:
560 560 d = util.parsedate(date, util.extendeddateformats)
561 561 else:
562 562 d = util.parsedate(date)
563 563 ui.write(("internal: %s %s\n") % d)
564 564 ui.write(("standard: %s\n") % util.datestr(d))
565 565 if range:
566 566 m = util.matchdate(range)
567 567 ui.write(("match: %s\n") % m(d[0]))
568 568
569 569 @command('debugdeltachain',
570 570 cmdutil.debugrevlogopts + cmdutil.formatteropts,
571 571 _('-c|-m|FILE'),
572 572 optionalrepo=True)
573 573 def debugdeltachain(ui, repo, file_=None, **opts):
574 574 """dump information about delta chains in a revlog
575 575
576 576 Output can be templatized. Available template keywords are:
577 577
578 578 :``rev``: revision number
579 579 :``chainid``: delta chain identifier (numbered by unique base)
580 580 :``chainlen``: delta chain length to this revision
581 581 :``prevrev``: previous revision in delta chain
582 582 :``deltatype``: role of delta / how it was computed
583 583 :``compsize``: compressed size of revision
584 584 :``uncompsize``: uncompressed size of revision
585 585 :``chainsize``: total size of compressed revisions in chain
586 586 :``chainratio``: total chain size divided by uncompressed revision size
587 587 (new delta chains typically start at ratio 2.00)
588 588 :``lindist``: linear distance from base revision in delta chain to end
589 589 of this revision
590 590 :``extradist``: total size of revisions not part of this delta chain from
591 591 base of delta chain to end of this revision; a measurement
592 592 of how much extra data we need to read/seek across to read
593 593 the delta chain for this revision
594 594 :``extraratio``: extradist divided by chainsize; another representation of
595 595 how much unrelated data is needed to load this delta chain
596 596
597 597 If the repository is configured to use the sparse read, additional keywords
598 598 are available:
599 599
600 600 :``readsize``: total size of data read from the disk for a revision
601 601 (sum of the sizes of all the blocks)
602 602 :``largestblock``: size of the largest block of data read from the disk
603 603 :``readdensity``: density of useful bytes in the data read from the disk
604 604 :``srchunks``: in how many data hunks the whole revision would be read
605 605
606 606 The sparse read can be enabled with experimental.sparse-read = True
607 607 """
608 608 opts = pycompat.byteskwargs(opts)
609 609 r = cmdutil.openrevlog(repo, 'debugdeltachain', file_, opts)
610 610 index = r.index
611 611 generaldelta = r.version & revlog.FLAG_GENERALDELTA
612 612 withsparseread = getattr(r, '_withsparseread', False)
613 613
614 614 def revinfo(rev):
615 615 e = index[rev]
616 616 compsize = e[1]
617 617 uncompsize = e[2]
618 618 chainsize = 0
619 619
620 620 if generaldelta:
621 621 if e[3] == e[5]:
622 622 deltatype = 'p1'
623 623 elif e[3] == e[6]:
624 624 deltatype = 'p2'
625 625 elif e[3] == rev - 1:
626 626 deltatype = 'prev'
627 627 elif e[3] == rev:
628 628 deltatype = 'base'
629 629 else:
630 630 deltatype = 'other'
631 631 else:
632 632 if e[3] == rev:
633 633 deltatype = 'base'
634 634 else:
635 635 deltatype = 'prev'
636 636
637 637 chain = r._deltachain(rev)[0]
638 638 for iterrev in chain:
639 639 e = index[iterrev]
640 640 chainsize += e[1]
641 641
642 642 return compsize, uncompsize, deltatype, chain, chainsize
643 643
644 644 fm = ui.formatter('debugdeltachain', opts)
645 645
646 646 fm.plain(' rev chain# chainlen prev delta '
647 647 'size rawsize chainsize ratio lindist extradist '
648 648 'extraratio')
649 649 if withsparseread:
650 650 fm.plain(' readsize largestblk rddensity srchunks')
651 651 fm.plain('\n')
652 652
653 653 chainbases = {}
654 654 for rev in r:
655 655 comp, uncomp, deltatype, chain, chainsize = revinfo(rev)
656 656 chainbase = chain[0]
657 657 chainid = chainbases.setdefault(chainbase, len(chainbases) + 1)
658 658 start = r.start
659 659 length = r.length
660 660 basestart = start(chainbase)
661 661 revstart = start(rev)
662 662 lineardist = revstart + comp - basestart
663 663 extradist = lineardist - chainsize
664 664 try:
665 665 prevrev = chain[-2]
666 666 except IndexError:
667 667 prevrev = -1
668 668
669 669 chainratio = float(chainsize) / float(uncomp)
670 670 extraratio = float(extradist) / float(chainsize)
671 671
672 672 fm.startitem()
673 673 fm.write('rev chainid chainlen prevrev deltatype compsize '
674 674 'uncompsize chainsize chainratio lindist extradist '
675 675 'extraratio',
676 676 '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
677 677 rev, chainid, len(chain), prevrev, deltatype, comp,
678 678 uncomp, chainsize, chainratio, lineardist, extradist,
679 679 extraratio,
680 680 rev=rev, chainid=chainid, chainlen=len(chain),
681 681 prevrev=prevrev, deltatype=deltatype, compsize=comp,
682 682 uncompsize=uncomp, chainsize=chainsize,
683 683 chainratio=chainratio, lindist=lineardist,
684 684 extradist=extradist, extraratio=extraratio)
685 685 if withsparseread:
686 686 readsize = 0
687 687 largestblock = 0
688 688 srchunks = 0
689 689
690 690 for revschunk in revlog._slicechunk(r, chain):
691 691 srchunks += 1
692 692 blkend = start(revschunk[-1]) + length(revschunk[-1])
693 693 blksize = blkend - start(revschunk[0])
694 694
695 695 readsize += blksize
696 696 if largestblock < blksize:
697 697 largestblock = blksize
698 698
699 699 readdensity = float(chainsize) / float(readsize)
700 700
701 701 fm.write('readsize largestblock readdensity srchunks',
702 702 ' %10d %10d %9.5f %8d',
703 703 readsize, largestblock, readdensity, srchunks,
704 704 readsize=readsize, largestblock=largestblock,
705 705 readdensity=readdensity, srchunks=srchunks)
706 706
707 707 fm.plain('\n')
708 708
709 709 fm.end()
710 710
711 711 @command('debugdirstate|debugstate',
712 712 [('', 'nodates', None, _('do not display the saved mtime')),
713 713 ('', 'datesort', None, _('sort by saved mtime'))],
714 714 _('[OPTION]...'))
715 715 def debugstate(ui, repo, **opts):
716 716 """show the contents of the current dirstate"""
717 717
718 718 nodates = opts.get(r'nodates')
719 719 datesort = opts.get(r'datesort')
720 720
721 721 timestr = ""
722 722 if datesort:
723 723 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
724 724 else:
725 725 keyfunc = None # sort by filename
726 726 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
727 727 if ent[3] == -1:
728 728 timestr = 'unset '
729 729 elif nodates:
730 730 timestr = 'set '
731 731 else:
732 732 timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
733 733 time.localtime(ent[3]))
734 734 timestr = encoding.strtolocal(timestr)
735 735 if ent[1] & 0o20000:
736 736 mode = 'lnk'
737 737 else:
738 738 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
739 739 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
740 740 for f in repo.dirstate.copies():
741 741 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
742 742
743 743 @command('debugdiscovery',
744 744 [('', 'old', None, _('use old-style discovery')),
745 745 ('', 'nonheads', None,
746 746 _('use old-style discovery with non-heads included')),
747 747 ('', 'rev', [], 'restrict discovery to this set of revs'),
748 748 ] + cmdutil.remoteopts,
749 749 _('[--rev REV] [OTHER]'))
750 750 def debugdiscovery(ui, repo, remoteurl="default", **opts):
751 751 """runs the changeset discovery protocol in isolation"""
752 752 opts = pycompat.byteskwargs(opts)
753 753 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
754 754 remote = hg.peer(repo, opts, remoteurl)
755 755 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
756 756
757 757 # make sure tests are repeatable
758 758 random.seed(12323)
759 759
760 760 def doit(pushedrevs, remoteheads, remote=remote):
761 761 if opts.get('old'):
762 762 if not util.safehasattr(remote, 'branches'):
763 763 # enable in-client legacy support
764 764 remote = localrepo.locallegacypeer(remote.local())
765 765 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
766 766 force=True)
767 767 common = set(common)
768 768 if not opts.get('nonheads'):
769 769 ui.write(("unpruned common: %s\n") %
770 770 " ".join(sorted(short(n) for n in common)))
771 771 dag = dagutil.revlogdag(repo.changelog)
772 772 all = dag.ancestorset(dag.internalizeall(common))
773 773 common = dag.externalizeall(dag.headsetofconnecteds(all))
774 774 else:
775 775 nodes = None
776 776 if pushedrevs:
777 777 revs = scmutil.revrange(repo, pushedrevs)
778 778 nodes = [repo[r].node() for r in revs]
779 779 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
780 780 ancestorsof=nodes)
781 781 common = set(common)
782 782 rheads = set(hds)
783 783 lheads = set(repo.heads())
784 784 ui.write(("common heads: %s\n") %
785 785 " ".join(sorted(short(n) for n in common)))
786 786 if lheads <= common:
787 787 ui.write(("local is subset\n"))
788 788 elif rheads <= common:
789 789 ui.write(("remote is subset\n"))
790 790
791 791 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
792 792 localrevs = opts['rev']
793 793 doit(localrevs, remoterevs)
794 794
795 795 _chunksize = 4 << 10
796 796
797 797 @command('debugdownload',
798 798 [
799 799 ('o', 'output', '', _('path')),
800 800 ],
801 801 optionalrepo=True)
802 802 def debugdownload(ui, repo, url, output=None, **opts):
803 803 """download a resource using Mercurial logic and config
804 804 """
805 805 fh = urlmod.open(ui, url, output)
806 806
807 807 dest = ui
808 808 if output:
809 809 dest = open(output, "wb", _chunksize)
810 810 try:
811 811 data = fh.read(_chunksize)
812 812 while data:
813 813 dest.write(data)
814 814 data = fh.read(_chunksize)
815 815 finally:
816 816 if output:
817 817 dest.close()
818 818
819 819 @command('debugextensions', cmdutil.formatteropts, [], norepo=True)
820 820 def debugextensions(ui, **opts):
821 821 '''show information about active extensions'''
822 822 opts = pycompat.byteskwargs(opts)
823 823 exts = extensions.extensions(ui)
824 824 hgver = util.version()
825 825 fm = ui.formatter('debugextensions', opts)
826 826 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
827 827 isinternal = extensions.ismoduleinternal(extmod)
828 828 extsource = pycompat.fsencode(extmod.__file__)
829 829 if isinternal:
830 830 exttestedwith = [] # never expose magic string to users
831 831 else:
832 832 exttestedwith = getattr(extmod, 'testedwith', '').split()
833 833 extbuglink = getattr(extmod, 'buglink', None)
834 834
835 835 fm.startitem()
836 836
837 837 if ui.quiet or ui.verbose:
838 838 fm.write('name', '%s\n', extname)
839 839 else:
840 840 fm.write('name', '%s', extname)
841 841 if isinternal or hgver in exttestedwith:
842 842 fm.plain('\n')
843 843 elif not exttestedwith:
844 844 fm.plain(_(' (untested!)\n'))
845 845 else:
846 846 lasttestedversion = exttestedwith[-1]
847 847 fm.plain(' (%s!)\n' % lasttestedversion)
848 848
849 849 fm.condwrite(ui.verbose and extsource, 'source',
850 850 _(' location: %s\n'), extsource or "")
851 851
852 852 if ui.verbose:
853 853 fm.plain(_(' bundled: %s\n') % ['no', 'yes'][isinternal])
854 854 fm.data(bundled=isinternal)
855 855
856 856 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
857 857 _(' tested with: %s\n'),
858 858 fm.formatlist(exttestedwith, name='ver'))
859 859
860 860 fm.condwrite(ui.verbose and extbuglink, 'buglink',
861 861 _(' bug reporting: %s\n'), extbuglink or "")
862 862
863 863 fm.end()
864 864
865 865 @command('debugfileset',
866 866 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
867 867 _('[-r REV] FILESPEC'))
868 868 def debugfileset(ui, repo, expr, **opts):
869 869 '''parse and apply a fileset specification'''
870 870 ctx = scmutil.revsingle(repo, opts.get(r'rev'), None)
871 871 if ui.verbose:
872 872 tree = fileset.parse(expr)
873 873 ui.note(fileset.prettyformat(tree), "\n")
874 874
875 875 for f in ctx.getfileset(expr):
876 876 ui.write("%s\n" % f)
877 877
878 878 @command('debugformat',
879 879 [] + cmdutil.formatteropts,
880 880 _(''))
881 881 def debugformat(ui, repo, **opts):
882 882 """display format information about the current repository
883 883
884 884 Use --verbose to get extra information about current config value and
885 885 Mercurial default."""
886 886 opts = pycompat.byteskwargs(opts)
887 887 maxvariantlength = max(len(fv.name) for fv in upgrade.allformatvariant)
888 888 maxvariantlength = max(len('format-variant'), maxvariantlength)
889 889
890 890 def makeformatname(name):
891 891 return '%s:' + (' ' * (maxvariantlength - len(name)))
892 892
893 893 fm = ui.formatter('debugformat', opts)
894 894 if fm.isplain():
895 895 def formatvalue(value):
896 896 if util.safehasattr(value, 'startswith'):
897 897 return value
898 898 if value:
899 899 return 'yes'
900 900 else:
901 901 return 'no'
902 902 else:
903 903 formatvalue = pycompat.identity
904 904
905 905 fm.plain('format-variant')
906 906 fm.plain(' ' * (maxvariantlength - len('format-variant')))
907 907 fm.plain(' repo')
908 908 if ui.verbose:
909 909 fm.plain(' config default')
910 910 fm.plain('\n')
911 911 for fv in upgrade.allformatvariant:
912 912 fm.startitem()
913 913 repovalue = fv.fromrepo(repo)
914 914 configvalue = fv.fromconfig(repo)
915 915
916 916 if repovalue != configvalue:
917 917 namelabel = 'formatvariant.name.mismatchconfig'
918 918 repolabel = 'formatvariant.repo.mismatchconfig'
919 919 elif repovalue != fv.default:
920 920 namelabel = 'formatvariant.name.mismatchdefault'
921 921 repolabel = 'formatvariant.repo.mismatchdefault'
922 922 else:
923 923 namelabel = 'formatvariant.name.uptodate'
924 924 repolabel = 'formatvariant.repo.uptodate'
925 925
926 926 fm.write('name', makeformatname(fv.name), fv.name,
927 927 label=namelabel)
928 928 fm.write('repo', ' %3s', formatvalue(repovalue),
929 929 label=repolabel)
930 930 if fv.default != configvalue:
931 931 configlabel = 'formatvariant.config.special'
932 932 else:
933 933 configlabel = 'formatvariant.config.default'
934 934 fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
935 935 label=configlabel)
936 936 fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
937 937 label='formatvariant.default')
938 938 fm.plain('\n')
939 939 fm.end()
940 940
941 941 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
942 942 def debugfsinfo(ui, path="."):
943 943 """show information detected about current filesystem"""
944 944 ui.write(('path: %s\n') % path)
945 945 ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
946 946 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
947 947 ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
948 948 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
949 949 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
950 950 casesensitive = '(unknown)'
951 951 try:
952 952 with tempfile.NamedTemporaryFile(prefix='.debugfsinfo', dir=path) as f:
953 953 casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
954 954 except OSError:
955 955 pass
956 956 ui.write(('case-sensitive: %s\n') % casesensitive)
957 957
958 958 @command('debuggetbundle',
959 959 [('H', 'head', [], _('id of head node'), _('ID')),
960 960 ('C', 'common', [], _('id of common node'), _('ID')),
961 961 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
962 962 _('REPO FILE [-H|-C ID]...'),
963 963 norepo=True)
964 964 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
965 965 """retrieves a bundle from a repo
966 966
967 967 Every ID must be a full-length hex node id string. Saves the bundle to the
968 968 given file.
969 969 """
970 970 opts = pycompat.byteskwargs(opts)
971 971 repo = hg.peer(ui, opts, repopath)
972 972 if not repo.capable('getbundle'):
973 973 raise error.Abort("getbundle() not supported by target repository")
974 974 args = {}
975 975 if common:
976 976 args[r'common'] = [bin(s) for s in common]
977 977 if head:
978 978 args[r'heads'] = [bin(s) for s in head]
979 979 # TODO: get desired bundlecaps from command line.
980 980 args[r'bundlecaps'] = None
981 981 bundle = repo.getbundle('debug', **args)
982 982
983 983 bundletype = opts.get('type', 'bzip2').lower()
984 984 btypes = {'none': 'HG10UN',
985 985 'bzip2': 'HG10BZ',
986 986 'gzip': 'HG10GZ',
987 987 'bundle2': 'HG20'}
988 988 bundletype = btypes.get(bundletype)
989 989 if bundletype not in bundle2.bundletypes:
990 990 raise error.Abort(_('unknown bundle type specified with --type'))
991 991 bundle2.writebundle(ui, bundle, bundlepath, bundletype)
992 992
993 993 @command('debugignore', [], '[FILE]')
994 994 def debugignore(ui, repo, *files, **opts):
995 995 """display the combined ignore pattern and information about ignored files
996 996
997 997 With no argument display the combined ignore pattern.
998 998
999 999 Given space separated file names, shows if the given file is ignored and
1000 1000 if so, show the ignore rule (file and line number) that matched it.
1001 1001 """
1002 1002 ignore = repo.dirstate._ignore
1003 1003 if not files:
1004 1004 # Show all the patterns
1005 1005 ui.write("%s\n" % repr(ignore))
1006 1006 else:
1007 1007 m = scmutil.match(repo[None], pats=files)
1008 1008 for f in m.files():
1009 1009 nf = util.normpath(f)
1010 1010 ignored = None
1011 1011 ignoredata = None
1012 1012 if nf != '.':
1013 1013 if ignore(nf):
1014 1014 ignored = nf
1015 1015 ignoredata = repo.dirstate._ignorefileandline(nf)
1016 1016 else:
1017 1017 for p in util.finddirs(nf):
1018 1018 if ignore(p):
1019 1019 ignored = p
1020 1020 ignoredata = repo.dirstate._ignorefileandline(p)
1021 1021 break
1022 1022 if ignored:
1023 1023 if ignored == nf:
1024 1024 ui.write(_("%s is ignored\n") % m.uipath(f))
1025 1025 else:
1026 1026 ui.write(_("%s is ignored because of "
1027 1027 "containing folder %s\n")
1028 1028 % (m.uipath(f), ignored))
1029 1029 ignorefile, lineno, line = ignoredata
1030 1030 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
1031 1031 % (ignorefile, lineno, line))
1032 1032 else:
1033 1033 ui.write(_("%s is not ignored\n") % m.uipath(f))
1034 1034
1035 1035 @command('debugindex', cmdutil.debugrevlogopts +
1036 1036 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1037 1037 _('[-f FORMAT] -c|-m|FILE'),
1038 1038 optionalrepo=True)
1039 1039 def debugindex(ui, repo, file_=None, **opts):
1040 1040 """dump the contents of an index file"""
1041 1041 opts = pycompat.byteskwargs(opts)
1042 1042 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1043 1043 format = opts.get('format', 0)
1044 1044 if format not in (0, 1):
1045 1045 raise error.Abort(_("unknown format %d") % format)
1046 1046
1047 1047 generaldelta = r.version & revlog.FLAG_GENERALDELTA
1048 1048 if generaldelta:
1049 1049 basehdr = ' delta'
1050 1050 else:
1051 1051 basehdr = ' base'
1052 1052
1053 1053 if ui.debugflag:
1054 1054 shortfn = hex
1055 1055 else:
1056 1056 shortfn = short
1057 1057
1058 1058 # There might not be anything in r, so have a sane default
1059 1059 idlen = 12
1060 1060 for i in r:
1061 1061 idlen = len(shortfn(r.node(i)))
1062 1062 break
1063 1063
1064 1064 if format == 0:
1065 1065 ui.write((" rev offset length " + basehdr + " linkrev"
1066 1066 " %s %s p2\n") % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
1067 1067 elif format == 1:
1068 1068 ui.write((" rev flag offset length"
1069 1069 " size " + basehdr + " link p1 p2"
1070 1070 " %s\n") % "nodeid".rjust(idlen))
1071 1071
1072 1072 for i in r:
1073 1073 node = r.node(i)
1074 1074 if generaldelta:
1075 1075 base = r.deltaparent(i)
1076 1076 else:
1077 1077 base = r.chainbase(i)
1078 1078 if format == 0:
1079 1079 try:
1080 1080 pp = r.parents(node)
1081 1081 except Exception:
1082 1082 pp = [nullid, nullid]
1083 1083 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1084 1084 i, r.start(i), r.length(i), base, r.linkrev(i),
1085 1085 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
1086 1086 elif format == 1:
1087 1087 pr = r.parentrevs(i)
1088 1088 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1089 1089 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1090 1090 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
1091 1091
1092 1092 @command('debugindexdot', cmdutil.debugrevlogopts,
1093 1093 _('-c|-m|FILE'), optionalrepo=True)
1094 1094 def debugindexdot(ui, repo, file_=None, **opts):
1095 1095 """dump an index DAG as a graphviz dot file"""
1096 1096 opts = pycompat.byteskwargs(opts)
1097 1097 r = cmdutil.openrevlog(repo, 'debugindexdot', file_, opts)
1098 1098 ui.write(("digraph G {\n"))
1099 1099 for i in r:
1100 1100 node = r.node(i)
1101 1101 pp = r.parents(node)
1102 1102 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1103 1103 if pp[1] != nullid:
1104 1104 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1105 1105 ui.write("}\n")
1106 1106
1107 1107 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
1108 1108 def debuginstall(ui, **opts):
1109 1109 '''test Mercurial installation
1110 1110
1111 1111 Returns 0 on success.
1112 1112 '''
1113 1113 opts = pycompat.byteskwargs(opts)
1114 1114
1115 1115 def writetemp(contents):
1116 1116 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1117 1117 f = os.fdopen(fd, pycompat.sysstr("wb"))
1118 1118 f.write(contents)
1119 1119 f.close()
1120 1120 return name
1121 1121
1122 1122 problems = 0
1123 1123
1124 1124 fm = ui.formatter('debuginstall', opts)
1125 1125 fm.startitem()
1126 1126
1127 1127 # encoding
1128 1128 fm.write('encoding', _("checking encoding (%s)...\n"), encoding.encoding)
1129 1129 err = None
1130 1130 try:
1131 1131 codecs.lookup(pycompat.sysstr(encoding.encoding))
1132 1132 except LookupError as inst:
1133 1133 err = util.forcebytestr(inst)
1134 1134 problems += 1
1135 1135 fm.condwrite(err, 'encodingerror', _(" %s\n"
1136 1136 " (check that your locale is properly set)\n"), err)
1137 1137
1138 1138 # Python
1139 1139 fm.write('pythonexe', _("checking Python executable (%s)\n"),
1140 1140 pycompat.sysexecutable)
1141 1141 fm.write('pythonver', _("checking Python version (%s)\n"),
1142 1142 ("%d.%d.%d" % sys.version_info[:3]))
1143 1143 fm.write('pythonlib', _("checking Python lib (%s)...\n"),
1144 1144 os.path.dirname(pycompat.fsencode(os.__file__)))
1145 1145
1146 1146 security = set(sslutil.supportedprotocols)
1147 1147 if sslutil.hassni:
1148 1148 security.add('sni')
1149 1149
1150 1150 fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
1151 1151 fm.formatlist(sorted(security), name='protocol',
1152 1152 fmt='%s', sep=','))
1153 1153
1154 1154 # These are warnings, not errors. So don't increment problem count. This
1155 1155 # may change in the future.
1156 1156 if 'tls1.2' not in security:
1157 1157 fm.plain(_(' TLS 1.2 not supported by Python install; '
1158 1158 'network connections lack modern security\n'))
1159 1159 if 'sni' not in security:
1160 1160 fm.plain(_(' SNI not supported by Python install; may have '
1161 1161 'connectivity issues with some servers\n'))
1162 1162
1163 1163 # TODO print CA cert info
1164 1164
1165 1165 # hg version
1166 1166 hgver = util.version()
1167 1167 fm.write('hgver', _("checking Mercurial version (%s)\n"),
1168 1168 hgver.split('+')[0])
1169 1169 fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
1170 1170 '+'.join(hgver.split('+')[1:]))
1171 1171
1172 1172 # compiled modules
1173 1173 fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
1174 1174 policy.policy)
1175 1175 fm.write('hgmodules', _("checking installed modules (%s)...\n"),
1176 1176 os.path.dirname(pycompat.fsencode(__file__)))
1177 1177
1178 1178 if policy.policy in ('c', 'allow'):
1179 1179 err = None
1180 1180 try:
1181 1181 from .cext import (
1182 1182 base85,
1183 1183 bdiff,
1184 1184 mpatch,
1185 1185 osutil,
1186 1186 )
1187 1187 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
1188 1188 except Exception as inst:
1189 1189 err = util.forcebytestr(inst)
1190 1190 problems += 1
1191 1191 fm.condwrite(err, 'extensionserror', " %s\n", err)
1192 1192
1193 1193 compengines = util.compengines._engines.values()
1194 1194 fm.write('compengines', _('checking registered compression engines (%s)\n'),
1195 1195 fm.formatlist(sorted(e.name() for e in compengines),
1196 1196 name='compengine', fmt='%s', sep=', '))
1197 1197 fm.write('compenginesavail', _('checking available compression engines '
1198 1198 '(%s)\n'),
1199 1199 fm.formatlist(sorted(e.name() for e in compengines
1200 1200 if e.available()),
1201 1201 name='compengine', fmt='%s', sep=', '))
1202 1202 wirecompengines = util.compengines.supportedwireengines(util.SERVERROLE)
1203 1203 fm.write('compenginesserver', _('checking available compression engines '
1204 1204 'for wire protocol (%s)\n'),
1205 1205 fm.formatlist([e.name() for e in wirecompengines
1206 1206 if e.wireprotosupport()],
1207 1207 name='compengine', fmt='%s', sep=', '))
1208 1208 re2 = 'missing'
1209 1209 if util._re2:
1210 1210 re2 = 'available'
1211 1211 fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
1212 1212 fm.data(re2=bool(util._re2))
1213 1213
1214 1214 # templates
1215 1215 p = templater.templatepaths()
1216 1216 fm.write('templatedirs', 'checking templates (%s)...\n', ' '.join(p))
1217 1217 fm.condwrite(not p, '', _(" no template directories found\n"))
1218 1218 if p:
1219 1219 m = templater.templatepath("map-cmdline.default")
1220 1220 if m:
1221 1221 # template found, check if it is working
1222 1222 err = None
1223 1223 try:
1224 1224 templater.templater.frommapfile(m)
1225 1225 except Exception as inst:
1226 1226 err = util.forcebytestr(inst)
1227 1227 p = None
1228 1228 fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
1229 1229 else:
1230 1230 p = None
1231 1231 fm.condwrite(p, 'defaulttemplate',
1232 1232 _("checking default template (%s)\n"), m)
1233 1233 fm.condwrite(not m, 'defaulttemplatenotfound',
1234 1234 _(" template '%s' not found\n"), "default")
1235 1235 if not p:
1236 1236 problems += 1
1237 1237 fm.condwrite(not p, '',
1238 1238 _(" (templates seem to have been installed incorrectly)\n"))
1239 1239
1240 1240 # editor
1241 1241 editor = ui.geteditor()
1242 1242 editor = util.expandpath(editor)
1243 1243 fm.write('editor', _("checking commit editor... (%s)\n"), editor)
1244 1244 cmdpath = util.findexe(pycompat.shlexsplit(editor)[0])
1245 1245 fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
1246 1246 _(" No commit editor set and can't find %s in PATH\n"
1247 1247 " (specify a commit editor in your configuration"
1248 1248 " file)\n"), not cmdpath and editor == 'vi' and editor)
1249 1249 fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
1250 1250 _(" Can't find editor '%s' in PATH\n"
1251 1251 " (specify a commit editor in your configuration"
1252 1252 " file)\n"), not cmdpath and editor)
1253 1253 if not cmdpath and editor != 'vi':
1254 1254 problems += 1
1255 1255
1256 1256 # check username
1257 1257 username = None
1258 1258 err = None
1259 1259 try:
1260 1260 username = ui.username()
1261 1261 except error.Abort as e:
1262 1262 err = util.forcebytestr(e)
1263 1263 problems += 1
1264 1264
1265 1265 fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
1266 1266 fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
1267 1267 " (specify a username in your configuration file)\n"), err)
1268 1268
1269 1269 fm.condwrite(not problems, '',
1270 1270 _("no problems detected\n"))
1271 1271 if not problems:
1272 1272 fm.data(problems=problems)
1273 1273 fm.condwrite(problems, 'problems',
1274 1274 _("%d problems detected,"
1275 1275 " please check your install!\n"), problems)
1276 1276 fm.end()
1277 1277
1278 1278 return problems
1279 1279
1280 1280 @command('debugknown', [], _('REPO ID...'), norepo=True)
1281 1281 def debugknown(ui, repopath, *ids, **opts):
1282 1282 """test whether node ids are known to a repo
1283 1283
1284 1284 Every ID must be a full-length hex node id string. Returns a list of 0s
1285 1285 and 1s indicating unknown/known.
1286 1286 """
1287 1287 opts = pycompat.byteskwargs(opts)
1288 1288 repo = hg.peer(ui, opts, repopath)
1289 1289 if not repo.capable('known'):
1290 1290 raise error.Abort("known() not supported by target repository")
1291 1291 flags = repo.known([bin(s) for s in ids])
1292 1292 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1293 1293
1294 1294 @command('debuglabelcomplete', [], _('LABEL...'))
1295 1295 def debuglabelcomplete(ui, repo, *args):
1296 1296 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
1297 1297 debugnamecomplete(ui, repo, *args)
1298 1298
1299 1299 @command('debuglocks',
1300 1300 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
1301 1301 ('W', 'force-wlock', None,
1302 1302 _('free the working state lock (DANGEROUS)')),
1303 1303 ('s', 'set-lock', None, _('set the store lock until stopped')),
1304 1304 ('S', 'set-wlock', None,
1305 1305 _('set the working state lock until stopped'))],
1306 1306 _('[OPTION]...'))
1307 1307 def debuglocks(ui, repo, **opts):
1308 1308 """show or modify state of locks
1309 1309
1310 1310 By default, this command will show which locks are held. This
1311 1311 includes the user and process holding the lock, the amount of time
1312 1312 the lock has been held, and the machine name where the process is
1313 1313 running if it's not local.
1314 1314
1315 1315 Locks protect the integrity of Mercurial's data, so should be
1316 1316 treated with care. System crashes or other interruptions may cause
1317 1317 locks to not be properly released, though Mercurial will usually
1318 1318 detect and remove such stale locks automatically.
1319 1319
1320 1320 However, detecting stale locks may not always be possible (for
1321 1321 instance, on a shared filesystem). Removing locks may also be
1322 1322 blocked by filesystem permissions.
1323 1323
1324 1324 Setting a lock will prevent other commands from changing the data.
1325 1325 The command will wait until an interruption (SIGINT, SIGTERM, ...) occurs.
1326 1326 The set locks are removed when the command exits.
1327 1327
1328 1328 Returns 0 if no locks are held.
1329 1329
1330 1330 """
1331 1331
1332 1332 if opts.get(r'force_lock'):
1333 1333 repo.svfs.unlink('lock')
1334 1334 if opts.get(r'force_wlock'):
1335 1335 repo.vfs.unlink('wlock')
1336 1336 if opts.get(r'force_lock') or opts.get(r'force_wlock'):
1337 1337 return 0
1338 1338
1339 1339 locks = []
1340 1340 try:
1341 1341 if opts.get(r'set_wlock'):
1342 1342 try:
1343 1343 locks.append(repo.wlock(False))
1344 1344 except error.LockHeld:
1345 1345 raise error.Abort(_('wlock is already held'))
1346 1346 if opts.get(r'set_lock'):
1347 1347 try:
1348 1348 locks.append(repo.lock(False))
1349 1349 except error.LockHeld:
1350 1350 raise error.Abort(_('lock is already held'))
1351 1351 if len(locks):
1352 1352 ui.promptchoice(_("ready to release the lock (y)? $$ &Yes"))
1353 1353 return 0
1354 1354 finally:
1355 1355 release(*locks)
1356 1356
1357 1357 now = time.time()
1358 1358 held = 0
1359 1359
1360 1360 def report(vfs, name, method):
1361 1361 # this causes stale locks to get reaped for more accurate reporting
1362 1362 try:
1363 1363 l = method(False)
1364 1364 except error.LockHeld:
1365 1365 l = None
1366 1366
1367 1367 if l:
1368 1368 l.release()
1369 1369 else:
1370 1370 try:
1371 1371 stat = vfs.lstat(name)
1372 1372 age = now - stat.st_mtime
1373 1373 user = util.username(stat.st_uid)
1374 1374 locker = vfs.readlock(name)
1375 1375 if ":" in locker:
1376 1376 host, pid = locker.split(':')
1377 1377 if host == socket.gethostname():
1378 1378 locker = 'user %s, process %s' % (user, pid)
1379 1379 else:
1380 1380 locker = 'user %s, process %s, host %s' \
1381 1381 % (user, pid, host)
1382 1382 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
1383 1383 return 1
1384 1384 except OSError as e:
1385 1385 if e.errno != errno.ENOENT:
1386 1386 raise
1387 1387
1388 1388 ui.write(("%-6s free\n") % (name + ":"))
1389 1389 return 0
1390 1390
1391 1391 held += report(repo.svfs, "lock", repo.lock)
1392 1392 held += report(repo.vfs, "wlock", repo.wlock)
1393 1393
1394 1394 return held
1395 1395
1396 1396 @command('debugmergestate', [], '')
1397 1397 def debugmergestate(ui, repo, *args):
1398 1398 """print merge state
1399 1399
1400 1400 Use --verbose to print out information about whether v1 or v2 merge state
1401 1401 was chosen."""
1402 1402 def _hashornull(h):
1403 1403 if h == nullhex:
1404 1404 return 'null'
1405 1405 else:
1406 1406 return h
1407 1407
1408 1408 def printrecords(version):
1409 1409 ui.write(('* version %s records\n') % version)
1410 1410 if version == 1:
1411 1411 records = v1records
1412 1412 else:
1413 1413 records = v2records
1414 1414
1415 1415 for rtype, record in records:
1416 1416 # pretty print some record types
1417 1417 if rtype == 'L':
1418 1418 ui.write(('local: %s\n') % record)
1419 1419 elif rtype == 'O':
1420 1420 ui.write(('other: %s\n') % record)
1421 1421 elif rtype == 'm':
1422 1422 driver, mdstate = record.split('\0', 1)
1423 1423 ui.write(('merge driver: %s (state "%s")\n')
1424 1424 % (driver, mdstate))
1425 1425 elif rtype in 'FDC':
1426 1426 r = record.split('\0')
1427 1427 f, state, hash, lfile, afile, anode, ofile = r[0:7]
1428 1428 if version == 1:
1429 1429 onode = 'not stored in v1 format'
1430 1430 flags = r[7]
1431 1431 else:
1432 1432 onode, flags = r[7:9]
1433 1433 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
1434 1434 % (f, rtype, state, _hashornull(hash)))
1435 1435 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
1436 1436 ui.write((' ancestor path: %s (node %s)\n')
1437 1437 % (afile, _hashornull(anode)))
1438 1438 ui.write((' other path: %s (node %s)\n')
1439 1439 % (ofile, _hashornull(onode)))
1440 1440 elif rtype == 'f':
1441 1441 filename, rawextras = record.split('\0', 1)
1442 1442 extras = rawextras.split('\0')
1443 1443 i = 0
1444 1444 extrastrings = []
1445 1445 while i < len(extras):
1446 1446 extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
1447 1447 i += 2
1448 1448
1449 1449 ui.write(('file extras: %s (%s)\n')
1450 1450 % (filename, ', '.join(extrastrings)))
1451 1451 elif rtype == 'l':
1452 1452 labels = record.split('\0', 2)
1453 1453 labels = [l for l in labels if len(l) > 0]
1454 1454 ui.write(('labels:\n'))
1455 1455 ui.write((' local: %s\n' % labels[0]))
1456 1456 ui.write((' other: %s\n' % labels[1]))
1457 1457 if len(labels) > 2:
1458 1458 ui.write((' base: %s\n' % labels[2]))
1459 1459 else:
1460 1460 ui.write(('unrecognized entry: %s\t%s\n')
1461 1461 % (rtype, record.replace('\0', '\t')))
1462 1462
1463 1463 # Avoid mergestate.read() since it may raise an exception for unsupported
1464 1464 # merge state records. We shouldn't be doing this, but this is OK since this
1465 1465 # command is pretty low-level.
1466 1466 ms = mergemod.mergestate(repo)
1467 1467
1468 1468 # sort so that reasonable information is on top
1469 1469 v1records = ms._readrecordsv1()
1470 1470 v2records = ms._readrecordsv2()
1471 1471 order = 'LOml'
1472 1472 def key(r):
1473 1473 idx = order.find(r[0])
1474 1474 if idx == -1:
1475 1475 return (1, r[1])
1476 1476 else:
1477 1477 return (0, idx)
1478 1478 v1records.sort(key=key)
1479 1479 v2records.sort(key=key)
1480 1480
1481 1481 if not v1records and not v2records:
1482 1482 ui.write(('no merge state found\n'))
1483 1483 elif not v2records:
1484 1484 ui.note(('no version 2 merge state\n'))
1485 1485 printrecords(1)
1486 1486 elif ms._v1v2match(v1records, v2records):
1487 1487 ui.note(('v1 and v2 states match: using v2\n'))
1488 1488 printrecords(2)
1489 1489 else:
1490 1490 ui.note(('v1 and v2 states mismatch: using v1\n'))
1491 1491 printrecords(1)
1492 1492 if ui.verbose:
1493 1493 printrecords(2)
1494 1494
1495 1495 @command('debugnamecomplete', [], _('NAME...'))
1496 1496 def debugnamecomplete(ui, repo, *args):
1497 1497 '''complete "names" - tags, open branch names, bookmark names'''
1498 1498
1499 1499 names = set()
1500 1500 # since we previously only listed open branches, we will handle that
1501 1501 # specially (after this for loop)
1502 1502 for name, ns in repo.names.iteritems():
1503 1503 if name != 'branches':
1504 1504 names.update(ns.listnames(repo))
1505 1505 names.update(tag for (tag, heads, tip, closed)
1506 1506 in repo.branchmap().iterbranches() if not closed)
1507 1507 completions = set()
1508 1508 if not args:
1509 1509 args = ['']
1510 1510 for a in args:
1511 1511 completions.update(n for n in names if n.startswith(a))
1512 1512 ui.write('\n'.join(sorted(completions)))
1513 1513 ui.write('\n')
1514 1514
1515 1515 @command('debugobsolete',
1516 1516 [('', 'flags', 0, _('markers flag')),
1517 1517 ('', 'record-parents', False,
1518 1518 _('record parent information for the precursor')),
1519 1519 ('r', 'rev', [], _('display markers relevant to REV')),
1520 1520 ('', 'exclusive', False, _('restrict display to markers only '
1521 1521 'relevant to REV')),
1522 1522 ('', 'index', False, _('display index of the marker')),
1523 1523 ('', 'delete', [], _('delete markers specified by indices')),
1524 1524 ] + cmdutil.commitopts2 + cmdutil.formatteropts,
1525 1525 _('[OBSOLETED [REPLACEMENT ...]]'))
1526 1526 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
1527 1527 """create arbitrary obsolete marker
1528 1528
1529 1529 With no arguments, displays the list of obsolescence markers."""
1530 1530
1531 1531 opts = pycompat.byteskwargs(opts)
1532 1532
1533 1533 def parsenodeid(s):
1534 1534 try:
1535 1535 # We do not use revsingle/revrange functions here to accept
1536 1536 # arbitrary node identifiers, possibly not present in the
1537 1537 # local repository.
1538 1538 n = bin(s)
1539 1539 if len(n) != len(nullid):
1540 1540 raise TypeError()
1541 1541 return n
1542 1542 except TypeError:
1543 1543 raise error.Abort('changeset references must be full hexadecimal '
1544 1544 'node identifiers')
1545 1545
1546 1546 if opts.get('delete'):
1547 1547 indices = []
1548 1548 for v in opts.get('delete'):
1549 1549 try:
1550 1550 indices.append(int(v))
1551 1551 except ValueError:
1552 1552 raise error.Abort(_('invalid index value: %r') % v,
1553 1553 hint=_('use integers for indices'))
1554 1554
1555 1555 if repo.currenttransaction():
1556 1556 raise error.Abort(_('cannot delete obsmarkers in the middle '
1557 1557 'of transaction.'))
1558 1558
1559 1559 with repo.lock():
1560 1560 n = repair.deleteobsmarkers(repo.obsstore, indices)
1561 1561 ui.write(_('deleted %i obsolescence markers\n') % n)
1562 1562
1563 1563 return
1564 1564
1565 1565 if precursor is not None:
1566 1566 if opts['rev']:
1567 1567 raise error.Abort('cannot select revision when creating marker')
1568 1568 metadata = {}
1569 1569 metadata['user'] = opts['user'] or ui.username()
1570 1570 succs = tuple(parsenodeid(succ) for succ in successors)
1571 1571 l = repo.lock()
1572 1572 try:
1573 1573 tr = repo.transaction('debugobsolete')
1574 1574 try:
1575 1575 date = opts.get('date')
1576 1576 if date:
1577 1577 date = util.parsedate(date)
1578 1578 else:
1579 1579 date = None
1580 1580 prec = parsenodeid(precursor)
1581 1581 parents = None
1582 1582 if opts['record_parents']:
1583 1583 if prec not in repo.unfiltered():
1584 1584 raise error.Abort('cannot used --record-parents on '
1585 1585 'unknown changesets')
1586 1586 parents = repo.unfiltered()[prec].parents()
1587 1587 parents = tuple(p.node() for p in parents)
1588 1588 repo.obsstore.create(tr, prec, succs, opts['flags'],
1589 1589 parents=parents, date=date,
1590 1590 metadata=metadata, ui=ui)
1591 1591 tr.close()
1592 1592 except ValueError as exc:
1593 1593 raise error.Abort(_('bad obsmarker input: %s') % exc)
1594 1594 finally:
1595 1595 tr.release()
1596 1596 finally:
1597 1597 l.release()
1598 1598 else:
1599 1599 if opts['rev']:
1600 1600 revs = scmutil.revrange(repo, opts['rev'])
1601 1601 nodes = [repo[r].node() for r in revs]
1602 1602 markers = list(obsutil.getmarkers(repo, nodes=nodes,
1603 1603 exclusive=opts['exclusive']))
1604 1604 markers.sort(key=lambda x: x._data)
1605 1605 else:
1606 1606 markers = obsutil.getmarkers(repo)
1607 1607
1608 1608 markerstoiter = markers
1609 1609 isrelevant = lambda m: True
1610 1610 if opts.get('rev') and opts.get('index'):
1611 1611 markerstoiter = obsutil.getmarkers(repo)
1612 1612 markerset = set(markers)
1613 1613 isrelevant = lambda m: m in markerset
1614 1614
1615 1615 fm = ui.formatter('debugobsolete', opts)
1616 1616 for i, m in enumerate(markerstoiter):
1617 1617 if not isrelevant(m):
1618 1618 # marker can be irrelevant when we're iterating over a set
1619 1619 # of markers (markerstoiter) which is bigger than the set
1620 1620 # of markers we want to display (markers)
1621 1621 # this can happen if both --index and --rev options are
1622 1622 # provided and thus we need to iterate over all of the markers
1623 1623 # to get the correct indices, but only display the ones that
1624 1624 # are relevant to --rev value
1625 1625 continue
1626 1626 fm.startitem()
1627 1627 ind = i if opts.get('index') else None
1628 1628 cmdutil.showmarker(fm, m, index=ind)
1629 1629 fm.end()
1630 1630
1631 1631 @command('debugpathcomplete',
1632 1632 [('f', 'full', None, _('complete an entire path')),
1633 1633 ('n', 'normal', None, _('show only normal files')),
1634 1634 ('a', 'added', None, _('show only added files')),
1635 1635 ('r', 'removed', None, _('show only removed files'))],
1636 1636 _('FILESPEC...'))
1637 1637 def debugpathcomplete(ui, repo, *specs, **opts):
1638 1638 '''complete part or all of a tracked path
1639 1639
1640 1640 This command supports shells that offer path name completion. It
1641 1641 currently completes only files already known to the dirstate.
1642 1642
1643 1643 Completion extends only to the next path segment unless
1644 1644 --full is specified, in which case entire paths are used.'''
1645 1645
1646 1646 def complete(path, acceptable):
1647 1647 dirstate = repo.dirstate
1648 1648 spec = os.path.normpath(os.path.join(pycompat.getcwd(), path))
1649 1649 rootdir = repo.root + pycompat.ossep
1650 1650 if spec != repo.root and not spec.startswith(rootdir):
1651 1651 return [], []
1652 1652 if os.path.isdir(spec):
1653 1653 spec += '/'
1654 1654 spec = spec[len(rootdir):]
1655 1655 fixpaths = pycompat.ossep != '/'
1656 1656 if fixpaths:
1657 1657 spec = spec.replace(pycompat.ossep, '/')
1658 1658 speclen = len(spec)
1659 1659 fullpaths = opts[r'full']
1660 1660 files, dirs = set(), set()
1661 1661 adddir, addfile = dirs.add, files.add
1662 1662 for f, st in dirstate.iteritems():
1663 1663 if f.startswith(spec) and st[0] in acceptable:
1664 1664 if fixpaths:
1665 1665 f = f.replace('/', pycompat.ossep)
1666 1666 if fullpaths:
1667 1667 addfile(f)
1668 1668 continue
1669 1669 s = f.find(pycompat.ossep, speclen)
1670 1670 if s >= 0:
1671 1671 adddir(f[:s])
1672 1672 else:
1673 1673 addfile(f)
1674 1674 return files, dirs
1675 1675
1676 1676 acceptable = ''
1677 1677 if opts[r'normal']:
1678 1678 acceptable += 'nm'
1679 1679 if opts[r'added']:
1680 1680 acceptable += 'a'
1681 1681 if opts[r'removed']:
1682 1682 acceptable += 'r'
1683 1683 cwd = repo.getcwd()
1684 1684 if not specs:
1685 1685 specs = ['.']
1686 1686
1687 1687 files, dirs = set(), set()
1688 1688 for spec in specs:
1689 1689 f, d = complete(spec, acceptable or 'nmar')
1690 1690 files.update(f)
1691 1691 dirs.update(d)
1692 1692 files.update(dirs)
1693 1693 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
1694 1694 ui.write('\n')
1695 1695
1696 1696 @command('debugpickmergetool',
1697 1697 [('r', 'rev', '', _('check for files in this revision'), _('REV')),
1698 1698 ('', 'changedelete', None, _('emulate merging change and delete')),
1699 1699 ] + cmdutil.walkopts + cmdutil.mergetoolopts,
1700 1700 _('[PATTERN]...'),
1701 1701 inferrepo=True)
1702 1702 def debugpickmergetool(ui, repo, *pats, **opts):
1703 1703 """examine which merge tool is chosen for specified file
1704 1704
1705 1705 As described in :hg:`help merge-tools`, Mercurial examines
1706 1706 configurations below in this order to decide which merge tool is
1707 1707 chosen for specified file.
1708 1708
1709 1709 1. ``--tool`` option
1710 1710 2. ``HGMERGE`` environment variable
1711 1711 3. configurations in ``merge-patterns`` section
1712 1712 4. configuration of ``ui.merge``
1713 1713 5. configurations in ``merge-tools`` section
1714 1714 6. ``hgmerge`` tool (for historical reason only)
1715 1715 7. default tool for fallback (``:merge`` or ``:prompt``)
1716 1716
1717 1717 This command writes out examination result in the style below::
1718 1718
1719 1719 FILE = MERGETOOL
1720 1720
1721 1721 By default, all files known in the first parent context of the
1722 1722 working directory are examined. Use file patterns and/or -I/-X
1723 1723 options to limit target files. -r/--rev is also useful to examine
1724 1724 files in another context without actual updating to it.
1725 1725
1726 1726 With --debug, this command shows warning messages while matching
1727 1727 against ``merge-patterns`` and so on, too. It is recommended to
1728 1728 use this option with explicit file patterns and/or -I/-X options,
1729 1729 because this option increases amount of output per file according
1730 1730 to configurations in hgrc.
1731 1731
1732 1732 With -v/--verbose, this command shows configurations below at
1733 1733 first (only if specified).
1734 1734
1735 1735 - ``--tool`` option
1736 1736 - ``HGMERGE`` environment variable
1737 1737 - configuration of ``ui.merge``
1738 1738
1739 1739 If merge tool is chosen before matching against
1740 1740 ``merge-patterns``, this command can't show any helpful
1741 1741 information, even with --debug. In such case, information above is
1742 1742 useful to know why a merge tool is chosen.
1743 1743 """
1744 1744 opts = pycompat.byteskwargs(opts)
1745 1745 overrides = {}
1746 1746 if opts['tool']:
1747 1747 overrides[('ui', 'forcemerge')] = opts['tool']
1748 1748 ui.note(('with --tool %r\n') % (opts['tool']))
1749 1749
1750 1750 with ui.configoverride(overrides, 'debugmergepatterns'):
1751 1751 hgmerge = encoding.environ.get("HGMERGE")
1752 1752 if hgmerge is not None:
1753 1753 ui.note(('with HGMERGE=%r\n') % (hgmerge))
1754 1754 uimerge = ui.config("ui", "merge")
1755 1755 if uimerge:
1756 1756 ui.note(('with ui.merge=%r\n') % (uimerge))
1757 1757
1758 1758 ctx = scmutil.revsingle(repo, opts.get('rev'))
1759 1759 m = scmutil.match(ctx, pats, opts)
1760 1760 changedelete = opts['changedelete']
1761 1761 for path in ctx.walk(m):
1762 1762 fctx = ctx[path]
1763 1763 try:
1764 1764 if not ui.debugflag:
1765 1765 ui.pushbuffer(error=True)
1766 1766 tool, toolpath = filemerge._picktool(repo, ui, path,
1767 1767 fctx.isbinary(),
1768 1768 'l' in fctx.flags(),
1769 1769 changedelete)
1770 1770 finally:
1771 1771 if not ui.debugflag:
1772 1772 ui.popbuffer()
1773 1773 ui.write(('%s = %s\n') % (path, tool))
1774 1774
1775 1775 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
1776 1776 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
1777 1777 '''access the pushkey key/value protocol
1778 1778
1779 1779 With two args, list the keys in the given namespace.
1780 1780
1781 1781 With five args, set a key to new if it currently is set to old.
1782 1782 Reports success or failure.
1783 1783 '''
1784 1784
1785 1785 target = hg.peer(ui, {}, repopath)
1786 1786 if keyinfo:
1787 1787 key, old, new = keyinfo
1788 1788 r = target.pushkey(namespace, key, old, new)
1789 1789 ui.status(str(r) + '\n')
1790 1790 return not r
1791 1791 else:
1792 1792 for k, v in sorted(target.listkeys(namespace).iteritems()):
1793 1793 ui.write("%s\t%s\n" % (util.escapestr(k),
1794 1794 util.escapestr(v)))
1795 1795
1796 1796 @command('debugpvec', [], _('A B'))
1797 1797 def debugpvec(ui, repo, a, b=None):
1798 1798 ca = scmutil.revsingle(repo, a)
1799 1799 cb = scmutil.revsingle(repo, b)
1800 1800 pa = pvec.ctxpvec(ca)
1801 1801 pb = pvec.ctxpvec(cb)
1802 1802 if pa == pb:
1803 1803 rel = "="
1804 1804 elif pa > pb:
1805 1805 rel = ">"
1806 1806 elif pa < pb:
1807 1807 rel = "<"
1808 1808 elif pa | pb:
1809 1809 rel = "|"
1810 1810 ui.write(_("a: %s\n") % pa)
1811 1811 ui.write(_("b: %s\n") % pb)
1812 1812 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
1813 1813 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
1814 1814 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
1815 1815 pa.distance(pb), rel))
1816 1816
1817 1817 @command('debugrebuilddirstate|debugrebuildstate',
1818 1818 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
1819 1819 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
1820 1820 'the working copy parent')),
1821 1821 ],
1822 1822 _('[-r REV]'))
1823 1823 def debugrebuilddirstate(ui, repo, rev, **opts):
1824 1824 """rebuild the dirstate as it would look like for the given revision
1825 1825
1826 1826 If no revision is specified the first current parent will be used.
1827 1827
1828 1828 The dirstate will be set to the files of the given revision.
1829 1829 The actual working directory content or existing dirstate
1830 1830 information such as adds or removes is not considered.
1831 1831
1832 1832 ``minimal`` will only rebuild the dirstate status for files that claim to be
1833 1833 tracked but are not in the parent manifest, or that exist in the parent
1834 1834 manifest but are not in the dirstate. It will not change adds, removes, or
1835 1835 modified files that are in the working copy parent.
1836 1836
1837 1837 One use of this command is to make the next :hg:`status` invocation
1838 1838 check the actual file content.
1839 1839 """
1840 1840 ctx = scmutil.revsingle(repo, rev)
1841 1841 with repo.wlock():
1842 1842 dirstate = repo.dirstate
1843 1843 changedfiles = None
1844 1844 # See command doc for what minimal does.
1845 1845 if opts.get(r'minimal'):
1846 1846 manifestfiles = set(ctx.manifest().keys())
1847 1847 dirstatefiles = set(dirstate)
1848 1848 manifestonly = manifestfiles - dirstatefiles
1849 1849 dsonly = dirstatefiles - manifestfiles
1850 1850 dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
1851 1851 changedfiles = manifestonly | dsnotadded
1852 1852
1853 1853 dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
1854 1854
1855 1855 @command('debugrebuildfncache', [], '')
1856 1856 def debugrebuildfncache(ui, repo):
1857 1857 """rebuild the fncache file"""
1858 1858 repair.rebuildfncache(ui, repo)
1859 1859
1860 1860 @command('debugrename',
1861 1861 [('r', 'rev', '', _('revision to debug'), _('REV'))],
1862 1862 _('[-r REV] FILE'))
1863 1863 def debugrename(ui, repo, file1, *pats, **opts):
1864 1864 """dump rename information"""
1865 1865
1866 1866 opts = pycompat.byteskwargs(opts)
1867 1867 ctx = scmutil.revsingle(repo, opts.get('rev'))
1868 1868 m = scmutil.match(ctx, (file1,) + pats, opts)
1869 1869 for abs in ctx.walk(m):
1870 1870 fctx = ctx[abs]
1871 1871 o = fctx.filelog().renamed(fctx.filenode())
1872 1872 rel = m.rel(abs)
1873 1873 if o:
1874 1874 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1875 1875 else:
1876 1876 ui.write(_("%s not renamed\n") % rel)
1877 1877
1878 1878 @command('debugrevlog', cmdutil.debugrevlogopts +
1879 1879 [('d', 'dump', False, _('dump index data'))],
1880 1880 _('-c|-m|FILE'),
1881 1881 optionalrepo=True)
1882 1882 def debugrevlog(ui, repo, file_=None, **opts):
1883 1883 """show data and statistics about a revlog"""
1884 1884 opts = pycompat.byteskwargs(opts)
1885 1885 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
1886 1886
1887 1887 if opts.get("dump"):
1888 1888 numrevs = len(r)
1889 1889 ui.write(("# rev p1rev p2rev start end deltastart base p1 p2"
1890 1890 " rawsize totalsize compression heads chainlen\n"))
1891 1891 ts = 0
1892 1892 heads = set()
1893 1893
1894 1894 for rev in xrange(numrevs):
1895 1895 dbase = r.deltaparent(rev)
1896 1896 if dbase == -1:
1897 1897 dbase = rev
1898 1898 cbase = r.chainbase(rev)
1899 1899 clen = r.chainlen(rev)
1900 1900 p1, p2 = r.parentrevs(rev)
1901 1901 rs = r.rawsize(rev)
1902 1902 ts = ts + rs
1903 1903 heads -= set(r.parentrevs(rev))
1904 1904 heads.add(rev)
1905 1905 try:
1906 1906 compression = ts / r.end(rev)
1907 1907 except ZeroDivisionError:
1908 1908 compression = 0
1909 1909 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
1910 1910 "%11d %5d %8d\n" %
1911 1911 (rev, p1, p2, r.start(rev), r.end(rev),
1912 1912 r.start(dbase), r.start(cbase),
1913 1913 r.start(p1), r.start(p2),
1914 1914 rs, ts, compression, len(heads), clen))
1915 1915 return 0
1916 1916
1917 1917 v = r.version
1918 1918 format = v & 0xFFFF
1919 1919 flags = []
1920 1920 gdelta = False
1921 1921 if v & revlog.FLAG_INLINE_DATA:
1922 1922 flags.append('inline')
1923 1923 if v & revlog.FLAG_GENERALDELTA:
1924 1924 gdelta = True
1925 1925 flags.append('generaldelta')
1926 1926 if not flags:
1927 1927 flags = ['(none)']
1928 1928
1929 1929 nummerges = 0
1930 1930 numfull = 0
1931 1931 numprev = 0
1932 1932 nump1 = 0
1933 1933 nump2 = 0
1934 1934 numother = 0
1935 1935 nump1prev = 0
1936 1936 nump2prev = 0
1937 1937 chainlengths = []
1938 1938 chainbases = []
1939 1939 chainspans = []
1940 1940
1941 1941 datasize = [None, 0, 0]
1942 1942 fullsize = [None, 0, 0]
1943 1943 deltasize = [None, 0, 0]
1944 1944 chunktypecounts = {}
1945 1945 chunktypesizes = {}
1946 1946
1947 1947 def addsize(size, l):
1948 1948 if l[0] is None or size < l[0]:
1949 1949 l[0] = size
1950 1950 if size > l[1]:
1951 1951 l[1] = size
1952 1952 l[2] += size
1953 1953
1954 1954 numrevs = len(r)
1955 1955 for rev in xrange(numrevs):
1956 1956 p1, p2 = r.parentrevs(rev)
1957 1957 delta = r.deltaparent(rev)
1958 1958 if format > 0:
1959 1959 addsize(r.rawsize(rev), datasize)
1960 1960 if p2 != nullrev:
1961 1961 nummerges += 1
1962 1962 size = r.length(rev)
1963 1963 if delta == nullrev:
1964 1964 chainlengths.append(0)
1965 1965 chainbases.append(r.start(rev))
1966 1966 chainspans.append(size)
1967 1967 numfull += 1
1968 1968 addsize(size, fullsize)
1969 1969 else:
1970 1970 chainlengths.append(chainlengths[delta] + 1)
1971 1971 baseaddr = chainbases[delta]
1972 1972 revaddr = r.start(rev)
1973 1973 chainbases.append(baseaddr)
1974 1974 chainspans.append((revaddr - baseaddr) + size)
1975 1975 addsize(size, deltasize)
1976 1976 if delta == rev - 1:
1977 1977 numprev += 1
1978 1978 if delta == p1:
1979 1979 nump1prev += 1
1980 1980 elif delta == p2:
1981 1981 nump2prev += 1
1982 1982 elif delta == p1:
1983 1983 nump1 += 1
1984 1984 elif delta == p2:
1985 1985 nump2 += 1
1986 1986 elif delta != nullrev:
1987 1987 numother += 1
1988 1988
1989 1989 # Obtain data on the raw chunks in the revlog.
1990 1990 segment = r._getsegmentforrevs(rev, rev)[1]
1991 1991 if segment:
1992 1992 chunktype = bytes(segment[0:1])
1993 1993 else:
1994 1994 chunktype = 'empty'
1995 1995
1996 1996 if chunktype not in chunktypecounts:
1997 1997 chunktypecounts[chunktype] = 0
1998 1998 chunktypesizes[chunktype] = 0
1999 1999
2000 2000 chunktypecounts[chunktype] += 1
2001 2001 chunktypesizes[chunktype] += size
2002 2002
2003 2003 # Adjust size min value for empty cases
2004 2004 for size in (datasize, fullsize, deltasize):
2005 2005 if size[0] is None:
2006 2006 size[0] = 0
2007 2007
2008 2008 numdeltas = numrevs - numfull
2009 2009 numoprev = numprev - nump1prev - nump2prev
2010 2010 totalrawsize = datasize[2]
2011 2011 datasize[2] /= numrevs
2012 2012 fulltotal = fullsize[2]
2013 2013 fullsize[2] /= numfull
2014 2014 deltatotal = deltasize[2]
2015 2015 if numrevs - numfull > 0:
2016 2016 deltasize[2] /= numrevs - numfull
2017 2017 totalsize = fulltotal + deltatotal
2018 2018 avgchainlen = sum(chainlengths) / numrevs
2019 2019 maxchainlen = max(chainlengths)
2020 2020 maxchainspan = max(chainspans)
2021 2021 compratio = 1
2022 2022 if totalsize:
2023 2023 compratio = totalrawsize / totalsize
2024 2024
2025 2025 basedfmtstr = '%%%dd\n'
2026 2026 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2027 2027
2028 2028 def dfmtstr(max):
2029 2029 return basedfmtstr % len(str(max))
2030 2030 def pcfmtstr(max, padding=0):
2031 2031 return basepcfmtstr % (len(str(max)), ' ' * padding)
2032 2032
2033 2033 def pcfmt(value, total):
2034 2034 if total:
2035 2035 return (value, 100 * float(value) / total)
2036 2036 else:
2037 2037 return value, 100.0
2038 2038
2039 2039 ui.write(('format : %d\n') % format)
2040 2040 ui.write(('flags : %s\n') % ', '.join(flags))
2041 2041
2042 2042 ui.write('\n')
2043 2043 fmt = pcfmtstr(totalsize)
2044 2044 fmt2 = dfmtstr(totalsize)
2045 2045 ui.write(('revisions : ') + fmt2 % numrevs)
2046 2046 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2047 2047 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2048 2048 ui.write(('revisions : ') + fmt2 % numrevs)
2049 2049 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2050 2050 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2051 2051 ui.write(('revision size : ') + fmt2 % totalsize)
2052 2052 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2053 2053 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2054 2054
2055 2055 def fmtchunktype(chunktype):
2056 2056 if chunktype == 'empty':
2057 2057 return ' %s : ' % chunktype
2058 2058 elif chunktype in pycompat.bytestr(string.ascii_letters):
2059 2059 return ' 0x%s (%s) : ' % (hex(chunktype), chunktype)
2060 2060 else:
2061 2061 return ' 0x%s : ' % hex(chunktype)
2062 2062
2063 2063 ui.write('\n')
2064 2064 ui.write(('chunks : ') + fmt2 % numrevs)
2065 2065 for chunktype in sorted(chunktypecounts):
2066 2066 ui.write(fmtchunktype(chunktype))
2067 2067 ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
2068 2068 ui.write(('chunks size : ') + fmt2 % totalsize)
2069 2069 for chunktype in sorted(chunktypecounts):
2070 2070 ui.write(fmtchunktype(chunktype))
2071 2071 ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
2072 2072
2073 2073 ui.write('\n')
2074 2074 fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
2075 2075 ui.write(('avg chain length : ') + fmt % avgchainlen)
2076 2076 ui.write(('max chain length : ') + fmt % maxchainlen)
2077 2077 ui.write(('max chain reach : ') + fmt % maxchainspan)
2078 2078 ui.write(('compression ratio : ') + fmt % compratio)
2079 2079
2080 2080 if format > 0:
2081 2081 ui.write('\n')
2082 2082 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2083 2083 % tuple(datasize))
2084 2084 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2085 2085 % tuple(fullsize))
2086 2086 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2087 2087 % tuple(deltasize))
2088 2088
2089 2089 if numdeltas > 0:
2090 2090 ui.write('\n')
2091 2091 fmt = pcfmtstr(numdeltas)
2092 2092 fmt2 = pcfmtstr(numdeltas, 4)
2093 2093 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2094 2094 if numprev > 0:
2095 2095 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2096 2096 numprev))
2097 2097 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2098 2098 numprev))
2099 2099 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2100 2100 numprev))
2101 2101 if gdelta:
2102 2102 ui.write(('deltas against p1 : ')
2103 2103 + fmt % pcfmt(nump1, numdeltas))
2104 2104 ui.write(('deltas against p2 : ')
2105 2105 + fmt % pcfmt(nump2, numdeltas))
2106 2106 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2107 2107 numdeltas))
2108 2108
2109 2109 @command('debugrevspec',
2110 2110 [('', 'optimize', None,
2111 2111 _('print parsed tree after optimizing (DEPRECATED)')),
2112 2112 ('', 'show-revs', True, _('print list of result revisions (default)')),
2113 2113 ('s', 'show-set', None, _('print internal representation of result set')),
2114 2114 ('p', 'show-stage', [],
2115 2115 _('print parsed tree at the given stage'), _('NAME')),
2116 2116 ('', 'no-optimized', False, _('evaluate tree without optimization')),
2117 2117 ('', 'verify-optimized', False, _('verify optimized result')),
2118 2118 ],
2119 2119 ('REVSPEC'))
2120 2120 def debugrevspec(ui, repo, expr, **opts):
2121 2121 """parse and apply a revision specification
2122 2122
2123 2123 Use -p/--show-stage option to print the parsed tree at the given stages.
2124 2124 Use -p all to print tree at every stage.
2125 2125
2126 2126 Use --no-show-revs option with -s or -p to print only the set
2127 2127 representation or the parsed tree respectively.
2128 2128
2129 2129 Use --verify-optimized to compare the optimized result with the unoptimized
2130 2130 one. Returns 1 if the optimized result differs.
2131 2131 """
2132 2132 opts = pycompat.byteskwargs(opts)
2133 2133 aliases = ui.configitems('revsetalias')
2134 2134 stages = [
2135 2135 ('parsed', lambda tree: tree),
2136 2136 ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
2137 2137 ui.warn)),
2138 2138 ('concatenated', revsetlang.foldconcat),
2139 2139 ('analyzed', revsetlang.analyze),
2140 2140 ('optimized', revsetlang.optimize),
2141 2141 ]
2142 2142 if opts['no_optimized']:
2143 2143 stages = stages[:-1]
2144 2144 if opts['verify_optimized'] and opts['no_optimized']:
2145 2145 raise error.Abort(_('cannot use --verify-optimized with '
2146 2146 '--no-optimized'))
2147 2147 stagenames = set(n for n, f in stages)
2148 2148
2149 2149 showalways = set()
2150 2150 showchanged = set()
2151 2151 if ui.verbose and not opts['show_stage']:
2152 2152 # show parsed tree by --verbose (deprecated)
2153 2153 showalways.add('parsed')
2154 2154 showchanged.update(['expanded', 'concatenated'])
2155 2155 if opts['optimize']:
2156 2156 showalways.add('optimized')
2157 2157 if opts['show_stage'] and opts['optimize']:
2158 2158 raise error.Abort(_('cannot use --optimize with --show-stage'))
2159 2159 if opts['show_stage'] == ['all']:
2160 2160 showalways.update(stagenames)
2161 2161 else:
2162 2162 for n in opts['show_stage']:
2163 2163 if n not in stagenames:
2164 2164 raise error.Abort(_('invalid stage name: %s') % n)
2165 2165 showalways.update(opts['show_stage'])
2166 2166
2167 2167 treebystage = {}
2168 2168 printedtree = None
2169 2169 tree = revsetlang.parse(expr, lookup=repo.__contains__)
2170 2170 for n, f in stages:
2171 2171 treebystage[n] = tree = f(tree)
2172 2172 if n in showalways or (n in showchanged and tree != printedtree):
2173 2173 if opts['show_stage'] or n != 'parsed':
2174 2174 ui.write(("* %s:\n") % n)
2175 2175 ui.write(revsetlang.prettyformat(tree), "\n")
2176 2176 printedtree = tree
2177 2177
2178 2178 if opts['verify_optimized']:
2179 2179 arevs = revset.makematcher(treebystage['analyzed'])(repo)
2180 2180 brevs = revset.makematcher(treebystage['optimized'])(repo)
2181 2181 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2182 2182 ui.write(("* analyzed set:\n"), smartset.prettyformat(arevs), "\n")
2183 2183 ui.write(("* optimized set:\n"), smartset.prettyformat(brevs), "\n")
2184 2184 arevs = list(arevs)
2185 2185 brevs = list(brevs)
2186 2186 if arevs == brevs:
2187 2187 return 0
2188 2188 ui.write(('--- analyzed\n'), label='diff.file_a')
2189 2189 ui.write(('+++ optimized\n'), label='diff.file_b')
2190 2190 sm = difflib.SequenceMatcher(None, arevs, brevs)
2191 2191 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2192 2192 if tag in ('delete', 'replace'):
2193 2193 for c in arevs[alo:ahi]:
2194 2194 ui.write('-%s\n' % c, label='diff.deleted')
2195 2195 if tag in ('insert', 'replace'):
2196 2196 for c in brevs[blo:bhi]:
2197 2197 ui.write('+%s\n' % c, label='diff.inserted')
2198 2198 if tag == 'equal':
2199 2199 for c in arevs[alo:ahi]:
2200 2200 ui.write(' %s\n' % c)
2201 2201 return 1
2202 2202
2203 2203 func = revset.makematcher(tree)
2204 2204 revs = func(repo)
2205 2205 if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
2206 2206 ui.write(("* set:\n"), smartset.prettyformat(revs), "\n")
2207 2207 if not opts['show_revs']:
2208 2208 return
2209 2209 for c in revs:
2210 ui.write("%s\n" % c)
2210 ui.write("%d\n" % c)
2211 2211
2212 2212 @command('debugsetparents', [], _('REV1 [REV2]'))
2213 2213 def debugsetparents(ui, repo, rev1, rev2=None):
2214 2214 """manually set the parents of the current working directory
2215 2215
2216 2216 This is useful for writing repository conversion tools, but should
2217 2217 be used with care. For example, neither the working directory nor the
2218 2218 dirstate is updated, so file status may be incorrect after running this
2219 2219 command.
2220 2220
2221 2221 Returns 0 on success.
2222 2222 """
2223 2223
2224 2224 r1 = scmutil.revsingle(repo, rev1).node()
2225 2225 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2226 2226
2227 2227 with repo.wlock():
2228 2228 repo.setparents(r1, r2)
2229 2229
2230 2230 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
2231 2231 def debugssl(ui, repo, source=None, **opts):
2232 2232 '''test a secure connection to a server
2233 2233
2234 2234 This builds the certificate chain for the server on Windows, installing the
2235 2235 missing intermediates and trusted root via Windows Update if necessary. It
2236 2236 does nothing on other platforms.
2237 2237
2238 2238 If SOURCE is omitted, the 'default' path will be used. If a URL is given,
2239 2239 that server is used. See :hg:`help urls` for more information.
2240 2240
2241 2241 If the update succeeds, retry the original operation. Otherwise, the cause
2242 2242 of the SSL error is likely another issue.
2243 2243 '''
2244 2244 if not pycompat.iswindows:
2245 2245 raise error.Abort(_('certificate chain building is only possible on '
2246 2246 'Windows'))
2247 2247
2248 2248 if not source:
2249 2249 if not repo:
2250 2250 raise error.Abort(_("there is no Mercurial repository here, and no "
2251 2251 "server specified"))
2252 2252 source = "default"
2253 2253
2254 2254 source, branches = hg.parseurl(ui.expandpath(source))
2255 2255 url = util.url(source)
2256 2256 addr = None
2257 2257
2258 2258 defaultport = {'https': 443, 'ssh': 22}
2259 2259 if url.scheme in defaultport:
2260 2260 try:
2261 2261 addr = (url.host, int(url.port or defaultport[url.scheme]))
2262 2262 except ValueError:
2263 2263 raise error.Abort(_("malformed port number in URL"))
2264 2264 else:
2265 2265 raise error.Abort(_("only https and ssh connections are supported"))
2266 2266
2267 2267 from . import win32
2268 2268
2269 2269 s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
2270 2270 cert_reqs=ssl.CERT_NONE, ca_certs=None)
2271 2271
2272 2272 try:
2273 2273 s.connect(addr)
2274 2274 cert = s.getpeercert(True)
2275 2275
2276 2276 ui.status(_('checking the certificate chain for %s\n') % url.host)
2277 2277
2278 2278 complete = win32.checkcertificatechain(cert, build=False)
2279 2279
2280 2280 if not complete:
2281 2281 ui.status(_('certificate chain is incomplete, updating... '))
2282 2282
2283 2283 if not win32.checkcertificatechain(cert):
2284 2284 ui.status(_('failed.\n'))
2285 2285 else:
2286 2286 ui.status(_('done.\n'))
2287 2287 else:
2288 2288 ui.status(_('full certificate chain is available\n'))
2289 2289 finally:
2290 2290 s.close()
2291 2291
2292 2292 @command('debugsub',
2293 2293 [('r', 'rev', '',
2294 2294 _('revision to check'), _('REV'))],
2295 2295 _('[-r REV] [REV]'))
2296 2296 def debugsub(ui, repo, rev=None):
2297 2297 ctx = scmutil.revsingle(repo, rev, None)
2298 2298 for k, v in sorted(ctx.substate.items()):
2299 2299 ui.write(('path %s\n') % k)
2300 2300 ui.write((' source %s\n') % v[0])
2301 2301 ui.write((' revision %s\n') % v[1])
2302 2302
2303 2303 @command('debugsuccessorssets',
2304 2304 [('', 'closest', False, _('return closest successors sets only'))],
2305 2305 _('[REV]'))
2306 2306 def debugsuccessorssets(ui, repo, *revs, **opts):
2307 2307 """show set of successors for revision
2308 2308
2309 2309 A successors set of changeset A is a consistent group of revisions that
2310 2310 succeed A. It contains non-obsolete changesets only unless closests
2311 2311 successors set is set.
2312 2312
2313 2313 In most cases a changeset A has a single successors set containing a single
2314 2314 successor (changeset A replaced by A').
2315 2315
2316 2316 A changeset that is made obsolete with no successors are called "pruned".
2317 2317 Such changesets have no successors sets at all.
2318 2318
2319 2319 A changeset that has been "split" will have a successors set containing
2320 2320 more than one successor.
2321 2321
2322 2322 A changeset that has been rewritten in multiple different ways is called
2323 2323 "divergent". Such changesets have multiple successor sets (each of which
2324 2324 may also be split, i.e. have multiple successors).
2325 2325
2326 2326 Results are displayed as follows::
2327 2327
2328 2328 <rev1>
2329 2329 <successors-1A>
2330 2330 <rev2>
2331 2331 <successors-2A>
2332 2332 <successors-2B1> <successors-2B2> <successors-2B3>
2333 2333
2334 2334 Here rev2 has two possible (i.e. divergent) successors sets. The first
2335 2335 holds one element, whereas the second holds three (i.e. the changeset has
2336 2336 been split).
2337 2337 """
2338 2338 # passed to successorssets caching computation from one call to another
2339 2339 cache = {}
2340 2340 ctx2str = str
2341 2341 node2str = short
2342 2342 for rev in scmutil.revrange(repo, revs):
2343 2343 ctx = repo[rev]
2344 2344 ui.write('%s\n'% ctx2str(ctx))
2345 2345 for succsset in obsutil.successorssets(repo, ctx.node(),
2346 2346 closest=opts[r'closest'],
2347 2347 cache=cache):
2348 2348 if succsset:
2349 2349 ui.write(' ')
2350 2350 ui.write(node2str(succsset[0]))
2351 2351 for node in succsset[1:]:
2352 2352 ui.write(' ')
2353 2353 ui.write(node2str(node))
2354 2354 ui.write('\n')
2355 2355
2356 2356 @command('debugtemplate',
2357 2357 [('r', 'rev', [], _('apply template on changesets'), _('REV')),
2358 2358 ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
2359 2359 _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
2360 2360 optionalrepo=True)
2361 2361 def debugtemplate(ui, repo, tmpl, **opts):
2362 2362 """parse and apply a template
2363 2363
2364 2364 If -r/--rev is given, the template is processed as a log template and
2365 2365 applied to the given changesets. Otherwise, it is processed as a generic
2366 2366 template.
2367 2367
2368 2368 Use --verbose to print the parsed tree.
2369 2369 """
2370 2370 revs = None
2371 2371 if opts[r'rev']:
2372 2372 if repo is None:
2373 2373 raise error.RepoError(_('there is no Mercurial repository here '
2374 2374 '(.hg not found)'))
2375 2375 revs = scmutil.revrange(repo, opts[r'rev'])
2376 2376
2377 2377 props = {}
2378 2378 for d in opts[r'define']:
2379 2379 try:
2380 2380 k, v = (e.strip() for e in d.split('=', 1))
2381 2381 if not k or k == 'ui':
2382 2382 raise ValueError
2383 2383 props[k] = v
2384 2384 except ValueError:
2385 2385 raise error.Abort(_('malformed keyword definition: %s') % d)
2386 2386
2387 2387 if ui.verbose:
2388 2388 aliases = ui.configitems('templatealias')
2389 2389 tree = templater.parse(tmpl)
2390 2390 ui.note(templater.prettyformat(tree), '\n')
2391 2391 newtree = templater.expandaliases(tree, aliases)
2392 2392 if newtree != tree:
2393 2393 ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
2394 2394
2395 2395 if revs is None:
2396 2396 tres = formatter.templateresources(ui, repo)
2397 2397 t = formatter.maketemplater(ui, tmpl, resources=tres)
2398 2398 ui.write(t.render(props))
2399 2399 else:
2400 2400 displayer = logcmdutil.maketemplater(ui, repo, tmpl)
2401 2401 for r in revs:
2402 2402 displayer.show(repo[r], **pycompat.strkwargs(props))
2403 2403 displayer.close()
2404 2404
2405 2405 @command('debugupdatecaches', [])
2406 2406 def debugupdatecaches(ui, repo, *pats, **opts):
2407 2407 """warm all known caches in the repository"""
2408 2408 with repo.wlock(), repo.lock():
2409 2409 repo.updatecaches()
2410 2410
2411 2411 @command('debugupgraderepo', [
2412 2412 ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
2413 2413 ('', 'run', False, _('performs an upgrade')),
2414 2414 ])
2415 2415 def debugupgraderepo(ui, repo, run=False, optimize=None):
2416 2416 """upgrade a repository to use different features
2417 2417
2418 2418 If no arguments are specified, the repository is evaluated for upgrade
2419 2419 and a list of problems and potential optimizations is printed.
2420 2420
2421 2421 With ``--run``, a repository upgrade is performed. Behavior of the upgrade
2422 2422 can be influenced via additional arguments. More details will be provided
2423 2423 by the command output when run without ``--run``.
2424 2424
2425 2425 During the upgrade, the repository will be locked and no writes will be
2426 2426 allowed.
2427 2427
2428 2428 At the end of the upgrade, the repository may not be readable while new
2429 2429 repository data is swapped in. This window will be as long as it takes to
2430 2430 rename some directories inside the ``.hg`` directory. On most machines, this
2431 2431 should complete almost instantaneously and the chances of a consumer being
2432 2432 unable to access the repository should be low.
2433 2433 """
2434 2434 return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize)
2435 2435
2436 2436 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
2437 2437 inferrepo=True)
2438 2438 def debugwalk(ui, repo, *pats, **opts):
2439 2439 """show how files match on given patterns"""
2440 2440 opts = pycompat.byteskwargs(opts)
2441 2441 m = scmutil.match(repo[None], pats, opts)
2442 2442 ui.write(('matcher: %r\n' % m))
2443 2443 items = list(repo[None].walk(m))
2444 2444 if not items:
2445 2445 return
2446 2446 f = lambda fn: fn
2447 2447 if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
2448 2448 f = lambda fn: util.normpath(fn)
2449 2449 fmt = 'f %%-%ds %%-%ds %%s' % (
2450 2450 max([len(abs) for abs in items]),
2451 2451 max([len(m.rel(abs)) for abs in items]))
2452 2452 for abs in items:
2453 2453 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2454 2454 ui.write("%s\n" % line.rstrip())
2455 2455
2456 2456 @command('debugwireargs',
2457 2457 [('', 'three', '', 'three'),
2458 2458 ('', 'four', '', 'four'),
2459 2459 ('', 'five', '', 'five'),
2460 2460 ] + cmdutil.remoteopts,
2461 2461 _('REPO [OPTIONS]... [ONE [TWO]]'),
2462 2462 norepo=True)
2463 2463 def debugwireargs(ui, repopath, *vals, **opts):
2464 2464 opts = pycompat.byteskwargs(opts)
2465 2465 repo = hg.peer(ui, opts, repopath)
2466 2466 for opt in cmdutil.remoteopts:
2467 2467 del opts[opt[1]]
2468 2468 args = {}
2469 2469 for k, v in opts.iteritems():
2470 2470 if v:
2471 2471 args[k] = v
2472 2472 args = pycompat.strkwargs(args)
2473 2473 # run twice to check that we don't mess up the stream for the next command
2474 2474 res1 = repo.debugwireargs(*vals, **args)
2475 2475 res2 = repo.debugwireargs(*vals, **args)
2476 2476 ui.write("%s\n" % res1)
2477 2477 if res1 != res2:
2478 2478 ui.warn("%s\n" % res2)
General Comments 0
You need to be logged in to leave comments. Login now