author | Kirill Smelkov <kirr@mns.spb.ru> |
Fri, 28 Dec 2007 00:03:55 -0600 | |
changeset 5751 | bc475d1f74ca |
parent 5738 | 2a54e2b177b6 |
child 5766 | 23caedc5a28f |
permissions | -rw-r--r-- |
1855
0ba9dee8cfbd
Fixed spacing/indentation, removed #! script header, added short description.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1854
diff
changeset
|
1 |
# bisect extension for mercurial |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
2 |
# |
1861
65949d1c9bf7
Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1856
diff
changeset
|
3 |
# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org> |
65949d1c9bf7
Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1856
diff
changeset
|
4 |
# Inspired by git bisect, extension skeleton taken from mq.py. |
65949d1c9bf7
Added copyright information to hbisect.py
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1856
diff
changeset
|
5 |
# |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
6 |
# This software may be used and distributed according to the terms |
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
7 |
# of the GNU General Public License, incorporated herein by reference. |
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
8 |
|
3891 | 9 |
from mercurial.i18n import _ |
5731
19691160d7f5
bisect: remove unused imports
Matt Mackall <mpm@selenic.com>
parents:
5730
diff
changeset
|
10 |
from mercurial import hg, util, cmdutil |
19691160d7f5
bisect: remove unused imports
Matt Mackall <mpm@selenic.com>
parents:
5730
diff
changeset
|
11 |
import os, array |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
12 |
|
5737 | 13 |
def _bisect(changelog, state): |
14 |
clparents = changelog.parentrevs |
|
15 |
# only the earliest bad revision matters |
|
16 |
badrev = min([changelog.rev(n) for n in state['bad']]) |
|
17 |
bad = changelog.node(badrev) |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
18 |
|
5737 | 19 |
# build ancestors array |
20 |
ancestors = [[]] * (changelog.count() + 1) # an extra for [-1] |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
21 |
|
5737 | 22 |
# clear good revs from array |
23 |
for node in state['good']: |
|
24 |
ancestors[changelog.rev(node)] = None |
|
25 |
for rev in xrange(changelog.count(), -1, -1): |
|
26 |
if ancestors[rev] is None: |
|
27 |
for prev in clparents(rev): |
|
28 |
ancestors[prev] = None |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
29 |
|
5737 | 30 |
if ancestors[badrev] is None: |
31 |
raise util.Abort(_("Inconsistent state, %s:%s is good and bad") |
|
32 |
% (badrev, hg.short(bad))) |
|
5723
e3b09819496b
bisect: switch to rev-based calculation
Matt Mackall <mpm@selenic.com>
parents:
5722
diff
changeset
|
33 |
|
5737 | 34 |
# accumulate ancestor lists |
35 |
for rev in xrange(badrev + 1): |
|
36 |
if ancestors[rev] == []: |
|
37 |
p1, p2 = clparents(rev) |
|
38 |
a1, a2 = ancestors[p1], ancestors[p2] |
|
39 |
if a1: |
|
40 |
if a2: |
|
41 |
# merge ancestor lists |
|
42 |
a = dict.fromkeys(a2) |
|
43 |
a.update(dict.fromkeys(a1)) |
|
44 |
a[rev] = None |
|
45 |
ancestors[rev] = array.array("l", a.keys()) |
|
5726
19cbe2aea2bc
bisect: switch individual ancestor lists from dict to list
Matt Mackall <mpm@selenic.com>
parents:
5725
diff
changeset
|
46 |
else: |
5737 | 47 |
ancestors[rev] = a1 + array.array("l", [rev]) |
48 |
elif a2: |
|
49 |
ancestors[rev] = a2 + array.array("l", [rev]) |
|
50 |
else: |
|
51 |
ancestors[rev] = array.array("l", [rev]) |
|
5721
8d63fa48d44a
bisect: clarify some bisection code
Matt Mackall <mpm@selenic.com>
parents:
5720
diff
changeset
|
52 |
|
5737 | 53 |
if badrev not in ancestors[badrev]: |
54 |
raise util.Abort(_("Could not find the first bad revision")) |
|
5721
8d63fa48d44a
bisect: clarify some bisection code
Matt Mackall <mpm@selenic.com>
parents:
5720
diff
changeset
|
55 |
|
5737 | 56 |
# have we narrowed it down to one entry? |
57 |
tot = len(ancestors[badrev]) |
|
58 |
if tot == 1: |
|
59 |
return (bad, 0) |
|
5734
944b231fa0e7
bisect: move reporting out of core bisect function
Matt Mackall <mpm@selenic.com>
parents:
5733
diff
changeset
|
60 |
|
5737 | 61 |
# find the best node to test |
62 |
best_rev = None |
|
63 |
best_len = -1 |
|
64 |
skip = dict.fromkeys([changelog.rev(n) for n in state['skip']]) |
|
65 |
for n in ancestors[badrev]: |
|
66 |
if n in skip: |
|
67 |
continue |
|
68 |
a = len(ancestors[n]) # number of ancestors |
|
69 |
b = tot - a # number of non-ancestors |
|
70 |
value = min(a, b) # how good is this test? |
|
71 |
if value > best_len: |
|
72 |
best_len = value |
|
73 |
best_rev = n |
|
74 |
assert best_rev is not None |
|
75 |
best_node = changelog.node(best_rev) |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
76 |
|
5737 | 77 |
return (best_node, tot) |
5733 | 78 |
|
5737 | 79 |
def bisect(ui, repo, rev=None, extra=None, |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
80 |
reset=None, good=None, bad=None, skip=None): |
5729
73646515c435
bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents:
5728
diff
changeset
|
81 |
"""Subdivision search of changesets |
4390
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
82 |
|
5729
73646515c435
bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents:
5728
diff
changeset
|
83 |
This extension helps to find changesets which introduce problems. |
73646515c435
bisect: slightly improve the help message
Matt Mackall <mpm@selenic.com>
parents:
5728
diff
changeset
|
84 |
To use, mark the earliest changeset you know exhibits the problem |
4390
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
85 |
as bad, then mark the latest changeset which is free from the problem |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
86 |
as good. Bisect will update your working directory to a revision for |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
87 |
testing. Once you have performed tests, mark the working directory |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
88 |
as bad or good and bisect will either update to another candidate |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
89 |
changeset or announce that it has found the bad revision. |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
90 |
|
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
91 |
Note: bisect expects bad revisions to be descendants of good revisions. |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
92 |
If you are looking for the point at which a problem was fixed, then make |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
93 |
the problem-free state "bad" and the problematic state "good." |
052062b98f26
Flesh out bisect help text
Brendan Cully <brendan@kublai.com>
parents:
3891
diff
changeset
|
94 |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
95 |
""" |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
96 |
# backward compatibility |
5737 | 97 |
if rev in "good bad reset init".split(): |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
98 |
ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n")) |
5737 | 99 |
cmd, rev, extra = rev, extra, None |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
100 |
if cmd == "good": |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
101 |
good = True |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
102 |
elif cmd == "bad": |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
103 |
bad = True |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
104 |
else: |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
105 |
reset = True |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
106 |
elif extra or good + bad + skip + reset > 1: |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
107 |
raise util.Abort("Incompatible arguments") |
1855
0ba9dee8cfbd
Fixed spacing/indentation, removed #! script header, added short description.
Thomas Arendsen Hein <thomas@intevation.de>
parents:
1854
diff
changeset
|
108 |
|
5737 | 109 |
if reset: |
110 |
p = repo.join("bisect.state") |
|
111 |
if os.path.exists(p): |
|
112 |
os.unlink(p) |
|
113 |
return |
|
114 |
||
115 |
# load state |
|
116 |
state = {'good': [], 'bad': [], 'skip': []} |
|
117 |
if os.path.exists(repo.join("bisect.state")): |
|
118 |
for l in repo.opener("bisect.state"): |
|
119 |
kind, node = l[:-1].split() |
|
120 |
node = repo.lookup(node) |
|
121 |
if kind not in state: |
|
122 |
raise util.Abort(_("unknown bisect kind %s") % kind) |
|
123 |
state[kind].append(node) |
|
124 |
||
125 |
# update state |
|
126 |
node = repo.lookup(rev or '.') |
|
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
127 |
if good: |
5737 | 128 |
state['good'].append(node) |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
129 |
elif bad: |
5737 | 130 |
state['bad'].append(node) |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
131 |
elif skip: |
5737 | 132 |
state['skip'].append(node) |
133 |
||
134 |
# save state |
|
5738
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
135 |
f = repo.opener("bisect.state", "w", atomictemp=True) |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
136 |
wlock = repo.wlock() |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
137 |
try: |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
138 |
for kind in state: |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
139 |
for node in state[kind]: |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
140 |
f.write("%s %s\n" % (kind, hg.hex(node))) |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
141 |
f.rename() |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
142 |
finally: |
2a54e2b177b6
bisect: use proper locking when updating bisect.state
Matt Mackall <mpm@selenic.com>
parents:
5737
diff
changeset
|
143 |
del wlock |
5737 | 144 |
|
145 |
if not state['good'] or not state['bad']: |
|
146 |
return |
|
147 |
||
148 |
# actually bisect |
|
149 |
node, changesets = _bisect(repo.changelog, state) |
|
150 |
if changesets == 0: |
|
151 |
ui.write(_("The first bad revision is:\n")) |
|
152 |
displayer = cmdutil.show_changeset(ui, repo, {}) |
|
153 |
displayer.show(changenode=node) |
|
154 |
elif node is not None: |
|
155 |
# compute the approximate number of remaining tests |
|
156 |
tests, size = 0, 2 |
|
157 |
while size <= changesets: |
|
158 |
tests, size = tests + 1, size * 2 |
|
159 |
rev = repo.changelog.rev(node) |
|
160 |
ui.write(_("Testing changeset %s:%s " |
|
161 |
"(%s changesets remaining, ~%s tests)\n") |
|
162 |
% (rev, hg.short(node), changesets, tests)) |
|
163 |
cmdutil.bail_if_changed(repo) |
|
164 |
return hg.clean(repo, node) |
|
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
165 |
|
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
166 |
cmdtable = { |
5737 | 167 |
"bisect": (bisect, |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
168 |
[('r', 'reset', False, _('reset bisect state')), |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
169 |
('g', 'good', False, _('mark changeset good')), |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
170 |
('b', 'bad', False, _('mark changeset bad')), |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
171 |
('s', 'skip', False, _('skip testing changeset'))], |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
172 |
_("hg bisect [-gbsr] [REV]")) |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
173 |
} |