[PATCH (review)] bisect: track the current changeset (issue3382)
Bryan O'Sullivan
bos at serpentine.com
Thu Apr 19 01:37:58 CDT 2012
# HG changeset patch
# User Bryan O'Sullivan <bryano at fb.com>
# Date 1334817381 25200
# Node ID 786bb91704c3694f307d66b9d062ef96b4f6a168
# Parent 2057572031e922253988d9315f9ee04df37b829d
bisect: track the current changeset (issue3382)
These changes allow --command and --noupdate to be used together,
as otherwise the command cannot find out what changeset is currently
being bisected.
Introduce a new revset feature, bisect(current), that identifies
the changeset currently being bisected.
When running a command, set the environment variable HG_NODE to
tell the command which changeset is being visited.
Fix a bug: the bisect state file wasn't being written before running
commands, so a command that cared about bisect state would read
stale data.
diff -r 2057572031e9 -r 786bb91704c3 mercurial/commands.py
--- a/mercurial/commands.py Wed Apr 18 21:27:35 2012 -0700
+++ b/mercurial/commands.py Wed Apr 18 23:36:21 2012 -0700
@@ -514,10 +514,12 @@
revision as good or bad without checking it out first.
If you supply a command, it will be used for automatic bisection.
- Its exit status will be used to mark revisions as good or bad:
- status 0 means good, 125 means to skip the revision, 127
- (command not found) will abort the bisection, and any other
- non-zero exit status means the revision is bad.
+ The environment variable HG_NODE will contain the ID of the
+ changeset being tested. The exit status of the command will be
+ used to mark revisions as good or bad: status 0 means good, 125
+ means to skip the revision, 127 (command not found) will abort the
+ bisection, and any other non-zero exit status means the revision
+ is bad.
.. container:: verbose
@@ -557,6 +559,11 @@
hg log -r "bisect(pruned)"
+ - see the changeset currently being bisected (especially useful
+ if running with -U/--noupdate)::
+
+ hg log -r "bisect(current)"
+
- see all changesets that took part in the current bisection::
hg log -r "bisect(range)"
@@ -641,9 +648,22 @@
if command:
changesets = 1
try:
+ node = state['current'][0]
+ except:
+ if noupdate:
+ raise util.Abort(_('current bisect revision is unknown - '
+ 'start a new bisect to fix'))
+ node, p2 = repo.dirstate.parents()
+ if p2 != nullid:
+ raise util.Abort(_('current bisect revision is a merge'))
+ try:
while changesets:
# update state
- status = util.system(command, out=ui.fout)
+ state['current'] = [node]
+ hbisect.save_state(repo, state)
+ status = util.system(command,
+ environ={'HG_NODE': hex(node)},
+ out=ui.fout)
if status == 125:
transition = "skip"
elif status == 0:
@@ -655,7 +675,7 @@
raise util.Abort(_("%s killed") % command)
else:
transition = "bad"
- ctx = scmutil.revsingle(repo, rev)
+ ctx = scmutil.revsingle(repo, rev, node)
rev = None # clear for future iterations
state[transition].append(ctx.node())
ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
@@ -663,9 +683,12 @@
# bisect
nodes, changesets, good = hbisect.bisect(repo.changelog, state)
# update to next check
- cmdutil.bailifchanged(repo)
- hg.clean(repo, nodes[0], show_stats=False)
+ node = nodes[0]
+ if not noupdate:
+ cmdutil.bailifchanged(repo)
+ hg.clean(repo, node, show_stats=False)
finally:
+ state['current'] = [node]
hbisect.save_state(repo, state)
print_result(nodes, good)
return
@@ -697,6 +720,8 @@
if extendnode is not None:
ui.write(_("Extending search to changeset %d:%s\n"
% (extendnode.rev(), extendnode)))
+ state['current'] = [extendnode]
+ hbisect.save_state(repo, state)
if noupdate:
return
cmdutil.bailifchanged(repo)
@@ -716,6 +741,8 @@
ui.write(_("Testing changeset %d:%s "
"(%d changesets remaining, ~%d tests)\n")
% (rev, short(node), changesets, tests))
+ state['current'] = [node]
+ hbisect.save_state(repo, state)
if not noupdate:
cmdutil.bailifchanged(repo)
return hg.clean(repo, node)
diff -r 2057572031e9 -r 786bb91704c3 mercurial/hbisect.py
--- a/mercurial/hbisect.py Wed Apr 18 21:27:35 2012 -0700
+++ b/mercurial/hbisect.py Wed Apr 18 23:36:21 2012 -0700
@@ -132,7 +132,7 @@
def load_state(repo):
- state = {'good': [], 'bad': [], 'skip': []}
+ state = {'current': [], 'good': [], 'bad': [], 'skip': []}
if os.path.exists(repo.join("bisect.state")):
for l in repo.opener("bisect.state"):
kind, node = l[:-1].split()
@@ -164,10 +164,11 @@
- ``pruned`` : csets that are goods, bads or skipped
- ``untested`` : csets whose fate is yet unknown
- ``ignored`` : csets ignored due to DAG topology
+ - ``current`` : the cset currently being bisected
"""
state = load_state(repo)
- if status in ('good', 'bad', 'skip'):
- return [repo.changelog.rev(n) for n in state[status]]
+ if status in ('good', 'bad', 'skip', 'current'):
+ return map(repo.changelog.rev, state[status])
else:
# In the floowing sets, we do *not* call 'bisect()' with more
# than one level of recusrsion, because that can be very, very
@@ -233,6 +234,9 @@
if rev in get(repo, 'skip'):
# i18n: bisect changeset status
return _('skipped')
+ if rev in get(repo, 'current'):
+ # i18n: bisect changeset status
+ return _('current')
if rev in get(repo, 'untested'):
# i18n: bisect changeset status
return _('untested')
diff -r 2057572031e9 -r 786bb91704c3 mercurial/revset.py
--- a/mercurial/revset.py Wed Apr 18 21:27:35 2012 -0700
+++ b/mercurial/revset.py Wed Apr 18 23:36:21 2012 -0700
@@ -289,6 +289,7 @@
- ``pruned`` : csets that are goods, bads or skipped
- ``untested`` : csets whose fate is yet unknown
- ``ignored`` : csets ignored due to DAG topology
+ - ``current`` : the cset currently being bisected
"""
status = getstring(x, _("bisect requires a string")).lower()
state = set(hbisect.get(repo, status))
diff -r 2057572031e9 -r 786bb91704c3 tests/test-bisect.t
--- a/tests/test-bisect.t Wed Apr 18 21:27:35 2012 -0700
+++ b/tests/test-bisect.t Wed Apr 18 23:36:21 2012 -0700
@@ -224,6 +224,7 @@
Testing changeset 12:1941b52820a5 (23 changesets remaining, ~4 tests)
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cat .hg/bisect.state
+ current 1941b52820a544549596820a8ae006842b0e2c64
skip 9d7d07bc967ca98ad0600c24953fd289ad5fa991
skip ce8f0998e922c179e80819d5066fbe46e2998784
skip e7fa0811edb063f6319531f0d0a865882138e180
@@ -396,6 +397,12 @@
date: Thu Jan 01 00:00:06 1970 +0000
summary: msg 6
+ $ hg log -r "bisect(current)"
+ changeset: 5:7874a09ea728
+ user: test
+ date: Thu Jan 01 00:00:05 1970 +0000
+ summary: msg 5
+
$ hg log -r "bisect(skip)"
changeset: 1:5cd978ea5149
user: test
@@ -466,3 +473,40 @@
date: Thu Jan 01 00:00:06 1970 +0000
summary: msg 6
+
+
+test bisecting via a command without updating the working dir, and
+ensure that the bisect state file is updated before running a test
+command
+
+ $ hg update null
+ 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+ $ cat > script.sh <<'EOF'
+ > #!/bin/sh
+ > test -n "$HG_NODE" || (echo HG_NODE missing; exit 127)
+ > current="`hg log -r \"bisect(current)\" --template {node}`"
+ > test "$current" = "$HG_NODE" || (echo current is bad: $current; exit 127)
+ > rev="`hg log -r $HG_NODE --template {rev}`"
+ > test "$rev" -ge 6
+ > EOF
+ $ chmod +x script.sh
+ $ hg bisect -r
+ $ hg bisect --good tip --noupdate
+ $ hg bisect --bad 0 --noupdate
+ Testing changeset 15:e7fa0811edb0 (31 changesets remaining, ~4 tests)
+ $ hg bisect --command "'`pwd`/script.sh' and some params" --noupdate
+ Changeset 15:e7fa0811edb0: good
+ Changeset 7:03750880c6b5: good
+ Changeset 3:b53bea5e2fcb: bad
+ Changeset 5:7874a09ea728: bad
+ Changeset 6:a3d5c6fdf0d3: good
+ The first good revision is:
+ changeset: 6:a3d5c6fdf0d3
+ user: test
+ date: Thu Jan 01 00:00:06 1970 +0000
+ summary: msg 6
+
+
+ensure that we still don't have a working dir
+
+ $ hg parents
More information about the Mercurial-devel
mailing list