##// END OF EJS Templates
dirstate: ignore symlinks when fs cannot handle them (issue1888)...
dirstate: ignore symlinks when fs cannot handle them (issue1888) When the filesystem cannot handle the executable bit, we currently ignore it completely when looking for modified files. Similarly, it is impossible to set or clear the bit when the filesystem ignores it. This patch makes Mercurial treat symbolic links the same way. Symlinks are a little different since they manifest themselves as small files containing a filename (the symlink target). On Windows, these files show up as regular files, and on Linux and Mac they show up as real symlinks. Issue1888 presents a case where the symlink files are better ignored from the Windows side. A Linux client creates symlinks in a working copy which is shared over a network between Linux and Windows clients. The Samba server is helpful and defererences the symlink when the Windows client looks at it. This means that Mercurial on the Windows side sees file content instead of a file name in the symlink, and hence flags the link as modified. Ignoring the change would be much more helpful, similarly to how Mercurial does not report any changes when executable bits are ignored in a checkout on Windows. An initial checkout of a symbolic link on a file system that cannot handle symbolic links will still result in a regular file containing the target file name as its content. Sharing such a checkout with a Linux client will not turn the file into a symlink automatically, but 'hg revert' can fix that. After the revert, the Windows client will see the correct file content (provided by the Samba server when it follows the link on the Linux side) and otherwise ignore the change. Running 'hg perfstatus' 10 times gives these results: Before: After: min: 0.544703 min: 0.546549 med: 0.547592 med: 0.548881 avg: 0.549146 avg: 0.548549 max: 0.564112 max: 0.551504 The median time is increased about 0.24%.

File last commit:

r10263:25e57239 stable
r11769:ca6cebd8 stable
Show More
hbisect.py
153 lines | 4.9 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>
Martin Geisler
add blank line after copyright notices and after header
r8228 #
Matt Mackall
bisect: make bisect a built-in command
r5775 # Inspired by git bisect, extension skeleton taken from mq.py.
#
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
bisect: make bisect a built-in command
r5775
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
Martin Geisler
replace set-like dictionaries with real sets...
r8152 skip = set([changelog.rev(n) for n in state['skip']])
Matt Mackall
bisect: make bisect a built-in command
r5775
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]
Matt Mackall
bisect: limit considered set to descendants of first good rev
r9583 goodrev = min(goodrevs)
# build visit array
ancestors = [None] * (len(changelog) + 1) # an extra for [-1]
# set nodes descended from goodrev
ancestors[goodrev] = []
for rev in xrange(goodrev + 1, len(changelog)):
for prev in clparents(rev):
if ancestors[prev] == []:
ancestors[rev] = []
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)
Benoit Boissinot
bisect: use integer division
r7902 perfect = tot // 2
Matt Mackall
bisect: make bisect a built-in command
r5775
# find the best node to test
best_rev = None
best_len = -1
Benoit Boissinot
bisect: use set instead of dict
r8463 poison = set()
Matt Mackall
bisect: make bisect a built-in command
r5775 for rev in candidates:
if rev in poison:
Martin Geisler
hbisect: use set.update for bulk updates
r8482 # poison children
poison.update(children.get(rev, []))
Matt Mackall
bisect: make bisect a built-in command
r5775 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?
Martin Geisler
hbisect: use set.update for bulk updates
r8482 # poison children
poison.update(children.get(rev, []))
Matt Mackall
bisect: make bisect a built-in command
r5775 continue
for c in children.get(rev, []):
if ancestors[c]:
Martin Geisler
replace set-like dictionaries with real sets...
r8152 ancestors[c] = list(set(ancestors[c] + a))
Matt Mackall
bisect: make bisect a built-in command
r5775 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:
Ronny Pfannschmidt
switch lock releasing in the core from gc to explicit
r8109 wlock.release()
Alexander Solovyov
bisect: ability to check revision with command
r7227