##// END OF EJS Templates
hgweb: fix long line lengths introduced in 2dc868712dcc
hgweb: fix long line lengths introduced in 2dc868712dcc

File last commit:

r7557:21233de9 default
r7575:3ccaefc8 default
Show More
hbisect.py
144 lines | 4.7 KiB | text/x-python | PythonLexer
Matt Mackall
bisect: make bisect a built-in command
r5775 # changelog bisection for mercurial
#
# Copyright 2007 Matt Mackall
# Copyright 2005, 2006 Benoit Boissinot <benoit.boissinot@ens-lyon.org>
# Inspired by git bisect, extension skeleton taken from mq.py.
#
# This software may be used and distributed according to the terms
# of the GNU General Public License, incorporated herein by reference.
Alexander Solovyov
bisect: ability to check revision with command
r7227 import os
Matt Mackall
bisect: make bisect a built-in command
r5775 from i18n import _
Alexander Solovyov
bisect: ability to check revision with command
r7227 from node import short, hex
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 import util
Matt Mackall
bisect: make bisect a built-in command
r5775
def bisect(changelog, state):
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 """find the next node (if any) for testing during a bisect search.
returns a (nodes, number, good) tuple.
'nodes' is the final result of the bisect if 'number' is 0.
Otherwise 'number' indicates the remaining possible candidates for
the search and 'nodes' contains the next bisect target.
'good' is True if bisect is searching for a first good changeset, False
if searching for a first bad one.
"""
Matt Mackall
bisect: make bisect a built-in command
r5775 clparents = changelog.parentrevs
skip = dict.fromkeys([changelog.rev(n) for n in state['skip']])
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 def buildancestors(bad, good):
# only the earliest bad revision matters
badrev = min([changelog.rev(n) for n in bad])
goodrevs = [changelog.rev(n) for n in good]
# build ancestors array
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 ancestors = [[]] * (len(changelog) + 1) # an extra for [-1]
Matt Mackall
bisect: make bisect a built-in command
r5775
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 # clear good revs from array
for node in goodrevs:
ancestors[node] = None
Matt Mackall
add __len__ and __iter__ methods to repo and revlog
r6750 for rev in xrange(len(changelog), -1, -1):
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if ancestors[rev] is None:
for prev in clparents(rev):
ancestors[prev] = None
Matt Mackall
bisect: make bisect a built-in command
r5775
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if ancestors[badrev] is None:
Matt Mackall
bisect: improve tests...
r5777 return badrev, None
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 return badrev, ancestors
good = 0
badrev, ancestors = buildancestors(state['bad'], state['good'])
if not ancestors: # looking for bad to good transition?
good = 1
badrev, ancestors = buildancestors(state['good'], state['bad'])
Matt Mackall
bisect: improve tests...
r5777 bad = changelog.node(badrev)
Matt Mackall
bisect: handle search for bad to good transitions...
r5776 if not ancestors: # now we're confused
Matt Mackall
bisect: make bisect a built-in command
r5775 raise util.Abort(_("Inconsistent state, %s:%s is good and bad")
Joel Rosdahl
Avoid importing mercurial.node/mercurial.repo stuff from mercurial.hg
r6217 % (badrev, short(bad)))
Matt Mackall
bisect: make bisect a built-in command
r5775
# build children dict
children = {}
visit = [badrev]
candidates = []
while visit:
rev = visit.pop(0)
if ancestors[rev] == []:
candidates.append(rev)
for prev in clparents(rev):
if prev != -1:
if prev in children:
children[prev].append(rev)
else:
children[prev] = [rev]
visit.append(prev)
candidates.sort()
# have we narrowed it down to one entry?
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 # or have all other possible candidates besides 'bad' have been skipped?
Matt Mackall
bisect: make bisect a built-in command
r5775 tot = len(candidates)
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 unskipped = [c for c in candidates if (c not in skip) and (c != badrev)]
if tot == 1 or not unskipped:
return ([changelog.node(rev) for rev in candidates], 0, good)
Matt Mackall
bisect: make bisect a built-in command
r5775 perfect = tot / 2
# find the best node to test
best_rev = None
best_len = -1
poison = {}
for rev in candidates:
if rev in poison:
for c in children.get(rev, []):
poison[c] = True # poison children
continue
a = ancestors[rev] or [rev]
ancestors[rev] = None
x = len(a) # number of ancestors
y = tot - x # number of non-ancestors
value = min(x, y) # how good is this test?
if value > best_len and rev not in skip:
best_len = value
best_rev = rev
if value == perfect: # found a perfect candidate? quit early
break
Bernhard Leiner
Circumvent removal of valid bisect candidates due to previously skipped ones...
r7557 if y < perfect and rev not in skip: # all downhill from here?
Matt Mackall
bisect: make bisect a built-in command
r5775 for c in children.get(rev, []):
poison[c] = True # poison children
continue
for c in children.get(rev, []):
if ancestors[c]:
ancestors[c] = dict.fromkeys(ancestors[c] + a).keys()
else:
ancestors[c] = a + [c]
assert best_rev is not None
best_node = changelog.node(best_rev)
Bernhard Leiner
Add support for multiple possible bisect results (issue1228, issue1182)...
r6858 return ([best_node], tot, good)
Alexander Solovyov
bisect: ability to check revision with command
r7227
def load_state(repo):
state = {'good': [], 'bad': [], 'skip': []}
if os.path.exists(repo.join("bisect.state")):
for l in repo.opener("bisect.state"):
kind, node = l[:-1].split()
node = repo.lookup(node)
if kind not in state:
raise util.Abort(_("unknown bisect kind %s") % kind)
state[kind].append(node)
return state
def save_state(repo, state):
f = repo.opener("bisect.state", "w", atomictemp=True)
wlock = repo.wlock()
try:
for kind in state:
for node in state[kind]:
f.write("%s %s\n" % (kind, hex(node)))
f.rename()
finally:
del wlock