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