[PATCH 1 of 1] split out debugcommands.py

Adrian Buehlmann adrian at cadifra.com
Tue May 10 10:37:42 CDT 2011


# HG changeset patch
# User Adrian Buehlmann <adrian at cadifra.com>
# Date 1304972841 -7200
# Node ID a568ae1ff3c2c26007e8d572d3a52c90f1a2a508
# Parent  4d891ed9a6afa65bc8df53a1a64ec6806b81988f
split out debugcommands.py

diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -8,14 +8,12 @@
 from node import hex, bin, nullid, nullrev, short
 from lock import release
 from i18n import _, gettext
-import os, re, sys, difflib, time, tempfile
-import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
+import os, re, sys, difflib
+import hg, scmutil, util, extensions, copies, error, bookmarks
 import patch, help, url, encoding, templatekw, discovery
 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
 import merge as mergemod
 import minirst, revset, templatefilters
-import dagparser, context, simplemerge
-import random, setdiscovery, treediscovery, dagutil
 
 # Commands start here, listed alphabetically
 
@@ -950,231 +948,6 @@
     finally:
         wlock.release()
 
-def debugancestor(ui, repo, *args):
-    """find the ancestor revision of two revisions in a given index"""
-    if len(args) == 3:
-        index, rev1, rev2 = args
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
-        lookup = r.lookup
-    elif len(args) == 2:
-        if not repo:
-            raise util.Abort(_("there is no Mercurial repository here "
-                               "(.hg not found)"))
-        rev1, rev2 = args
-        r = repo.changelog
-        lookup = repo.lookup
-    else:
-        raise util.Abort(_('either two or three arguments required'))
-    a = r.ancestor(lookup(rev1), lookup(rev2))
-    ui.write("%d:%s\n" % (r.rev(a), hex(a)))
-
-def debugbuilddag(ui, repo, text,
-                  mergeable_file=False,
-                  overwritten_file=False,
-                  new_file=False):
-    """builds a repo with a given dag from scratch in the current empty repo
-
-    Elements:
-
-     - "+n" is a linear run of n nodes based on the current default parent
-     - "." is a single node based on the current default parent
-     - "$" resets the default parent to null (implied at the start);
-           otherwise the default parent is always the last node created
-     - "<p" sets the default parent to the backref p
-     - "*p" is a fork at parent p, which is a backref
-     - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
-     - "/p2" is a merge of the preceding node and p2
-     - ":tag" defines a local tag for the preceding node
-     - "@branch" sets the named branch for subsequent nodes
-     - "#...\\n" is a comment up to the end of the line
-
-    Whitespace between the above elements is ignored.
-
-    A backref is either
-
-     - a number n, which references the node curr-n, where curr is the current
-       node, or
-     - the name of a local tag you placed earlier using ":tag", or
-     - empty to denote the default parent.
-
-    All string valued-elements are either strictly alphanumeric, or must
-    be enclosed in double quotes ("..."), with "\\" as escape character.
-    """
-
-    cl = repo.changelog
-    if len(cl) > 0:
-        raise util.Abort(_('repository is not empty'))
-
-    if mergeable_file:
-        linesperrev = 2
-        # determine number of revs in DAG
-        n = 0
-        for type, data in dagparser.parsedag(text):
-            if type == 'n':
-                n += 1
-        # make a file with k lines per rev
-        initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
-        initialmergedlines.append("")
-
-    tags = []
-
-    tr = repo.transaction("builddag")
-    try:
-
-        at = -1
-        atbranch = 'default'
-        nodeids = []
-        for type, data in dagparser.parsedag(text):
-            if type == 'n':
-                ui.note('node %s\n' % str(data))
-                id, ps = data
-
-                files = []
-                fctxs = {}
-
-                p2 = None
-                if mergeable_file:
-                    fn = "mf"
-                    p1 = repo[ps[0]]
-                    if len(ps) > 1:
-                        p2 = repo[ps[1]]
-                        pa = p1.ancestor(p2)
-                        base, local, other = [x[fn].data() for x in pa, p1, p2]
-                        m3 = simplemerge.Merge3Text(base, local, other)
-                        ml = [l.strip() for l in m3.merge_lines()]
-                        ml.append("")
-                    elif at > 0:
-                        ml = p1[fn].data().split("\n")
-                    else:
-                        ml = initialmergedlines
-                    ml[id * linesperrev] += " r%i" % id
-                    mergedtext = "\n".join(ml)
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(fn, mergedtext)
-
-                if overwritten_file:
-                    fn = "of"
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
-
-                if new_file:
-                    fn = "nf%i" % id
-                    files.append(fn)
-                    fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
-                    if len(ps) > 1:
-                        if not p2:
-                            p2 = repo[ps[1]]
-                        for fn in p2:
-                            if fn.startswith("nf"):
-                                files.append(fn)
-                                fctxs[fn] = p2[fn]
-
-                def fctxfn(repo, cx, path):
-                    return fctxs.get(path)
-
-                if len(ps) == 0 or ps[0] < 0:
-                    pars = [None, None]
-                elif len(ps) == 1:
-                    pars = [nodeids[ps[0]], None]
-                else:
-                    pars = [nodeids[p] for p in ps]
-                cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
-                                    date=(id, 0),
-                                    user="debugbuilddag",
-                                    extra={'branch': atbranch})
-                nodeid = repo.commitctx(cx)
-                nodeids.append(nodeid)
-                at = id
-            elif type == 'l':
-                id, name = data
-                ui.note('tag %s\n' % name)
-                tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
-            elif type == 'a':
-                ui.note('branch %s\n' % data)
-                atbranch = data
-        tr.close()
-    finally:
-        tr.release()
-
-    if tags:
-        repo.opener.write("localtags", "".join(tags))
-
-def debugcommands(ui, cmd='', *args):
-    """list all available commands and options"""
-    for cmd, vals in sorted(table.iteritems()):
-        cmd = cmd.split('|')[0].strip('^')
-        opts = ', '.join([i[1] for i in vals[1]])
-        ui.write('%s: %s\n' % (cmd, opts))
-
-def debugcomplete(ui, cmd='', **opts):
-    """returns the completion list associated with the given command"""
-
-    if opts.get('options'):
-        options = []
-        otables = [globalopts]
-        if cmd:
-            aliases, entry = cmdutil.findcmd(cmd, table, False)
-            otables.append(entry[1])
-        for t in otables:
-            for o in t:
-                if "(DEPRECATED)" in o[3]:
-                    continue
-                if o[0]:
-                    options.append('-%s' % o[0])
-                options.append('--%s' % o[1])
-        ui.write("%s\n" % "\n".join(options))
-        return
-
-    cmdlist = cmdutil.findpossible(cmd, table)
-    if ui.verbose:
-        cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
-    ui.write("%s\n" % "\n".join(sorted(cmdlist)))
-
-def debugfsinfo(ui, path = "."):
-    """show information detected about current filesystem"""
-    util.writefile('.debugfsinfo', '')
-    ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
-    ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
-    ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
-                                and 'yes' or 'no'))
-    os.unlink('.debugfsinfo')
-
-def debugrebuildstate(ui, repo, rev="tip"):
-    """rebuild the dirstate as it would look like for the given revision"""
-    ctx = cmdutil.revsingle(repo, rev)
-    wlock = repo.wlock()
-    try:
-        repo.dirstate.rebuild(ctx.node(), ctx.manifest())
-    finally:
-        wlock.release()
-
-def debugcheckstate(ui, repo):
-    """validate the correctness of the current dirstate"""
-    parent1, parent2 = repo.dirstate.parents()
-    m1 = repo[parent1].manifest()
-    m2 = repo[parent2].manifest()
-    errors = 0
-    for f in repo.dirstate:
-        state = repo.dirstate[f]
-        if state in "nr" and f not in m1:
-            ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
-            errors += 1
-        if state in "a" and f in m1:
-            ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
-            errors += 1
-        if state in "m" and f not in m1 and f not in m2:
-            ui.warn(_("%s in state %s, but not in either manifest\n") %
-                    (f, state))
-            errors += 1
-    for f in m1:
-        state = repo.dirstate[f]
-        if state not in "nrm":
-            ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
-            errors += 1
-    if errors:
-        error = _(".hg/dirstate inconsistent with current parent's manifest")
-        raise util.Abort(error)
-
 def showconfig(ui, repo, *values, **opts):
     """show combined config settings from all hgrc files
 
@@ -1218,507 +991,6 @@
                      ui.configsource(section, name, untrusted))
             ui.write('%s=%s\n' % (sectname, value))
 
-def debugknown(ui, repopath, *ids, **opts):
-    """test whether node ids are known to a repo
-
-    Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
-    indicating unknown/known.
-    """
-    repo = hg.repository(ui, repopath)
-    if not repo.capable('known'):
-        raise util.Abort("known() not supported by target repository")
-    flags = repo.known([bin(s) for s in ids])
-    ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
-
-def debugbundle(ui, bundlepath, all=None, **opts):
-    """lists the contents of a bundle"""
-    f = url.open(ui, bundlepath)
-    try:
-        gen = changegroup.readbundle(f, bundlepath)
-        if all:
-            ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
-
-            def showchunks(named):
-                ui.write("\n%s\n" % named)
-                chain = None
-                while 1:
-                    chunkdata = gen.deltachunk(chain)
-                    if not chunkdata:
-                        break
-                    node = chunkdata['node']
-                    p1 = chunkdata['p1']
-                    p2 = chunkdata['p2']
-                    cs = chunkdata['cs']
-                    deltabase = chunkdata['deltabase']
-                    delta = chunkdata['delta']
-                    ui.write("%s %s %s %s %s %s\n" %
-                             (hex(node), hex(p1), hex(p2),
-                              hex(cs), hex(deltabase), len(delta)))
-                    chain = node
-
-            chunkdata = gen.changelogheader()
-            showchunks("changelog")
-            chunkdata = gen.manifestheader()
-            showchunks("manifest")
-            while 1:
-                chunkdata = gen.filelogheader()
-                if not chunkdata:
-                    break
-                fname = chunkdata['filename']
-                showchunks(fname)
-        else:
-            chunkdata = gen.changelogheader()
-            chain = None
-            while 1:
-                chunkdata = gen.deltachunk(chain)
-                if not chunkdata:
-                    break
-                node = chunkdata['node']
-                ui.write("%s\n" % hex(node))
-                chain = node
-    finally:
-        f.close()
-
-def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
-    """retrieves a bundle from a repo
-
-    Every ID must be a full-length hex node id string. Saves the bundle to the
-    given file.
-    """
-    repo = hg.repository(ui, repopath)
-    if not repo.capable('getbundle'):
-        raise util.Abort("getbundle() not supported by target repository")
-    args = {}
-    if common:
-        args['common'] = [bin(s) for s in common]
-    if head:
-        args['heads'] = [bin(s) for s in head]
-    bundle = repo.getbundle('debug', **args)
-
-    bundletype = opts.get('type', 'bzip2').lower()
-    btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
-    bundletype = btypes.get(bundletype)
-    if bundletype not in changegroup.bundletypes:
-        raise util.Abort(_('unknown bundle type specified with --type'))
-    changegroup.writebundle(bundle, bundlepath, bundletype)
-
-def debugpushkey(ui, repopath, namespace, *keyinfo):
-    '''access the pushkey key/value protocol
-
-    With two args, list the keys in the given namespace.
-
-    With five args, set a key to new if it currently is set to old.
-    Reports success or failure.
-    '''
-
-    target = hg.repository(ui, repopath)
-    if keyinfo:
-        key, old, new = keyinfo
-        r = target.pushkey(namespace, key, old, new)
-        ui.status(str(r) + '\n')
-        return not r
-    else:
-        for k, v in target.listkeys(namespace).iteritems():
-            ui.write("%s\t%s\n" % (k.encode('string-escape'),
-                                   v.encode('string-escape')))
-
-def debugrevspec(ui, repo, expr):
-    '''parse and apply a revision specification'''
-    if ui.verbose:
-        tree = revset.parse(expr)[0]
-        ui.note(tree, "\n")
-        newtree = revset.findaliases(ui, tree)
-        if newtree != tree:
-            ui.note(newtree, "\n")
-    func = revset.match(ui, expr)
-    for c in func(repo, range(len(repo))):
-        ui.write("%s\n" % c)
-
-def debugsetparents(ui, repo, rev1, rev2=None):
-    """manually set the parents of the current working directory
-
-    This is useful for writing repository conversion tools, but should
-    be used with care.
-
-    Returns 0 on success.
-    """
-
-    r1 = cmdutil.revsingle(repo, rev1).node()
-    r2 = cmdutil.revsingle(repo, rev2, 'null').node()
-
-    wlock = repo.wlock()
-    try:
-        repo.dirstate.setparents(r1, r2)
-    finally:
-        wlock.release()
-
-def debugstate(ui, repo, nodates=None, datesort=None):
-    """show the contents of the current dirstate"""
-    timestr = ""
-    showdate = not nodates
-    if datesort:
-        keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
-    else:
-        keyfunc = None # sort by filename
-    for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
-        if showdate:
-            if ent[3] == -1:
-                # Pad or slice to locale representation
-                locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
-                                               time.localtime(0)))
-                timestr = 'unset'
-                timestr = (timestr[:locale_len] +
-                           ' ' * (locale_len - len(timestr)))
-            else:
-                timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
-                                        time.localtime(ent[3]))
-        if ent[1] & 020000:
-            mode = 'lnk'
-        else:
-            mode = '%3o' % (ent[1] & 0777)
-        ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
-    for f in repo.dirstate.copies():
-        ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
-
-def debugsub(ui, repo, rev=None):
-    ctx = cmdutil.revsingle(repo, rev, None)
-    for k, v in sorted(ctx.substate.items()):
-        ui.write('path %s\n' % k)
-        ui.write(' source   %s\n' % v[0])
-        ui.write(' revision %s\n' % v[1])
-
-def debugdag(ui, repo, file_=None, *revs, **opts):
-    """format the changelog or an index DAG as a concise textual description
-
-    If you pass a revlog index, the revlog's DAG is emitted. If you list
-    revision numbers, they get labelled in the output as rN.
-
-    Otherwise, the changelog DAG of the current repo is emitted.
-    """
-    spaces = opts.get('spaces')
-    dots = opts.get('dots')
-    if file_:
-        rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
-        revs = set((int(r) for r in revs))
-        def events():
-            for r in rlog:
-                yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
-                if r in revs:
-                    yield 'l', (r, "r%i" % r)
-    elif repo:
-        cl = repo.changelog
-        tags = opts.get('tags')
-        branches = opts.get('branches')
-        if tags:
-            labels = {}
-            for l, n in repo.tags().items():
-                labels.setdefault(cl.rev(n), []).append(l)
-        def events():
-            b = "default"
-            for r in cl:
-                if branches:
-                    newb = cl.read(cl.node(r))[5]['branch']
-                    if newb != b:
-                        yield 'a', newb
-                        b = newb
-                yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
-                if tags:
-                    ls = labels.get(r)
-                    if ls:
-                        for l in ls:
-                            yield 'l', (r, l)
-    else:
-        raise util.Abort(_('need repo for changelog dag'))
-
-    for line in dagparser.dagtextlines(events(),
-                                       addspaces=spaces,
-                                       wraplabels=True,
-                                       wrapannotations=True,
-                                       wrapnonlinear=dots,
-                                       usedots=dots,
-                                       maxlinewidth=70):
-        ui.write(line)
-        ui.write("\n")
-
-def debugdata(ui, repo, file_, rev):
-    """dump the contents of a data file revision"""
-    r = None
-    if repo:
-        filelog = repo.file(file_)
-        if len(filelog):
-            r = filelog
-    if not r:
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
-                          file_[:-2] + ".i")
-    try:
-        ui.write(r.revision(r.lookup(rev)))
-    except KeyError:
-        raise util.Abort(_('invalid revision identifier %s') % rev)
-
-def debugdate(ui, date, range=None, **opts):
-    """parse and display a date"""
-    if opts["extended"]:
-        d = util.parsedate(date, util.extendeddateformats)
-    else:
-        d = util.parsedate(date)
-    ui.write("internal: %s %s\n" % d)
-    ui.write("standard: %s\n" % util.datestr(d))
-    if range:
-        m = util.matchdate(range)
-        ui.write("match: %s\n" % m(d[0]))
-
-def debugignore(ui, repo, *values, **opts):
-    """display the combined ignore pattern"""
-    ignore = repo.dirstate._ignore
-    if hasattr(ignore, 'includepat'):
-        ui.write("%s\n" % ignore.includepat)
-    else:
-        raise util.Abort(_("no ignore patterns found"))
-
-def debugdiscovery(ui, repo, remoteurl="default", **opts):
-    """runs the changeset discovery protocol in isolation"""
-    remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
-    remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
-    ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
-
-    # make sure tests are repeatable
-    random.seed(12323)
-
-    def doit(localheads, remoteheads):
-        if opts.get('old'):
-            if localheads:
-                raise util.Abort('cannot use localheads with old style discovery')
-            common, _in, hds = treediscovery.findcommonincoming(repo, remote,
-                                                                force=True)
-            common = set(common)
-            if not opts.get('nonheads'):
-                ui.write("unpruned common: %s\n" % " ".join([short(n)
-                                                            for n in common]))
-                dag = dagutil.revlogdag(repo.changelog)
-                all = dag.ancestorset(dag.internalizeall(common))
-                common = dag.externalizeall(dag.headsetofconnecteds(all))
-        else:
-            common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
-        common = set(common)
-        rheads = set(hds)
-        lheads = set(repo.heads())
-        ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
-        if lheads <= common:
-            ui.write("local is subset\n")
-        elif rheads <= common:
-            ui.write("remote is subset\n")
-
-    serverlogs = opts.get('serverlog')
-    if serverlogs:
-        for filename in serverlogs:
-            logfile = open(filename, 'r')
-            try:
-                line = logfile.readline()
-                while line:
-                    parts = line.strip().split(';')
-                    op = parts[1]
-                    if op == 'cg':
-                        pass
-                    elif op == 'cgss':
-                        doit(parts[2].split(' '), parts[3].split(' '))
-                    elif op == 'unb':
-                        doit(parts[3].split(' '), parts[2].split(' '))
-                    line = logfile.readline()
-            finally:
-                logfile.close()
-
-    else:
-        remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
-                                                 opts.get('remote_head'))
-        localrevs = opts.get('local_head')
-        doit(localrevs, remoterevs)
-
-
-def debugindex(ui, repo, file_, **opts):
-    """dump the contents of an index file"""
-    r = None
-    if repo:
-        filelog = repo.file(file_)
-        if len(filelog):
-            r = filelog
-
-    format = opts.get('format', 0)
-    if format not in (0, 1):
-        raise util.Abort(_("unknown format %d") % format)
-
-    if not r:
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
-
-    generaldelta = r.version & revlog.REVLOGGENERALDELTA
-    if generaldelta:
-        basehdr = ' delta'
-    else:
-        basehdr = '  base'
-
-    if format == 0:
-        ui.write("   rev    offset  length " + basehdr + " linkrev"
-                 " nodeid       p1           p2\n")
-    elif format == 1:
-        ui.write("   rev flag   offset   length"
-                 "     size " + basehdr + "   link     p1     p2       nodeid\n")
-
-    for i in r:
-        node = r.node(i)
-        if generaldelta:
-            base = r.deltaparent(i)
-        else:
-            base = r.chainbase(i)
-        if format == 0:
-            try:
-                pp = r.parents(node)
-            except:
-                pp = [nullid, nullid]
-            ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
-                    i, r.start(i), r.length(i), base, r.linkrev(i),
-                    short(node), short(pp[0]), short(pp[1])))
-        elif format == 1:
-            pr = r.parentrevs(i)
-            ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
-                    i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
-                    base, r.linkrev(i), pr[0], pr[1], short(node)))
-
-def debugindexdot(ui, repo, file_):
-    """dump an index DAG as a graphviz dot file"""
-    r = None
-    if repo:
-        filelog = repo.file(file_)
-        if len(filelog):
-            r = filelog
-    if not r:
-        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
-    ui.write("digraph G {\n")
-    for i in r:
-        node = r.node(i)
-        pp = r.parents(node)
-        ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
-        if pp[1] != nullid:
-            ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
-    ui.write("}\n")
-
-def debuginstall(ui):
-    '''test Mercurial installation
-
-    Returns 0 on success.
-    '''
-
-    def writetemp(contents):
-        (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
-        f = os.fdopen(fd, "wb")
-        f.write(contents)
-        f.close()
-        return name
-
-    problems = 0
-
-    # encoding
-    ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
-    try:
-        encoding.fromlocal("test")
-    except util.Abort, inst:
-        ui.write(" %s\n" % inst)
-        ui.write(_(" (check that your locale is properly set)\n"))
-        problems += 1
-
-    # compiled modules
-    ui.status(_("Checking installed modules (%s)...\n")
-              % os.path.dirname(__file__))
-    try:
-        import bdiff, mpatch, base85, osutil
-    except Exception, inst:
-        ui.write(" %s\n" % inst)
-        ui.write(_(" One or more extensions could not be found"))
-        ui.write(_(" (check that you compiled the extensions)\n"))
-        problems += 1
-
-    # templates
-    ui.status(_("Checking templates...\n"))
-    try:
-        import templater
-        templater.templater(templater.templatepath("map-cmdline.default"))
-    except Exception, inst:
-        ui.write(" %s\n" % inst)
-        ui.write(_(" (templates seem to have been installed incorrectly)\n"))
-        problems += 1
-
-    # editor
-    ui.status(_("Checking commit editor...\n"))
-    editor = ui.geteditor()
-    cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
-    if not cmdpath:
-        if editor == 'vi':
-            ui.write(_(" No commit editor set and can't find vi in PATH\n"))
-            ui.write(_(" (specify a commit editor in your configuration"
-                       " file)\n"))
-        else:
-            ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
-            ui.write(_(" (specify a commit editor in your configuration"
-                       " file)\n"))
-            problems += 1
-
-    # check username
-    ui.status(_("Checking username...\n"))
-    try:
-        ui.username()
-    except util.Abort, e:
-        ui.write(" %s\n" % e)
-        ui.write(_(" (specify a username in your configuration file)\n"))
-        problems += 1
-
-    if not problems:
-        ui.status(_("No problems detected\n"))
-    else:
-        ui.write(_("%s problems detected,"
-                   " please check your install!\n") % problems)
-
-    return problems
-
-def debugrename(ui, repo, file1, *pats, **opts):
-    """dump rename information"""
-
-    ctx = cmdutil.revsingle(repo, opts.get('rev'))
-    m = cmdutil.match(repo, (file1,) + pats, opts)
-    for abs in ctx.walk(m):
-        fctx = ctx[abs]
-        o = fctx.filelog().renamed(fctx.filenode())
-        rel = m.rel(abs)
-        if o:
-            ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
-        else:
-            ui.write(_("%s not renamed\n") % rel)
-
-def debugwalk(ui, repo, *pats, **opts):
-    """show how files match on given patterns"""
-    m = cmdutil.match(repo, pats, opts)
-    items = list(repo.walk(m))
-    if not items:
-        return
-    fmt = 'f  %%-%ds  %%-%ds  %%s' % (
-        max([len(abs) for abs in items]),
-        max([len(m.rel(abs)) for abs in items]))
-    for abs in items:
-        line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
-        ui.write("%s\n" % line.rstrip())
-
-def debugwireargs(ui, repopath, *vals, **opts):
-    repo = hg.repository(hg.remoteui(ui, opts), repopath)
-    for opt in remoteopts:
-        del opts[opt[1]]
-    args = {}
-    for k, v in opts.iteritems():
-        if v:
-            args[k] = v
-    # run twice to check that we don't mess up the stream for the next command
-    res1 = repo.debugwireargs(*vals, **args)
-    res2 = repo.debugwireargs(*vals, **args)
-    ui.write("%s\n" % res1)
-    if res1 != res2:
-        ui.warn("%s\n" % res2)
-
 def diff(ui, repo, *pats, **opts):
     """diff repository (or selected files)
 
