mercurial/debugcommands.py
changeset 43076 2372284d9457
parent 43067 0fde7d47ad6f
child 43077 687b865b95ad
equal deleted inserted replaced
43075:57875cf423c9 43076:2372284d9457
    86     dateutil,
    86     dateutil,
    87     procutil,
    87     procutil,
    88     stringutil,
    88     stringutil,
    89 )
    89 )
    90 
    90 
    91 from .revlogutils import (
    91 from .revlogutils import deltas as deltautil
    92     deltas as deltautil
       
    93 )
       
    94 
    92 
    95 release = lockmod.release
    93 release = lockmod.release
    96 
    94 
    97 command = registrar.command()
    95 command = registrar.command()
       
    96 
    98 
    97 
    99 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
    98 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
   100 def debugancestor(ui, repo, *args):
    99 def debugancestor(ui, repo, *args):
   101     """find the ancestor revision of two revisions in a given index"""
   100     """find the ancestor revision of two revisions in a given index"""
   102     if len(args) == 3:
   101     if len(args) == 3:
   103         index, rev1, rev2 = args
   102         index, rev1, rev2 = args
   104         r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
   103         r = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), index)
   105         lookup = r.lookup
   104         lookup = r.lookup
   106     elif len(args) == 2:
   105     elif len(args) == 2:
   107         if not repo:
   106         if not repo:
   108             raise error.Abort(_('there is no Mercurial repository here '
   107             raise error.Abort(
   109                                 '(.hg not found)'))
   108                 _('there is no Mercurial repository here ' '(.hg not found)')
       
   109             )
   110         rev1, rev2 = args
   110         rev1, rev2 = args
   111         r = repo.changelog
   111         r = repo.changelog
   112         lookup = repo.lookup
   112         lookup = repo.lookup
   113     else:
   113     else:
   114         raise error.Abort(_('either two or three arguments required'))
   114         raise error.Abort(_('either two or three arguments required'))
   115     a = r.ancestor(lookup(rev1), lookup(rev2))
   115     a = r.ancestor(lookup(rev1), lookup(rev2))
   116     ui.write('%d:%s\n' % (r.rev(a), hex(a)))
   116     ui.write('%d:%s\n' % (r.rev(a), hex(a)))
   117 
   117 
       
   118 
   118 @command('debugapplystreamclonebundle', [], 'FILE')
   119 @command('debugapplystreamclonebundle', [], 'FILE')
   119 def debugapplystreamclonebundle(ui, repo, fname):
   120 def debugapplystreamclonebundle(ui, repo, fname):
   120     """apply a stream clone bundle file"""
   121     """apply a stream clone bundle file"""
   121     f = hg.openpath(ui, fname)
   122     f = hg.openpath(ui, fname)
   122     gen = exchange.readbundle(ui, f, fname)
   123     gen = exchange.readbundle(ui, f, fname)
   123     gen.apply(repo)
   124     gen.apply(repo)
   124 
   125 
   125 @command('debugbuilddag',
   126 
   126     [('m', 'mergeable-file', None, _('add single file mergeable changes')),
   127 @command(
   127     ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
   128     'debugbuilddag',
   128     ('n', 'new-file', None, _('add new file at each rev'))],
   129     [
   129     _('[OPTION]... [TEXT]'))
   130         ('m', 'mergeable-file', None, _('add single file mergeable changes')),
   130 def debugbuilddag(ui, repo, text=None,
   131         (
   131                   mergeable_file=False,
   132             'o',
   132                   overwritten_file=False,
   133             'overwritten-file',
   133                   new_file=False):
   134             None,
       
   135             _('add single file all revs overwrite'),
       
   136         ),
       
   137         ('n', 'new-file', None, _('add new file at each rev')),
       
   138     ],
       
   139     _('[OPTION]... [TEXT]'),
       
   140 )
       
   141 def debugbuilddag(
       
   142     ui,
       
   143     repo,
       
   144     text=None,
       
   145     mergeable_file=False,
       
   146     overwritten_file=False,
       
   147     new_file=False,
       
   148 ):
   134     """builds a repo with a given DAG from scratch in the current empty repo
   149     """builds a repo with a given DAG from scratch in the current empty repo
   135 
   150 
   136     The description of the DAG is read from stdin if not given on the
   151     The description of the DAG is read from stdin if not given on the
   137     command line.
   152     command line.
   138 
   153 
   178             total += 1
   193             total += 1
   179 
   194 
   180     if mergeable_file:
   195     if mergeable_file:
   181         linesperrev = 2
   196         linesperrev = 2
   182         # make a file with k lines per rev
   197         # make a file with k lines per rev
   183         initialmergedlines = ['%d' % i
   198         initialmergedlines = [
   184                               for i in pycompat.xrange(0, total * linesperrev)]
   199             '%d' % i for i in pycompat.xrange(0, total * linesperrev)
       
   200         ]
   185         initialmergedlines.append("")
   201         initialmergedlines.append("")
   186 
   202 
   187     tags = []
   203     tags = []
   188     progress = ui.makeprogress(_('building'), unit=_('revisions'),
   204     progress = ui.makeprogress(_('building'), unit=_('revisions'), total=total)
   189                                total=total)
       
   190     with progress, repo.wlock(), repo.lock(), repo.transaction("builddag"):
   205     with progress, repo.wlock(), repo.lock(), repo.transaction("builddag"):
   191         at = -1
   206         at = -1
   192         atbranch = 'default'
   207         atbranch = 'default'
   193         nodeids = []
   208         nodeids = []
   194         id = 0
   209         id = 0
   206                     fn = "mf"
   221                     fn = "mf"
   207                     p1 = repo[ps[0]]
   222                     p1 = repo[ps[0]]
   208                     if len(ps) > 1:
   223                     if len(ps) > 1:
   209                         p2 = repo[ps[1]]
   224                         p2 = repo[ps[1]]
   210                         pa = p1.ancestor(p2)
   225                         pa = p1.ancestor(p2)
   211                         base, local, other = [x[fn].data() for x in (pa, p1,
   226                         base, local, other = [
   212                                                                      p2)]
   227                             x[fn].data() for x in (pa, p1, p2)
       
   228                         ]
   213                         m3 = simplemerge.Merge3Text(base, local, other)
   229                         m3 = simplemerge.Merge3Text(base, local, other)
   214                         ml = [l.strip() for l in m3.merge_lines()]
   230                         ml = [l.strip() for l in m3.merge_lines()]
   215                         ml.append("")
   231                         ml.append("")
   216                     elif at > 0:
   232                     elif at > 0:
   217                         ml = p1[fn].data().split("\n")
   233                         ml = p1[fn].data().split("\n")
   239                                 files.append(fn)
   255                                 files.append(fn)
   240                                 filecontent[fn] = p2[fn].data()
   256                                 filecontent[fn] = p2[fn].data()
   241 
   257 
   242                 def fctxfn(repo, cx, path):
   258                 def fctxfn(repo, cx, path):
   243                     if path in filecontent:
   259                     if path in filecontent:
   244                         return context.memfilectx(repo, cx, path,
   260                         return context.memfilectx(
   245                                                   filecontent[path])
   261                             repo, cx, path, filecontent[path]
       
   262                         )
   246                     return None
   263                     return None
   247 
   264 
   248                 if len(ps) == 0 or ps[0] < 0:
   265                 if len(ps) == 0 or ps[0] < 0:
   249                     pars = [None, None]
   266                     pars = [None, None]
   250                 elif len(ps) == 1:
   267                 elif len(ps) == 1:
   251                     pars = [nodeids[ps[0]], None]
   268                     pars = [nodeids[ps[0]], None]
   252                 else:
   269                 else:
   253                     pars = [nodeids[p] for p in ps]
   270                     pars = [nodeids[p] for p in ps]
   254                 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
   271                 cx = context.memctx(
   255                                     date=(id, 0),
   272                     repo,
   256                                     user="debugbuilddag",
   273                     pars,
   257                                     extra={'branch': atbranch})
   274                     "r%i" % id,
       
   275                     files,
       
   276                     fctxfn,
       
   277                     date=(id, 0),
       
   278                     user="debugbuilddag",
       
   279                     extra={'branch': atbranch},
       
   280                 )
   258                 nodeid = repo.commitctx(cx)
   281                 nodeid = repo.commitctx(cx)
   259                 nodeids.append(nodeid)
   282                 nodeids.append(nodeid)
   260                 at = id
   283                 at = id
   261             elif type == 'l':
   284             elif type == 'l':
   262                 id, name = data
   285                 id, name = data
   268             progress.update(id)
   291             progress.update(id)
   269 
   292 
   270         if tags:
   293         if tags:
   271             repo.vfs.write("localtags", "".join(tags))
   294             repo.vfs.write("localtags", "".join(tags))
   272 
   295 
       
   296 
   273 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
   297 def _debugchangegroup(ui, gen, all=None, indent=0, **opts):
   274     indent_string = ' ' * indent
   298     indent_string = ' ' * indent
   275     if all:
   299     if all:
   276         ui.write(("%sformat: id, p1, p2, cset, delta base, len(delta)\n")
   300         ui.write(
   277                  % indent_string)
   301             "%sformat: id, p1, p2, cset, delta base, len(delta)\n"
       
   302             % indent_string
       
   303         )
   278 
   304 
   279         def showchunks(named):
   305         def showchunks(named):
   280             ui.write("\n%s%s\n" % (indent_string, named))
   306             ui.write("\n%s%s\n" % (indent_string, named))
   281             for deltadata in gen.deltaiter():
   307             for deltadata in gen.deltaiter():
   282                 node, p1, p2, cs, deltabase, delta, flags = deltadata
   308                 node, p1, p2, cs, deltabase, delta, flags = deltadata
   283                 ui.write("%s%s %s %s %s %s %d\n" %
   309                 ui.write(
   284                          (indent_string, hex(node), hex(p1), hex(p2),
   310                     "%s%s %s %s %s %s %d\n"
   285                           hex(cs), hex(deltabase), len(delta)))
   311                     % (
       
   312                         indent_string,
       
   313                         hex(node),
       
   314                         hex(p1),
       
   315                         hex(p2),
       
   316                         hex(cs),
       
   317                         hex(deltabase),
       
   318                         len(delta),
       
   319                     )
       
   320                 )
   286 
   321 
   287         chunkdata = gen.changelogheader()
   322         chunkdata = gen.changelogheader()
   288         showchunks("changelog")
   323         showchunks("changelog")
   289         chunkdata = gen.manifestheader()
   324         chunkdata = gen.manifestheader()
   290         showchunks("manifest")
   325         showchunks("manifest")
   296             raise error.Abort(_('use debugbundle2 for this file'))
   331             raise error.Abort(_('use debugbundle2 for this file'))
   297         chunkdata = gen.changelogheader()
   332         chunkdata = gen.changelogheader()
   298         for deltadata in gen.deltaiter():
   333         for deltadata in gen.deltaiter():
   299             node, p1, p2, cs, deltabase, delta, flags = deltadata
   334             node, p1, p2, cs, deltabase, delta, flags = deltadata
   300             ui.write("%s%s\n" % (indent_string, hex(node)))
   335             ui.write("%s%s\n" % (indent_string, hex(node)))
       
   336 
   301 
   337 
   302 def _debugobsmarkers(ui, part, indent=0, **opts):
   338 def _debugobsmarkers(ui, part, indent=0, **opts):
   303     """display version and markers contained in 'data'"""
   339     """display version and markers contained in 'data'"""
   304     opts = pycompat.byteskwargs(opts)
   340     opts = pycompat.byteskwargs(opts)
   305     data = part.read()
   341     data = part.read()
   320             fm.startitem()
   356             fm.startitem()
   321             fm.plain(indent_string)
   357             fm.plain(indent_string)
   322             cmdutil.showmarker(fm, m)
   358             cmdutil.showmarker(fm, m)
   323         fm.end()
   359         fm.end()
   324 
   360 
       
   361 
   325 def _debugphaseheads(ui, data, indent=0):
   362 def _debugphaseheads(ui, data, indent=0):
   326     """display version and markers contained in 'data'"""
   363     """display version and markers contained in 'data'"""
   327     indent_string = ' ' * indent
   364     indent_string = ' ' * indent
   328     headsbyphase = phases.binarydecode(data)
   365     headsbyphase = phases.binarydecode(data)
   329     for phase in phases.allphases:
   366     for phase in phases.allphases:
   330         for head in headsbyphase[phase]:
   367         for head in headsbyphase[phase]:
   331             ui.write(indent_string)
   368             ui.write(indent_string)
   332             ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
   369             ui.write('%s %s\n' % (hex(head), phases.phasenames[phase]))
   333 
   370 
       
   371 
   334 def _quasirepr(thing):
   372 def _quasirepr(thing):
   335     if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
   373     if isinstance(thing, (dict, util.sortdict, collections.OrderedDict)):
   336         return '{%s}' % (
   374         return '{%s}' % (
   337             b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing)))
   375             b', '.join(b'%s: %s' % (k, thing[k]) for k in sorted(thing))
       
   376         )
   338     return pycompat.bytestr(repr(thing))
   377     return pycompat.bytestr(repr(thing))
       
   378 
   339 
   379 
   340 def _debugbundle2(ui, gen, all=None, **opts):
   380 def _debugbundle2(ui, gen, all=None, **opts):
   341     """lists the contents of a bundle2"""
   381     """lists the contents of a bundle2"""
   342     if not isinstance(gen, bundle2.unbundle20):
   382     if not isinstance(gen, bundle2.unbundle20):
   343         raise error.Abort(_('not a bundle2 file'))
   383         raise error.Abort(_('not a bundle2 file'))
   358                 _debugobsmarkers(ui, part, indent=4, **opts)
   398                 _debugobsmarkers(ui, part, indent=4, **opts)
   359         if part.type == 'phase-heads':
   399         if part.type == 'phase-heads':
   360             if not ui.quiet:
   400             if not ui.quiet:
   361                 _debugphaseheads(ui, part, indent=4)
   401                 _debugphaseheads(ui, part, indent=4)
   362 
   402 
   363 @command('debugbundle',
   403 
   364         [('a', 'all', None, _('show all details')),
   404 @command(
   365          ('', 'part-type', [], _('show only the named part type')),
   405     'debugbundle',
   366          ('', 'spec', None, _('print the bundlespec of the bundle'))],
   406     [
   367         _('FILE'),
   407         ('a', 'all', None, _('show all details')),
   368         norepo=True)
   408         ('', 'part-type', [], _('show only the named part type')),
       
   409         ('', 'spec', None, _('print the bundlespec of the bundle')),
       
   410     ],
       
   411     _('FILE'),
       
   412     norepo=True,
       
   413 )
   369 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
   414 def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
   370     """lists the contents of a bundle"""
   415     """lists the contents of a bundle"""
   371     with hg.openpath(ui, bundlepath) as f:
   416     with hg.openpath(ui, bundlepath) as f:
   372         if spec:
   417         if spec:
   373             spec = exchange.getbundlespec(ui, f)
   418             spec = exchange.getbundlespec(ui, f)
   377         gen = exchange.readbundle(ui, f, bundlepath)
   422         gen = exchange.readbundle(ui, f, bundlepath)
   378         if isinstance(gen, bundle2.unbundle20):
   423         if isinstance(gen, bundle2.unbundle20):
   379             return _debugbundle2(ui, gen, all=all, **opts)
   424             return _debugbundle2(ui, gen, all=all, **opts)
   380         _debugchangegroup(ui, gen, all=all, **opts)
   425         _debugchangegroup(ui, gen, all=all, **opts)
   381 
   426 
   382 @command('debugcapabilities',
   427 
   383         [], _('PATH'),
   428 @command('debugcapabilities', [], _('PATH'), norepo=True)
   384         norepo=True)
       
   385 def debugcapabilities(ui, path, **opts):
   429 def debugcapabilities(ui, path, **opts):
   386     """lists the capabilities of a remote peer"""
   430     """lists the capabilities of a remote peer"""
   387     opts = pycompat.byteskwargs(opts)
   431     opts = pycompat.byteskwargs(opts)
   388     peer = hg.peer(ui, opts, path)
   432     peer = hg.peer(ui, opts, path)
   389     caps = peer.capabilities()
   433     caps = peer.capabilities()
   390     ui.write(('Main capabilities:\n'))
   434     ui.write('Main capabilities:\n')
   391     for c in sorted(caps):
   435     for c in sorted(caps):
   392         ui.write(('  %s\n') % c)
   436         ui.write('  %s\n' % c)
   393     b2caps = bundle2.bundle2caps(peer)
   437     b2caps = bundle2.bundle2caps(peer)
   394     if b2caps:
   438     if b2caps:
   395         ui.write(('Bundle2 capabilities:\n'))
   439         ui.write('Bundle2 capabilities:\n')
   396         for key, values in sorted(b2caps.iteritems()):
   440         for key, values in sorted(b2caps.iteritems()):
   397             ui.write(('  %s\n') % key)
   441             ui.write('  %s\n' % key)
   398             for v in values:
   442             for v in values:
   399                 ui.write(('    %s\n') % v)
   443                 ui.write('    %s\n' % v)
       
   444 
   400 
   445 
   401 @command('debugcheckstate', [], '')
   446 @command('debugcheckstate', [], '')
   402 def debugcheckstate(ui, repo):
   447 def debugcheckstate(ui, repo):
   403     """validate the correctness of the current dirstate"""
   448     """validate the correctness of the current dirstate"""
   404     parent1, parent2 = repo.dirstate.parents()
   449     parent1, parent2 = repo.dirstate.parents()
   412             errors += 1
   457             errors += 1
   413         if state in "a" and f in m1:
   458         if state in "a" and f in m1:
   414             ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
   459             ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
   415             errors += 1
   460             errors += 1
   416         if state in "m" and f not in m1 and f not in m2:
   461         if state in "m" and f not in m1 and f not in m2:
   417             ui.warn(_("%s in state %s, but not in either manifest\n") %
   462             ui.warn(
   418                     (f, state))
   463                 _("%s in state %s, but not in either manifest\n") % (f, state)
       
   464             )
   419             errors += 1
   465             errors += 1
   420     for f in m1:
   466     for f in m1:
   421         state = repo.dirstate[f]
   467         state = repo.dirstate[f]
   422         if state not in "nrm":
   468         if state not in "nrm":
   423             ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
   469             ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
   424             errors += 1
   470             errors += 1
   425     if errors:
   471     if errors:
   426         error = _(".hg/dirstate inconsistent with current parent's manifest")
   472         error = _(".hg/dirstate inconsistent with current parent's manifest")
   427         raise error.Abort(error)
   473         raise error.Abort(error)
   428 
   474 
   429 @command('debugcolor',
   475 
   430         [('', 'style', None, _('show all configured styles'))],
   476 @command(
   431         'hg debugcolor')
   477     'debugcolor',
       
   478     [('', 'style', None, _('show all configured styles'))],
       
   479     'hg debugcolor',
       
   480 )
   432 def debugcolor(ui, repo, **opts):
   481 def debugcolor(ui, repo, **opts):
   433     """show available color, effects or style"""
   482     """show available color, effects or style"""
   434     ui.write(('color mode: %s\n') % stringutil.pprint(ui._colormode))
   483     ui.write('color mode: %s\n' % stringutil.pprint(ui._colormode))
   435     if opts.get(r'style'):
   484     if opts.get(r'style'):
   436         return _debugdisplaystyle(ui)
   485         return _debugdisplaystyle(ui)
   437     else:
   486     else:
   438         return _debugdisplaycolor(ui)
   487         return _debugdisplaycolor(ui)
       
   488 
   439 
   489 
   440 def _debugdisplaycolor(ui):
   490 def _debugdisplaycolor(ui):
   441     ui = ui.copy()
   491     ui = ui.copy()
   442     ui._styles.clear()
   492     ui._styles.clear()
   443     for effect in color._activeeffects(ui).keys():
   493     for effect in color._activeeffects(ui).keys():
   448                 ui._styles[k] = k[6:]
   498                 ui._styles[k] = k[6:]
   449             elif k.startswith('terminfo.'):
   499             elif k.startswith('terminfo.'):
   450                 ui._styles[k] = k[9:]
   500                 ui._styles[k] = k[9:]
   451     ui.write(_('available colors:\n'))
   501     ui.write(_('available colors:\n'))
   452     # sort label with a '_' after the other to group '_background' entry.
   502     # sort label with a '_' after the other to group '_background' entry.
   453     items = sorted(ui._styles.items(),
   503     items = sorted(ui._styles.items(), key=lambda i: ('_' in i[0], i[0], i[1]))
   454                    key=lambda i: ('_' in i[0], i[0], i[1]))
       
   455     for colorname, label in items:
   504     for colorname, label in items:
   456         ui.write(('%s\n') % colorname, label=label)
   505         ui.write('%s\n' % colorname, label=label)
       
   506 
   457 
   507 
   458 def _debugdisplaystyle(ui):
   508 def _debugdisplaystyle(ui):
   459     ui.write(_('available style:\n'))
   509     ui.write(_('available style:\n'))
   460     if not ui._styles:
   510     if not ui._styles:
   461         return
   511         return
   467             ui.write(': ')
   517             ui.write(': ')
   468             ui.write(' ' * (max(0, width - len(label))))
   518             ui.write(' ' * (max(0, width - len(label))))
   469             ui.write(', '.join(ui.label(e, e) for e in effects.split()))
   519             ui.write(', '.join(ui.label(e, e) for e in effects.split()))
   470         ui.write('\n')
   520         ui.write('\n')
   471 
   521 
       
   522 
   472 @command('debugcreatestreamclonebundle', [], 'FILE')
   523 @command('debugcreatestreamclonebundle', [], 'FILE')
   473 def debugcreatestreamclonebundle(ui, repo, fname):
   524 def debugcreatestreamclonebundle(ui, repo, fname):
   474     """create a stream clone bundle file
   525     """create a stream clone bundle file
   475 
   526 
   476     Stream bundles are special bundles that are essentially archives of
   527     Stream bundles are special bundles that are essentially archives of
   477     revlog files. They are commonly used for cloning very quickly.
   528     revlog files. They are commonly used for cloning very quickly.
   478     """
   529     """
   479     # TODO we may want to turn this into an abort when this functionality
   530     # TODO we may want to turn this into an abort when this functionality
   480     # is moved into `hg bundle`.
   531     # is moved into `hg bundle`.
   481     if phases.hassecret(repo):
   532     if phases.hassecret(repo):
   482         ui.warn(_('(warning: stream clone bundle will contain secret '
   533         ui.warn(
   483                   'revisions)\n'))
   534             _(
       
   535                 '(warning: stream clone bundle will contain secret '
       
   536                 'revisions)\n'
       
   537             )
       
   538         )
   484 
   539 
   485     requirements, gen = streamclone.generatebundlev1(repo)
   540     requirements, gen = streamclone.generatebundlev1(repo)
   486     changegroup.writechunks(ui, gen, fname)
   541     changegroup.writechunks(ui, gen, fname)
   487 
   542 
   488     ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
   543     ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
   489 
   544 
   490 @command('debugdag',
   545 
   491     [('t', 'tags', None, _('use tags as labels')),
   546 @command(
   492     ('b', 'branches', None, _('annotate with branch names')),
   547     'debugdag',
   493     ('', 'dots', None, _('use dots for runs')),
   548     [
   494     ('s', 'spaces', None, _('separate elements by spaces'))],
   549         ('t', 'tags', None, _('use tags as labels')),
       
   550         ('b', 'branches', None, _('annotate with branch names')),
       
   551         ('', 'dots', None, _('use dots for runs')),
       
   552         ('s', 'spaces', None, _('separate elements by spaces')),
       
   553     ],
   495     _('[OPTION]... [FILE [REV]...]'),
   554     _('[OPTION]... [FILE [REV]...]'),
   496     optionalrepo=True)
   555     optionalrepo=True,
       
   556 )
   497 def debugdag(ui, repo, file_=None, *revs, **opts):
   557 def debugdag(ui, repo, file_=None, *revs, **opts):
   498     """format the changelog or an index DAG as a concise textual description
   558     """format the changelog or an index DAG as a concise textual description
   499 
   559 
   500     If you pass a revlog index, the revlog's DAG is emitted. If you list
   560     If you pass a revlog index, the revlog's DAG is emitted. If you list
   501     revision numbers, they get labeled in the output as rN.
   561     revision numbers, they get labeled in the output as rN.
   503     Otherwise, the changelog DAG of the current repo is emitted.
   563     Otherwise, the changelog DAG of the current repo is emitted.
   504     """
   564     """
   505     spaces = opts.get(r'spaces')
   565     spaces = opts.get(r'spaces')
   506     dots = opts.get(r'dots')
   566     dots = opts.get(r'dots')
   507     if file_:
   567     if file_:
   508         rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False),
   568         rlog = revlog.revlog(vfsmod.vfs(encoding.getcwd(), audit=False), file_)
   509                              file_)
       
   510         revs = set((int(r) for r in revs))
   569         revs = set((int(r) for r in revs))
       
   570 
   511         def events():
   571         def events():
   512             for r in rlog:
   572             for r in rlog:
   513                 yield 'n', (r, list(p for p in rlog.parentrevs(r)
   573                 yield 'n', (r, list(p for p in rlog.parentrevs(r) if p != -1))
   514                                         if p != -1))
       
   515                 if r in revs:
   574                 if r in revs:
   516                     yield 'l', (r, "r%i" % r)
   575                     yield 'l', (r, "r%i" % r)
       
   576 
   517     elif repo:
   577     elif repo:
   518         cl = repo.changelog
   578         cl = repo.changelog
   519         tags = opts.get(r'tags')
   579         tags = opts.get(r'tags')
   520         branches = opts.get(r'branches')
   580         branches = opts.get(r'branches')
   521         if tags:
   581         if tags:
   522             labels = {}
   582             labels = {}
   523             for l, n in repo.tags().items():
   583             for l, n in repo.tags().items():
   524                 labels.setdefault(cl.rev(n), []).append(l)
   584                 labels.setdefault(cl.rev(n), []).append(l)
       
   585 
   525         def events():
   586         def events():
   526             b = "default"
   587             b = "default"
   527             for r in cl:
   588             for r in cl:
   528                 if branches:
   589                 if branches:
   529                     newb = cl.read(cl.node(r))[5]['branch']
   590                     newb = cl.read(cl.node(r))[5]['branch']
   530                     if newb != b:
   591                     if newb != b:
   531                         yield 'a', newb
   592                         yield 'a', newb
   532                         b = newb
   593                         b = newb
   533                 yield 'n', (r, list(p for p in cl.parentrevs(r)
   594                 yield 'n', (r, list(p for p in cl.parentrevs(r) if p != -1))
   534                                         if p != -1))
       
   535                 if tags:
   595                 if tags:
   536                     ls = labels.get(r)
   596                     ls = labels.get(r)
   537                     if ls:
   597                     if ls:
   538                         for l in ls:
   598                         for l in ls:
   539                             yield 'l', (r, l)
   599                             yield 'l', (r, l)
       
   600 
   540     else:
   601     else:
   541         raise error.Abort(_('need repo for changelog dag'))
   602         raise error.Abort(_('need repo for changelog dag'))
   542 
   603 
   543     for line in dagparser.dagtextlines(events(),
   604     for line in dagparser.dagtextlines(
   544                                        addspaces=spaces,
   605         events(),
   545                                        wraplabels=True,
   606         addspaces=spaces,
   546                                        wrapannotations=True,
   607         wraplabels=True,
   547                                        wrapnonlinear=dots,
   608         wrapannotations=True,
   548                                        usedots=dots,
   609         wrapnonlinear=dots,
   549                                        maxlinewidth=70):
   610         usedots=dots,
       
   611         maxlinewidth=70,
       
   612     ):
   550         ui.write(line)
   613         ui.write(line)
   551         ui.write("\n")
   614         ui.write("\n")
       
   615 
   552 
   616 
   553 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
   617 @command('debugdata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
   554 def debugdata(ui, repo, file_, rev=None, **opts):
   618 def debugdata(ui, repo, file_, rev=None, **opts):
   555     """dump the contents of a data file revision"""
   619     """dump the contents of a data file revision"""
   556     opts = pycompat.byteskwargs(opts)
   620     opts = pycompat.byteskwargs(opts)
   564     try:
   628     try:
   565         ui.write(r.rawdata(r.lookup(rev)))
   629         ui.write(r.rawdata(r.lookup(rev)))
   566     except KeyError:
   630     except KeyError:
   567         raise error.Abort(_('invalid revision identifier %s') % rev)
   631         raise error.Abort(_('invalid revision identifier %s') % rev)
   568 
   632 
   569 @command('debugdate',
   633 
       
   634 @command(
       
   635     'debugdate',
   570     [('e', 'extended', None, _('try extended date formats'))],
   636     [('e', 'extended', None, _('try extended date formats'))],
   571     _('[-e] DATE [RANGE]'),
   637     _('[-e] DATE [RANGE]'),
   572     norepo=True, optionalrepo=True)
   638     norepo=True,
       
   639     optionalrepo=True,
       
   640 )
   573 def debugdate(ui, date, range=None, **opts):
   641 def debugdate(ui, date, range=None, **opts):
   574     """parse and display a date"""
   642     """parse and display a date"""
   575     if opts[r"extended"]:
   643     if opts[r"extended"]:
   576         d = dateutil.parsedate(date, util.extendeddateformats)
   644         d = dateutil.parsedate(date, util.extendeddateformats)
   577     else:
   645     else:
   578         d = dateutil.parsedate(date)
   646         d = dateutil.parsedate(date)
   579     ui.write(("internal: %d %d\n") % d)
   647     ui.write("internal: %d %d\n" % d)
   580     ui.write(("standard: %s\n") % dateutil.datestr(d))
   648     ui.write("standard: %s\n" % dateutil.datestr(d))
   581     if range:
   649     if range:
   582         m = dateutil.matchdate(range)
   650         m = dateutil.matchdate(range)
   583         ui.write(("match: %s\n") % m(d[0]))
   651         ui.write("match: %s\n" % m(d[0]))
   584 
   652 
   585 @command('debugdeltachain',
   653 
       
   654 @command(
       
   655     'debugdeltachain',
   586     cmdutil.debugrevlogopts + cmdutil.formatteropts,
   656     cmdutil.debugrevlogopts + cmdutil.formatteropts,
   587     _('-c|-m|FILE'),
   657     _('-c|-m|FILE'),
   588     optionalrepo=True)
   658     optionalrepo=True,
       
   659 )
   589 def debugdeltachain(ui, repo, file_=None, **opts):
   660 def debugdeltachain(ui, repo, file_=None, **opts):
   590     """dump information about delta chains in a revlog
   661     """dump information about delta chains in a revlog
   591 
   662 
   592     Output can be templatized. Available template keywords are:
   663     Output can be templatized. Available template keywords are:
   593 
   664 
   659 
   730 
   660         return compsize, uncompsize, deltatype, chain, chainsize
   731         return compsize, uncompsize, deltatype, chain, chainsize
   661 
   732 
   662     fm = ui.formatter('debugdeltachain', opts)
   733     fm = ui.formatter('debugdeltachain', opts)
   663 
   734 
   664     fm.plain('    rev  chain# chainlen     prev   delta       '
   735     fm.plain(
   665              'size    rawsize  chainsize     ratio   lindist extradist '
   736         '    rev  chain# chainlen     prev   delta       '
   666              'extraratio')
   737         'size    rawsize  chainsize     ratio   lindist extradist '
       
   738         'extraratio'
       
   739     )
   667     if withsparseread:
   740     if withsparseread:
   668         fm.plain('   readsize largestblk rddensity srchunks')
   741         fm.plain('   readsize largestblk rddensity srchunks')
   669     fm.plain('\n')
   742     fm.plain('\n')
   670 
   743 
   671     chainbases = {}
   744     chainbases = {}
   691             extraratio = float(extradist) / float(chainsize)
   764             extraratio = float(extradist) / float(chainsize)
   692         else:
   765         else:
   693             extraratio = extradist
   766             extraratio = extradist
   694 
   767 
   695         fm.startitem()
   768         fm.startitem()
   696         fm.write('rev chainid chainlen prevrev deltatype compsize '
   769         fm.write(
   697                  'uncompsize chainsize chainratio lindist extradist '
   770             'rev chainid chainlen prevrev deltatype compsize '
   698                  'extraratio',
   771             'uncompsize chainsize chainratio lindist extradist '
   699                  '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
   772             'extraratio',
   700                  rev, chainid, len(chain), prevrev, deltatype, comp,
   773             '%7d %7d %8d %8d %7s %10d %10d %10d %9.5f %9d %9d %10.5f',
   701                  uncomp, chainsize, chainratio, lineardist, extradist,
   774             rev,
   702                  extraratio,
   775             chainid,
   703                  rev=rev, chainid=chainid, chainlen=len(chain),
   776             len(chain),
   704                  prevrev=prevrev, deltatype=deltatype, compsize=comp,
   777             prevrev,
   705                  uncompsize=uncomp, chainsize=chainsize,
   778             deltatype,
   706                  chainratio=chainratio, lindist=lineardist,
   779             comp,
   707                  extradist=extradist, extraratio=extraratio)
   780             uncomp,
       
   781             chainsize,
       
   782             chainratio,
       
   783             lineardist,
       
   784             extradist,
       
   785             extraratio,
       
   786             rev=rev,
       
   787             chainid=chainid,
       
   788             chainlen=len(chain),
       
   789             prevrev=prevrev,
       
   790             deltatype=deltatype,
       
   791             compsize=comp,
       
   792             uncompsize=uncomp,
       
   793             chainsize=chainsize,
       
   794             chainratio=chainratio,
       
   795             lindist=lineardist,
       
   796             extradist=extradist,
       
   797             extraratio=extraratio,
       
   798         )
   708         if withsparseread:
   799         if withsparseread:
   709             readsize = 0
   800             readsize = 0
   710             largestblock = 0
   801             largestblock = 0
   711             srchunks = 0
   802             srchunks = 0
   712 
   803 
   722             if readsize:
   813             if readsize:
   723                 readdensity = float(chainsize) / float(readsize)
   814                 readdensity = float(chainsize) / float(readsize)
   724             else:
   815             else:
   725                 readdensity = 1
   816                 readdensity = 1
   726 
   817 
   727             fm.write('readsize largestblock readdensity srchunks',
   818             fm.write(
   728                      ' %10d %10d %9.5f %8d',
   819                 'readsize largestblock readdensity srchunks',
   729                      readsize, largestblock, readdensity, srchunks,
   820                 ' %10d %10d %9.5f %8d',
   730                      readsize=readsize, largestblock=largestblock,
   821                 readsize,
   731                      readdensity=readdensity, srchunks=srchunks)
   822                 largestblock,
       
   823                 readdensity,
       
   824                 srchunks,
       
   825                 readsize=readsize,
       
   826                 largestblock=largestblock,
       
   827                 readdensity=readdensity,
       
   828                 srchunks=srchunks,
       
   829             )
   732 
   830 
   733         fm.plain('\n')
   831         fm.plain('\n')
   734 
   832 
   735     fm.end()
   833     fm.end()
   736 
   834 
   737 @command('debugdirstate|debugstate',
   835 
   738     [('', 'nodates', None, _('do not display the saved mtime (DEPRECATED)')),
   836 @command(
   739      ('', 'dates', True, _('display the saved mtime')),
   837     'debugdirstate|debugstate',
   740      ('', 'datesort', None, _('sort by saved mtime'))],
   838     [
   741     _('[OPTION]...'))
   839         ('', 'nodates', None, _('do not display the saved mtime (DEPRECATED)')),
       
   840         ('', 'dates', True, _('display the saved mtime')),
       
   841         ('', 'datesort', None, _('sort by saved mtime')),
       
   842     ],
       
   843     _('[OPTION]...'),
       
   844 )
   742 def debugstate(ui, repo, **opts):
   845 def debugstate(ui, repo, **opts):
   743     """show the contents of the current dirstate"""
   846     """show the contents of the current dirstate"""
   744 
   847 
   745     nodates = not opts[r'dates']
   848     nodates = not opts[r'dates']
   746     if opts.get(r'nodates') is not None:
   849     if opts.get(r'nodates') is not None:
   747         nodates = True
   850         nodates = True
   748     datesort = opts.get(r'datesort')
   851     datesort = opts.get(r'datesort')
   749 
   852 
   750     if datesort:
   853     if datesort:
   751         keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
   854         keyfunc = lambda x: (x[1][3], x[0])  # sort by mtime, then by filename
   752     else:
   855     else:
   753         keyfunc = None # sort by filename
   856         keyfunc = None  # sort by filename
   754     for file_, ent in sorted(repo.dirstate.iteritems(), key=keyfunc):
   857     for file_, ent in sorted(repo.dirstate.iteritems(), key=keyfunc):
   755         if ent[3] == -1:
   858         if ent[3] == -1:
   756             timestr = 'unset               '
   859             timestr = 'unset               '
   757         elif nodates:
   860         elif nodates:
   758             timestr = 'set                 '
   861             timestr = 'set                 '
   759         else:
   862         else:
   760             timestr = time.strftime(r"%Y-%m-%d %H:%M:%S ",
   863             timestr = time.strftime(
   761                                     time.localtime(ent[3]))
   864                 r"%Y-%m-%d %H:%M:%S ", time.localtime(ent[3])
       
   865             )
   762             timestr = encoding.strtolocal(timestr)
   866             timestr = encoding.strtolocal(timestr)
   763         if ent[1] & 0o20000:
   867         if ent[1] & 0o20000:
   764             mode = 'lnk'
   868             mode = 'lnk'
   765         else:
   869         else:
   766             mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
   870             mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
   767         ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
   871         ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
   768     for f in repo.dirstate.copies():
   872     for f in repo.dirstate.copies():
   769         ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
   873         ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
   770 
   874 
   771 @command('debugdiscovery',
   875 
   772     [('', 'old', None, _('use old-style discovery')),
   876 @command(
   773     ('', 'nonheads', None,
   877     'debugdiscovery',
   774      _('use old-style discovery with non-heads included')),
   878     [
   775     ('', 'rev', [], 'restrict discovery to this set of revs'),
   879         ('', 'old', None, _('use old-style discovery')),
   776     ('', 'seed', '12323', 'specify the random seed use for discovery'),
   880         (
   777     ] + cmdutil.remoteopts,
   881             '',
   778     _('[--rev REV] [OTHER]'))
   882             'nonheads',
       
   883             None,
       
   884             _('use old-style discovery with non-heads included'),
       
   885         ),
       
   886         ('', 'rev', [], 'restrict discovery to this set of revs'),
       
   887         ('', 'seed', '12323', 'specify the random seed use for discovery'),
       
   888     ]
       
   889     + cmdutil.remoteopts,
       
   890     _('[--rev REV] [OTHER]'),
       
   891 )
   779 def debugdiscovery(ui, repo, remoteurl="default", **opts):
   892 def debugdiscovery(ui, repo, remoteurl="default", **opts):
   780     """runs the changeset discovery protocol in isolation"""
   893     """runs the changeset discovery protocol in isolation"""
   781     opts = pycompat.byteskwargs(opts)
   894     opts = pycompat.byteskwargs(opts)
   782     remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
   895     remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl))
   783     remote = hg.peer(repo, opts, remoteurl)
   896     remote = hg.peer(repo, opts, remoteurl)
   784     ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
   897     ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
   785 
   898 
   786     # make sure tests are repeatable
   899     # make sure tests are repeatable
   787     random.seed(int(opts['seed']))
   900     random.seed(int(opts['seed']))
   788 
   901 
   789 
       
   790 
       
   791     if opts.get('old'):
   902     if opts.get('old'):
       
   903 
   792         def doit(pushedrevs, remoteheads, remote=remote):
   904         def doit(pushedrevs, remoteheads, remote=remote):
   793             if not util.safehasattr(remote, 'branches'):
   905             if not util.safehasattr(remote, 'branches'):
   794                 # enable in-client legacy support
   906                 # enable in-client legacy support
   795                 remote = localrepo.locallegacypeer(remote.local())
   907                 remote = localrepo.locallegacypeer(remote.local())
   796             common, _in, hds = treediscovery.findcommonincoming(repo, remote,
   908             common, _in, hds = treediscovery.findcommonincoming(
   797                                                                 force=True)
   909                 repo, remote, force=True
       
   910             )
   798             common = set(common)
   911             common = set(common)
   799             if not opts.get('nonheads'):
   912             if not opts.get('nonheads'):
   800                 ui.write(("unpruned common: %s\n") %
   913                 ui.write(
   801                          " ".join(sorted(short(n) for n in common)))
   914                     "unpruned common: %s\n"
       
   915                     % " ".join(sorted(short(n) for n in common))
       
   916                 )
   802 
   917 
   803                 clnode = repo.changelog.node
   918                 clnode = repo.changelog.node
   804                 common = repo.revs('heads(::%ln)', common)
   919                 common = repo.revs('heads(::%ln)', common)
   805                 common = {clnode(r) for r in common}
   920                 common = {clnode(r) for r in common}
   806             return common, hds
   921             return common, hds
       
   922 
   807     else:
   923     else:
       
   924 
   808         def doit(pushedrevs, remoteheads, remote=remote):
   925         def doit(pushedrevs, remoteheads, remote=remote):
   809             nodes = None
   926             nodes = None
   810             if pushedrevs:
   927             if pushedrevs:
   811                 revs = scmutil.revrange(repo, pushedrevs)
   928                 revs = scmutil.revrange(repo, pushedrevs)
   812                 nodes = [repo[r].node() for r in revs]
   929                 nodes = [repo[r].node() for r in revs]
   813             common, any, hds = setdiscovery.findcommonheads(ui, repo, remote,
   930             common, any, hds = setdiscovery.findcommonheads(
   814                                                             ancestorsof=nodes)
   931                 ui, repo, remote, ancestorsof=nodes
       
   932             )
   815             return common, hds
   933             return common, hds
   816 
   934 
   817     remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
   935     remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches, revs=None)
   818     localrevs = opts['rev']
   936     localrevs = opts['rev']
   819     with util.timedcm('debug-discovery') as t:
   937     with util.timedcm('debug-discovery') as t:
   837     data['nb-revs'] = len(repo.revs('all()'))
   955     data['nb-revs'] = len(repo.revs('all()'))
   838     data['nb-revs-common'] = len(repo.revs('::%ln', common))
   956     data['nb-revs-common'] = len(repo.revs('::%ln', common))
   839     data['nb-revs-missing'] = data['nb-revs'] - data['nb-revs-common']
   957     data['nb-revs-missing'] = data['nb-revs'] - data['nb-revs-common']
   840 
   958 
   841     # display discovery summary
   959     # display discovery summary
   842     ui.write(("elapsed time:  %(elapsed)f seconds\n") % data)
   960     ui.write("elapsed time:  %(elapsed)f seconds\n" % data)
   843     ui.write(("heads summary:\n"))
   961     ui.write("heads summary:\n")
   844     ui.write(("  total common heads:  %(nb-common)9d\n") % data)
   962     ui.write("  total common heads:  %(nb-common)9d\n" % data)
   845     ui.write(("    also local heads:  %(nb-common-local)9d\n") % data)
   963     ui.write("    also local heads:  %(nb-common-local)9d\n" % data)
   846     ui.write(("    also remote heads: %(nb-common-remote)9d\n") % data)
   964     ui.write("    also remote heads: %(nb-common-remote)9d\n" % data)
   847     ui.write(("    both:              %(nb-common-both)9d\n") % data)
   965     ui.write("    both:              %(nb-common-both)9d\n" % data)
   848     ui.write(("  local heads:         %(nb-local)9d\n") % data)
   966     ui.write("  local heads:         %(nb-local)9d\n" % data)
   849     ui.write(("    common:            %(nb-common-local)9d\n") % data)
   967     ui.write("    common:            %(nb-common-local)9d\n" % data)
   850     ui.write(("    missing:           %(nb-local-missing)9d\n") % data)
   968     ui.write("    missing:           %(nb-local-missing)9d\n" % data)
   851     ui.write(("  remote heads:        %(nb-remote)9d\n") % data)
   969     ui.write("  remote heads:        %(nb-remote)9d\n" % data)
   852     ui.write(("    common:            %(nb-common-remote)9d\n") % data)
   970     ui.write("    common:            %(nb-common-remote)9d\n" % data)
   853     ui.write(("    unknown:           %(nb-remote-unknown)9d\n") % data)
   971     ui.write("    unknown:           %(nb-remote-unknown)9d\n" % data)
   854     ui.write(("local changesets:      %(nb-revs)9d\n") % data)
   972     ui.write("local changesets:      %(nb-revs)9d\n" % data)
   855     ui.write(("  common:              %(nb-revs-common)9d\n") % data)
   973     ui.write("  common:              %(nb-revs-common)9d\n" % data)
   856     ui.write(("  missing:             %(nb-revs-missing)9d\n") % data)
   974     ui.write("  missing:             %(nb-revs-missing)9d\n" % data)
   857 
   975 
   858     if ui.verbose:
   976     if ui.verbose:
   859         ui.write(("common heads: %s\n") %
   977         ui.write(
   860                  " ".join(sorted(short(n) for n in common)))
   978             "common heads: %s\n" % " ".join(sorted(short(n) for n in common))
       
   979         )
       
   980 
   861 
   981 
   862 _chunksize = 4 << 10
   982 _chunksize = 4 << 10
   863 
   983 
   864 @command('debugdownload',
   984 
   865     [
   985 @command('debugdownload', [('o', 'output', '', _('path')),], optionalrepo=True)
   866         ('o', 'output', '', _('path')),
       
   867     ],
       
   868     optionalrepo=True)
       
   869 def debugdownload(ui, repo, url, output=None, **opts):
   986 def debugdownload(ui, repo, url, output=None, **opts):
   870     """download a resource using Mercurial logic and config
   987     """download a resource using Mercurial logic and config
   871     """
   988     """
   872     fh = urlmod.open(ui, url, output)
   989     fh = urlmod.open(ui, url, output)
   873 
   990 
   880             dest.write(data)
   997             dest.write(data)
   881             data = fh.read(_chunksize)
   998             data = fh.read(_chunksize)
   882     finally:
   999     finally:
   883         if output:
  1000         if output:
   884             dest.close()
  1001             dest.close()
       
  1002 
   885 
  1003 
   886 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
  1004 @command('debugextensions', cmdutil.formatteropts, [], optionalrepo=True)
   887 def debugextensions(ui, repo, **opts):
  1005 def debugextensions(ui, repo, **opts):
   888     '''show information about active extensions'''
  1006     '''show information about active extensions'''
   889     opts = pycompat.byteskwargs(opts)
  1007     opts = pycompat.byteskwargs(opts)
   911                 fm.plain(_(' (untested!)\n'))
  1029                 fm.plain(_(' (untested!)\n'))
   912             else:
  1030             else:
   913                 lasttestedversion = exttestedwith[-1]
  1031                 lasttestedversion = exttestedwith[-1]
   914                 fm.plain(' (%s!)\n' % lasttestedversion)
  1032                 fm.plain(' (%s!)\n' % lasttestedversion)
   915 
  1033 
   916         fm.condwrite(ui.verbose and extsource, 'source',
  1034         fm.condwrite(
   917                  _('  location: %s\n'), extsource or "")
  1035             ui.verbose and extsource,
       
  1036             'source',
       
  1037             _('  location: %s\n'),
       
  1038             extsource or "",
       
  1039         )
   918 
  1040 
   919         if ui.verbose:
  1041         if ui.verbose:
   920             fm.plain(_('  bundled: %s\n') % ['no', 'yes'][isinternal])
  1042             fm.plain(_('  bundled: %s\n') % ['no', 'yes'][isinternal])
   921         fm.data(bundled=isinternal)
  1043         fm.data(bundled=isinternal)
   922 
  1044 
   923         fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
  1045         fm.condwrite(
   924                      _('  tested with: %s\n'),
  1046             ui.verbose and exttestedwith,
   925                      fm.formatlist(exttestedwith, name='ver'))
  1047             'testedwith',
   926 
  1048             _('  tested with: %s\n'),
   927         fm.condwrite(ui.verbose and extbuglink, 'buglink',
  1049             fm.formatlist(exttestedwith, name='ver'),
   928                  _('  bug reporting: %s\n'), extbuglink or "")
  1050         )
       
  1051 
       
  1052         fm.condwrite(
       
  1053             ui.verbose and extbuglink,
       
  1054             'buglink',
       
  1055             _('  bug reporting: %s\n'),
       
  1056             extbuglink or "",
       
  1057         )
   929 
  1058 
   930     fm.end()
  1059     fm.end()
   931 
  1060 
   932 @command('debugfileset',
  1061 
   933     [('r', 'rev', '', _('apply the filespec on this revision'), _('REV')),
  1062 @command(
   934      ('', 'all-files', False,
  1063     'debugfileset',
   935       _('test files from all revisions and working directory')),
  1064     [
   936      ('s', 'show-matcher', None,
  1065         ('r', 'rev', '', _('apply the filespec on this revision'), _('REV')),
   937       _('print internal representation of matcher')),
  1066         (
   938      ('p', 'show-stage', [],
  1067             '',
   939       _('print parsed tree at the given stage'), _('NAME'))],
  1068             'all-files',
   940     _('[-r REV] [--all-files] [OPTION]... FILESPEC'))
  1069             False,
       
  1070             _('test files from all revisions and working directory'),
       
  1071         ),
       
  1072         (
       
  1073             's',
       
  1074             'show-matcher',
       
  1075             None,
       
  1076             _('print internal representation of matcher'),
       
  1077         ),
       
  1078         (
       
  1079             'p',
       
  1080             'show-stage',
       
  1081             [],
       
  1082             _('print parsed tree at the given stage'),
       
  1083             _('NAME'),
       
  1084         ),
       
  1085     ],
       
  1086     _('[-r REV] [--all-files] [OPTION]... FILESPEC'),
       
  1087 )
   941 def debugfileset(ui, repo, expr, **opts):
  1088 def debugfileset(ui, repo, expr, **opts):
   942     '''parse and apply a fileset specification'''
  1089     '''parse and apply a fileset specification'''
   943     from . import fileset
  1090     from . import fileset
   944     fileset.symbols # force import of fileset so we have predicates to optimize
  1091 
       
  1092     fileset.symbols  # force import of fileset so we have predicates to optimize
   945     opts = pycompat.byteskwargs(opts)
  1093     opts = pycompat.byteskwargs(opts)
   946     ctx = scmutil.revsingle(repo, opts.get('rev'), None)
  1094     ctx = scmutil.revsingle(repo, opts.get('rev'), None)
   947 
  1095 
   948     stages = [
  1096     stages = [
   949         ('parsed', pycompat.identity),
  1097         ('parsed', pycompat.identity),
   967     tree = filesetlang.parse(expr)
  1115     tree = filesetlang.parse(expr)
   968     for n, f in stages:
  1116     for n, f in stages:
   969         tree = f(tree)
  1117         tree = f(tree)
   970         if n in showalways:
  1118         if n in showalways:
   971             if opts['show_stage'] or n != 'parsed':
  1119             if opts['show_stage'] or n != 'parsed':
   972                 ui.write(("* %s:\n") % n)
  1120                 ui.write("* %s:\n" % n)
   973             ui.write(filesetlang.prettyformat(tree), "\n")
  1121             ui.write(filesetlang.prettyformat(tree), "\n")
   974 
  1122 
   975     files = set()
  1123     files = set()
   976     if opts['all_files']:
  1124     if opts['all_files']:
   977         for r in repo:
  1125         for r in repo:
   978             c = repo[r]
  1126             c = repo[r]
   979             files.update(c.files())
  1127             files.update(c.files())
   980             files.update(c.substate)
  1128             files.update(c.substate)
   981     if opts['all_files'] or ctx.rev() is None:
  1129     if opts['all_files'] or ctx.rev() is None:
   982         wctx = repo[None]
  1130         wctx = repo[None]
   983         files.update(repo.dirstate.walk(scmutil.matchall(repo),
  1131         files.update(
   984                                         subrepos=list(wctx.substate),
  1132             repo.dirstate.walk(
   985                                         unknown=True, ignored=True))
  1133                 scmutil.matchall(repo),
       
  1134                 subrepos=list(wctx.substate),
       
  1135                 unknown=True,
       
  1136                 ignored=True,
       
  1137             )
       
  1138         )
   986         files.update(wctx.substate)
  1139         files.update(wctx.substate)
   987     else:
  1140     else:
   988         files.update(ctx.files())
  1141         files.update(ctx.files())
   989         files.update(ctx.substate)
  1142         files.update(ctx.substate)
   990 
  1143 
   991     m = ctx.matchfileset(expr)
  1144     m = ctx.matchfileset(expr)
   992     if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
  1145     if opts['show_matcher'] or (opts['show_matcher'] is None and ui.verbose):
   993         ui.write(('* matcher:\n'), stringutil.prettyrepr(m), '\n')
  1146         ui.write('* matcher:\n', stringutil.prettyrepr(m), '\n')
   994     for f in sorted(files):
  1147     for f in sorted(files):
   995         if not m(f):
  1148         if not m(f):
   996             continue
  1149             continue
   997         ui.write("%s\n" % f)
  1150         ui.write("%s\n" % f)
   998 
  1151 
   999 @command('debugformat',
  1152 
  1000          [] + cmdutil.formatteropts)
  1153 @command('debugformat', [] + cmdutil.formatteropts)
  1001 def debugformat(ui, repo, **opts):
  1154 def debugformat(ui, repo, **opts):
  1002     """display format information about the current repository
  1155     """display format information about the current repository
  1003 
  1156 
  1004     Use --verbose to get extra information about current config value and
  1157     Use --verbose to get extra information about current config value and
  1005     Mercurial default."""
  1158     Mercurial default."""
  1010     def makeformatname(name):
  1163     def makeformatname(name):
  1011         return '%s:' + (' ' * (maxvariantlength - len(name)))
  1164         return '%s:' + (' ' * (maxvariantlength - len(name)))
  1012 
  1165 
  1013     fm = ui.formatter('debugformat', opts)
  1166     fm = ui.formatter('debugformat', opts)
  1014     if fm.isplain():
  1167     if fm.isplain():
       
  1168 
  1015         def formatvalue(value):
  1169         def formatvalue(value):
  1016             if util.safehasattr(value, 'startswith'):
  1170             if util.safehasattr(value, 'startswith'):
  1017                 return value
  1171                 return value
  1018             if value:
  1172             if value:
  1019                 return 'yes'
  1173                 return 'yes'
  1020             else:
  1174             else:
  1021                 return 'no'
  1175                 return 'no'
       
  1176 
  1022     else:
  1177     else:
  1023         formatvalue = pycompat.identity
  1178         formatvalue = pycompat.identity
  1024 
  1179 
  1025     fm.plain('format-variant')
  1180     fm.plain('format-variant')
  1026     fm.plain(' ' * (maxvariantlength - len('format-variant')))
  1181     fm.plain(' ' * (maxvariantlength - len('format-variant')))
  1041             repolabel = 'formatvariant.repo.mismatchdefault'
  1196             repolabel = 'formatvariant.repo.mismatchdefault'
  1042         else:
  1197         else:
  1043             namelabel = 'formatvariant.name.uptodate'
  1198             namelabel = 'formatvariant.name.uptodate'
  1044             repolabel = 'formatvariant.repo.uptodate'
  1199             repolabel = 'formatvariant.repo.uptodate'
  1045 
  1200 
  1046         fm.write('name', makeformatname(fv.name), fv.name,
  1201         fm.write('name', makeformatname(fv.name), fv.name, label=namelabel)
  1047                  label=namelabel)
  1202         fm.write('repo', ' %3s', formatvalue(repovalue), label=repolabel)
  1048         fm.write('repo', ' %3s', formatvalue(repovalue),
       
  1049                  label=repolabel)
       
  1050         if fv.default != configvalue:
  1203         if fv.default != configvalue:
  1051             configlabel = 'formatvariant.config.special'
  1204             configlabel = 'formatvariant.config.special'
  1052         else:
  1205         else:
  1053             configlabel = 'formatvariant.config.default'
  1206             configlabel = 'formatvariant.config.default'
  1054         fm.condwrite(ui.verbose, 'config', ' %6s', formatvalue(configvalue),
  1207         fm.condwrite(
  1055                      label=configlabel)
  1208             ui.verbose,
  1056         fm.condwrite(ui.verbose, 'default', ' %7s', formatvalue(fv.default),
  1209             'config',
  1057                      label='formatvariant.default')
  1210             ' %6s',
       
  1211             formatvalue(configvalue),
       
  1212             label=configlabel,
       
  1213         )
       
  1214         fm.condwrite(
       
  1215             ui.verbose,
       
  1216             'default',
       
  1217             ' %7s',
       
  1218             formatvalue(fv.default),
       
  1219             label='formatvariant.default',
       
  1220         )
  1058         fm.plain('\n')
  1221         fm.plain('\n')
  1059     fm.end()
  1222     fm.end()
       
  1223 
  1060 
  1224 
  1061 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
  1225 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
  1062 def debugfsinfo(ui, path="."):
  1226 def debugfsinfo(ui, path="."):
  1063     """show information detected about current filesystem"""
  1227     """show information detected about current filesystem"""
  1064     ui.write(('path: %s\n') % path)
  1228     ui.write('path: %s\n' % path)
  1065     ui.write(('mounted on: %s\n') % (util.getfsmountpoint(path) or '(unknown)'))
  1229     ui.write('mounted on: %s\n' % (util.getfsmountpoint(path) or '(unknown)'))
  1066     ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
  1230     ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
  1067     ui.write(('fstype: %s\n') % (util.getfstype(path) or '(unknown)'))
  1231     ui.write('fstype: %s\n' % (util.getfstype(path) or '(unknown)'))
  1068     ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
  1232     ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
  1069     ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
  1233     ui.write('hardlink: %s\n' % (util.checknlink(path) and 'yes' or 'no'))
  1070     casesensitive = '(unknown)'
  1234     casesensitive = '(unknown)'
  1071     try:
  1235     try:
  1072         with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
  1236         with pycompat.namedtempfile(prefix='.debugfsinfo', dir=path) as f:
  1073             casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
  1237             casesensitive = util.fscasesensitive(f.name) and 'yes' or 'no'
  1074     except OSError:
  1238     except OSError:
  1075         pass
  1239         pass
  1076     ui.write(('case-sensitive: %s\n') % casesensitive)
  1240     ui.write('case-sensitive: %s\n' % casesensitive)
  1077 
  1241 
  1078 @command('debuggetbundle',
  1242 
  1079     [('H', 'head', [], _('id of head node'), _('ID')),
  1243 @command(
  1080     ('C', 'common', [], _('id of common node'), _('ID')),
  1244     'debuggetbundle',
  1081     ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
  1245     [
       
  1246         ('H', 'head', [], _('id of head node'), _('ID')),
       
  1247         ('C', 'common', [], _('id of common node'), _('ID')),
       
  1248         ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
       
  1249     ],
  1082     _('REPO FILE [-H|-C ID]...'),
  1250     _('REPO FILE [-H|-C ID]...'),
  1083     norepo=True)
  1251     norepo=True,
       
  1252 )
  1084 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
  1253 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
  1085     """retrieves a bundle from a repo
  1254     """retrieves a bundle from a repo
  1086 
  1255 
  1087     Every ID must be a full-length hex node id string. Saves the bundle to the
  1256     Every ID must be a full-length hex node id string. Saves the bundle to the
  1088     given file.
  1257     given file.
  1099     # TODO: get desired bundlecaps from command line.
  1268     # TODO: get desired bundlecaps from command line.
  1100     args[r'bundlecaps'] = None
  1269     args[r'bundlecaps'] = None
  1101     bundle = repo.getbundle('debug', **args)
  1270     bundle = repo.getbundle('debug', **args)
  1102 
  1271 
  1103     bundletype = opts.get('type', 'bzip2').lower()
  1272     bundletype = opts.get('type', 'bzip2').lower()
  1104     btypes = {'none': 'HG10UN',
  1273     btypes = {
  1105               'bzip2': 'HG10BZ',
  1274         'none': 'HG10UN',
  1106               'gzip': 'HG10GZ',
  1275         'bzip2': 'HG10BZ',
  1107               'bundle2': 'HG20'}
  1276         'gzip': 'HG10GZ',
       
  1277         'bundle2': 'HG20',
       
  1278     }
  1108     bundletype = btypes.get(bundletype)
  1279     bundletype = btypes.get(bundletype)
  1109     if bundletype not in bundle2.bundletypes:
  1280     if bundletype not in bundle2.bundletypes:
  1110         raise error.Abort(_('unknown bundle type specified with --type'))
  1281         raise error.Abort(_('unknown bundle type specified with --type'))
  1111     bundle2.writebundle(ui, bundle, bundlepath, bundletype)
  1282     bundle2.writebundle(ui, bundle, bundlepath, bundletype)
       
  1283 
  1112 
  1284 
  1113 @command('debugignore', [], '[FILE]')
  1285 @command('debugignore', [], '[FILE]')
  1114 def debugignore(ui, repo, *files, **opts):
  1286 def debugignore(ui, repo, *files, **opts):
  1115     """display the combined ignore pattern and information about ignored files
  1287     """display the combined ignore pattern and information about ignored files
  1116 
  1288 
  1142                             break
  1314                             break
  1143             if ignored:
  1315             if ignored:
  1144                 if ignored == nf:
  1316                 if ignored == nf:
  1145                     ui.write(_("%s is ignored\n") % uipathfn(f))
  1317                     ui.write(_("%s is ignored\n") % uipathfn(f))
  1146                 else:
  1318                 else:
  1147                     ui.write(_("%s is ignored because of "
  1319                     ui.write(
  1148                                "containing directory %s\n")
  1320                         _(
  1149                              % (uipathfn(f), ignored))
  1321                             "%s is ignored because of "
       
  1322                             "containing directory %s\n"
       
  1323                         )
       
  1324                         % (uipathfn(f), ignored)
       
  1325                     )
  1150                 ignorefile, lineno, line = ignoredata
  1326                 ignorefile, lineno, line = ignoredata
  1151                 ui.write(_("(ignore rule in %s, line %d: '%s')\n")
  1327                 ui.write(
  1152                          % (ignorefile, lineno, line))
  1328                     _("(ignore rule in %s, line %d: '%s')\n")
       
  1329                     % (ignorefile, lineno, line)
       
  1330                 )
  1153             else:
  1331             else:
  1154                 ui.write(_("%s is not ignored\n") % uipathfn(f))
  1332                 ui.write(_("%s is not ignored\n") % uipathfn(f))
  1155 
  1333 
  1156 @command('debugindex', cmdutil.debugrevlogopts + cmdutil.formatteropts,
  1334 
  1157          _('-c|-m|FILE'))
  1335 @command(
       
  1336     'debugindex',
       
  1337     cmdutil.debugrevlogopts + cmdutil.formatteropts,
       
  1338     _('-c|-m|FILE'),
       
  1339 )
  1158 def debugindex(ui, repo, file_=None, **opts):
  1340 def debugindex(ui, repo, file_=None, **opts):
  1159     """dump index data for a storage primitive"""
  1341     """dump index data for a storage primitive"""
  1160     opts = pycompat.byteskwargs(opts)
  1342     opts = pycompat.byteskwargs(opts)
  1161     store = cmdutil.openstorage(repo, 'debugindex', file_, opts)
  1343     store = cmdutil.openstorage(repo, 'debugindex', file_, opts)
  1162 
  1344 
  1169     for i in store:
  1351     for i in store:
  1170         idlen = len(shortfn(store.node(i)))
  1352         idlen = len(shortfn(store.node(i)))
  1171         break
  1353         break
  1172 
  1354 
  1173     fm = ui.formatter('debugindex', opts)
  1355     fm = ui.formatter('debugindex', opts)
  1174     fm.plain(b'   rev linkrev %s %s p2\n' % (
  1356     fm.plain(
  1175         b'nodeid'.ljust(idlen),
  1357         b'   rev linkrev %s %s p2\n'
  1176         b'p1'.ljust(idlen)))
  1358         % (b'nodeid'.ljust(idlen), b'p1'.ljust(idlen))
       
  1359     )
  1177 
  1360 
  1178     for rev in store:
  1361     for rev in store:
  1179         node = store.node(rev)
  1362         node = store.node(rev)
  1180         parents = store.parents(node)
  1363         parents = store.parents(node)
  1181 
  1364 
  1187         fm.write(b'p2', '%s', shortfn(parents[1]))
  1370         fm.write(b'p2', '%s', shortfn(parents[1]))
  1188         fm.plain(b'\n')
  1371         fm.plain(b'\n')
  1189 
  1372 
  1190     fm.end()
  1373     fm.end()
  1191 
  1374 
  1192 @command('debugindexdot', cmdutil.debugrevlogopts,
  1375 
  1193     _('-c|-m|FILE'), optionalrepo=True)
  1376 @command(
       
  1377     'debugindexdot', cmdutil.debugrevlogopts, _('-c|-m|FILE'), optionalrepo=True
       
  1378 )
  1194 def debugindexdot(ui, repo, file_=None, **opts):
  1379 def debugindexdot(ui, repo, file_=None, **opts):
  1195     """dump an index DAG as a graphviz dot file"""
  1380     """dump an index DAG as a graphviz dot file"""
  1196     opts = pycompat.byteskwargs(opts)
  1381     opts = pycompat.byteskwargs(opts)
  1197     r = cmdutil.openstorage(repo, 'debugindexdot', file_, opts)
  1382     r = cmdutil.openstorage(repo, 'debugindexdot', file_, opts)
  1198     ui.write(("digraph G {\n"))
  1383     ui.write("digraph G {\n")
  1199     for i in r:
  1384     for i in r:
  1200         node = r.node(i)
  1385         node = r.node(i)
  1201         pp = r.parents(node)
  1386         pp = r.parents(node)
  1202         ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
  1387         ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
  1203         if pp[1] != nullid:
  1388         if pp[1] != nullid:
  1204             ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
  1389             ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
  1205     ui.write("}\n")
  1390     ui.write("}\n")
       
  1391 
  1206 
  1392 
  1207 @command('debugindexstats', [])
  1393 @command('debugindexstats', [])
  1208 def debugindexstats(ui, repo):
  1394 def debugindexstats(ui, repo):
  1209     """show stats related to the changelog index"""
  1395     """show stats related to the changelog index"""
  1210     repo.changelog.shortest(nullid, 1)
  1396     repo.changelog.shortest(nullid, 1)
  1212     if not util.safehasattr(index, 'stats'):
  1398     if not util.safehasattr(index, 'stats'):
  1213         raise error.Abort(_('debugindexstats only works with native code'))
  1399         raise error.Abort(_('debugindexstats only works with native code'))
  1214     for k, v in sorted(index.stats().items()):
  1400     for k, v in sorted(index.stats().items()):
  1215         ui.write('%s: %d\n' % (k, v))
  1401         ui.write('%s: %d\n' % (k, v))
  1216 
  1402 
       
  1403 
  1217 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
  1404 @command('debuginstall', [] + cmdutil.formatteropts, '', norepo=True)
  1218 def debuginstall(ui, **opts):
  1405 def debuginstall(ui, **opts):
  1219     '''test Mercurial installation
  1406     '''test Mercurial installation
  1220 
  1407 
  1221     Returns 0 on success.
  1408     Returns 0 on success.
  1233     try:
  1420     try:
  1234         codecs.lookup(pycompat.sysstr(encoding.encoding))
  1421         codecs.lookup(pycompat.sysstr(encoding.encoding))
  1235     except LookupError as inst:
  1422     except LookupError as inst:
  1236         err = stringutil.forcebytestr(inst)
  1423         err = stringutil.forcebytestr(inst)
  1237         problems += 1
  1424         problems += 1
  1238     fm.condwrite(err, 'encodingerror', _(" %s\n"
  1425     fm.condwrite(
  1239                  " (check that your locale is properly set)\n"), err)
  1426         err,
       
  1427         'encodingerror',
       
  1428         _(" %s\n" " (check that your locale is properly set)\n"),
       
  1429         err,
       
  1430     )
  1240 
  1431 
  1241     # Python
  1432     # Python
  1242     fm.write('pythonexe', _("checking Python executable (%s)\n"),
  1433     fm.write(
  1243              pycompat.sysexecutable or _("unknown"))
  1434         'pythonexe',
  1244     fm.write('pythonver', _("checking Python version (%s)\n"),
  1435         _("checking Python executable (%s)\n"),
  1245              ("%d.%d.%d" % sys.version_info[:3]))
  1436         pycompat.sysexecutable or _("unknown"),
  1246     fm.write('pythonlib', _("checking Python lib (%s)...\n"),
  1437     )
  1247              os.path.dirname(pycompat.fsencode(os.__file__)))
  1438     fm.write(
       
  1439         'pythonver',
       
  1440         _("checking Python version (%s)\n"),
       
  1441         ("%d.%d.%d" % sys.version_info[:3]),
       
  1442     )
       
  1443     fm.write(
       
  1444         'pythonlib',
       
  1445         _("checking Python lib (%s)...\n"),
       
  1446         os.path.dirname(pycompat.fsencode(os.__file__)),
       
  1447     )
  1248 
  1448 
  1249     security = set(sslutil.supportedprotocols)
  1449     security = set(sslutil.supportedprotocols)
  1250     if sslutil.hassni:
  1450     if sslutil.hassni:
  1251         security.add('sni')
  1451         security.add('sni')
  1252 
  1452 
  1253     fm.write('pythonsecurity', _("checking Python security support (%s)\n"),
  1453     fm.write(
  1254              fm.formatlist(sorted(security), name='protocol',
  1454         'pythonsecurity',
  1255                            fmt='%s', sep=','))
  1455         _("checking Python security support (%s)\n"),
       
  1456         fm.formatlist(sorted(security), name='protocol', fmt='%s', sep=','),
       
  1457     )
  1256 
  1458 
  1257     # These are warnings, not errors. So don't increment problem count. This
  1459     # These are warnings, not errors. So don't increment problem count. This
  1258     # may change in the future.
  1460     # may change in the future.
  1259     if 'tls1.2' not in security:
  1461     if 'tls1.2' not in security:
  1260         fm.plain(_('  TLS 1.2 not supported by Python install; '
  1462         fm.plain(
  1261                    'network connections lack modern security\n'))
  1463             _(
       
  1464                 '  TLS 1.2 not supported by Python install; '
       
  1465                 'network connections lack modern security\n'
       
  1466             )
       
  1467         )
  1262     if 'sni' not in security:
  1468     if 'sni' not in security:
  1263         fm.plain(_('  SNI not supported by Python install; may have '
  1469         fm.plain(
  1264                    'connectivity issues with some servers\n'))
  1470             _(
       
  1471                 '  SNI not supported by Python install; may have '
       
  1472                 'connectivity issues with some servers\n'
       
  1473             )
       
  1474         )
  1265 
  1475 
  1266     # TODO print CA cert info
  1476     # TODO print CA cert info
  1267 
  1477 
  1268     # hg version
  1478     # hg version
  1269     hgver = util.version()
  1479     hgver = util.version()
  1270     fm.write('hgver', _("checking Mercurial version (%s)\n"),
  1480     fm.write(
  1271              hgver.split('+')[0])
  1481         'hgver', _("checking Mercurial version (%s)\n"), hgver.split('+')[0]
  1272     fm.write('hgverextra', _("checking Mercurial custom build (%s)\n"),
  1482     )
  1273              '+'.join(hgver.split('+')[1:]))
  1483     fm.write(
       
  1484         'hgverextra',
       
  1485         _("checking Mercurial custom build (%s)\n"),
       
  1486         '+'.join(hgver.split('+')[1:]),
       
  1487     )
  1274 
  1488 
  1275     # compiled modules
  1489     # compiled modules
  1276     fm.write('hgmodulepolicy', _("checking module policy (%s)\n"),
  1490     fm.write(
  1277              policy.policy)
  1491         'hgmodulepolicy', _("checking module policy (%s)\n"), policy.policy
  1278     fm.write('hgmodules', _("checking installed modules (%s)...\n"),
  1492     )
  1279              os.path.dirname(pycompat.fsencode(__file__)))
  1493     fm.write(
       
  1494         'hgmodules',
       
  1495         _("checking installed modules (%s)...\n"),
       
  1496         os.path.dirname(pycompat.fsencode(__file__)),
       
  1497     )
  1280 
  1498 
  1281     rustandc = policy.policy in ('rust+c', 'rust+c-allow')
  1499     rustandc = policy.policy in ('rust+c', 'rust+c-allow')
  1282     rustext = rustandc  # for now, that's the only case
  1500     rustext = rustandc  # for now, that's the only case
  1283     cext = policy.policy in ('c', 'allow') or rustandc
  1501     cext = policy.policy in ('c', 'allow') or rustandc
  1284     nopure = cext or rustext
  1502     nopure = cext or rustext
  1290                     base85,
  1508                     base85,
  1291                     bdiff,
  1509                     bdiff,
  1292                     mpatch,
  1510                     mpatch,
  1293                     osutil,
  1511                     osutil,
  1294                 )
  1512                 )
       
  1513 
  1295                 # quiet pyflakes
  1514                 # quiet pyflakes
  1296                 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
  1515                 dir(bdiff), dir(mpatch), dir(base85), dir(osutil)
  1297             if rustext:
  1516             if rustext:
  1298                 from .rustext import (
  1517                 from .rustext import (
  1299                     ancestor,
  1518                     ancestor,
  1300                     dirstate,
  1519                     dirstate,
  1301                 )
  1520                 )
  1302                 dir(ancestor), dir(dirstate) # quiet pyflakes
  1521 
       
  1522                 dir(ancestor), dir(dirstate)  # quiet pyflakes
  1303         except Exception as inst:
  1523         except Exception as inst:
  1304             err = stringutil.forcebytestr(inst)
  1524             err = stringutil.forcebytestr(inst)
  1305             problems += 1
  1525             problems += 1
  1306         fm.condwrite(err, 'extensionserror', " %s\n", err)
  1526         fm.condwrite(err, 'extensionserror', " %s\n", err)
  1307 
  1527 
  1308     compengines = util.compengines._engines.values()
  1528     compengines = util.compengines._engines.values()
  1309     fm.write('compengines', _('checking registered compression engines (%s)\n'),
  1529     fm.write(
  1310              fm.formatlist(sorted(e.name() for e in compengines),
  1530         'compengines',
  1311                            name='compengine', fmt='%s', sep=', '))
  1531         _('checking registered compression engines (%s)\n'),
  1312     fm.write('compenginesavail', _('checking available compression engines '
  1532         fm.formatlist(
  1313                                    '(%s)\n'),
  1533             sorted(e.name() for e in compengines),
  1314              fm.formatlist(sorted(e.name() for e in compengines
  1534             name='compengine',
  1315                                   if e.available()),
  1535             fmt='%s',
  1316                            name='compengine', fmt='%s', sep=', '))
  1536             sep=', ',
       
  1537         ),
       
  1538     )
       
  1539     fm.write(
       
  1540         'compenginesavail',
       
  1541         _('checking available compression engines ' '(%s)\n'),
       
  1542         fm.formatlist(
       
  1543             sorted(e.name() for e in compengines if e.available()),
       
  1544             name='compengine',
       
  1545             fmt='%s',
       
  1546             sep=', ',
       
  1547         ),
       
  1548     )
  1317     wirecompengines = compression.compengines.supportedwireengines(
  1549     wirecompengines = compression.compengines.supportedwireengines(
  1318         compression.SERVERROLE)
  1550         compression.SERVERROLE
  1319     fm.write('compenginesserver', _('checking available compression engines '
  1551     )
  1320                                     'for wire protocol (%s)\n'),
  1552     fm.write(
  1321              fm.formatlist([e.name() for e in wirecompengines
  1553         'compenginesserver',
  1322                             if e.wireprotosupport()],
  1554         _('checking available compression engines ' 'for wire protocol (%s)\n'),
  1323                            name='compengine', fmt='%s', sep=', '))
  1555         fm.formatlist(
       
  1556             [e.name() for e in wirecompengines if e.wireprotosupport()],
       
  1557             name='compengine',
       
  1558             fmt='%s',
       
  1559             sep=', ',
       
  1560         ),
       
  1561     )
  1324     re2 = 'missing'
  1562     re2 = 'missing'
  1325     if util._re2:
  1563     if util._re2:
  1326         re2 = 'available'
  1564         re2 = 'available'
  1327     fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
  1565     fm.plain(_('checking "re2" regexp engine (%s)\n') % re2)
  1328     fm.data(re2=bool(util._re2))
  1566     fm.data(re2=bool(util._re2))
  1342                 err = stringutil.forcebytestr(inst)
  1580                 err = stringutil.forcebytestr(inst)
  1343                 p = None
  1581                 p = None
  1344             fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
  1582             fm.condwrite(err, 'defaulttemplateerror', " %s\n", err)
  1345         else:
  1583         else:
  1346             p = None
  1584             p = None
  1347         fm.condwrite(p, 'defaulttemplate',
  1585         fm.condwrite(
  1348                      _("checking default template (%s)\n"), m)
  1586             p, 'defaulttemplate', _("checking default template (%s)\n"), m
  1349         fm.condwrite(not m, 'defaulttemplatenotfound',
  1587         )
  1350                      _(" template '%s' not found\n"), "default")
  1588         fm.condwrite(
       
  1589             not m,
       
  1590             'defaulttemplatenotfound',
       
  1591             _(" template '%s' not found\n"),
       
  1592             "default",
       
  1593         )
  1351     if not p:
  1594     if not p:
  1352         problems += 1
  1595         problems += 1
  1353     fm.condwrite(not p, '',
  1596     fm.condwrite(
  1354                  _(" (templates seem to have been installed incorrectly)\n"))
  1597         not p, '', _(" (templates seem to have been installed incorrectly)\n")
       
  1598     )
  1355 
  1599 
  1356     # editor
  1600     # editor
  1357     editor = ui.geteditor()
  1601     editor = ui.geteditor()
  1358     editor = util.expandpath(editor)
  1602     editor = util.expandpath(editor)
  1359     editorbin = procutil.shellsplit(editor)[0]
  1603     editorbin = procutil.shellsplit(editor)[0]
  1360     fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
  1604     fm.write('editor', _("checking commit editor... (%s)\n"), editorbin)
  1361     cmdpath = procutil.findexe(editorbin)
  1605     cmdpath = procutil.findexe(editorbin)
  1362     fm.condwrite(not cmdpath and editor == 'vi', 'vinotfound',
  1606     fm.condwrite(
  1363                  _(" No commit editor set and can't find %s in PATH\n"
  1607         not cmdpath and editor == 'vi',
  1364                    " (specify a commit editor in your configuration"
  1608         'vinotfound',
  1365                    " file)\n"), not cmdpath and editor == 'vi' and editorbin)
  1609         _(
  1366     fm.condwrite(not cmdpath and editor != 'vi', 'editornotfound',
  1610             " No commit editor set and can't find %s in PATH\n"
  1367                  _(" Can't find editor '%s' in PATH\n"
  1611             " (specify a commit editor in your configuration"
  1368                    " (specify a commit editor in your configuration"
  1612             " file)\n"
  1369                    " file)\n"), not cmdpath and editorbin)
  1613         ),
       
  1614         not cmdpath and editor == 'vi' and editorbin,
       
  1615     )
       
  1616     fm.condwrite(
       
  1617         not cmdpath and editor != 'vi',
       
  1618         'editornotfound',
       
  1619         _(
       
  1620             " Can't find editor '%s' in PATH\n"
       
  1621             " (specify a commit editor in your configuration"
       
  1622             " file)\n"
       
  1623         ),
       
  1624         not cmdpath and editorbin,
       
  1625     )
  1370     if not cmdpath and editor != 'vi':
  1626     if not cmdpath and editor != 'vi':
  1371         problems += 1
  1627         problems += 1
  1372 
  1628 
  1373     # check username
  1629     # check username
  1374     username = None
  1630     username = None
  1377         username = ui.username()
  1633         username = ui.username()
  1378     except error.Abort as e:
  1634     except error.Abort as e:
  1379         err = stringutil.forcebytestr(e)
  1635         err = stringutil.forcebytestr(e)
  1380         problems += 1
  1636         problems += 1
  1381 
  1637 
  1382     fm.condwrite(username, 'username',  _("checking username (%s)\n"), username)
  1638     fm.condwrite(username, 'username', _("checking username (%s)\n"), username)
  1383     fm.condwrite(err, 'usernameerror', _("checking username...\n %s\n"
  1639     fm.condwrite(
  1384         " (specify a username in your configuration file)\n"), err)
  1640         err,
       
  1641         'usernameerror',
       
  1642         _(
       
  1643             "checking username...\n %s\n"
       
  1644             " (specify a username in your configuration file)\n"
       
  1645         ),
       
  1646         err,
       
  1647     )
  1385 
  1648 
  1386     for name, mod in extensions.extensions():
  1649     for name, mod in extensions.extensions():
  1387         handler = getattr(mod, 'debuginstall', None)
  1650         handler = getattr(mod, 'debuginstall', None)
  1388         if handler is not None:
  1651         if handler is not None:
  1389             problems += handler(ui, fm)
  1652             problems += handler(ui, fm)
  1390 
  1653 
  1391     fm.condwrite(not problems, '',
  1654     fm.condwrite(not problems, '', _("no problems detected\n"))
  1392                  _("no problems detected\n"))
       
  1393     if not problems:
  1655     if not problems:
  1394         fm.data(problems=problems)
  1656         fm.data(problems=problems)
  1395     fm.condwrite(problems, 'problems',
  1657     fm.condwrite(
  1396                  _("%d problems detected,"
  1658         problems,
  1397                    " please check your install!\n"), problems)
  1659         'problems',
       
  1660         _("%d problems detected," " please check your install!\n"),
       
  1661         problems,
       
  1662     )
  1398     fm.end()
  1663     fm.end()
  1399 
  1664 
  1400     return problems
  1665     return problems
       
  1666 
  1401 
  1667 
  1402 @command('debugknown', [], _('REPO ID...'), norepo=True)
  1668 @command('debugknown', [], _('REPO ID...'), norepo=True)
  1403 def debugknown(ui, repopath, *ids, **opts):
  1669 def debugknown(ui, repopath, *ids, **opts):
  1404     """test whether node ids are known to a repo
  1670     """test whether node ids are known to a repo
  1405 
  1671 
  1411     if not repo.capable('known'):
  1677     if not repo.capable('known'):
  1412         raise error.Abort("known() not supported by target repository")
  1678         raise error.Abort("known() not supported by target repository")
  1413     flags = repo.known([bin(s) for s in ids])
  1679     flags = repo.known([bin(s) for s in ids])
  1414     ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
  1680     ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
  1415 
  1681 
       
  1682 
  1416 @command('debuglabelcomplete', [], _('LABEL...'))
  1683 @command('debuglabelcomplete', [], _('LABEL...'))
  1417 def debuglabelcomplete(ui, repo, *args):
  1684 def debuglabelcomplete(ui, repo, *args):
  1418     '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
  1685     '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
  1419     debugnamecomplete(ui, repo, *args)
  1686     debugnamecomplete(ui, repo, *args)
  1420 
  1687 
  1421 @command('debuglocks',
  1688 
  1422          [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
  1689 @command(
  1423           ('W', 'force-wlock', None,
  1690     'debuglocks',
  1424            _('free the working state lock (DANGEROUS)')),
  1691     [
  1425           ('s', 'set-lock', None, _('set the store lock until stopped')),
  1692         ('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
  1426           ('S', 'set-wlock', None,
  1693         (
  1427            _('set the working state lock until stopped'))],
  1694             'W',
  1428          _('[OPTION]...'))
  1695             'force-wlock',
       
  1696             None,
       
  1697             _('free the working state lock (DANGEROUS)'),
       
  1698         ),
       
  1699         ('s', 'set-lock', None, _('set the store lock until stopped')),
       
  1700         ('S', 'set-wlock', None, _('set the working state lock until stopped')),
       
  1701     ],
       
  1702     _('[OPTION]...'),
       
  1703 )
  1429 def debuglocks(ui, repo, **opts):
  1704 def debuglocks(ui, repo, **opts):
  1430     """show or modify state of locks
  1705     """show or modify state of locks
  1431 
  1706 
  1432     By default, this command will show which locks are held. This
  1707     By default, this command will show which locks are held. This
  1433     includes the user and process holding the lock, the amount of time
  1708     includes the user and process holding the lock, the amount of time
  1497                 if ":" in locker:
  1772                 if ":" in locker:
  1498                     host, pid = locker.split(':')
  1773                     host, pid = locker.split(':')
  1499                     if host == socket.gethostname():
  1774                     if host == socket.gethostname():
  1500                         locker = 'user %s, process %s' % (user or b'None', pid)
  1775                         locker = 'user %s, process %s' % (user or b'None', pid)
  1501                     else:
  1776                     else:
  1502                         locker = ('user %s, process %s, host %s'
  1777                         locker = 'user %s, process %s, host %s' % (
  1503                                   % (user or b'None', pid, host))
  1778                             user or b'None',
  1504                 ui.write(("%-6s %s (%ds)\n") % (name + ":", locker, age))
  1779                             pid,
       
  1780                             host,
       
  1781                         )
       
  1782                 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
  1505                 return 1
  1783                 return 1
  1506             except OSError as e:
  1784             except OSError as e:
  1507                 if e.errno != errno.ENOENT:
  1785                 if e.errno != errno.ENOENT:
  1508                     raise
  1786                     raise
  1509 
  1787 
  1510         ui.write(("%-6s free\n") % (name + ":"))
  1788         ui.write("%-6s free\n" % (name + ":"))
  1511         return 0
  1789         return 0
  1512 
  1790 
  1513     held += report(repo.svfs, "lock", repo.lock)
  1791     held += report(repo.svfs, "lock", repo.lock)
  1514     held += report(repo.vfs, "wlock", repo.wlock)
  1792     held += report(repo.vfs, "wlock", repo.wlock)
  1515 
  1793 
  1516     return held
  1794     return held
  1517 
  1795 
  1518 @command('debugmanifestfulltextcache', [
  1796 
       
  1797 @command(
       
  1798     'debugmanifestfulltextcache',
       
  1799     [
  1519         ('', 'clear', False, _('clear the cache')),
  1800         ('', 'clear', False, _('clear the cache')),
  1520         ('a', 'add', [], _('add the given manifest nodes to the cache'),
  1801         (
  1521          _('NODE'))
  1802             'a',
  1522     ], '')
  1803             'add',
       
  1804             [],
       
  1805             _('add the given manifest nodes to the cache'),
       
  1806             _('NODE'),
       
  1807         ),
       
  1808     ],
       
  1809     '',
       
  1810 )
  1523 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
  1811 def debugmanifestfulltextcache(ui, repo, add=(), **opts):
  1524     """show, clear or amend the contents of the manifest fulltext cache"""
  1812     """show, clear or amend the contents of the manifest fulltext cache"""
  1525 
  1813 
  1526     def getcache():
  1814     def getcache():
  1527         r = repo.manifestlog.getstorage(b'')
  1815         r = repo.manifestlog.getstorage(b'')
  1528         try:
  1816         try:
  1529             return r._fulltextcache
  1817             return r._fulltextcache
  1530         except AttributeError:
  1818         except AttributeError:
  1531             msg = _("Current revlog implementation doesn't appear to have a "
  1819             msg = _(
  1532                     "manifest fulltext cache\n")
  1820                 "Current revlog implementation doesn't appear to have a "
       
  1821                 "manifest fulltext cache\n"
       
  1822             )
  1533             raise error.Abort(msg)
  1823             raise error.Abort(msg)
  1534 
  1824 
  1535     if opts.get(r'clear'):
  1825     if opts.get(r'clear'):
  1536         with repo.wlock():
  1826         with repo.wlock():
  1537             cache = getcache()
  1827             cache = getcache()
  1553     cache = getcache()
  1843     cache = getcache()
  1554     if not len(cache):
  1844     if not len(cache):
  1555         ui.write(_('cache empty\n'))
  1845         ui.write(_('cache empty\n'))
  1556     else:
  1846     else:
  1557         ui.write(
  1847         ui.write(
  1558             _('cache contains %d manifest entries, in order of most to '
  1848             _(
  1559               'least recent:\n') % (len(cache),))
  1849                 'cache contains %d manifest entries, in order of most to '
       
  1850                 'least recent:\n'
       
  1851             )
       
  1852             % (len(cache),)
       
  1853         )
  1560         totalsize = 0
  1854         totalsize = 0
  1561         for nodeid in cache:
  1855         for nodeid in cache:
  1562             # Use cache.get to not update the LRU order
  1856             # Use cache.get to not update the LRU order
  1563             data = cache.peek(nodeid)
  1857             data = cache.peek(nodeid)
  1564             size = len(data)
  1858             size = len(data)
  1565             totalsize += size + 24   # 20 bytes nodeid, 4 bytes size
  1859             totalsize += size + 24  # 20 bytes nodeid, 4 bytes size
  1566             ui.write(_('id: %s, size %s\n') % (
  1860             ui.write(
  1567                 hex(nodeid), util.bytecount(size)))
  1861                 _('id: %s, size %s\n') % (hex(nodeid), util.bytecount(size))
       
  1862             )
  1568         ondisk = cache._opener.stat('manifestfulltextcache').st_size
  1863         ondisk = cache._opener.stat('manifestfulltextcache').st_size
  1569         ui.write(
  1864         ui.write(
  1570             _('total cache data size %s, on-disk %s\n') % (
  1865             _('total cache data size %s, on-disk %s\n')
  1571                 util.bytecount(totalsize), util.bytecount(ondisk))
  1866             % (util.bytecount(totalsize), util.bytecount(ondisk))
  1572         )
  1867         )
       
  1868 
  1573 
  1869 
  1574 @command('debugmergestate', [], '')
  1870 @command('debugmergestate', [], '')
  1575 def debugmergestate(ui, repo, *args):
  1871 def debugmergestate(ui, repo, *args):
  1576     """print merge state
  1872     """print merge state
  1577 
  1873 
  1578     Use --verbose to print out information about whether v1 or v2 merge state
  1874     Use --verbose to print out information about whether v1 or v2 merge state
  1579     was chosen."""
  1875     was chosen."""
       
  1876 
  1580     def _hashornull(h):
  1877     def _hashornull(h):
  1581         if h == nullhex:
  1878         if h == nullhex:
  1582             return 'null'
  1879             return 'null'
  1583         else:
  1880         else:
  1584             return h
  1881             return h
  1585 
  1882 
  1586     def printrecords(version):
  1883     def printrecords(version):
  1587         ui.write(('* version %d records\n') % version)
  1884         ui.write('* version %d records\n' % version)
  1588         if version == 1:
  1885         if version == 1:
  1589             records = v1records
  1886             records = v1records
  1590         else:
  1887         else:
  1591             records = v2records
  1888             records = v2records
  1592 
  1889 
  1593         for rtype, record in records:
  1890         for rtype, record in records:
  1594             # pretty print some record types
  1891             # pretty print some record types
  1595             if rtype == 'L':
  1892             if rtype == 'L':
  1596                 ui.write(('local: %s\n') % record)
  1893                 ui.write('local: %s\n' % record)
  1597             elif rtype == 'O':
  1894             elif rtype == 'O':
  1598                 ui.write(('other: %s\n') % record)
  1895                 ui.write('other: %s\n' % record)
  1599             elif rtype == 'm':
  1896             elif rtype == 'm':
  1600                 driver, mdstate = record.split('\0', 1)
  1897                 driver, mdstate = record.split('\0', 1)
  1601                 ui.write(('merge driver: %s (state "%s")\n')
  1898                 ui.write('merge driver: %s (state "%s")\n' % (driver, mdstate))
  1602                          % (driver, mdstate))
       
  1603             elif rtype in 'FDC':
  1899             elif rtype in 'FDC':
  1604                 r = record.split('\0')
  1900                 r = record.split('\0')
  1605                 f, state, hash, lfile, afile, anode, ofile = r[0:7]
  1901                 f, state, hash, lfile, afile, anode, ofile = r[0:7]
  1606                 if version == 1:
  1902                 if version == 1:
  1607                     onode = 'not stored in v1 format'
  1903                     onode = 'not stored in v1 format'
  1608                     flags = r[7]
  1904                     flags = r[7]
  1609                 else:
  1905                 else:
  1610                     onode, flags = r[7:9]
  1906                     onode, flags = r[7:9]
  1611                 ui.write(('file: %s (record type "%s", state "%s", hash %s)\n')
  1907                 ui.write(
  1612                          % (f, rtype, state, _hashornull(hash)))
  1908                     'file: %s (record type "%s", state "%s", hash %s)\n'
  1613                 ui.write(('  local path: %s (flags "%s")\n') % (lfile, flags))
  1909                     % (f, rtype, state, _hashornull(hash))
  1614                 ui.write(('  ancestor path: %s (node %s)\n')
  1910                 )
  1615                          % (afile, _hashornull(anode)))
  1911                 ui.write('  local path: %s (flags "%s")\n' % (lfile, flags))
  1616                 ui.write(('  other path: %s (node %s)\n')
  1912                 ui.write(
  1617                          % (ofile, _hashornull(onode)))
  1913                     '  ancestor path: %s (node %s)\n'
       
  1914                     % (afile, _hashornull(anode))
       
  1915                 )
       
  1916                 ui.write(
       
  1917                     '  other path: %s (node %s)\n' % (ofile, _hashornull(onode))
       
  1918                 )
  1618             elif rtype == 'f':
  1919             elif rtype == 'f':
  1619                 filename, rawextras = record.split('\0', 1)
  1920                 filename, rawextras = record.split('\0', 1)
  1620                 extras = rawextras.split('\0')
  1921                 extras = rawextras.split('\0')
  1621                 i = 0
  1922                 i = 0
  1622                 extrastrings = []
  1923                 extrastrings = []
  1623                 while i < len(extras):
  1924                 while i < len(extras):
  1624                     extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
  1925                     extrastrings.append('%s = %s' % (extras[i], extras[i + 1]))
  1625                     i += 2
  1926                     i += 2
  1626 
  1927 
  1627                 ui.write(('file extras: %s (%s)\n')
  1928                 ui.write(
  1628                          % (filename, ', '.join(extrastrings)))
  1929                     'file extras: %s (%s)\n'
       
  1930                     % (filename, ', '.join(extrastrings))
       
  1931                 )
  1629             elif rtype == 'l':
  1932             elif rtype == 'l':
  1630                 labels = record.split('\0', 2)
  1933                 labels = record.split('\0', 2)
  1631                 labels = [l for l in labels if len(l) > 0]
  1934                 labels = [l for l in labels if len(l) > 0]
  1632                 ui.write(('labels:\n'))
  1935                 ui.write('labels:\n')
  1633                 ui.write(('  local: %s\n' % labels[0]))
  1936                 ui.write(('  local: %s\n' % labels[0]))
  1634                 ui.write(('  other: %s\n' % labels[1]))
  1937                 ui.write(('  other: %s\n' % labels[1]))
  1635                 if len(labels) > 2:
  1938                 if len(labels) > 2:
  1636                     ui.write(('  base:  %s\n' % labels[2]))
  1939                     ui.write(('  base:  %s\n' % labels[2]))
  1637             else:
  1940             else:
  1638                 ui.write(('unrecognized entry: %s\t%s\n')
  1941                 ui.write(
  1639                          % (rtype, record.replace('\0', '\t')))
  1942                     'unrecognized entry: %s\t%s\n'
       
  1943                     % (rtype, record.replace('\0', '\t'))
       
  1944                 )
  1640 
  1945 
  1641     # Avoid mergestate.read() since it may raise an exception for unsupported
  1946     # Avoid mergestate.read() since it may raise an exception for unsupported
  1642     # merge state records. We shouldn't be doing this, but this is OK since this
  1947     # merge state records. We shouldn't be doing this, but this is OK since this
  1643     # command is pretty low-level.
  1948     # command is pretty low-level.
  1644     ms = mergemod.mergestate(repo)
  1949     ms = mergemod.mergestate(repo)
  1645 
  1950 
  1646     # sort so that reasonable information is on top
  1951     # sort so that reasonable information is on top
  1647     v1records = ms._readrecordsv1()
  1952     v1records = ms._readrecordsv1()
  1648     v2records = ms._readrecordsv2()
  1953     v2records = ms._readrecordsv2()
  1649     order = 'LOml'
  1954     order = 'LOml'
       
  1955 
  1650     def key(r):
  1956     def key(r):
  1651         idx = order.find(r[0])
  1957         idx = order.find(r[0])
  1652         if idx == -1:
  1958         if idx == -1:
  1653             return (1, r[1])
  1959             return (1, r[1])
  1654         else:
  1960         else:
  1655             return (0, idx)
  1961             return (0, idx)
       
  1962 
  1656     v1records.sort(key=key)
  1963     v1records.sort(key=key)
  1657     v2records.sort(key=key)
  1964     v2records.sort(key=key)
  1658 
  1965 
  1659     if not v1records and not v2records:
  1966     if not v1records and not v2records:
  1660         ui.write(('no merge state found\n'))
  1967         ui.write('no merge state found\n')
  1661     elif not v2records:
  1968     elif not v2records:
  1662         ui.note(('no version 2 merge state\n'))
  1969         ui.note('no version 2 merge state\n')
  1663         printrecords(1)
  1970         printrecords(1)
  1664     elif ms._v1v2match(v1records, v2records):
  1971     elif ms._v1v2match(v1records, v2records):
  1665         ui.note(('v1 and v2 states match: using v2\n'))
  1972         ui.note('v1 and v2 states match: using v2\n')
  1666         printrecords(2)
  1973         printrecords(2)
  1667     else:
  1974     else:
  1668         ui.note(('v1 and v2 states mismatch: using v1\n'))
  1975         ui.note('v1 and v2 states mismatch: using v1\n')
  1669         printrecords(1)
  1976         printrecords(1)
  1670         if ui.verbose:
  1977         if ui.verbose:
  1671             printrecords(2)
  1978             printrecords(2)
       
  1979 
  1672 
  1980 
  1673 @command('debugnamecomplete', [], _('NAME...'))
  1981 @command('debugnamecomplete', [], _('NAME...'))
  1674 def debugnamecomplete(ui, repo, *args):
  1982 def debugnamecomplete(ui, repo, *args):
  1675     '''complete "names" - tags, open branch names, bookmark names'''
  1983     '''complete "names" - tags, open branch names, bookmark names'''
  1676 
  1984 
  1678     # since we previously only listed open branches, we will handle that
  1986     # since we previously only listed open branches, we will handle that
  1679     # specially (after this for loop)
  1987     # specially (after this for loop)
  1680     for name, ns in repo.names.iteritems():
  1988     for name, ns in repo.names.iteritems():
  1681         if name != 'branches':
  1989         if name != 'branches':
  1682             names.update(ns.listnames(repo))
  1990             names.update(ns.listnames(repo))
  1683     names.update(tag for (tag, heads, tip, closed)
  1991     names.update(
  1684                  in repo.branchmap().iterbranches() if not closed)
  1992         tag
       
  1993         for (tag, heads, tip, closed) in repo.branchmap().iterbranches()
       
  1994         if not closed
       
  1995     )
  1685     completions = set()
  1996     completions = set()
  1686     if not args:
  1997     if not args:
  1687         args = ['']
  1998         args = ['']
  1688     for a in args:
  1999     for a in args:
  1689         completions.update(n for n in names if n.startswith(a))
  2000         completions.update(n for n in names if n.startswith(a))
  1690     ui.write('\n'.join(sorted(completions)))
  2001     ui.write('\n'.join(sorted(completions)))
  1691     ui.write('\n')
  2002     ui.write('\n')
  1692 
  2003 
  1693 @command('debugobsolete',
  2004 
  1694         [('', 'flags', 0, _('markers flag')),
  2005 @command(
  1695          ('', 'record-parents', False,
  2006     'debugobsolete',
  1696           _('record parent information for the precursor')),
  2007     [
  1697          ('r', 'rev', [], _('display markers relevant to REV')),
  2008         ('', 'flags', 0, _('markers flag')),
  1698          ('', 'exclusive', False, _('restrict display to markers only '
  2009         (
  1699                                     'relevant to REV')),
  2010             '',
  1700          ('', 'index', False, _('display index of the marker')),
  2011             'record-parents',
  1701          ('', 'delete', [], _('delete markers specified by indices')),
  2012             False,
  1702         ] + cmdutil.commitopts2 + cmdutil.formatteropts,
  2013             _('record parent information for the precursor'),
  1703          _('[OBSOLETED [REPLACEMENT ...]]'))
  2014         ),
       
  2015         ('r', 'rev', [], _('display markers relevant to REV')),
       
  2016         (
       
  2017             '',
       
  2018             'exclusive',
       
  2019             False,
       
  2020             _('restrict display to markers only ' 'relevant to REV'),
       
  2021         ),
       
  2022         ('', 'index', False, _('display index of the marker')),
       
  2023         ('', 'delete', [], _('delete markers specified by indices')),
       
  2024     ]
       
  2025     + cmdutil.commitopts2
       
  2026     + cmdutil.formatteropts,
       
  2027     _('[OBSOLETED [REPLACEMENT ...]]'),
       
  2028 )
  1704 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
  2029 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
  1705     """create arbitrary obsolete marker
  2030     """create arbitrary obsolete marker
  1706 
  2031 
  1707     With no arguments, displays the list of obsolescence markers."""
  2032     With no arguments, displays the list of obsolescence markers."""
  1708 
  2033 
  1716             n = bin(s)
  2041             n = bin(s)
  1717             if len(n) != len(nullid):
  2042             if len(n) != len(nullid):
  1718                 raise TypeError()
  2043                 raise TypeError()
  1719             return n
  2044             return n
  1720         except TypeError:
  2045         except TypeError:
  1721             raise error.Abort('changeset references must be full hexadecimal '
  2046             raise error.Abort(
  1722                              'node identifiers')
  2047                 'changeset references must be full hexadecimal '
       
  2048                 'node identifiers'
       
  2049             )
  1723 
  2050 
  1724     if opts.get('delete'):
  2051     if opts.get('delete'):
  1725         indices = []
  2052         indices = []
  1726         for v in opts.get('delete'):
  2053         for v in opts.get('delete'):
  1727             try:
  2054             try:
  1728                 indices.append(int(v))
  2055                 indices.append(int(v))
  1729             except ValueError:
  2056             except ValueError:
  1730                 raise error.Abort(_('invalid index value: %r') % v,
  2057                 raise error.Abort(
  1731                                   hint=_('use integers for indices'))
  2058                     _('invalid index value: %r') % v,
       
  2059                     hint=_('use integers for indices'),
       
  2060                 )
  1732 
  2061 
  1733         if repo.currenttransaction():
  2062         if repo.currenttransaction():
  1734             raise error.Abort(_('cannot delete obsmarkers in the middle '
  2063             raise error.Abort(
  1735                                 'of transaction.'))
  2064                 _('cannot delete obsmarkers in the middle ' 'of transaction.')
       
  2065             )
  1736 
  2066 
  1737         with repo.lock():
  2067         with repo.lock():
  1738             n = repair.deleteobsmarkers(repo.obsstore, indices)
  2068             n = repair.deleteobsmarkers(repo.obsstore, indices)
  1739             ui.write(_('deleted %i obsolescence markers\n') % n)
  2069             ui.write(_('deleted %i obsolescence markers\n') % n)
  1740 
  2070 
  1757                     date = None
  2087                     date = None
  1758                 prec = parsenodeid(precursor)
  2088                 prec = parsenodeid(precursor)
  1759                 parents = None
  2089                 parents = None
  1760                 if opts['record_parents']:
  2090                 if opts['record_parents']:
  1761                     if prec not in repo.unfiltered():
  2091                     if prec not in repo.unfiltered():
  1762                         raise error.Abort('cannot used --record-parents on '
  2092                         raise error.Abort(
  1763                                          'unknown changesets')
  2093                             'cannot used --record-parents on '
       
  2094                             'unknown changesets'
       
  2095                         )
  1764                     parents = repo.unfiltered()[prec].parents()
  2096                     parents = repo.unfiltered()[prec].parents()
  1765                     parents = tuple(p.node() for p in parents)
  2097                     parents = tuple(p.node() for p in parents)
  1766                 repo.obsstore.create(tr, prec, succs, opts['flags'],
  2098                 repo.obsstore.create(
  1767                                      parents=parents, date=date,
  2099                     tr,
  1768                                      metadata=metadata, ui=ui)
  2100                     prec,
       
  2101                     succs,
       
  2102                     opts['flags'],
       
  2103                     parents=parents,
       
  2104                     date=date,
       
  2105                     metadata=metadata,
       
  2106                     ui=ui,
       
  2107                 )
  1769                 tr.close()
  2108                 tr.close()
  1770             except ValueError as exc:
  2109             except ValueError as exc:
  1771                 raise error.Abort(_('bad obsmarker input: %s') %
  2110                 raise error.Abort(
  1772                                   pycompat.bytestr(exc))
  2111                     _('bad obsmarker input: %s') % pycompat.bytestr(exc)
       
  2112                 )
  1773             finally:
  2113             finally:
  1774                 tr.release()
  2114                 tr.release()
  1775         finally:
  2115         finally:
  1776             l.release()
  2116             l.release()
  1777     else:
  2117     else:
  1778         if opts['rev']:
  2118         if opts['rev']:
  1779             revs = scmutil.revrange(repo, opts['rev'])
  2119             revs = scmutil.revrange(repo, opts['rev'])
  1780             nodes = [repo[r].node() for r in revs]
  2120             nodes = [repo[r].node() for r in revs]
  1781             markers = list(obsutil.getmarkers(repo, nodes=nodes,
  2121             markers = list(
  1782                                                exclusive=opts['exclusive']))
  2122                 obsutil.getmarkers(
       
  2123                     repo, nodes=nodes, exclusive=opts['exclusive']
       
  2124                 )
       
  2125             )
  1783             markers.sort(key=lambda x: x._data)
  2126             markers.sort(key=lambda x: x._data)
  1784         else:
  2127         else:
  1785             markers = obsutil.getmarkers(repo)
  2128             markers = obsutil.getmarkers(repo)
  1786 
  2129 
  1787         markerstoiter = markers
  2130         markerstoiter = markers
  1805             fm.startitem()
  2148             fm.startitem()
  1806             ind = i if opts.get('index') else None
  2149             ind = i if opts.get('index') else None
  1807             cmdutil.showmarker(fm, m, index=ind)
  2150             cmdutil.showmarker(fm, m, index=ind)
  1808         fm.end()
  2151         fm.end()
  1809 
  2152 
  1810 @command('debugp1copies',
  2153 
  1811          [('r', 'rev', '', _('revision to debug'), _('REV'))],
  2154 @command(
  1812          _('[-r REV]'))
  2155     'debugp1copies',
       
  2156     [('r', 'rev', '', _('revision to debug'), _('REV'))],
       
  2157     _('[-r REV]'),
       
  2158 )
  1813 def debugp1copies(ui, repo, **opts):
  2159 def debugp1copies(ui, repo, **opts):
  1814     """dump copy information compared to p1"""
  2160     """dump copy information compared to p1"""
  1815 
  2161 
  1816     opts = pycompat.byteskwargs(opts)
  2162     opts = pycompat.byteskwargs(opts)
  1817     ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
  2163     ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
  1818     for dst, src in ctx.p1copies().items():
  2164     for dst, src in ctx.p1copies().items():
  1819         ui.write('%s -> %s\n' % (src, dst))
  2165         ui.write('%s -> %s\n' % (src, dst))
  1820 
  2166 
  1821 @command('debugp2copies',
  2167 
  1822          [('r', 'rev', '', _('revision to debug'), _('REV'))],
  2168 @command(
  1823          _('[-r REV]'))
  2169     'debugp2copies',
       
  2170     [('r', 'rev', '', _('revision to debug'), _('REV'))],
       
  2171     _('[-r REV]'),
       
  2172 )
  1824 def debugp1copies(ui, repo, **opts):
  2173 def debugp1copies(ui, repo, **opts):
  1825     """dump copy information compared to p2"""
  2174     """dump copy information compared to p2"""
  1826 
  2175 
  1827     opts = pycompat.byteskwargs(opts)
  2176     opts = pycompat.byteskwargs(opts)
  1828     ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
  2177     ctx = scmutil.revsingle(repo, opts.get('rev'), default=None)
  1829     for dst, src in ctx.p2copies().items():
  2178     for dst, src in ctx.p2copies().items():
  1830         ui.write('%s -> %s\n' % (src, dst))
  2179         ui.write('%s -> %s\n' % (src, dst))
  1831 
  2180 
  1832 @command('debugpathcomplete',
  2181 
  1833          [('f', 'full', None, _('complete an entire path')),
  2182 @command(
  1834           ('n', 'normal', None, _('show only normal files')),
  2183     'debugpathcomplete',
  1835           ('a', 'added', None, _('show only added files')),
  2184     [
  1836           ('r', 'removed', None, _('show only removed files'))],
  2185         ('f', 'full', None, _('complete an entire path')),
  1837          _('FILESPEC...'))
  2186         ('n', 'normal', None, _('show only normal files')),
       
  2187         ('a', 'added', None, _('show only added files')),
       
  2188         ('r', 'removed', None, _('show only removed files')),
       
  2189     ],
       
  2190     _('FILESPEC...'),
       
  2191 )
  1838 def debugpathcomplete(ui, repo, *specs, **opts):
  2192 def debugpathcomplete(ui, repo, *specs, **opts):
  1839     '''complete part or all of a tracked path
  2193     '''complete part or all of a tracked path
  1840 
  2194 
  1841     This command supports shells that offer path name completion. It
  2195     This command supports shells that offer path name completion. It
  1842     currently completes only files already known to the dirstate.
  2196     currently completes only files already known to the dirstate.
  1850         rootdir = repo.root + pycompat.ossep
  2204         rootdir = repo.root + pycompat.ossep
  1851         if spec != repo.root and not spec.startswith(rootdir):
  2205         if spec != repo.root and not spec.startswith(rootdir):
  1852             return [], []
  2206             return [], []
  1853         if os.path.isdir(spec):
  2207         if os.path.isdir(spec):
  1854             spec += '/'
  2208             spec += '/'
  1855         spec = spec[len(rootdir):]
  2209         spec = spec[len(rootdir) :]
  1856         fixpaths = pycompat.ossep != '/'
  2210         fixpaths = pycompat.ossep != '/'
  1857         if fixpaths:
  2211         if fixpaths:
  1858             spec = spec.replace(pycompat.ossep, '/')
  2212             spec = spec.replace(pycompat.ossep, '/')
  1859         speclen = len(spec)
  2213         speclen = len(spec)
  1860         fullpaths = opts[r'full']
  2214         fullpaths = opts[r'full']
  1892         dirs.update(d)
  2246         dirs.update(d)
  1893     files.update(dirs)
  2247     files.update(dirs)
  1894     ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
  2248     ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
  1895     ui.write('\n')
  2249     ui.write('\n')
  1896 
  2250 
  1897 @command('debugpathcopies',
  2251 
  1898          cmdutil.walkopts,
  2252 @command(
  1899          'hg debugpathcopies REV1 REV2 [FILE]',
  2253     'debugpathcopies',
  1900          inferrepo=True)
  2254     cmdutil.walkopts,
       
  2255     'hg debugpathcopies REV1 REV2 [FILE]',
       
  2256     inferrepo=True,
       
  2257 )
  1901 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
  2258 def debugpathcopies(ui, repo, rev1, rev2, *pats, **opts):
  1902     """show copies between two revisions"""
  2259     """show copies between two revisions"""
  1903     ctx1 = scmutil.revsingle(repo, rev1)
  2260     ctx1 = scmutil.revsingle(repo, rev1)
  1904     ctx2 = scmutil.revsingle(repo, rev2)
  2261     ctx2 = scmutil.revsingle(repo, rev2)
  1905     m = scmutil.match(ctx1, pats, opts)
  2262     m = scmutil.match(ctx1, pats, opts)
  1906     for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
  2263     for dst, src in sorted(copies.pathcopies(ctx1, ctx2, m).items()):
  1907         ui.write('%s -> %s\n' % (src, dst))
  2264         ui.write('%s -> %s\n' % (src, dst))
       
  2265 
  1908 
  2266 
  1909 @command('debugpeer', [], _('PATH'), norepo=True)
  2267 @command('debugpeer', [], _('PATH'), norepo=True)
  1910 def debugpeer(ui, path):
  2268 def debugpeer(ui, path):
  1911     """establish a connection to a peer repository"""
  2269     """establish a connection to a peer repository"""
  1912     # Always enable peer request logging. Requires --debug to display
  2270     # Always enable peer request logging. Requires --debug to display
  1923 
  2281 
  1924         ui.write(_('url: %s\n') % peer.url())
  2282         ui.write(_('url: %s\n') % peer.url())
  1925         ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
  2283         ui.write(_('local: %s\n') % (_('yes') if local else _('no')))
  1926         ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
  2284         ui.write(_('pushable: %s\n') % (_('yes') if canpush else _('no')))
  1927 
  2285 
  1928 @command('debugpickmergetool',
  2286 
  1929         [('r', 'rev', '', _('check for files in this revision'), _('REV')),
  2287 @command(
  1930          ('', 'changedelete', None, _('emulate merging change and delete')),
  2288     'debugpickmergetool',
  1931         ] + cmdutil.walkopts + cmdutil.mergetoolopts,
  2289     [
  1932         _('[PATTERN]...'),
  2290         ('r', 'rev', '', _('check for files in this revision'), _('REV')),
  1933         inferrepo=True)
  2291         ('', 'changedelete', None, _('emulate merging change and delete')),
       
  2292     ]
       
  2293     + cmdutil.walkopts
       
  2294     + cmdutil.mergetoolopts,
       
  2295     _('[PATTERN]...'),
       
  2296     inferrepo=True,
       
  2297 )
  1934 def debugpickmergetool(ui, repo, *pats, **opts):
  2298 def debugpickmergetool(ui, repo, *pats, **opts):
  1935     """examine which merge tool is chosen for specified file
  2299     """examine which merge tool is chosen for specified file
  1936 
  2300 
  1937     As described in :hg:`help merge-tools`, Mercurial examines
  2301     As described in :hg:`help merge-tools`, Mercurial examines
  1938     configurations below in this order to decide which merge tool is
  2302     configurations below in this order to decide which merge tool is
  1975     """
  2339     """
  1976     opts = pycompat.byteskwargs(opts)
  2340     opts = pycompat.byteskwargs(opts)
  1977     overrides = {}
  2341     overrides = {}
  1978     if opts['tool']:
  2342     if opts['tool']:
  1979         overrides[('ui', 'forcemerge')] = opts['tool']
  2343         overrides[('ui', 'forcemerge')] = opts['tool']
  1980         ui.note(('with --tool %r\n') % (pycompat.bytestr(opts['tool'])))
  2344         ui.note('with --tool %r\n' % (pycompat.bytestr(opts['tool'])))
  1981 
  2345 
  1982     with ui.configoverride(overrides, 'debugmergepatterns'):
  2346     with ui.configoverride(overrides, 'debugmergepatterns'):
  1983         hgmerge = encoding.environ.get("HGMERGE")
  2347         hgmerge = encoding.environ.get("HGMERGE")
  1984         if hgmerge is not None:
  2348         if hgmerge is not None:
  1985             ui.note(('with HGMERGE=%r\n') % (pycompat.bytestr(hgmerge)))
  2349             ui.note('with HGMERGE=%r\n' % (pycompat.bytestr(hgmerge)))
  1986         uimerge = ui.config("ui", "merge")
  2350         uimerge = ui.config("ui", "merge")
  1987         if uimerge:
  2351         if uimerge:
  1988             ui.note(('with ui.merge=%r\n') % (pycompat.bytestr(uimerge)))
  2352             ui.note('with ui.merge=%r\n' % (pycompat.bytestr(uimerge)))
  1989 
  2353 
  1990         ctx = scmutil.revsingle(repo, opts.get('rev'))
  2354         ctx = scmutil.revsingle(repo, opts.get('rev'))
  1991         m = scmutil.match(ctx, pats, opts)
  2355         m = scmutil.match(ctx, pats, opts)
  1992         changedelete = opts['changedelete']
  2356         changedelete = opts['changedelete']
  1993         for path in ctx.walk(m):
  2357         for path in ctx.walk(m):
  1994             fctx = ctx[path]
  2358             fctx = ctx[path]
  1995             try:
  2359             try:
  1996                 if not ui.debugflag:
  2360                 if not ui.debugflag:
  1997                     ui.pushbuffer(error=True)
  2361                     ui.pushbuffer(error=True)
  1998                 tool, toolpath = filemerge._picktool(repo, ui, path,
  2362                 tool, toolpath = filemerge._picktool(
  1999                                                      fctx.isbinary(),
  2363                     repo,
  2000                                                      'l' in fctx.flags(),
  2364                     ui,
  2001                                                      changedelete)
  2365                     path,
       
  2366                     fctx.isbinary(),
       
  2367                     'l' in fctx.flags(),
       
  2368                     changedelete,
       
  2369                 )
  2002             finally:
  2370             finally:
  2003                 if not ui.debugflag:
  2371                 if not ui.debugflag:
  2004                     ui.popbuffer()
  2372                     ui.popbuffer()
  2005             ui.write(('%s = %s\n') % (path, tool))
  2373             ui.write('%s = %s\n' % (path, tool))
       
  2374 
  2006 
  2375 
  2007 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
  2376 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
  2008 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
  2377 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
  2009     '''access the pushkey key/value protocol
  2378     '''access the pushkey key/value protocol
  2010 
  2379 
  2016 
  2385 
  2017     target = hg.peer(ui, {}, repopath)
  2386     target = hg.peer(ui, {}, repopath)
  2018     if keyinfo:
  2387     if keyinfo:
  2019         key, old, new = keyinfo
  2388         key, old, new = keyinfo
  2020         with target.commandexecutor() as e:
  2389         with target.commandexecutor() as e:
  2021             r = e.callcommand('pushkey', {
  2390             r = e.callcommand(
  2022                 'namespace': namespace,
  2391                 'pushkey',
  2023                 'key': key,
  2392                 {'namespace': namespace, 'key': key, 'old': old, 'new': new,},
  2024                 'old': old,
  2393             ).result()
  2025                 'new': new,
       
  2026             }).result()
       
  2027 
  2394 
  2028         ui.status(pycompat.bytestr(r) + '\n')
  2395         ui.status(pycompat.bytestr(r) + '\n')
  2029         return not r
  2396         return not r
  2030     else:
  2397     else:
  2031         for k, v in sorted(target.listkeys(namespace).iteritems()):
  2398         for k, v in sorted(target.listkeys(namespace).iteritems()):
  2032             ui.write("%s\t%s\n" % (stringutil.escapestr(k),
  2399             ui.write(
  2033                                    stringutil.escapestr(v)))
  2400                 "%s\t%s\n" % (stringutil.escapestr(k), stringutil.escapestr(v))
       
  2401             )
       
  2402 
  2034 
  2403 
  2035 @command('debugpvec', [], _('A B'))
  2404 @command('debugpvec', [], _('A B'))
  2036 def debugpvec(ui, repo, a, b=None):
  2405 def debugpvec(ui, repo, a, b=None):
  2037     ca = scmutil.revsingle(repo, a)
  2406     ca = scmutil.revsingle(repo, a)
  2038     cb = scmutil.revsingle(repo, b)
  2407     cb = scmutil.revsingle(repo, b)
  2047     elif pa | pb:
  2416     elif pa | pb:
  2048         rel = "|"
  2417         rel = "|"
  2049     ui.write(_("a: %s\n") % pa)
  2418     ui.write(_("a: %s\n") % pa)
  2050     ui.write(_("b: %s\n") % pb)
  2419     ui.write(_("b: %s\n") % pb)
  2051     ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
  2420     ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
  2052     ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
  2421     ui.write(
  2053              (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
  2422         _("delta: %d hdist: %d distance: %d relation: %s\n")
  2054               pa.distance(pb), rel))
  2423         % (
  2055 
  2424             abs(pa._depth - pb._depth),
  2056 @command('debugrebuilddirstate|debugrebuildstate',
  2425             pvec._hamming(pa._vec, pb._vec),
  2057     [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
  2426             pa.distance(pb),
  2058      ('', 'minimal', None, _('only rebuild files that are inconsistent with '
  2427             rel,
  2059                              'the working copy parent')),
  2428         )
       
  2429     )
       
  2430 
       
  2431 
       
  2432 @command(
       
  2433     'debugrebuilddirstate|debugrebuildstate',
       
  2434     [
       
  2435         ('r', 'rev', '', _('revision to rebuild to'), _('REV')),
       
  2436         (
       
  2437             '',
       
  2438             'minimal',
       
  2439             None,
       
  2440             _(
       
  2441                 'only rebuild files that are inconsistent with '
       
  2442                 'the working copy parent'
       
  2443             ),
       
  2444         ),
  2060     ],
  2445     ],
  2061     _('[-r REV]'))
  2446     _('[-r REV]'),
       
  2447 )
  2062 def debugrebuilddirstate(ui, repo, rev, **opts):
  2448 def debugrebuilddirstate(ui, repo, rev, **opts):
  2063     """rebuild the dirstate as it would look like for the given revision
  2449     """rebuild the dirstate as it would look like for the given revision
  2064 
  2450 
  2065     If no revision is specified the first current parent will be used.
  2451     If no revision is specified the first current parent will be used.
  2066 
  2452 
  2089             dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
  2475             dsnotadded = set(f for f in dsonly if dirstate[f] != 'a')
  2090             changedfiles = manifestonly | dsnotadded
  2476             changedfiles = manifestonly | dsnotadded
  2091 
  2477 
  2092         dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
  2478         dirstate.rebuild(ctx.node(), ctx.manifest(), changedfiles)
  2093 
  2479 
       
  2480 
  2094 @command('debugrebuildfncache', [], '')
  2481 @command('debugrebuildfncache', [], '')
  2095 def debugrebuildfncache(ui, repo):
  2482 def debugrebuildfncache(ui, repo):
  2096     """rebuild the fncache file"""
  2483     """rebuild the fncache file"""
  2097     repair.rebuildfncache(ui, repo)
  2484     repair.rebuildfncache(ui, repo)
  2098 
  2485 
  2099 @command('debugrename',
  2486 
       
  2487 @command(
       
  2488     'debugrename',
  2100     [('r', 'rev', '', _('revision to debug'), _('REV'))],
  2489     [('r', 'rev', '', _('revision to debug'), _('REV'))],
  2101     _('[-r REV] [FILE]...'))
  2490     _('[-r REV] [FILE]...'),
       
  2491 )
  2102 def debugrename(ui, repo, *pats, **opts):
  2492 def debugrename(ui, repo, *pats, **opts):
  2103     """dump rename information"""
  2493     """dump rename information"""
  2104 
  2494 
  2105     opts = pycompat.byteskwargs(opts)
  2495     opts = pycompat.byteskwargs(opts)
  2106     ctx = scmutil.revsingle(repo, opts.get('rev'))
  2496     ctx = scmutil.revsingle(repo, opts.get('rev'))
  2112         if o:
  2502         if o:
  2113             ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
  2503             ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
  2114         else:
  2504         else:
  2115             ui.write(_("%s not renamed\n") % rel)
  2505             ui.write(_("%s not renamed\n") % rel)
  2116 
  2506 
  2117 @command('debugrevlog', cmdutil.debugrevlogopts +
  2507 
  2118     [('d', 'dump', False, _('dump index data'))],
  2508 @command(
       
  2509     'debugrevlog',
       
  2510     cmdutil.debugrevlogopts + [('d', 'dump', False, _('dump index data'))],
  2119     _('-c|-m|FILE'),
  2511     _('-c|-m|FILE'),
  2120     optionalrepo=True)
  2512     optionalrepo=True,
       
  2513 )
  2121 def debugrevlog(ui, repo, file_=None, **opts):
  2514 def debugrevlog(ui, repo, file_=None, **opts):
  2122     """show data and statistics about a revlog"""
  2515     """show data and statistics about a revlog"""
  2123     opts = pycompat.byteskwargs(opts)
  2516     opts = pycompat.byteskwargs(opts)
  2124     r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
  2517     r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
  2125 
  2518 
  2126     if opts.get("dump"):
  2519     if opts.get("dump"):
  2127         numrevs = len(r)
  2520         numrevs = len(r)
  2128         ui.write(("# rev p1rev p2rev start   end deltastart base   p1   p2"
  2521         ui.write(
  2129                  " rawsize totalsize compression heads chainlen\n"))
  2522             (
       
  2523                 "# rev p1rev p2rev start   end deltastart base   p1   p2"
       
  2524                 " rawsize totalsize compression heads chainlen\n"
       
  2525             )
       
  2526         )
  2130         ts = 0
  2527         ts = 0
  2131         heads = set()
  2528         heads = set()
  2132 
  2529 
  2133         for rev in pycompat.xrange(numrevs):
  2530         for rev in pycompat.xrange(numrevs):
  2134             dbase = r.deltaparent(rev)
  2531             dbase = r.deltaparent(rev)
  2143             heads.add(rev)
  2540             heads.add(rev)
  2144             try:
  2541             try:
  2145                 compression = ts / r.end(rev)
  2542                 compression = ts / r.end(rev)
  2146             except ZeroDivisionError:
  2543             except ZeroDivisionError:
  2147                 compression = 0
  2544                 compression = 0
  2148             ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
  2545             ui.write(
  2149                      "%11d %5d %8d\n" %
  2546                 "%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
  2150                      (rev, p1, p2, r.start(rev), r.end(rev),
  2547                 "%11d %5d %8d\n"
  2151                       r.start(dbase), r.start(cbase),
  2548                 % (
  2152                       r.start(p1), r.start(p2),
  2549                     rev,
  2153                       rs, ts, compression, len(heads), clen))
  2550                     p1,
       
  2551                     p2,
       
  2552                     r.start(rev),
       
  2553                     r.end(rev),
       
  2554                     r.start(dbase),
       
  2555                     r.start(cbase),
       
  2556                     r.start(p1),
       
  2557                     r.start(p2),
       
  2558                     rs,
       
  2559                     ts,
       
  2560                     compression,
       
  2561                     len(heads),
       
  2562                     clen,
       
  2563                 )
       
  2564             )
  2154         return 0
  2565         return 0
  2155 
  2566 
  2156     v = r.version
  2567     v = r.version
  2157     format = v & 0xFFFF
  2568     format = v & 0xFFFF
  2158     flags = []
  2569     flags = []
  2317     basedfmtstr = '%%%dd\n'
  2728     basedfmtstr = '%%%dd\n'
  2318     basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
  2729     basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
  2319 
  2730 
  2320     def dfmtstr(max):
  2731     def dfmtstr(max):
  2321         return basedfmtstr % len(str(max))
  2732         return basedfmtstr % len(str(max))
       
  2733 
  2322     def pcfmtstr(max, padding=0):
  2734     def pcfmtstr(max, padding=0):
  2323         return basepcfmtstr % (len(str(max)), ' ' * padding)
  2735         return basepcfmtstr % (len(str(max)), ' ' * padding)
  2324 
  2736 
  2325     def pcfmt(value, total):
  2737     def pcfmt(value, total):
  2326         if total:
  2738         if total:
  2327             return (value, 100 * float(value) / total)
  2739             return (value, 100 * float(value) / total)
  2328         else:
  2740         else:
  2329             return value, 100.0
  2741             return value, 100.0
  2330 
  2742 
  2331     ui.write(('format : %d\n') % format)
  2743     ui.write('format : %d\n' % format)
  2332     ui.write(('flags  : %s\n') % ', '.join(flags))
  2744     ui.write('flags  : %s\n' % ', '.join(flags))
  2333 
  2745 
  2334     ui.write('\n')
  2746     ui.write('\n')
  2335     fmt = pcfmtstr(totalsize)
  2747     fmt = pcfmtstr(totalsize)
  2336     fmt2 = dfmtstr(totalsize)
  2748     fmt2 = dfmtstr(totalsize)
  2337     ui.write(('revisions     : ') + fmt2 % numrevs)
  2749     ui.write('revisions     : ' + fmt2 % numrevs)
  2338     ui.write(('    merges    : ') + fmt % pcfmt(nummerges, numrevs))
  2750     ui.write('    merges    : ' + fmt % pcfmt(nummerges, numrevs))
  2339     ui.write(('    normal    : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
  2751     ui.write('    normal    : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
  2340     ui.write(('revisions     : ') + fmt2 % numrevs)
  2752     ui.write('revisions     : ' + fmt2 % numrevs)
  2341     ui.write(('    empty     : ') + fmt % pcfmt(numempty, numrevs))
  2753     ui.write('    empty     : ' + fmt % pcfmt(numempty, numrevs))
  2342     ui.write(('                   text  : ')
  2754     ui.write(
  2343              + fmt % pcfmt(numemptytext, numemptytext + numemptydelta))
  2755         '                   text  : '
  2344     ui.write(('                   delta : ')
  2756         + fmt % pcfmt(numemptytext, numemptytext + numemptydelta)
  2345              + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta))
  2757     )
  2346     ui.write(('    snapshot  : ') + fmt % pcfmt(numfull + numsemi, numrevs))
  2758     ui.write(
       
  2759         '                   delta : '
       
  2760         + fmt % pcfmt(numemptydelta, numemptytext + numemptydelta)
       
  2761     )
       
  2762     ui.write('    snapshot  : ' + fmt % pcfmt(numfull + numsemi, numrevs))
  2347     for depth in sorted(numsnapdepth):
  2763     for depth in sorted(numsnapdepth):
  2348         ui.write(('      lvl-%-3d :       ' % depth)
  2764         ui.write(
  2349                  + fmt % pcfmt(numsnapdepth[depth], numrevs))
  2765             ('      lvl-%-3d :       ' % depth)
  2350     ui.write(('    deltas    : ') + fmt % pcfmt(numdeltas, numrevs))
  2766             + fmt % pcfmt(numsnapdepth[depth], numrevs)
  2351     ui.write(('revision size : ') + fmt2 % totalsize)
  2767         )
  2352     ui.write(('    snapshot  : ')
  2768     ui.write('    deltas    : ' + fmt % pcfmt(numdeltas, numrevs))
  2353              + fmt % pcfmt(fulltotal + semitotal, totalsize))
  2769     ui.write('revision size : ' + fmt2 % totalsize)
       
  2770     ui.write('    snapshot  : ' + fmt % pcfmt(fulltotal + semitotal, totalsize))
  2354     for depth in sorted(numsnapdepth):
  2771     for depth in sorted(numsnapdepth):
  2355         ui.write(('      lvl-%-3d :       ' % depth)
  2772         ui.write(
  2356                  + fmt % pcfmt(snaptotal[depth], totalsize))
  2773             ('      lvl-%-3d :       ' % depth)
  2357     ui.write(('    deltas    : ') + fmt % pcfmt(deltatotal, totalsize))
  2774             + fmt % pcfmt(snaptotal[depth], totalsize)
       
  2775         )
       
  2776     ui.write('    deltas    : ' + fmt % pcfmt(deltatotal, totalsize))
  2358 
  2777 
  2359     def fmtchunktype(chunktype):
  2778     def fmtchunktype(chunktype):
  2360         if chunktype == 'empty':
  2779         if chunktype == 'empty':
  2361             return '    %s     : ' % chunktype
  2780             return '    %s     : ' % chunktype
  2362         elif chunktype in pycompat.bytestr(string.ascii_letters):
  2781         elif chunktype in pycompat.bytestr(string.ascii_letters):
  2363             return '    0x%s (%s)  : ' % (hex(chunktype), chunktype)
  2782             return '    0x%s (%s)  : ' % (hex(chunktype), chunktype)
  2364         else:
  2783         else:
  2365             return '    0x%s      : ' % hex(chunktype)
  2784             return '    0x%s      : ' % hex(chunktype)
  2366 
  2785 
  2367     ui.write('\n')
  2786     ui.write('\n')
  2368     ui.write(('chunks        : ') + fmt2 % numrevs)
  2787     ui.write('chunks        : ' + fmt2 % numrevs)
  2369     for chunktype in sorted(chunktypecounts):
  2788     for chunktype in sorted(chunktypecounts):
  2370         ui.write(fmtchunktype(chunktype))
  2789         ui.write(fmtchunktype(chunktype))
  2371         ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
  2790         ui.write(fmt % pcfmt(chunktypecounts[chunktype], numrevs))
  2372     ui.write(('chunks size   : ') + fmt2 % totalsize)
  2791     ui.write('chunks size   : ' + fmt2 % totalsize)
  2373     for chunktype in sorted(chunktypecounts):
  2792     for chunktype in sorted(chunktypecounts):
  2374         ui.write(fmtchunktype(chunktype))
  2793         ui.write(fmtchunktype(chunktype))
  2375         ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
  2794         ui.write(fmt % pcfmt(chunktypesizes[chunktype], totalsize))
  2376 
  2795 
  2377     ui.write('\n')
  2796     ui.write('\n')
  2378     fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
  2797     fmt = dfmtstr(max(avgchainlen, maxchainlen, maxchainspan, compratio))
  2379     ui.write(('avg chain length  : ') + fmt % avgchainlen)
  2798     ui.write('avg chain length  : ' + fmt % avgchainlen)
  2380     ui.write(('max chain length  : ') + fmt % maxchainlen)
  2799     ui.write('max chain length  : ' + fmt % maxchainlen)
  2381     ui.write(('max chain reach   : ') + fmt % maxchainspan)
  2800     ui.write('max chain reach   : ' + fmt % maxchainspan)
  2382     ui.write(('compression ratio : ') + fmt % compratio)
  2801     ui.write('compression ratio : ' + fmt % compratio)
  2383 
  2802 
  2384     if format > 0:
  2803     if format > 0:
  2385         ui.write('\n')
  2804         ui.write('\n')
  2386         ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
  2805         ui.write(
  2387                  % tuple(datasize))
  2806             'uncompressed data size (min/max/avg) : %d / %d / %d\n'
  2388     ui.write(('full revision size (min/max/avg)     : %d / %d / %d\n')
  2807             % tuple(datasize)
  2389              % tuple(fullsize))
  2808         )
  2390     ui.write(('inter-snapshot size (min/max/avg)    : %d / %d / %d\n')
  2809     ui.write(
  2391              % tuple(semisize))
  2810         'full revision size (min/max/avg)     : %d / %d / %d\n'
       
  2811         % tuple(fullsize)
       
  2812     )
       
  2813     ui.write(
       
  2814         'inter-snapshot size (min/max/avg)    : %d / %d / %d\n'
       
  2815         % tuple(semisize)
       
  2816     )
  2392     for depth in sorted(snapsizedepth):
  2817     for depth in sorted(snapsizedepth):
  2393         if depth == 0:
  2818         if depth == 0:
  2394             continue
  2819             continue
  2395         ui.write(('    level-%-3d (min/max/avg)          : %d / %d / %d\n')
  2820         ui.write(
  2396                  % ((depth,) + tuple(snapsizedepth[depth])))
  2821             '    level-%-3d (min/max/avg)          : %d / %d / %d\n'
  2397     ui.write(('delta size (min/max/avg)             : %d / %d / %d\n')
  2822             % ((depth,) + tuple(snapsizedepth[depth]))
  2398              % tuple(deltasize))
  2823         )
       
  2824     ui.write(
       
  2825         'delta size (min/max/avg)             : %d / %d / %d\n'
       
  2826         % tuple(deltasize)
       
  2827     )
  2399 
  2828 
  2400     if numdeltas > 0:
  2829     if numdeltas > 0:
  2401         ui.write('\n')
  2830         ui.write('\n')
  2402         fmt = pcfmtstr(numdeltas)
  2831         fmt = pcfmtstr(numdeltas)
  2403         fmt2 = pcfmtstr(numdeltas, 4)
  2832         fmt2 = pcfmtstr(numdeltas, 4)
  2404         ui.write(('deltas against prev  : ') + fmt % pcfmt(numprev, numdeltas))
  2833         ui.write('deltas against prev  : ' + fmt % pcfmt(numprev, numdeltas))
  2405         if numprev > 0:
  2834         if numprev > 0:
  2406             ui.write(('    where prev = p1  : ') + fmt2 % pcfmt(nump1prev,
  2835             ui.write(
  2407                                                               numprev))
  2836                 '    where prev = p1  : ' + fmt2 % pcfmt(nump1prev, numprev)
  2408             ui.write(('    where prev = p2  : ') + fmt2 % pcfmt(nump2prev,
  2837             )
  2409                                                               numprev))
  2838             ui.write(
  2410             ui.write(('    other            : ') + fmt2 % pcfmt(numoprev,
  2839                 '    where prev = p2  : ' + fmt2 % pcfmt(nump2prev, numprev)
  2411                                                               numprev))
  2840             )
       
  2841             ui.write(
       
  2842                 '    other            : ' + fmt2 % pcfmt(numoprev, numprev)
       
  2843             )
  2412         if gdelta:
  2844         if gdelta:
  2413             ui.write(('deltas against p1    : ')
  2845             ui.write('deltas against p1    : ' + fmt % pcfmt(nump1, numdeltas))
  2414                      + fmt % pcfmt(nump1, numdeltas))
  2846             ui.write('deltas against p2    : ' + fmt % pcfmt(nump2, numdeltas))
  2415             ui.write(('deltas against p2    : ')
  2847             ui.write(
  2416                      + fmt % pcfmt(nump2, numdeltas))
  2848                 'deltas against other : ' + fmt % pcfmt(numother, numdeltas)
  2417             ui.write(('deltas against other : ') + fmt % pcfmt(numother,
  2849             )
  2418                                                              numdeltas))
  2850 
  2419 
  2851 
  2420 @command('debugrevlogindex', cmdutil.debugrevlogopts +
  2852 @command(
  2421     [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
  2853     'debugrevlogindex',
       
  2854     cmdutil.debugrevlogopts
       
  2855     + [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
  2422     _('[-f FORMAT] -c|-m|FILE'),
  2856     _('[-f FORMAT] -c|-m|FILE'),
  2423     optionalrepo=True)
  2857     optionalrepo=True,
       
  2858 )
  2424 def debugrevlogindex(ui, repo, file_=None, **opts):
  2859 def debugrevlogindex(ui, repo, file_=None, **opts):
  2425     """dump the contents of a revlog index"""
  2860     """dump the contents of a revlog index"""
  2426     opts = pycompat.byteskwargs(opts)
  2861     opts = pycompat.byteskwargs(opts)
  2427     r = cmdutil.openrevlog(repo, 'debugrevlogindex', file_, opts)
  2862     r = cmdutil.openrevlog(repo, 'debugrevlogindex', file_, opts)
  2428     format = opts.get('format', 0)
  2863     format = opts.get('format', 0)
  2440         idlen = len(shortfn(r.node(i)))
  2875         idlen = len(shortfn(r.node(i)))
  2441         break
  2876         break
  2442 
  2877 
  2443     if format == 0:
  2878     if format == 0:
  2444         if ui.verbose:
  2879         if ui.verbose:
  2445             ui.write(("   rev    offset  length linkrev"
  2880             ui.write(
  2446                      " %s %s p2\n") % ("nodeid".ljust(idlen),
  2881                 ("   rev    offset  length linkrev" " %s %s p2\n")
  2447                                        "p1".ljust(idlen)))
  2882                 % ("nodeid".ljust(idlen), "p1".ljust(idlen))
       
  2883             )
  2448         else:
  2884         else:
  2449             ui.write(("   rev linkrev %s %s p2\n") % (
  2885             ui.write(
  2450                 "nodeid".ljust(idlen), "p1".ljust(idlen)))
  2886                 "   rev linkrev %s %s p2\n"
       
  2887                 % ("nodeid".ljust(idlen), "p1".ljust(idlen))
       
  2888             )
  2451     elif format == 1:
  2889     elif format == 1:
  2452         if ui.verbose:
  2890         if ui.verbose:
  2453             ui.write(("   rev flag   offset   length     size   link     p1"
  2891             ui.write(
  2454                       "     p2 %s\n") % "nodeid".rjust(idlen))
  2892                 (
       
  2893                     "   rev flag   offset   length     size   link     p1"
       
  2894                     "     p2 %s\n"
       
  2895                 )
       
  2896                 % "nodeid".rjust(idlen)
       
  2897             )
  2455         else:
  2898         else:
  2456             ui.write(("   rev flag     size   link     p1     p2 %s\n") %
  2899             ui.write(
  2457                      "nodeid".rjust(idlen))
  2900                 "   rev flag     size   link     p1     p2 %s\n"
       
  2901                 % "nodeid".rjust(idlen)
       
  2902             )
  2458 
  2903 
  2459     for i in r:
  2904     for i in r:
  2460         node = r.node(i)
  2905         node = r.node(i)
  2461         if format == 0:
  2906         if format == 0:
  2462             try:
  2907             try:
  2463                 pp = r.parents(node)
  2908                 pp = r.parents(node)
  2464             except Exception:
  2909             except Exception:
  2465                 pp = [nullid, nullid]
  2910                 pp = [nullid, nullid]
  2466             if ui.verbose:
  2911             if ui.verbose:
  2467                 ui.write("% 6d % 9d % 7d % 7d %s %s %s\n" % (
  2912                 ui.write(
  2468                         i, r.start(i), r.length(i), r.linkrev(i),
  2913                     "% 6d % 9d % 7d % 7d %s %s %s\n"
  2469                         shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
  2914                     % (
       
  2915                         i,
       
  2916                         r.start(i),
       
  2917                         r.length(i),
       
  2918                         r.linkrev(i),
       
  2919                         shortfn(node),
       
  2920                         shortfn(pp[0]),
       
  2921                         shortfn(pp[1]),
       
  2922                     )
       
  2923                 )
  2470             else:
  2924             else:
  2471                 ui.write("% 6d % 7d %s %s %s\n" % (
  2925                 ui.write(
  2472                     i, r.linkrev(i), shortfn(node), shortfn(pp[0]),
  2926                     "% 6d % 7d %s %s %s\n"
  2473                     shortfn(pp[1])))
  2927                     % (
       
  2928                         i,
       
  2929                         r.linkrev(i),
       
  2930                         shortfn(node),
       
  2931                         shortfn(pp[0]),
       
  2932                         shortfn(pp[1]),
       
  2933                     )
       
  2934                 )
  2474         elif format == 1:
  2935         elif format == 1:
  2475             pr = r.parentrevs(i)
  2936             pr = r.parentrevs(i)
  2476             if ui.verbose:
  2937             if ui.verbose:
  2477                 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n" % (
  2938                 ui.write(
  2478                         i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
  2939                     "% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d %s\n"
  2479                         r.linkrev(i), pr[0], pr[1], shortfn(node)))
  2940                     % (
       
  2941                         i,
       
  2942                         r.flags(i),
       
  2943                         r.start(i),
       
  2944                         r.length(i),
       
  2945                         r.rawsize(i),
       
  2946                         r.linkrev(i),
       
  2947                         pr[0],
       
  2948                         pr[1],
       
  2949                         shortfn(node),
       
  2950                     )
       
  2951                 )
  2480             else:
  2952             else:
  2481                 ui.write("% 6d %04x % 8d % 6d % 6d % 6d %s\n" % (
  2953                 ui.write(
  2482                     i, r.flags(i), r.rawsize(i), r.linkrev(i), pr[0], pr[1],
  2954                     "% 6d %04x % 8d % 6d % 6d % 6d %s\n"
  2483                     shortfn(node)))
  2955                     % (
  2484 
  2956                         i,
  2485 @command('debugrevspec',
  2957                         r.flags(i),
  2486     [('', 'optimize', None,
  2958                         r.rawsize(i),
  2487       _('print parsed tree after optimizing (DEPRECATED)')),
  2959                         r.linkrev(i),
  2488      ('', 'show-revs', True, _('print list of result revisions (default)')),
  2960                         pr[0],
  2489      ('s', 'show-set', None, _('print internal representation of result set')),
  2961                         pr[1],
  2490      ('p', 'show-stage', [],
  2962                         shortfn(node),
  2491       _('print parsed tree at the given stage'), _('NAME')),
  2963                     )
  2492      ('', 'no-optimized', False, _('evaluate tree without optimization')),
  2964                 )
  2493      ('', 'verify-optimized', False, _('verify optimized result')),
  2965 
  2494      ],
  2966 
  2495     ('REVSPEC'))
  2967 @command(
       
  2968     'debugrevspec',
       
  2969     [
       
  2970         (
       
  2971             '',
       
  2972             'optimize',
       
  2973             None,
       
  2974             _('print parsed tree after optimizing (DEPRECATED)'),
       
  2975         ),
       
  2976         ('', 'show-revs', True, _('print list of result revisions (default)')),
       
  2977         (
       
  2978             's',
       
  2979             'show-set',
       
  2980             None,
       
  2981             _('print internal representation of result set'),
       
  2982         ),
       
  2983         (
       
  2984             'p',
       
  2985             'show-stage',
       
  2986             [],
       
  2987             _('print parsed tree at the given stage'),
       
  2988             _('NAME'),
       
  2989         ),
       
  2990         ('', 'no-optimized', False, _('evaluate tree without optimization')),
       
  2991         ('', 'verify-optimized', False, _('verify optimized result')),
       
  2992     ],
       
  2993     'REVSPEC',
       
  2994 )
  2496 def debugrevspec(ui, repo, expr, **opts):
  2995 def debugrevspec(ui, repo, expr, **opts):
  2497     """parse and apply a revision specification
  2996     """parse and apply a revision specification
  2498 
  2997 
  2499     Use -p/--show-stage option to print the parsed tree at the given stages.
  2998     Use -p/--show-stage option to print the parsed tree at the given stages.
  2500     Use -p all to print tree at every stage.
  2999     Use -p all to print tree at every stage.
  2507     """
  3006     """
  2508     opts = pycompat.byteskwargs(opts)
  3007     opts = pycompat.byteskwargs(opts)
  2509     aliases = ui.configitems('revsetalias')
  3008     aliases = ui.configitems('revsetalias')
  2510     stages = [
  3009     stages = [
  2511         ('parsed', lambda tree: tree),
  3010         ('parsed', lambda tree: tree),
  2512         ('expanded', lambda tree: revsetlang.expandaliases(tree, aliases,
  3011         (
  2513                                                            ui.warn)),
  3012             'expanded',
       
  3013             lambda tree: revsetlang.expandaliases(tree, aliases, ui.warn),
       
  3014         ),
  2514         ('concatenated', revsetlang.foldconcat),
  3015         ('concatenated', revsetlang.foldconcat),
  2515         ('analyzed', revsetlang.analyze),
  3016         ('analyzed', revsetlang.analyze),
  2516         ('optimized', revsetlang.optimize),
  3017         ('optimized', revsetlang.optimize),
  2517     ]
  3018     ]
  2518     if opts['no_optimized']:
  3019     if opts['no_optimized']:
  2519         stages = stages[:-1]
  3020         stages = stages[:-1]
  2520     if opts['verify_optimized'] and opts['no_optimized']:
  3021     if opts['verify_optimized'] and opts['no_optimized']:
  2521         raise error.Abort(_('cannot use --verify-optimized with '
  3022         raise error.Abort(
  2522                             '--no-optimized'))
  3023             _('cannot use --verify-optimized with ' '--no-optimized')
       
  3024         )
  2523     stagenames = set(n for n, f in stages)
  3025     stagenames = set(n for n, f in stages)
  2524 
  3026 
  2525     showalways = set()
  3027     showalways = set()
  2526     showchanged = set()
  3028     showchanged = set()
  2527     if ui.verbose and not opts['show_stage']:
  3029     if ui.verbose and not opts['show_stage']:
  2545     tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
  3047     tree = revsetlang.parse(expr, lookup=revset.lookupfn(repo))
  2546     for n, f in stages:
  3048     for n, f in stages:
  2547         treebystage[n] = tree = f(tree)
  3049         treebystage[n] = tree = f(tree)
  2548         if n in showalways or (n in showchanged and tree != printedtree):
  3050         if n in showalways or (n in showchanged and tree != printedtree):
  2549             if opts['show_stage'] or n != 'parsed':
  3051             if opts['show_stage'] or n != 'parsed':
  2550                 ui.write(("* %s:\n") % n)
  3052                 ui.write("* %s:\n" % n)
  2551             ui.write(revsetlang.prettyformat(tree), "\n")
  3053             ui.write(revsetlang.prettyformat(tree), "\n")
  2552             printedtree = tree
  3054             printedtree = tree
  2553 
  3055 
  2554     if opts['verify_optimized']:
  3056     if opts['verify_optimized']:
  2555         arevs = revset.makematcher(treebystage['analyzed'])(repo)
  3057         arevs = revset.makematcher(treebystage['analyzed'])(repo)
  2556         brevs = revset.makematcher(treebystage['optimized'])(repo)
  3058         brevs = revset.makematcher(treebystage['optimized'])(repo)
  2557         if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
  3059         if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
  2558             ui.write(("* analyzed set:\n"), stringutil.prettyrepr(arevs), "\n")
  3060             ui.write("* analyzed set:\n", stringutil.prettyrepr(arevs), "\n")
  2559             ui.write(("* optimized set:\n"), stringutil.prettyrepr(brevs), "\n")
  3061             ui.write("* optimized set:\n", stringutil.prettyrepr(brevs), "\n")
  2560         arevs = list(arevs)
  3062         arevs = list(arevs)
  2561         brevs = list(brevs)
  3063         brevs = list(brevs)
  2562         if arevs == brevs:
  3064         if arevs == brevs:
  2563             return 0
  3065             return 0
  2564         ui.write(('--- analyzed\n'), label='diff.file_a')
  3066         ui.write('--- analyzed\n', label='diff.file_a')
  2565         ui.write(('+++ optimized\n'), label='diff.file_b')
  3067         ui.write('+++ optimized\n', label='diff.file_b')
  2566         sm = difflib.SequenceMatcher(None, arevs, brevs)
  3068         sm = difflib.SequenceMatcher(None, arevs, brevs)
  2567         for tag, alo, ahi, blo, bhi in sm.get_opcodes():
  3069         for tag, alo, ahi, blo, bhi in sm.get_opcodes():
  2568             if tag in (r'delete', r'replace'):
  3070             if tag in (r'delete', r'replace'):
  2569                 for c in arevs[alo:ahi]:
  3071                 for c in arevs[alo:ahi]:
  2570                     ui.write('-%d\n' % c, label='diff.deleted')
  3072                     ui.write('-%d\n' % c, label='diff.deleted')
  2577         return 1
  3079         return 1
  2578 
  3080 
  2579     func = revset.makematcher(tree)
  3081     func = revset.makematcher(tree)
  2580     revs = func(repo)
  3082     revs = func(repo)
  2581     if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
  3083     if opts['show_set'] or (opts['show_set'] is None and ui.verbose):
  2582         ui.write(("* set:\n"), stringutil.prettyrepr(revs), "\n")
  3084         ui.write("* set:\n", stringutil.prettyrepr(revs), "\n")
  2583     if not opts['show_revs']:
  3085     if not opts['show_revs']:
  2584         return
  3086         return
  2585     for c in revs:
  3087     for c in revs:
  2586         ui.write("%d\n" % c)
  3088         ui.write("%d\n" % c)
  2587 
  3089 
  2588 @command('debugserve', [
  3090 
  2589     ('', 'sshstdio', False, _('run an SSH server bound to process handles')),
  3091 @command(
  2590     ('', 'logiofd', '', _('file descriptor to log server I/O to')),
  3092     'debugserve',
  2591     ('', 'logiofile', '', _('file to log server I/O to')),
  3093     [
  2592 ], '')
  3094         (
       
  3095             '',
       
  3096             'sshstdio',
       
  3097             False,
       
  3098             _('run an SSH server bound to process handles'),
       
  3099         ),
       
  3100         ('', 'logiofd', '', _('file descriptor to log server I/O to')),
       
  3101         ('', 'logiofile', '', _('file to log server I/O to')),
       
  3102     ],
       
  3103     '',
       
  3104 )
  2593 def debugserve(ui, repo, **opts):
  3105 def debugserve(ui, repo, **opts):
  2594     """run a server with advanced settings
  3106     """run a server with advanced settings
  2595 
  3107 
  2596     This command is similar to :hg:`serve`. It exists partially as a
  3108     This command is similar to :hg:`serve`. It exists partially as a
  2597     workaround to the fact that ``hg serve --stdio`` must have specific
  3109     workaround to the fact that ``hg serve --stdio`` must have specific
  2620         logfh = open(opts['logiofile'], 'ab', 1)
  3132         logfh = open(opts['logiofile'], 'ab', 1)
  2621 
  3133 
  2622     s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
  3134     s = wireprotoserver.sshserver(ui, repo, logfh=logfh)
  2623     s.serve_forever()
  3135     s.serve_forever()
  2624 
  3136 
       
  3137 
  2625 @command('debugsetparents', [], _('REV1 [REV2]'))
  3138 @command('debugsetparents', [], _('REV1 [REV2]'))
  2626 def debugsetparents(ui, repo, rev1, rev2=None):
  3139 def debugsetparents(ui, repo, rev1, rev2=None):
  2627     """manually set the parents of the current working directory
  3140     """manually set the parents of the current working directory
  2628 
  3141 
  2629     This is useful for writing repository conversion tools, but should
  3142     This is useful for writing repository conversion tools, but should
  2637     node1 = scmutil.revsingle(repo, rev1).node()
  3150     node1 = scmutil.revsingle(repo, rev1).node()
  2638     node2 = scmutil.revsingle(repo, rev2, 'null').node()
  3151     node2 = scmutil.revsingle(repo, rev2, 'null').node()
  2639 
  3152 
  2640     with repo.wlock():
  3153     with repo.wlock():
  2641         repo.setparents(node1, node2)
  3154         repo.setparents(node1, node2)
       
  3155 
  2642 
  3156 
  2643 @command('debugsidedata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
  3157 @command('debugsidedata', cmdutil.debugrevlogopts, _('-c|-m|FILE REV'))
  2644 def debugsidedata(ui, repo, file_, rev=None, **opts):
  3158 def debugsidedata(ui, repo, file_, rev=None, **opts):
  2645     """dump the side data for a cl/manifest/file revision"""
  3159     """dump the side data for a cl/manifest/file revision"""
  2646     opts = pycompat.byteskwargs(opts)
  3160     opts = pycompat.byteskwargs(opts)
  2663         for key, value in sidedata:
  3177         for key, value in sidedata:
  2664             ui.write((' entry-%04o size %d\n' % (key, len(value))))
  3178             ui.write((' entry-%04o size %d\n' % (key, len(value))))
  2665             if ui.verbose:
  3179             if ui.verbose:
  2666                 ui.write(('  %s\n' % stringutil.pprint(value)))
  3180                 ui.write(('  %s\n' % stringutil.pprint(value)))
  2667 
  3181 
       
  3182 
  2668 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
  3183 @command('debugssl', [], '[SOURCE]', optionalrepo=True)
  2669 def debugssl(ui, repo, source=None, **opts):
  3184 def debugssl(ui, repo, source=None, **opts):
  2670     '''test a secure connection to a server
  3185     '''test a secure connection to a server
  2671 
  3186 
  2672     This builds the certificate chain for the server on Windows, installing the
  3187     This builds the certificate chain for the server on Windows, installing the
  2678 
  3193 
  2679     If the update succeeds, retry the original operation.  Otherwise, the cause
  3194     If the update succeeds, retry the original operation.  Otherwise, the cause
  2680     of the SSL error is likely another issue.
  3195     of the SSL error is likely another issue.
  2681     '''
  3196     '''
  2682     if not pycompat.iswindows:
  3197     if not pycompat.iswindows:
  2683         raise error.Abort(_('certificate chain building is only possible on '
  3198         raise error.Abort(
  2684                             'Windows'))
  3199             _('certificate chain building is only possible on ' 'Windows')
       
  3200         )
  2685 
  3201 
  2686     if not source:
  3202     if not source:
  2687         if not repo:
  3203         if not repo:
  2688             raise error.Abort(_("there is no Mercurial repository here, and no "
  3204             raise error.Abort(
  2689                                 "server specified"))
  3205                 _(
       
  3206                     "there is no Mercurial repository here, and no "
       
  3207                     "server specified"
       
  3208                 )
       
  3209             )
  2690         source = "default"
  3210         source = "default"
  2691 
  3211 
  2692     source, branches = hg.parseurl(ui.expandpath(source))
  3212     source, branches = hg.parseurl(ui.expandpath(source))
  2693     url = util.url(source)
  3213     url = util.url(source)
  2694 
  3214 
  2701     else:
  3221     else:
  2702         raise error.Abort(_("only https and ssh connections are supported"))
  3222         raise error.Abort(_("only https and ssh connections are supported"))
  2703 
  3223 
  2704     from . import win32
  3224     from . import win32
  2705 
  3225 
  2706     s = ssl.wrap_socket(socket.socket(), ssl_version=ssl.PROTOCOL_TLS,
  3226     s = ssl.wrap_socket(
  2707                         cert_reqs=ssl.CERT_NONE, ca_certs=None)
  3227         socket.socket(),
       
  3228         ssl_version=ssl.PROTOCOL_TLS,
       
  3229         cert_reqs=ssl.CERT_NONE,
       
  3230         ca_certs=None,
       
  3231     )
  2708 
  3232 
  2709     try:
  3233     try:
  2710         s.connect(addr)
  3234         s.connect(addr)
  2711         cert = s.getpeercert(True)
  3235         cert = s.getpeercert(True)
  2712 
  3236 
  2724         else:
  3248         else:
  2725             ui.status(_('full certificate chain is available\n'))
  3249             ui.status(_('full certificate chain is available\n'))
  2726     finally:
  3250     finally:
  2727         s.close()
  3251         s.close()
  2728 
  3252 
  2729 @command('debugsub',
  3253 
  2730     [('r', 'rev', '',
  3254 @command(
  2731      _('revision to check'), _('REV'))],
  3255     'debugsub',
  2732     _('[-r REV] [REV]'))
  3256     [('r', 'rev', '', _('revision to check'), _('REV'))],
       
  3257     _('[-r REV] [REV]'),
       
  3258 )
  2733 def debugsub(ui, repo, rev=None):
  3259 def debugsub(ui, repo, rev=None):
  2734     ctx = scmutil.revsingle(repo, rev, None)
  3260     ctx = scmutil.revsingle(repo, rev, None)
  2735     for k, v in sorted(ctx.substate.items()):
  3261     for k, v in sorted(ctx.substate.items()):
  2736         ui.write(('path %s\n') % k)
  3262         ui.write('path %s\n' % k)
  2737         ui.write((' source   %s\n') % v[0])
  3263         ui.write(' source   %s\n' % v[0])
  2738         ui.write((' revision %s\n') % v[1])
  3264         ui.write(' revision %s\n' % v[1])
  2739 
  3265 
  2740 @command('debugsuccessorssets',
  3266 
       
  3267 @command(
       
  3268     'debugsuccessorssets',
  2741     [('', 'closest', False, _('return closest successors sets only'))],
  3269     [('', 'closest', False, _('return closest successors sets only'))],
  2742     _('[REV]'))
  3270     _('[REV]'),
       
  3271 )
  2743 def debugsuccessorssets(ui, repo, *revs, **opts):
  3272 def debugsuccessorssets(ui, repo, *revs, **opts):
  2744     """show set of successors for revision
  3273     """show set of successors for revision
  2745 
  3274 
  2746     A successors set of changeset A is a consistent group of revisions that
  3275     A successors set of changeset A is a consistent group of revisions that
  2747     succeed A. It contains non-obsolete changesets only unless closests
  3276     succeed A. It contains non-obsolete changesets only unless closests
  2776     cache = {}
  3305     cache = {}
  2777     ctx2str = bytes
  3306     ctx2str = bytes
  2778     node2str = short
  3307     node2str = short
  2779     for rev in scmutil.revrange(repo, revs):
  3308     for rev in scmutil.revrange(repo, revs):
  2780         ctx = repo[rev]
  3309         ctx = repo[rev]
  2781         ui.write('%s\n'% ctx2str(ctx))
  3310         ui.write('%s\n' % ctx2str(ctx))
  2782         for succsset in obsutil.successorssets(repo, ctx.node(),
  3311         for succsset in obsutil.successorssets(
  2783                                                 closest=opts[r'closest'],
  3312             repo, ctx.node(), closest=opts[r'closest'], cache=cache
  2784                                                 cache=cache):
  3313         ):
  2785             if succsset:
  3314             if succsset:
  2786                 ui.write('    ')
  3315                 ui.write('    ')
  2787                 ui.write(node2str(succsset[0]))
  3316                 ui.write(node2str(succsset[0]))
  2788                 for node in succsset[1:]:
  3317                 for node in succsset[1:]:
  2789                     ui.write(' ')
  3318                     ui.write(' ')
  2790                     ui.write(node2str(node))
  3319                     ui.write(node2str(node))
  2791             ui.write('\n')
  3320             ui.write('\n')
  2792 
  3321 
  2793 @command('debugtemplate',
  3322 
  2794     [('r', 'rev', [], _('apply template on changesets'), _('REV')),
  3323 @command(
  2795      ('D', 'define', [], _('define template keyword'), _('KEY=VALUE'))],
  3324     'debugtemplate',
       
  3325     [
       
  3326         ('r', 'rev', [], _('apply template on changesets'), _('REV')),
       
  3327         ('D', 'define', [], _('define template keyword'), _('KEY=VALUE')),
       
  3328     ],
  2796     _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
  3329     _('[-r REV]... [-D KEY=VALUE]... TEMPLATE'),
  2797     optionalrepo=True)
  3330     optionalrepo=True,
       
  3331 )
  2798 def debugtemplate(ui, repo, tmpl, **opts):
  3332 def debugtemplate(ui, repo, tmpl, **opts):
  2799     """parse and apply a template
  3333     """parse and apply a template
  2800 
  3334 
  2801     If -r/--rev is given, the template is processed as a log template and
  3335     If -r/--rev is given, the template is processed as a log template and
  2802     applied to the given changesets. Otherwise, it is processed as a generic
  3336     applied to the given changesets. Otherwise, it is processed as a generic
  2805     Use --verbose to print the parsed tree.
  3339     Use --verbose to print the parsed tree.
  2806     """
  3340     """
  2807     revs = None
  3341     revs = None
  2808     if opts[r'rev']:
  3342     if opts[r'rev']:
  2809         if repo is None:
  3343         if repo is None:
  2810             raise error.RepoError(_('there is no Mercurial repository here '
  3344             raise error.RepoError(
  2811                                     '(.hg not found)'))
  3345                 _('there is no Mercurial repository here ' '(.hg not found)')
       
  3346             )
  2812         revs = scmutil.revrange(repo, opts[r'rev'])
  3347         revs = scmutil.revrange(repo, opts[r'rev'])
  2813 
  3348 
  2814     props = {}
  3349     props = {}
  2815     for d in opts[r'define']:
  3350     for d in opts[r'define']:
  2816         try:
  3351         try:
  2825         aliases = ui.configitems('templatealias')
  3360         aliases = ui.configitems('templatealias')
  2826         tree = templater.parse(tmpl)
  3361         tree = templater.parse(tmpl)
  2827         ui.note(templater.prettyformat(tree), '\n')
  3362         ui.note(templater.prettyformat(tree), '\n')
  2828         newtree = templater.expandaliases(tree, aliases)
  3363         newtree = templater.expandaliases(tree, aliases)
  2829         if newtree != tree:
  3364         if newtree != tree:
  2830             ui.note(("* expanded:\n"), templater.prettyformat(newtree), '\n')
  3365             ui.note("* expanded:\n", templater.prettyformat(newtree), '\n')
  2831 
  3366 
  2832     if revs is None:
  3367     if revs is None:
  2833         tres = formatter.templateresources(ui, repo)
  3368         tres = formatter.templateresources(ui, repo)
  2834         t = formatter.maketemplater(ui, tmpl, resources=tres)
  3369         t = formatter.maketemplater(ui, tmpl, resources=tres)
  2835         if ui.verbose:
  3370         if ui.verbose:
  2836             kwds, funcs = t.symbolsuseddefault()
  3371             kwds, funcs = t.symbolsuseddefault()
  2837             ui.write(("* keywords: %s\n") % ', '.join(sorted(kwds)))
  3372             ui.write("* keywords: %s\n" % ', '.join(sorted(kwds)))
  2838             ui.write(("* functions: %s\n") % ', '.join(sorted(funcs)))
  3373             ui.write("* functions: %s\n" % ', '.join(sorted(funcs)))
  2839         ui.write(t.renderdefault(props))
  3374         ui.write(t.renderdefault(props))
  2840     else:
  3375     else:
  2841         displayer = logcmdutil.maketemplater(ui, repo, tmpl)
  3376         displayer = logcmdutil.maketemplater(ui, repo, tmpl)
  2842         if ui.verbose:
  3377         if ui.verbose:
  2843             kwds, funcs = displayer.t.symbolsuseddefault()
  3378             kwds, funcs = displayer.t.symbolsuseddefault()
  2844             ui.write(("* keywords: %s\n") % ', '.join(sorted(kwds)))
  3379             ui.write("* keywords: %s\n" % ', '.join(sorted(kwds)))
  2845             ui.write(("* functions: %s\n") % ', '.join(sorted(funcs)))
  3380             ui.write("* functions: %s\n" % ', '.join(sorted(funcs)))
  2846         for r in revs:
  3381         for r in revs:
  2847             displayer.show(repo[r], **pycompat.strkwargs(props))
  3382             displayer.show(repo[r], **pycompat.strkwargs(props))
  2848         displayer.close()
  3383         displayer.close()
  2849 
  3384 
  2850 @command('debuguigetpass', [
  3385 
  2851     ('p', 'prompt', '', _('prompt text'), _('TEXT')),
  3386 @command(
  2852 ], _('[-p TEXT]'), norepo=True)
  3387     'debuguigetpass',
       
  3388     [('p', 'prompt', '', _('prompt text'), _('TEXT')),],
       
  3389     _('[-p TEXT]'),
       
  3390     norepo=True,
       
  3391 )
  2853 def debuguigetpass(ui, prompt=''):
  3392 def debuguigetpass(ui, prompt=''):
  2854     """show prompt to type password"""
  3393     """show prompt to type password"""
  2855     r = ui.getpass(prompt)
  3394     r = ui.getpass(prompt)
  2856     ui.write(('respose: %s\n') % r)
  3395     ui.write('respose: %s\n' % r)
  2857 
  3396 
  2858 @command('debuguiprompt', [
  3397 
  2859     ('p', 'prompt', '', _('prompt text'), _('TEXT')),
  3398 @command(
  2860 ], _('[-p TEXT]'), norepo=True)
  3399     'debuguiprompt',
       
  3400     [('p', 'prompt', '', _('prompt text'), _('TEXT')),],
       
  3401     _('[-p TEXT]'),
       
  3402     norepo=True,
       
  3403 )
  2861 def debuguiprompt(ui, prompt=''):
  3404 def debuguiprompt(ui, prompt=''):
  2862     """show plain prompt"""
  3405     """show plain prompt"""
  2863     r = ui.prompt(prompt)
  3406     r = ui.prompt(prompt)
  2864     ui.write(('response: %s\n') % r)
  3407     ui.write('response: %s\n' % r)
       
  3408 
  2865 
  3409 
  2866 @command('debugupdatecaches', [])
  3410 @command('debugupdatecaches', [])
  2867 def debugupdatecaches(ui, repo, *pats, **opts):
  3411 def debugupdatecaches(ui, repo, *pats, **opts):
  2868     """warm all known caches in the repository"""
  3412     """warm all known caches in the repository"""
  2869     with repo.wlock(), repo.lock():
  3413     with repo.wlock(), repo.lock():
  2870         repo.updatecaches(full=True)
  3414         repo.updatecaches(full=True)
  2871 
  3415 
  2872 @command('debugupgraderepo', [
  3416 
  2873     ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
  3417 @command(
  2874     ('', 'run', False, _('performs an upgrade')),
  3418     'debugupgraderepo',
  2875     ('', 'backup', True, _('keep the old repository content around')),
  3419     [
  2876     ('', 'changelog', None, _('select the changelog for upgrade')),
  3420         ('o', 'optimize', [], _('extra optimization to perform'), _('NAME')),
  2877     ('', 'manifest', None, _('select the manifest for upgrade')),
  3421         ('', 'run', False, _('performs an upgrade')),
  2878 ])
  3422         ('', 'backup', True, _('keep the old repository content around')),
       
  3423         ('', 'changelog', None, _('select the changelog for upgrade')),
       
  3424         ('', 'manifest', None, _('select the manifest for upgrade')),
       
  3425     ],
       
  3426 )
  2879 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
  3427 def debugupgraderepo(ui, repo, run=False, optimize=None, backup=True, **opts):
  2880     """upgrade a repository to use different features
  3428     """upgrade a repository to use different features
  2881 
  3429 
  2882     If no arguments are specified, the repository is evaluated for upgrade
  3430     If no arguments are specified, the repository is evaluated for upgrade
  2883     and a list of problems and potential optimizations is printed.
  3431     and a list of problems and potential optimizations is printed.
  2901       * `--manifest`: only optimize the manifest
  3449       * `--manifest`: only optimize the manifest
  2902       * `--no-manifest`: optimize all revlog but the manifest
  3450       * `--no-manifest`: optimize all revlog but the manifest
  2903       * `--changelog`: optimize the changelog only
  3451       * `--changelog`: optimize the changelog only
  2904       * `--no-changelog --no-manifest`: optimize filelogs only
  3452       * `--no-changelog --no-manifest`: optimize filelogs only
  2905     """
  3453     """
  2906     return upgrade.upgraderepo(ui, repo, run=run, optimize=optimize,
  3454     return upgrade.upgraderepo(
  2907                                backup=backup, **opts)
  3455         ui, repo, run=run, optimize=optimize, backup=backup, **opts
  2908 
  3456     )
  2909 @command('debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'),
  3457 
  2910          inferrepo=True)
  3458 
       
  3459 @command(
       
  3460     'debugwalk', cmdutil.walkopts, _('[OPTION]... [FILE]...'), inferrepo=True
       
  3461 )
  2911 def debugwalk(ui, repo, *pats, **opts):
  3462 def debugwalk(ui, repo, *pats, **opts):
  2912     """show how files match on given patterns"""
  3463     """show how files match on given patterns"""
  2913     opts = pycompat.byteskwargs(opts)
  3464     opts = pycompat.byteskwargs(opts)
  2914     m = scmutil.match(repo[None], pats, opts)
  3465     m = scmutil.match(repo[None], pats, opts)
  2915     if ui.verbose:
  3466     if ui.verbose:
  2916         ui.write(('* matcher:\n'), stringutil.prettyrepr(m), '\n')
  3467         ui.write('* matcher:\n', stringutil.prettyrepr(m), '\n')
  2917     items = list(repo[None].walk(m))
  3468     items = list(repo[None].walk(m))
  2918     if not items:
  3469     if not items:
  2919         return
  3470         return
  2920     f = lambda fn: fn
  3471     f = lambda fn: fn
  2921     if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
  3472     if ui.configbool('ui', 'slash') and pycompat.ossep != '/':
  2922         f = lambda fn: util.normpath(fn)
  3473         f = lambda fn: util.normpath(fn)
  2923     fmt = 'f  %%-%ds  %%-%ds  %%s' % (
  3474     fmt = 'f  %%-%ds  %%-%ds  %%s' % (
  2924         max([len(abs) for abs in items]),
  3475         max([len(abs) for abs in items]),
  2925         max([len(repo.pathto(abs)) for abs in items]))
  3476         max([len(repo.pathto(abs)) for abs in items]),
       
  3477     )
  2926     for abs in items:
  3478     for abs in items:
  2927         line = fmt % (abs, f(repo.pathto(abs)), m.exact(abs) and 'exact' or '')
  3479         line = fmt % (abs, f(repo.pathto(abs)), m.exact(abs) and 'exact' or '')
  2928         ui.write("%s\n" % line.rstrip())
  3480         ui.write("%s\n" % line.rstrip())
       
  3481 
  2929 
  3482 
  2930 @command('debugwhyunstable', [], _('REV'))
  3483 @command('debugwhyunstable', [], _('REV'))
  2931 def debugwhyunstable(ui, repo, rev):
  3484 def debugwhyunstable(ui, repo, rev):
  2932     """explain instabilities of a changeset"""
  3485     """explain instabilities of a changeset"""
  2933     for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
  3486     for entry in obsutil.whyunstable(repo, scmutil.revsingle(repo, rev)):
  2934         dnodes = ''
  3487         dnodes = ''
  2935         if entry.get('divergentnodes'):
  3488         if entry.get('divergentnodes'):
  2936             dnodes = ' '.join('%s (%s)' % (ctx.hex(), ctx.phasestr())
  3489             dnodes = (
  2937                               for ctx in entry['divergentnodes']) + ' '
  3490                 ' '.join(
  2938         ui.write('%s: %s%s %s\n' % (entry['instability'], dnodes,
  3491                     '%s (%s)' % (ctx.hex(), ctx.phasestr())
  2939                                     entry['reason'], entry['node']))
  3492                     for ctx in entry['divergentnodes']
  2940 
  3493                 )
  2941 @command('debugwireargs',
  3494                 + ' '
  2942     [('', 'three', '', 'three'),
  3495             )
  2943     ('', 'four', '', 'four'),
  3496         ui.write(
  2944     ('', 'five', '', 'five'),
  3497             '%s: %s%s %s\n'
  2945     ] + cmdutil.remoteopts,
  3498             % (entry['instability'], dnodes, entry['reason'], entry['node'])
       
  3499         )
       
  3500 
       
  3501 
       
  3502 @command(
       
  3503     'debugwireargs',
       
  3504     [
       
  3505         ('', 'three', '', 'three'),
       
  3506         ('', 'four', '', 'four'),
       
  3507         ('', 'five', '', 'five'),
       
  3508     ]
       
  3509     + cmdutil.remoteopts,
  2946     _('REPO [OPTIONS]... [ONE [TWO]]'),
  3510     _('REPO [OPTIONS]... [ONE [TWO]]'),
  2947     norepo=True)
  3511     norepo=True,
       
  3512 )
  2948 def debugwireargs(ui, repopath, *vals, **opts):
  3513 def debugwireargs(ui, repopath, *vals, **opts):
  2949     opts = pycompat.byteskwargs(opts)
  3514     opts = pycompat.byteskwargs(opts)
  2950     repo = hg.peer(ui, opts, repopath)
  3515     repo = hg.peer(ui, opts, repopath)
  2951     for opt in cmdutil.remoteopts:
  3516     for opt in cmdutil.remoteopts:
  2952         del opts[opt[1]]
  3517         del opts[opt[1]]
  2960     res2 = repo.debugwireargs(*vals, **args)
  3525     res2 = repo.debugwireargs(*vals, **args)
  2961     ui.write("%s\n" % res1)
  3526     ui.write("%s\n" % res1)
  2962     if res1 != res2:
  3527     if res1 != res2:
  2963         ui.warn("%s\n" % res2)
  3528         ui.warn("%s\n" % res2)
  2964 
  3529 
       
  3530 
  2965 def _parsewirelangblocks(fh):
  3531 def _parsewirelangblocks(fh):
  2966     activeaction = None
  3532     activeaction = None
  2967     blocklines = []
  3533     blocklines = []
  2968     lastindent = 0
  3534     lastindent = 0
  2969 
  3535 
  3001 
  3567 
  3002     # Flush last block.
  3568     # Flush last block.
  3003     if activeaction:
  3569     if activeaction:
  3004         yield activeaction, blocklines
  3570         yield activeaction, blocklines
  3005 
  3571 
  3006 @command('debugwireproto',
  3572 
       
  3573 @command(
       
  3574     'debugwireproto',
  3007     [
  3575     [
  3008         ('', 'localssh', False, _('start an SSH server for this repo')),
  3576         ('', 'localssh', False, _('start an SSH server for this repo')),
  3009         ('', 'peer', '', _('construct a specific version of the peer')),
  3577         ('', 'peer', '', _('construct a specific version of the peer')),
  3010         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
  3578         ('', 'noreadstderr', False, _('do not read from stderr of the remote')),
  3011         ('', 'nologhandshake', False,
  3579         (
  3012          _('do not log I/O related to the peer handshake')),
  3580             '',
  3013     ] + cmdutil.remoteopts,
  3581             'nologhandshake',
       
  3582             False,
       
  3583             _('do not log I/O related to the peer handshake'),
       
  3584         ),
       
  3585     ]
       
  3586     + cmdutil.remoteopts,
  3014     _('[PATH]'),
  3587     _('[PATH]'),
  3015     optionalrepo=True)
  3588     optionalrepo=True,
       
  3589 )
  3016 def debugwireproto(ui, repo, path=None, **opts):
  3590 def debugwireproto(ui, repo, path=None, **opts):
  3017     """send wire protocol commands to a server
  3591     """send wire protocol commands to a server
  3018 
  3592 
  3019     This command can be used to issue wire protocol commands to remote
  3593     This command can be used to issue wire protocol commands to remote
  3020     peers and to debug the raw data being exchanged.
  3594     peers and to debug the raw data being exchanged.
  3198 
  3772 
  3199     if opts['localssh'] and not repo:
  3773     if opts['localssh'] and not repo:
  3200         raise error.Abort(_('--localssh requires a repository'))
  3774         raise error.Abort(_('--localssh requires a repository'))
  3201 
  3775 
  3202     if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
  3776     if opts['peer'] and opts['peer'] not in ('raw', 'http2', 'ssh1', 'ssh2'):
  3203         raise error.Abort(_('invalid value for --peer'),
  3777         raise error.Abort(
  3204                           hint=_('valid values are "raw", "ssh1", and "ssh2"'))
  3778             _('invalid value for --peer'),
       
  3779             hint=_('valid values are "raw", "ssh1", and "ssh2"'),
       
  3780         )
  3205 
  3781 
  3206     if path and opts['localssh']:
  3782     if path and opts['localssh']:
  3207         raise error.Abort(_('cannot specify --localssh with an explicit '
  3783         raise error.Abort(
  3208                             'path'))
  3784             _('cannot specify --localssh with an explicit ' 'path')
       
  3785         )
  3209 
  3786 
  3210     if ui.interactive():
  3787     if ui.interactive():
  3211         ui.write(_('(waiting for commands on stdin)\n'))
  3788         ui.write(_('(waiting for commands on stdin)\n'))
  3212 
  3789 
  3213     blocks = list(_parsewirelangblocks(ui.fin))
  3790     blocks = list(_parsewirelangblocks(ui.fin))
  3221     if opts['localssh']:
  3798     if opts['localssh']:
  3222         # We start the SSH server in its own process so there is process
  3799         # We start the SSH server in its own process so there is process
  3223         # separation. This prevents a whole class of potential bugs around
  3800         # separation. This prevents a whole class of potential bugs around
  3224         # shared state from interfering with server operation.
  3801         # shared state from interfering with server operation.
  3225         args = procutil.hgcmd() + [
  3802         args = procutil.hgcmd() + [
  3226             '-R', repo.root,
  3803             '-R',
  3227             'debugserve', '--sshstdio',
  3804             repo.root,
       
  3805             'debugserve',
       
  3806             '--sshstdio',
  3228         ]
  3807         ]
  3229         proc = subprocess.Popen(pycompat.rapply(procutil.tonativestr, args),
  3808         proc = subprocess.Popen(
  3230                                 stdin=subprocess.PIPE,
  3809             pycompat.rapply(procutil.tonativestr, args),
  3231                                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
  3810             stdin=subprocess.PIPE,
  3232                                 bufsize=0)
  3811             stdout=subprocess.PIPE,
       
  3812             stderr=subprocess.PIPE,
       
  3813             bufsize=0,
       
  3814         )
  3233 
  3815 
  3234         stdin = proc.stdin
  3816         stdin = proc.stdin
  3235         stdout = proc.stdout
  3817         stdout = proc.stdout
  3236         stderr = proc.stderr
  3818         stderr = proc.stderr
  3237 
  3819 
  3238         # We turn the pipes into observers so we can log I/O.
  3820         # We turn the pipes into observers so we can log I/O.
  3239         if ui.verbose or opts['peer'] == 'raw':
  3821         if ui.verbose or opts['peer'] == 'raw':
  3240             stdin = util.makeloggingfileobject(ui, proc.stdin, b'i',
  3822             stdin = util.makeloggingfileobject(
  3241                                                logdata=True)
  3823                 ui, proc.stdin, b'i', logdata=True
  3242             stdout = util.makeloggingfileobject(ui, proc.stdout, b'o',
  3824             )
  3243                                                 logdata=True)
  3825             stdout = util.makeloggingfileobject(
  3244             stderr = util.makeloggingfileobject(ui, proc.stderr, b'e',
  3826                 ui, proc.stdout, b'o', logdata=True
  3245                                                 logdata=True)
  3827             )
       
  3828             stderr = util.makeloggingfileobject(
       
  3829                 ui, proc.stderr, b'e', logdata=True
       
  3830             )
  3246 
  3831 
  3247         # --localssh also implies the peer connection settings.
  3832         # --localssh also implies the peer connection settings.
  3248 
  3833 
  3249         url = 'ssh://localserver'
  3834         url = 'ssh://localserver'
  3250         autoreadstderr = not opts['noreadstderr']
  3835         autoreadstderr = not opts['noreadstderr']
  3251 
  3836 
  3252         if opts['peer'] == 'ssh1':
  3837         if opts['peer'] == 'ssh1':
  3253             ui.write(_('creating ssh peer for wire protocol version 1\n'))
  3838             ui.write(_('creating ssh peer for wire protocol version 1\n'))
  3254             peer = sshpeer.sshv1peer(ui, url, proc, stdin, stdout, stderr,
  3839             peer = sshpeer.sshv1peer(
  3255                                      None, autoreadstderr=autoreadstderr)
  3840                 ui,
       
  3841                 url,
       
  3842                 proc,
       
  3843                 stdin,
       
  3844                 stdout,
       
  3845                 stderr,
       
  3846                 None,
       
  3847                 autoreadstderr=autoreadstderr,
       
  3848             )
  3256         elif opts['peer'] == 'ssh2':
  3849         elif opts['peer'] == 'ssh2':
  3257             ui.write(_('creating ssh peer for wire protocol version 2\n'))
  3850             ui.write(_('creating ssh peer for wire protocol version 2\n'))
  3258             peer = sshpeer.sshv2peer(ui, url, proc, stdin, stdout, stderr,
  3851             peer = sshpeer.sshv2peer(
  3259                                      None, autoreadstderr=autoreadstderr)
  3852                 ui,
       
  3853                 url,
       
  3854                 proc,
       
  3855                 stdin,
       
  3856                 stdout,
       
  3857                 stderr,
       
  3858                 None,
       
  3859                 autoreadstderr=autoreadstderr,
       
  3860             )
  3260         elif opts['peer'] == 'raw':
  3861         elif opts['peer'] == 'raw':
  3261             ui.write(_('using raw connection to peer\n'))
  3862             ui.write(_('using raw connection to peer\n'))
  3262             peer = None
  3863             peer = None
  3263         else:
  3864         else:
  3264             ui.write(_('creating ssh peer from handshake results\n'))
  3865             ui.write(_('creating ssh peer from handshake results\n'))
  3265             peer = sshpeer.makepeer(ui, url, proc, stdin, stdout, stderr,
  3866             peer = sshpeer.makepeer(
  3266                                     autoreadstderr=autoreadstderr)
  3867                 ui,
       
  3868                 url,
       
  3869                 proc,
       
  3870                 stdin,
       
  3871                 stdout,
       
  3872                 stderr,
       
  3873                 autoreadstderr=autoreadstderr,
       
  3874             )
  3267 
  3875 
  3268     elif path:
  3876     elif path:
  3269         # We bypass hg.peer() so we can proxy the sockets.
  3877         # We bypass hg.peer() so we can proxy the sockets.
  3270         # TODO consider not doing this because we skip
  3878         # TODO consider not doing this because we skip
  3271         # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
  3879         # ``hg.wirepeersetupfuncs`` and potentially other useful functionality.
  3278             r'useragent': b'Mercurial debugwireproto',
  3886             r'useragent': b'Mercurial debugwireproto',
  3279         }
  3887         }
  3280 
  3888 
  3281         # Turn pipes/sockets into observers so we can log I/O.
  3889         # Turn pipes/sockets into observers so we can log I/O.
  3282         if ui.verbose:
  3890         if ui.verbose:
  3283             openerargs.update({
  3891             openerargs.update(
  3284                 r'loggingfh': ui,
  3892                 {
  3285                 r'loggingname': b's',
  3893                     r'loggingfh': ui,
  3286                 r'loggingopts': {
  3894                     r'loggingname': b's',
  3287                     r'logdata': True,
  3895                     r'loggingopts': {r'logdata': True, r'logdataapis': False,},
  3288                     r'logdataapis': False,
  3896                 }
  3289                 },
  3897             )
  3290             })
       
  3291 
  3898 
  3292         if ui.debugflag:
  3899         if ui.debugflag:
  3293             openerargs[r'loggingopts'][r'logdataapis'] = True
  3900             openerargs[r'loggingopts'][r'logdataapis'] = True
  3294 
  3901 
  3295         # Don't send default headers when in raw mode. This allows us to
  3902         # Don't send default headers when in raw mode. This allows us to
  3302 
  3909 
  3303         if opts['peer'] == 'http2':
  3910         if opts['peer'] == 'http2':
  3304             ui.write(_('creating http peer for wire protocol version 2\n'))
  3911             ui.write(_('creating http peer for wire protocol version 2\n'))
  3305             # We go through makepeer() because we need an API descriptor for
  3912             # We go through makepeer() because we need an API descriptor for
  3306             # the peer instance to be useful.
  3913             # the peer instance to be useful.
  3307             with ui.configoverride({
  3914             with ui.configoverride(
  3308                 ('experimental', 'httppeer.advertise-v2'): True}):
  3915                 {('experimental', 'httppeer.advertise-v2'): True}
       
  3916             ):
  3309                 if opts['nologhandshake']:
  3917                 if opts['nologhandshake']:
  3310                     ui.pushbuffer()
  3918                     ui.pushbuffer()
  3311 
  3919 
  3312                 peer = httppeer.makepeer(ui, path, opener=opener)
  3920                 peer = httppeer.makepeer(ui, path, opener=opener)
  3313 
  3921 
  3314                 if opts['nologhandshake']:
  3922                 if opts['nologhandshake']:
  3315                     ui.popbuffer()
  3923                     ui.popbuffer()
  3316 
  3924 
  3317             if not isinstance(peer, httppeer.httpv2peer):
  3925             if not isinstance(peer, httppeer.httpv2peer):
  3318                 raise error.Abort(_('could not instantiate HTTP peer for '
  3926                 raise error.Abort(
  3319                                     'wire protocol version 2'),
  3927                     _(
  3320                                   hint=_('the server may not have the feature '
  3928                         'could not instantiate HTTP peer for '
  3321                                          'enabled or is not allowing this '
  3929                         'wire protocol version 2'
  3322                                          'client version'))
  3930                     ),
       
  3931                     hint=_(
       
  3932                         'the server may not have the feature '
       
  3933                         'enabled or is not allowing this '
       
  3934                         'client version'
       
  3935                     ),
       
  3936                 )
  3323 
  3937 
  3324         elif opts['peer'] == 'raw':
  3938         elif opts['peer'] == 'raw':
  3325             ui.write(_('using raw connection to peer\n'))
  3939             ui.write(_('using raw connection to peer\n'))
  3326             peer = None
  3940             peer = None
  3327         elif opts['peer']:
  3941         elif opts['peer']:
  3328             raise error.Abort(_('--peer %s not supported with HTTP peers') %
  3942             raise error.Abort(
  3329                               opts['peer'])
  3943                 _('--peer %s not supported with HTTP peers') % opts['peer']
       
  3944             )
  3330         else:
  3945         else:
  3331             peer = httppeer.makepeer(ui, path, opener=opener)
  3946             peer = httppeer.makepeer(ui, path, opener=opener)
  3332 
  3947 
  3333         # We /could/ populate stdin/stdout with sock.makefile()...
  3948         # We /could/ populate stdin/stdout with sock.makefile()...
  3334     else:
  3949     else:
  3353             if not stdin:
  3968             if not stdin:
  3354                 raise error.Abort(_('cannot call flush on this peer'))
  3969                 raise error.Abort(_('cannot call flush on this peer'))
  3355             stdin.flush()
  3970             stdin.flush()
  3356         elif action.startswith('command'):
  3971         elif action.startswith('command'):
  3357             if not peer:
  3972             if not peer:
  3358                 raise error.Abort(_('cannot send commands unless peer instance '
  3973                 raise error.Abort(
  3359                                     'is available'))
  3974                     _(
       
  3975                         'cannot send commands unless peer instance '
       
  3976                         'is available'
       
  3977                     )
       
  3978                 )
  3360 
  3979 
  3361             command = action.split(' ', 1)[1]
  3980             command = action.split(' ', 1)[1]
  3362 
  3981 
  3363             args = {}
  3982             args = {}
  3364             for line in lines:
  3983             for line in lines:
  3384             ui.status(_('sending %s command\n') % command)
  4003             ui.status(_('sending %s command\n') % command)
  3385 
  4004 
  3386             if 'PUSHFILE' in args:
  4005             if 'PUSHFILE' in args:
  3387                 with open(args['PUSHFILE'], r'rb') as fh:
  4006                 with open(args['PUSHFILE'], r'rb') as fh:
  3388                     del args['PUSHFILE']
  4007                     del args['PUSHFILE']
  3389                     res, output = peer._callpush(command, fh,
  4008                     res, output = peer._callpush(
  3390                                                  **pycompat.strkwargs(args))
  4009                         command, fh, **pycompat.strkwargs(args)
       
  4010                     )
  3391                     ui.status(_('result: %s\n') % stringutil.escapestr(res))
  4011                     ui.status(_('result: %s\n') % stringutil.escapestr(res))
  3392                     ui.status(_('remote output: %s\n') %
  4012                     ui.status(
  3393                               stringutil.escapestr(output))
  4013                         _('remote output: %s\n') % stringutil.escapestr(output)
       
  4014                     )
  3394             else:
  4015             else:
  3395                 with peer.commandexecutor() as e:
  4016                 with peer.commandexecutor() as e:
  3396                     res = e.callcommand(command, args).result()
  4017                     res = e.callcommand(command, args).result()
  3397 
  4018 
  3398                 if isinstance(res, wireprotov2peer.commandresponse):
  4019                 if isinstance(res, wireprotov2peer.commandresponse):
  3399                     val = res.objects()
  4020                     val = res.objects()
  3400                     ui.status(_('response: %s\n') %
  4021                     ui.status(
  3401                               stringutil.pprint(val, bprefix=True, indent=2))
  4022                         _('response: %s\n')
       
  4023                         % stringutil.pprint(val, bprefix=True, indent=2)
       
  4024                     )
  3402                 else:
  4025                 else:
  3403                     ui.status(_('response: %s\n') %
  4026                     ui.status(
  3404                               stringutil.pprint(res, bprefix=True, indent=2))
  4027                         _('response: %s\n')
       
  4028                         % stringutil.pprint(res, bprefix=True, indent=2)
       
  4029                     )
  3405 
  4030 
  3406         elif action == 'batchbegin':
  4031         elif action == 'batchbegin':
  3407             if batchedcommands is not None:
  4032             if batchedcommands is not None:
  3408                 raise error.Abort(_('nested batchbegin not allowed'))
  4033                 raise error.Abort(_('nested batchbegin not allowed'))
  3409 
  4034 
  3410             batchedcommands = []
  4035             batchedcommands = []
  3411         elif action == 'batchsubmit':
  4036         elif action == 'batchsubmit':
  3412             # There is a batching API we could go through. But it would be
  4037             # There is a batching API we could go through. But it would be
  3413             # difficult to normalize requests into function calls. It is easier
  4038             # difficult to normalize requests into function calls. It is easier
  3414             # to bypass this layer and normalize to commands + args.
  4039             # to bypass this layer and normalize to commands + args.
  3415             ui.status(_('sending batch with %d sub-commands\n') %
  4040             ui.status(
  3416                       len(batchedcommands))
  4041                 _('sending batch with %d sub-commands\n') % len(batchedcommands)
       
  4042             )
  3417             for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
  4043             for i, chunk in enumerate(peer._submitbatch(batchedcommands)):
  3418                 ui.status(_('response #%d: %s\n') %
  4044                 ui.status(
  3419                           (i, stringutil.escapestr(chunk)))
  4045                     _('response #%d: %s\n') % (i, stringutil.escapestr(chunk))
       
  4046                 )
  3420 
  4047 
  3421             batchedcommands = None
  4048             batchedcommands = None
  3422 
  4049 
  3423         elif action.startswith('httprequest '):
  4050         elif action.startswith('httprequest '):
  3424             if not opener:
  4051             if not opener:
  3425                 raise error.Abort(_('cannot use httprequest without an HTTP '
  4052                 raise error.Abort(
  3426                                     'peer'))
  4053                     _('cannot use httprequest without an HTTP ' 'peer')
       
  4054                 )
  3427 
  4055 
  3428             request = action.split(' ', 2)
  4056             request = action.split(' ', 2)
  3429             if len(request) != 3:
  4057             if len(request) != 3:
  3430                 raise error.Abort(_('invalid httprequest: expected format is '
  4058                 raise error.Abort(
  3431                                     '"httprequest <method> <path>'))
  4059                     _(
       
  4060                         'invalid httprequest: expected format is '
       
  4061                         '"httprequest <method> <path>'
       
  4062                     )
       
  4063                 )
  3432 
  4064 
  3433             method, httppath = request[1:]
  4065             method, httppath = request[1:]
  3434             headers = {}
  4066             headers = {}
  3435             body = None
  4067             body = None
  3436             frames = []
  4068             frames = []
  3447                 if line.startswith(b'BODYFILE '):
  4079                 if line.startswith(b'BODYFILE '):
  3448                     with open(line.split(b' ', 1), 'rb') as fh:
  4080                     with open(line.split(b' ', 1), 'rb') as fh:
  3449                         body = fh.read()
  4081                         body = fh.read()
  3450                 elif line.startswith(b'frame '):
  4082                 elif line.startswith(b'frame '):
  3451                     frame = wireprotoframing.makeframefromhumanstring(
  4083                     frame = wireprotoframing.makeframefromhumanstring(
  3452                         line[len(b'frame '):])
  4084                         line[len(b'frame ') :]
       
  4085                     )
  3453 
  4086 
  3454                     frames.append(frame)
  4087                     frames.append(frame)
  3455                 else:
  4088                 else:
  3456                     raise error.Abort(_('unknown argument to httprequest: %s') %
  4089                     raise error.Abort(
  3457                                       line)
  4090                         _('unknown argument to httprequest: %s') % line
       
  4091                     )
  3458 
  4092 
  3459             url = path + httppath
  4093             url = path + httppath
  3460 
  4094 
  3461             if frames:
  4095             if frames:
  3462                 body = b''.join(bytes(f) for f in frames)
  4096                 body = b''.join(bytes(f) for f in frames)
  3476                 getattr(e, 'read', lambda: None)()
  4110                 getattr(e, 'read', lambda: None)()
  3477                 continue
  4111                 continue
  3478 
  4112 
  3479             ct = res.headers.get(r'Content-Type')
  4113             ct = res.headers.get(r'Content-Type')
  3480             if ct == r'application/mercurial-cbor':
  4114             if ct == r'application/mercurial-cbor':
  3481                 ui.write(_('cbor> %s\n') %
  4115                 ui.write(
  3482                          stringutil.pprint(cborutil.decodeall(body),
  4116                     _('cbor> %s\n')
  3483                                            bprefix=True,
  4117                     % stringutil.pprint(
  3484                                            indent=2))
  4118                         cborutil.decodeall(body), bprefix=True, indent=2
       
  4119                     )
       
  4120                 )
  3485 
  4121 
  3486         elif action == 'close':
  4122         elif action == 'close':
  3487             peer.close()
  4123             peer.close()
  3488         elif action == 'readavailable':
  4124         elif action == 'readavailable':
  3489             if not stdout or not stderr:
  4125             if not stdout or not stderr: