Mercurial > public > mercurial-scm > hg-stable
annotate hgext/hbisect.py @ 5766:23caedc5a28f
bisect: add noupdate option
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Mon, 31 Dec 2007 18:20:33 -0600 |
parents | 2a54e2b177b6 |
children | dd5f8ed31057 |
rev | line source |
---|---|
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, |
5766
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
80 reset=None, good=None, bad=None, skip=None, noupdate=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)) | |
5766
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
163 if not noupdate: |
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
164 cmdutil.bail_if_changed(repo) |
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
165 return hg.clean(repo, node) |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
166 |
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
167 cmdtable = { |
5737 | 168 "bisect": (bisect, |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
169 [('r', 'reset', False, _('reset bisect state')), |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
170 ('g', 'good', False, _('mark changeset good')), |
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
171 ('b', 'bad', False, _('mark changeset bad')), |
5766
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
172 ('s', 'skip', False, _('skip testing changeset')), |
23caedc5a28f
bisect: add noupdate option
Matt Mackall <mpm@selenic.com>
parents:
5738
diff
changeset
|
173 ('U', 'noupdate', False, _('do not update to target'))], |
5735
9079081b8982
bisect: use more standard command syntax and help
Matt Mackall <mpm@selenic.com>
parents:
5734
diff
changeset
|
174 _("hg bisect [-gbsr] [REV]")) |
1367
a7678cbd7c28
bisect extension for mercurial
Benoit Boissinot <benoit.boissinot@ens-lyon.org>
parents:
diff
changeset
|
175 } |