@@ -4555,94 +3827,6 @@
            _('forcibly copy over an existing managed file')),
          ] + walkopts + dryrunopts,
          _('[OPTION]... [SOURCE]... DEST')),
-    "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
-    "debugbuilddag":
-        (debugbuilddag,
-         [('m', 'mergeable-file', None, _('add single file mergeable changes')),
-          ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
-          ('n', 'new-file', None, _('add new file at each rev')),
-         ],
-         _('[OPTION]... TEXT')),
-    "debugbundle":
-        (debugbundle,
-         [('a', 'all', None, _('show all details')),
-          ],
-         _('FILE')),
-    "debugcheckstate": (debugcheckstate, [], ''),
-    "debugcommands": (debugcommands, [], _('[COMMAND]')),
-    "debugcomplete":
-        (debugcomplete,
-         [('o', 'options', None, _('show the command options'))],
-         _('[-o] CMD')),
-    "debugdag":
-        (debugdag,
-         [('t', 'tags', None, _('use tags as labels')),
-          ('b', 'branches', None, _('annotate with branch names')),
-          ('', 'dots', None, _('use dots for runs')),
-          ('s', 'spaces', None, _('separate elements by spaces')),
-         ],
-         _('[OPTION]... [FILE [REV]...]')),
-    "debugdate":
-        (debugdate,
-         [('e', 'extended', None, _('try extended date formats'))],
-         _('[-e] DATE [RANGE]')),
-    "debugdata": (debugdata, [], _('FILE REV')),
-    "debugdiscovery": (debugdiscovery,
-         [('', 'old', None,
-           _('use old-style discovery')),
-          ('', 'nonheads', None,
-           _('use old-style discovery with non-heads included')),
-         ] + remoteopts,
-         _('[-l REV] [-r REV] [-b BRANCH]...'
-           ' [OTHER]')),
-    "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
-    "debuggetbundle":
-        (debuggetbundle,
-         [('H', 'head', [], _('id of head node'), _('ID')),
-          ('C', 'common', [], _('id of common node'), _('ID')),
-          ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
-         ],
-         _('REPO FILE [-H|-C ID]...')),
-    "debugignore": (debugignore, [], ''),
-    "debugindex": (debugindex,
-                   [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
-                   _('FILE')),
-    "debugindexdot": (debugindexdot, [], _('FILE')),
-    "debuginstall": (debuginstall, [], ''),
-    "debugknown": (debugknown, [], _('REPO ID...')),
-    "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
-    "debugrebuildstate":
-        (debugrebuildstate,
-         [('r', 'rev', '',
-           _('revision to rebuild to'), _('REV'))],
-         _('[-r REV] [REV]')),
-    "debugrename":
-        (debugrename,
-         [('r', 'rev', '',
-           _('revision to debug'), _('REV'))],
-         _('[-r REV] FILE')),
-    "debugrevspec":
-        (debugrevspec, [], ('REVSPEC')),
-    "debugsetparents":
-        (debugsetparents, [], _('REV1 [REV2]')),
-    "debugstate":
-        (debugstate,
-         [('', 'nodates', None, _('do not display the saved mtime')),
-          ('', 'datesort', None, _('sort by saved mtime'))],
-         _('[OPTION]...')),
-    "debugsub":
-        (debugsub,
-         [('r', 'rev', '',
-           _('revision to check'), _('REV'))],
-         _('[-r REV] [REV]')),
-    "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
-    "debugwireargs":
-        (debugwireargs,
-         [('', 'three', '', 'three'),
-          ('', 'four', '', 'four'),
-          ('', 'five', '', 'five'),
-          ] + remoteopts,
-         _('REPO [OPTIONS]... [ONE [TWO]]')),
     "^diff":
         (diff,
          [('r', 'rev', [],
@@ -4976,8 +4160,5 @@
     "version": (version_, []),
 }
 
-norepo = ("clone init version help debugcommands debugcomplete"
-          " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
-          " debugknown debuggetbundle debugbundle")
-optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
-                " debugdata debugindex debugindexdot")
+norepo = ("clone init version help")
+optionalrepo = ("identify paths serve showconfig")
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
new file mode 100644
--- /dev/null
+++ b/mercurial/debugcommands.py
@@ -0,0 +1,840 @@
+# debugcommands.py - debug commands for mercurial
+#
+# Copyright Matt Mackall <mpm at selenic.com>
+#
+# This software may be used and distributed according to the terms of the
+# GNU General Public License version 2 or any later version.
+
+from node import hex, bin, nullid, nullrev, short
+from i18n import _
+import os, time, random
+import hg, scmutil, util, revlog, error, url, encoding
+import context, simplemerge
+import changegroup, discovery, cmdutil, revset
+import setdiscovery, treediscovery, dagparser, dagutil
+import commands
+
+# Commands start here, listed alphabetically
+
+def allcommands(ui, cmd='', *args):
+    """list all available commands and options"""
+    commands.table.update(table)
+    for cmd, vals in sorted(commands.table.iteritems()):
+        cmd = cmd.split('|')[0].strip('^')
+        opts = ', '.join([i[1] for i in vals[1]])
+        ui.write('%s: %s\n' % (cmd, opts))
+
+def ancestor(ui, repo, *args):
+    """find the ancestor revision of two revisions in a given index"""
+    if len(args) == 3:
+        index, rev1, rev2 = args
+        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
+        lookup = r.lookup
+    elif len(args) == 2:
+        if not repo:
+            raise util.Abort(_("there is no Mercurial repository here "
+                               "(.hg not found)"))
+        rev1, rev2 = args
+        r = repo.changelog
+        lookup = repo.lookup
+    else:
+        raise util.Abort(_('either two or three arguments required'))
+    a = r.ancestor(lookup(rev1), lookup(rev2))
+    ui.write("%d:%s\n" % (r.rev(a), hex(a)))
+
+def builddag(ui, repo, text, mergeable_file=False, overwritten_file=False,
+             new_file=False):
+    """builds a repo with a given dag from scratch in the current empty repo
+
+    Elements:
+
+     - "+n" is a linear run of n nodes based on the current default parent
+     - "." is a single node based on the current default parent
+     - "$" resets the default parent to null (implied at the start);
+           otherwise the default parent is always the last node created
+     - "<p" sets the default parent to the backref p
+     - "*p" is a fork at parent p, which is a backref
+     - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
+     - "/p2" is a merge of the preceding node and p2
+     - ":tag" defines a local tag for the preceding node
+     - "@branch" sets the named branch for subsequent nodes
+     - "#...\\n" is a comment up to the end of the line
+
+    Whitespace between the above elements is ignored.
+
+    A backref is either
+
+     - a number n, which references the node curr-n, where curr is the current
+       node, or
+     - the name of a local tag you placed earlier using ":tag", or
+     - empty to denote the default parent.
+
+    All string valued-elements are either strictly alphanumeric, or must
+    be enclosed in double quotes ("..."), with "\\" as escape character.
+    """
+
+    cl = repo.changelog
+    if len(cl) > 0:
+        raise util.Abort(_('repository is not empty'))
+
+    if mergeable_file:
+        linesperrev = 2
+        # determine number of revs in DAG
+        n = 0
+        for type, data in dagparser.parsedag(text):
+            if type == 'n':
+                n += 1
+        # make a file with k lines per rev
+        initialmergedlines = [str(i) for i in xrange(0, n * linesperrev)]
+        initialmergedlines.append("")
+
+    tags = []
+
+    tr = repo.transaction("builddag")
+    try:
+
+        at = -1
+        atbranch = 'default'
+        nodeids = []
+        for type, data in dagparser.parsedag(text):
+            if type == 'n':
+                ui.note('node %s\n' % str(data))
+                id, ps = data
+
+                files = []
+                fctxs = {}
+
+                p2 = None
+                if mergeable_file:
+                    fn = "mf"
+                    p1 = repo[ps[0]]
+                    if len(ps) > 1:
+                        p2 = repo[ps[1]]
+                        pa = p1.ancestor(p2)
+                        base, local, other = [x[fn].data() for x in pa, p1, p2]
+                        m3 = simplemerge.Merge3Text(base, local, other)
+                        ml = [l.strip() for l in m3.merge_lines()]
+                        ml.append("")
+                    elif at > 0:
+                        ml = p1[fn].data().split("\n")
+                    else:
+                        ml = initialmergedlines
+                    ml[id * linesperrev] += " r%i" % id
+                    mergedtext = "\n".join(ml)
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(fn, mergedtext)
+
+                if overwritten_file:
+                    fn = "of"
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
+
+                if new_file:
+                    fn = "nf%i" % id
+                    files.append(fn)
+                    fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
+                    if len(ps) > 1:
+                        if not p2:
+                            p2 = repo[ps[1]]
+                        for fn in p2:
+                            if fn.startswith("nf"):
+                                files.append(fn)
+                                fctxs[fn] = p2[fn]
+
+                def fctxfn(repo, cx, path):
+                    return fctxs.get(path)
+
+                if len(ps) == 0 or ps[0] < 0:
+                    pars = [None, None]
+                elif len(ps) == 1:
+                    pars = [nodeids[ps[0]], None]
+                else:
+                    pars = [nodeids[p] for p in ps]
+                cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
+                                    date=(id, 0),
+                                    user="debugbuilddag",
+                                    extra={'branch': atbranch})
+                nodeid = repo.commitctx(cx)
+                nodeids.append(nodeid)
+                at = id
+            elif type == 'l':
+                id, name = data
+                ui.note('tag %s\n' % name)
+                tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
+            elif type == 'a':
+                ui.note('branch %s\n' % data)
+                atbranch = data
+        tr.close()
+    finally:
+        tr.release()
+
+    if tags:
+        repo.opener.write("localtags", "".join(tags))
+
+def bundle(ui, bundlepath, all=None, **opts):
+    """lists the contents of a bundle"""
+    f = url.open(ui, bundlepath)
+    try:
+        gen = changegroup.readbundle(f, bundlepath)
+        if all:
+            ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
+
+            def showchunks(named):
+                ui.write("\n%s\n" % named)
+                chain = None
+                while 1:
+                    chunkdata = gen.deltachunk(chain)
+                    if not chunkdata:
+                        break
+                    node = chunkdata['node']
+                    p1 = chunkdata['p1']
+                    p2 = chunkdata['p2']
+                    cs = chunkdata['cs']
+                    deltabase = chunkdata['deltabase']
+                    delta = chunkdata['delta']
+                    ui.write("%s %s %s %s %s %s\n" %
+                             (hex(node), hex(p1), hex(p2),
+                              hex(cs), hex(deltabase), len(delta)))
+                    chain = node
+
+            chunkdata = gen.changelogheader()
+            showchunks("changelog")
+            chunkdata = gen.manifestheader()
+            showchunks("manifest")
+            while 1:
+                chunkdata = gen.filelogheader()
+                if not chunkdata:
+                    break
+                fname = chunkdata['filename']
+                showchunks(fname)
+        else:
+            chunkdata = gen.changelogheader()
+            chain = None
+            while 1:
+                chunkdata = gen.deltachunk(chain)
+                if not chunkdata:
+                    break
+                node = chunkdata['node']
+                ui.write("%s\n" % hex(node))
+                chain = node
+    finally:
+        f.close()
+
+def checkstate(ui, repo):
+    """validate the correctness of the current dirstate"""
+    parent1, parent2 = repo.dirstate.parents()
+    m1 = repo[parent1].manifest()
+    m2 = repo[parent2].manifest()
+    errors = 0
+    for f in repo.dirstate:
+        state = repo.dirstate[f]
+        if state in "nr" and f not in m1:
+            ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
+            errors += 1
+        if state in "a" and f in m1:
+            ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
+            errors += 1
+        if state in "m" and f not in m1 and f not in m2:
+            ui.warn(_("%s in state %s, but not in either manifest\n") %
+                    (f, state))
+            errors += 1
+    for f in m1:
+        state = repo.dirstate[f]
+        if state not in "nrm":
+            ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
+            errors += 1
+    if errors:
+        error = _(".hg/dirstate inconsistent with current parent's manifest")
+        raise util.Abort(error)
+
+def complete(ui, cmd='', **opts):
+    """returns the completion list associated with the given command"""
+
+    commands.table.update(table)
+
+    if opts.get('options'):
+        options = []
+        otables = [commands.globalopts]
+        if cmd:
+            aliases, entry = cmdutil.findcmd(cmd, commands.table, False)
+            otables.append(entry[1])
+        for t in otables:
+            for o in t:
+                if "(DEPRECATED)" in o[3]:
+                    continue
+                if o[0]:
+                    options.append('-%s' % o[0])
+                options.append('--%s' % o[1])
+        ui.write("%s\n" % "\n".join(options))
+        return
+
+    cmdlist = cmdutil.findpossible(cmd, commands.table)
+    if ui.verbose:
+        cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
+    ui.write("%s\n" % "\n".join(sorted(cmdlist)))
+
+def dag(ui, repo, file_=None, *revs, **opts):
+    """format the changelog or an index DAG as a concise textual description
+
+    If you pass a revlog index, the revlog's DAG is emitted. If you list
+    revision numbers, they get labelled in the output as rN.
+
+    Otherwise, the changelog DAG of the current repo is emitted.
+    """
+    spaces = opts.get('spaces')
+    dots = opts.get('dots')
+    if file_:
+        rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
+        revs = set((int(r) for r in revs))
+        def events():
+            for r in rlog:
+                yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
+                if r in revs:
+                    yield 'l', (r, "r%i" % r)
+    elif repo:
+        cl = repo.changelog
+        tags = opts.get('tags')
+        branches = opts.get('branches')
+        if tags:
+            labels = {}
+            for l, n in repo.tags().items():
+                labels.setdefault(cl.rev(n), []).append(l)
+        def events():
+            b = "default"
+            for r in cl:
+                if branches:
+                    newb = cl.read(cl.node(r))[5]['branch']
+                    if newb != b:
+                        yield 'a', newb
+                        b = newb
+                yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
+                if tags:
+                    ls = labels.get(r)
+                    if ls:
+                        for l in ls:
+                            yield 'l', (r, l)
+    else:
+        raise util.Abort(_('need repo for changelog dag'))
+
+    for line in dagparser.dagtextlines(events(),
+                                       addspaces=spaces,
+                                       wraplabels=True,
+                                       wrapannotations=True,
+                                       wrapnonlinear=dots,
+                                       usedots=dots,
+                                       maxlinewidth=70):
+        ui.write(line)
+        ui.write("\n")
+
+def data(ui, repo, file_, rev):
+    """dump the contents of a data file revision"""
+    r = None
+    if repo:
+        filelog = repo.file(file_)
+        if len(filelog):
+            r = filelog
+    if not r:
+        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
+                          file_[:-2] + ".i")
+    try:
+        ui.write(r.revision(r.lookup(rev)))
+    except KeyError:
+        raise util.Abort(_('invalid revision identifier %s') % rev)
+
+def date(ui, date, range=None, **opts):
+    """parse and display a date"""
+    if opts["extended"]:
+        d = util.parsedate(date, util.extendeddateformats)
+    else:
+        d = util.parsedate(date)
+    ui.write("internal: %s %s\n" % d)
+    ui.write("standard: %s\n" % util.datestr(d))
+    if range:
+        m = util.matchdate(range)
+        ui.write("match: %s\n" % m(d[0]))
+
+def discovery(ui, repo, remoteurl="default", **opts):
+    """runs the changeset discovery protocol in isolation"""
+    remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl), opts.get('branch'))
+    remote = hg.repository(hg.remoteui(repo, opts), remoteurl)
+    ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
+
+    # make sure tests are repeatable
+    random.seed(12323)
+
+    def doit(localheads, remoteheads):
+        if opts.get('old'):
+            if localheads:
+                raise util.Abort('cannot use localheads with old style discovery')
+            common, _in, hds = treediscovery.findcommonincoming(repo, remote,
+                                                                force=True)
+            common = set(common)
+            if not opts.get('nonheads'):
+                ui.write("unpruned common: %s\n" % " ".join([short(n)
+                                                            for n in common]))
+                dag = dagutil.revlogdag(repo.changelog)
+                all = dag.ancestorset(dag.internalizeall(common))
+                common = dag.externalizeall(dag.headsetofconnecteds(all))
+        else:
+            common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
+        common = set(common)
+        rheads = set(hds)
+        lheads = set(repo.heads())
+        ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
+        if lheads <= common:
+            ui.write("local is subset\n")
+        elif rheads <= common:
+            ui.write("remote is subset\n")
+
+    serverlogs = opts.get('serverlog')
+    if serverlogs:
+        for filename in serverlogs:
+            logfile = open(filename, 'r')
+            try:
+                line = logfile.readline()
+                while line:
+                    parts = line.strip().split(';')
+                    op = parts[1]
+                    if op == 'cg':
+                        pass
+                    elif op == 'cgss':
+                        doit(parts[2].split(' '), parts[3].split(' '))
+                    elif op == 'unb':
+                        doit(parts[3].split(' '), parts[2].split(' '))
+                    line = logfile.readline()
+            finally:
+                logfile.close()
+
+    else:
+        remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
+                                                 opts.get('remote_head'))
+        localrevs = opts.get('local_head')
+        doit(localrevs, remoterevs)
+
+def fsinfo(ui, path = "."):
+    """show information detected about current filesystem"""
+    util.writefile('.debugfsinfo', '')
+    ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
+    ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
+    ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
+                                and 'yes' or 'no'))
+    os.unlink('.debugfsinfo')
+
+def getbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
+    """retrieves a bundle from a repo
+
+    Every ID must be a full-length hex node id string. Saves the bundle to the
+    given file.
+    """
+    repo = hg.repository(ui, repopath)
+    if not repo.capable('getbundle'):
+        raise util.Abort("getbundle() not supported by target repository")
+    args = {}
+    if common:
+        args['common'] = [bin(s) for s in common]
+    if head:
+        args['heads'] = [bin(s) for s in head]
+    bundle = repo.getbundle('debug', **args)
+
+    bundletype = opts.get('type', 'bzip2').lower()
+    btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
+    bundletype = btypes.get(bundletype)
+    if bundletype not in changegroup.bundletypes:
+        raise util.Abort(_('unknown bundle type specified with --type'))
+    changegroup.writebundle(bundle, bundlepath, bundletype)
+
+def ignore(ui, repo, *values, **opts):
+    """display the combined ignore pattern"""
+    ignore = repo.dirstate._ignore
+    if hasattr(ignore, 'includepat'):
+        ui.write("%s\n" % ignore.includepat)
+    else:
+        raise util.Abort(_("no ignore patterns found"))
+
+def index(ui, repo, file_, **opts):
+    """dump the contents of an index file"""
+    r = None
+    if repo:
+        filelog = repo.file(file_)
+        if len(filelog):
+            r = filelog
+
+    format = opts.get('format', 0)
+    if format not in (0, 1):
+        raise util.Abort(_("unknown format %d") % format)
+
+    if not r:
+        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
+
+    generaldelta = r.version & revlog.REVLOGGENERALDELTA
+    if generaldelta:
+        basehdr = ' delta'
+    else:
+        basehdr = '  base'
+
+    if format == 0:
+        ui.write("   rev    offset  length " + basehdr + " linkrev"
+                 " nodeid       p1           p2\n")
+    elif format == 1:
+        ui.write("   rev flag   offset   length"
+                 "     size " + basehdr + "   link     p1     p2       nodeid\n")
+
+    for i in r:
+        node = r.node(i)
+        if generaldelta:
+            base = r.deltaparent(i)
+        else:
+            base = r.chainbase(i)
+        if format == 0:
+            try:
+                pp = r.parents(node)
+            except:
+                pp = [nullid, nullid]
+            ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
+                    i, r.start(i), r.length(i), base, r.linkrev(i),
+                    short(node), short(pp[0]), short(pp[1])))
+        elif format == 1:
+            pr = r.parentrevs(i)
+            ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
+                    i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
+                    base, r.linkrev(i), pr[0], pr[1], short(node)))
+
+def indexdot(ui, repo, file_):
+    """dump an index DAG as a graphviz dot file"""
+    r = None
+    if repo:
+        filelog = repo.file(file_)
+        if len(filelog):
+            r = filelog
+    if not r:
+        r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
+    ui.write("digraph G {\n")
+    for i in r:
+        node = r.node(i)
+        pp = r.parents(node)
+        ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
+        if pp[1] != nullid:
+            ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
+    ui.write("}\n")
+
+def install(ui):
+    '''test Mercurial installation
+
+    Returns 0 on success.
+    '''
+
+    def writetemp(contents):
+        (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
+        f = os.fdopen(fd, "wb")
+        f.write(contents)
+        f.close()
+        return name
+
+    problems = 0
+
+    # encoding
+    ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
+    try:
+        encoding.fromlocal("test")
+    except util.Abort, inst:
+        ui.write(" %s\n" % inst)
+        ui.write(_(" (check that your locale is properly set)\n"))
+        problems += 1
+
+    # compiled modules
+    ui.status(_("Checking installed modules (%s)...\n")
+              % os.path.dirname(__file__))
+    try:
+        import bdiff, mpatch, base85, osutil
+    except Exception, inst:
+        ui.write(" %s\n" % inst)
+        ui.write(_(" One or more extensions could not be found"))
+        ui.write(_(" (check that you compiled the extensions)\n"))
+        problems += 1
+
+    # templates
+    ui.status(_("Checking templates...\n"))
+    try:
+        import templater
+        templater.templater(templater.templatepath("map-cmdline.default"))
+    except Exception, inst:
+        ui.write(" %s\n" % inst)
+        ui.write(_(" (templates seem to have been installed incorrectly)\n"))
+        problems += 1
+
+    # editor
+    ui.status(_("Checking commit editor...\n"))
+    editor = ui.geteditor()
+    cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
+    if not cmdpath:
+        if editor == 'vi':
+            ui.write(_(" No commit editor set and can't find vi in PATH\n"))
+            ui.write(_(" (specify a commit editor in your configuration"
+                       " file)\n"))
+        else:
+            ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
+            ui.write(_(" (specify a commit editor in your configuration"
+                       " file)\n"))
+            problems += 1
+
+    # check username
+    ui.status(_("Checking username...\n"))
+    try:
+        ui.username()
+    except util.Abort, e:
+        ui.write(" %s\n" % e)
+        ui.write(_(" (specify a username in your configuration file)\n"))
+        problems += 1
+
+    if not problems:
+        ui.status(_("No problems detected\n"))
+    else:
+        ui.write(_("%s problems detected,"
+                   " please check your install!\n") % problems)
+
+    return problems
+
+def known(ui, repopath, *ids, **opts):
+    """test whether node ids are known to a repo
+
+    Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
+    indicating unknown/known.
+    """
+    repo = hg.repository(ui, repopath)
+    if not repo.capable('known'):
+        raise util.Abort("known() not supported by target repository")
+    flags = repo.known([bin(s) for s in ids])
+    ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
+
+def pushkey(ui, repopath, namespace, *keyinfo):
+    '''access the pushkey key/value protocol
+
+    With two args, list the keys in the given namespace.
+
+    With five args, set a key to new if it currently is set to old.
+    Reports success or failure.
+    '''
+
+    target = hg.repository(ui, repopath)
+    if keyinfo:
+        key, old, new = keyinfo
+        r = target.pushkey(namespace, key, old, new)
+        ui.status(str(r) + '\n')
+        return not r
+    else:
+        for k, v in target.listkeys(namespace).iteritems():
+            ui.write("%s\t%s\n" % (k.encode('string-escape'),
+                                   v.encode('string-escape')))
+
+def rebuildstate(ui, repo, rev="tip"):
+    """rebuild the dirstate as it would look like for the given revision"""
+    ctx = cmdutil.revsingle(repo, rev)
+    wlock = repo.wlock()
+    try:
+        repo.dirstate.rebuild(ctx.node(), ctx.manifest())
+    finally:
+        wlock.release()
+
+def rename(ui, repo, file1, *pats, **opts):
+    """dump rename information"""
+
+    ctx = cmdutil.revsingle(repo, opts.get('rev'))
+    m = cmdutil.match(repo, (file1,) + pats, opts)
+    for abs in ctx.walk(m):
+        fctx = ctx[abs]
+        o = fctx.filelog().renamed(fctx.filenode())
+        rel = m.rel(abs)
+        if o:
+            ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
+        else:
+            ui.write(_("%s not renamed\n") % rel)
+
+def revspec(ui, repo, expr):
+    '''parse and apply a revision specification'''
+    if ui.verbose:
+        tree = revset.parse(expr)[0]
+        ui.note(tree, "\n")
+        newtree = revset.findaliases(ui, tree)
+        if newtree != tree:
+            ui.note(newtree, "\n")
+    func = revset.match(ui, expr)
+    for c in func(repo, range(len(repo))):
+        ui.write("%s\n" % c)
+
+def setparents(ui, repo, rev1, rev2=None):
+    """manually set the parents of the current working directory
+
+    This is useful for writing repository conversion tools, but should
+    be used with care.
+
+    Returns 0 on success.
+    """
+
+    r1 = cmdutil.revsingle(repo, rev1).node()
+    r2 = cmdutil.revsingle(repo, rev2, 'null').node()
+
+    wlock = repo.wlock()
+    try:
+        repo.dirstate.setparents(r1, r2)
+    finally:
+        wlock.release()
+
+def state(ui, repo, nodates=None, datesort=None):
+    """show the contents of the current dirstate"""
+    timestr = ""
+    showdate = not nodates
+    if datesort:
+        keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
+    else:
+        keyfunc = None # sort by filename
+    for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
+        if showdate:
+            if ent[3] == -1:
+                # Pad or slice to locale representation
+                locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
+                                               time.localtime(0)))
+                timestr = 'unset'
+                timestr = (timestr[:locale_len] +
+                           ' ' * (locale_len - len(timestr)))
+            else:
+                timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
+                                        time.localtime(ent[3]))
+        if ent[1] & 020000:
+            mode = 'lnk'
+        else:
+            mode = '%3o' % (ent[1] & 0777)
+        ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
+    for f in repo.dirstate.copies():
+        ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
+
+def sub(ui, repo, rev=None):
+    ctx = cmdutil.revsingle(repo, rev, None)
+    for k, v in sorted(ctx.substate.items()):
+        ui.write('path %s\n' % k)
+        ui.write(' source   %s\n' % v[0])
+        ui.write(' revision %s\n' % v[1])
+
+def walk(ui, repo, *pats, **opts):
+    """show how files match on given patterns"""
+    m = cmdutil.match(repo, pats, opts)
+    items = list(repo.walk(m))
+    if not items:
+        return
+    fmt = 'f  %%-%ds  %%-%ds  %%s' % (
+        max([len(abs) for abs in items]),
+        max([len(m.rel(abs)) for abs in items]))
+    for abs in items:
+        line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
+        ui.write("%s\n" % line.rstrip())
+
+def wireargs(ui, repopath, *vals, **opts):
+    repo = hg.repository(hg.remoteui(ui, opts), repopath)
+    for opt in commands.remoteopts:
+        del opts[opt[1]]
+    args = {}
+    for k, v in opts.iteritems():
+        if v:
+            args[k] = v
+    # run twice to check that we don't mess up the stream for the next command
+    res1 = repo.debugwireargs(*vals, **args)
+    res2 = repo.debugwireargs(*vals, **args)
+    ui.write("%s\n" % res1)
+    if res1 != res2:
+        ui.warn("%s\n" % res2)
+
+# Command options and aliases are listed here, alphabetically
+
+table = {
+    "debugancestor": (ancestor, [], _('[INDEX] REV1 REV2')),
+    "debugbuilddag":
+        (builddag,
+         [('m', 'mergeable-file', None, _('add single file mergeable changes')),
+          ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
+          ('n', 'new-file', None, _('add new file at each rev')),
+         ],
+         _('[OPTION]... TEXT')),
+    "debugbundle":
+        (bundle,
+         [('a', 'all', None, _('show all details')),
+          ],
+         _('FILE')),
+    "debugcheckstate": (checkstate, [], ''),
+    "debugcommands": (allcommands, [], _('[COMMAND]')),
+    "debugcomplete":
+        (complete,
+         [('o', 'options', None, _('show the command options'))],
+         _('[-o] CMD')),
+    "debugdag":
+        (dag,
+         [('t', 'tags', None, _('use tags as labels')),
+          ('b', 'branches', None, _('annotate with branch names')),
+          ('', 'dots', None, _('use dots for runs')),
+          ('s', 'spaces', None, _('separate elements by spaces')),
+         ],
+         _('[OPTION]... [FILE [REV]...]')),
+    "debugdate":
+        (date,
+         [('e', 'extended', None, _('try extended date formats'))],
+         _('[-e] DATE [RANGE]')),
+    "debugdata": (data, [], _('FILE REV')),
+    "debugdiscovery": (discovery,
+         [('', 'old', None,
+           _('use old-style discovery')),
+          ('', 'nonheads', None,
+           _('use old-style discovery with non-heads included')),
+         ] + commands.remoteopts,
+         _('[-l REV] [-r REV] [-b BRANCH]...'
+           ' [OTHER]')),
+    "debugfsinfo": (fsinfo, [], _('[PATH]')),
+    "debuggetbundle":
+        (getbundle,
+         [('H', 'head', [], _('id of head node'), _('ID')),
+          ('C', 'common', [], _('id of common node'), _('ID')),
+          ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
+         ],
+         _('REPO FILE [-H|-C ID]...')),
+    "debugignore": (ignore, [], ''),
+    "debugindex": (index,
+                   [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
+                   _('FILE')),
+    "debugindexdot": (indexdot, [], _('FILE')),
+    "debuginstall": (install, [], ''),
+    "debugknown": (known, [], _('REPO ID...')),
+    "debugpushkey": (pushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
+    "debugrebuildstate":
+        (rebuildstate,
+         [('r', 'rev', '',
+           _('revision to rebuild to'), _('REV'))],
+         _('[-r REV] [REV]')),
+    "debugrename":
+        (rename,
+         [('r', 'rev', '',
+           _('revision to debug'), _('REV'))],
+         _('[-r REV] FILE')),
+    "debugrevspec":
+        (revspec, [], ('REVSPEC')),
+    "debugsetparents":
+        (setparents, [], _('REV1 [REV2]')),
+    "debugstate":
+        (state,
+         [('', 'nodates', None, _('do not display the saved mtime')),
+          ('', 'datesort', None, _('sort by saved mtime'))],
+         _('[OPTION]...')),
+    "debugsub":
+        (sub,
+         [('r', 'rev', '',
+           _('revision to check'), _('REV'))],
+         _('[-r REV] [REV]')),
+    "debugwalk": (walk, commands.walkopts, _('[OPTION]... [FILE]...')),
+    "debugwireargs":
+        (wireargs,
+         [('', 'three', '', 'three'),
+          ('', 'four', '', 'four'),
+          ('', 'five', '', 'five'),
+          ] + commands.remoteopts,
+         _('REPO [OPTIONS]... [ONE [TWO]]')),
+}
+
+norepo = ("debugcommands debugcomplete debugdate debuginstall debugfsinfo"
+          " debugpushkey debugwireargs debugknown debuggetbundle debugbundle")
+optionalrepo = ("debugancestor debugdag debugdata debugindex debugindexdot")
diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
@@ -7,7 +7,7 @@
 
 from i18n import _
 import os, sys, atexit, signal, pdb, socket, errno, shlex, time, traceback, re
-import util, commands, hg, fancyopts, extensions, hook, error
+import util, commands, debugcommands, hg, fancyopts, extensions, hook, error
 import cmdutil, encoding
 import ui as uimod
 
@@ -503,6 +503,12 @@
     rpath = _earlygetopt(["-R", "--repository", "--repo"], args)
     path, lui = _getlocal(ui, rpath)
 
+    if '_debugcommands' not in _loaded:
+        commands.table.update(debugcommands.table)
+        commands.norepo += ' ' + debugcommands.norepo
+        commands.optionalrepo += ' ' + debugcommands.optionalrepo
+        _loaded.add('_debugcommands')
+
     # Configure extensions in phases: uisetup, extsetup, cmdtable, and
     # reposetup. Programs like TortoiseHg will call _dispatch several
     # times so we keep track of configured extensions in _loaded.


More information about the Mercurial-devel mailing list