[PATCH 2 of 2] debugcommands: move debugbuilddag
Gregory Szorc
gregory.szorc at gmail.com
Thu Nov 10 17:47:32 UTC 2016
# HG changeset patch
# User Gregory Szorc <gregory.szorc at gmail.com>
# Date 1478799942 28800
# Thu Nov 10 09:45:42 2016 -0800
# Node ID 6a4f8298893b2c6c98a2cae4ddb46a704545f7e1
# Parent 52e8ce0d0992ad87be2815bd7c5f0d92aab21851
debugcommands: move debugbuilddag
And we drop some now unused imports from commands.py.
diff --git a/mercurial/commands.py b/mercurial/commands.py
--- a/mercurial/commands.py
+++ b/mercurial/commands.py
@@ -30,17 +30,16 @@ from .node import (
)
from . import (
archival,
bookmarks,
bundle2,
changegroup,
cmdutil,
commandserver,
- context,
copies,
dagparser,
dagutil,
destutil,
discovery,
encoding,
error,
exchange,
@@ -62,17 +61,16 @@ from . import (
policy,
pvec,
pycompat,
repair,
revlog,
revset,
scmutil,
setdiscovery,
- simplemerge,
sshserver,
sslutil,
streamclone,
templatekw,
templater,
treediscovery,
ui as uimod,
util,
@@ -1862,168 +1860,16 @@ def copy(ui, repo, *pats, **opts):
This command takes effect with the next commit. To undo a copy
before that, see :hg:`revert`.
Returns 0 on success, 1 if errors are encountered.
"""
with repo.wlock(False):
return cmdutil.copy(ui, repo, pats, opts)
- at command('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]'))
-def debugbuilddag(ui, repo, text=None,
- mergeable_file=False,
- overwritten_file=False,
- new_file=False):
- """builds a repo with a given DAG from scratch in the current empty repo
-
- The description of the DAG is read from stdin if not given on the
- command line.
-
- 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.
- """
-
- if text is None:
- ui.status(_("reading DAG from stdin\n"))
- text = ui.fin.read()
-
- cl = repo.changelog
- if len(cl) > 0:
- raise error.Abort(_('repository is not empty'))
-
- # determine number of revs in DAG
- total = 0
- for type, data in dagparser.parsedag(text):
- if type == 'n':
- total += 1
-
- if mergeable_file:
- linesperrev = 2
- # make a file with k lines per rev
- initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
- initialmergedlines.append("")
-
- tags = []
-
- wlock = lock = tr = None
- try:
- wlock = repo.wlock()
- lock = repo.lock()
- tr = repo.transaction("builddag")
-
- at = -1
- atbranch = 'default'
- nodeids = []
- id = 0
- ui.progress(_('building'), id, unit=_('revisions'), total=total)
- 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(repo, fn, mergedtext)
-
- if overwritten_file:
- fn = "of"
- files.append(fn)
- fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
-
- if new_file:
- fn = "nf%i" % id
- files.append(fn)
- fctxs[fn] = context.memfilectx(repo, 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
- ui.progress(_('building'), id, unit=_('revisions'), total=total)
- tr.close()
-
- if tags:
- repo.vfs.write("localtags", "".join(tags))
- finally:
- ui.progress(_('building'), None)
- release(tr, lock, wlock)
-
@command('debugbundle',
[('a', 'all', None, _('show all details')),
('', 'spec', None, _('print the bundlespec of the bundle'))],
_('FILE'),
norepo=True)
def debugbundle(ui, bundlepath, all=None, spec=None, **opts):
"""lists the contents of a bundle"""
with hg.openpath(ui, bundlepath) as f:
diff --git a/mercurial/debugcommands.py b/mercurial/debugcommands.py
--- a/mercurial/debugcommands.py
+++ b/mercurial/debugcommands.py
@@ -8,21 +8,27 @@
from __future__ import absolute_import
import os
from .i18n import _
from . import (
cmdutil,
commands,
+ context,
+ dagparser,
error,
+ lock as lockmod,
revlog,
scmutil,
+ simplemerge,
)
+release = lockmod.release
+
# We reuse the command table from commands because it is easier than
# teaching dispatch about multiple tables.
command = cmdutil.command(commands.table)
@command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
def debugancestor(ui, repo, *args):
"""find the ancestor revision of two revisions in a given index"""
if len(args) == 3:
@@ -35,8 +41,160 @@ def debugancestor(ui, repo, *args):
'(.hg not found)'))
rev1, rev2 = args
r = repo.changelog
lookup = repo.lookup
else:
raise error.Abort(_('either two or three arguments required'))
a = r.ancestor(lookup(rev1), lookup(rev2))
ui.write('%d:%s\n' % (r.rev(a), hex(a)))
+
+ at command('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]'))
+def debugbuilddag(ui, repo, text=None,
+ mergeable_file=False,
+ overwritten_file=False,
+ new_file=False):
+ """builds a repo with a given DAG from scratch in the current empty repo
+
+ The description of the DAG is read from stdin if not given on the
+ command line.
+
+ 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.
+ """
+
+ if text is None:
+ ui.status(_("reading DAG from stdin\n"))
+ text = ui.fin.read()
+
+ cl = repo.changelog
+ if len(cl) > 0:
+ raise error.Abort(_('repository is not empty'))
+
+ # determine number of revs in DAG
+ total = 0
+ for type, data in dagparser.parsedag(text):
+ if type == 'n':
+ total += 1
+
+ if mergeable_file:
+ linesperrev = 2
+ # make a file with k lines per rev
+ initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
+ initialmergedlines.append("")
+
+ tags = []
+
+ wlock = lock = tr = None
+ try:
+ wlock = repo.wlock()
+ lock = repo.lock()
+ tr = repo.transaction("builddag")
+
+ at = -1
+ atbranch = 'default'
+ nodeids = []
+ id = 0
+ ui.progress(_('building'), id, unit=_('revisions'), total=total)
+ 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(repo, fn, mergedtext)
+
+ if overwritten_file:
+ fn = "of"
+ files.append(fn)
+ fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
+
+ if new_file:
+ fn = "nf%i" % id
+ files.append(fn)
+ fctxs[fn] = context.memfilectx(repo, 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
+ ui.progress(_('building'), id, unit=_('revisions'), total=total)
+ tr.close()
+
+ if tags:
+ repo.vfs.write("localtags", "".join(tags))
+ finally:
+ ui.progress(_('building'), None)
+ release(tr, lock, wlock)
diff --git a/tests/test-ancestor.py b/tests/test-ancestor.py
--- a/tests/test-ancestor.py
+++ b/tests/test-ancestor.py
@@ -7,16 +7,17 @@ import os
import random
import sys
import time
from mercurial.node import nullrev
from mercurial import (
ancestor,
commands,
+ debugcommands,
hg,
ui as uimod,
util,
)
def buildgraph(rng, nodes=100, rootprob=0.05, mergeprob=0.2, prevprob=0.7):
'''nodes: total number of nodes in the graph
rootprob: probability that a new node (not 0) will be a root
@@ -221,17 +222,17 @@ def test_gca():
u = uimod.ui()
for i, dag in enumerate(dagtests):
repo = hg.repository(u, 'gca%d' % i, create=1)
cl = repo.changelog
if not util.safehasattr(cl.index, 'ancestors'):
# C version not available
return
- commands.debugbuilddag(u, repo, dag)
+ debugcommands.debugbuilddag(u, repo, dag)
# Compare the results of the Python and C versions. This does not
# include choosing a winner when more than one gca exists -- we make
# sure both return exactly the same set of gcas.
for a in cl:
for b in cl:
cgcas = sorted(cl.index.ancestors(a, b))
pygcas = sorted(ancestor.ancestors(cl.parentrevs, a, b))
if cgcas != pygcas:
More information about the Mercurial-devel
mailing list