##// END OF EJS Templates
bdiff: adjust criteria for getting optimal longest match in the A side middle...
bdiff: adjust criteria for getting optimal longest match in the A side middle We prefer matches closer to the middle to balance recursion, as introduced in f1ca249696ed. For ranges with uneven length, matches starting exactly in the middle should have preference. That will be optimal for matches of length 1. We will thus accept equality in the half check. For ranges with even length, half was ceil'ed when calculated but we got the preference for low matches from the 'less than half' check. To get the same result as before when we also accept equality, floor it. Without that, test-annotate.t would show some different (still correct but less optimal) results. This will change the heuristics. Tests shows a slightly different output - and sometimes slightly smaller bundles. The bundle size for 4.0 (hg bundle --base null -r 4.0 x.hg) happens to go from 22804885 to 22803824 bytes - an 0.005% reduction.

File last commit:

r30402:945f8229 default
r30429:38ed5488 default
Show More
debugcommands.py
203 lines | 6.9 KiB | text/x-python | PythonLexer
# debugcommands.py - command processing for debug* commands
#
# Copyright 2005-2016 Matt Mackall <mpm@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 __future__ import absolute_import
import os
from .i18n import _
from .node import (
hex,
)
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:
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 error.Abort(_('there is no Mercurial repository here '
'(.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)))
@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)