We sometimes missed deps when more than one dep required a stamp check.

If must_build was nonempty when recursively calling isdirty() that
returned a list, we'd lose the original value of must_build.
This commit is contained in:
Alan Falloon 2015-05-06 17:56:14 -04:00 committed by Avery Pennarun
commit 67c1d4f7d8
10 changed files with 47 additions and 5 deletions

14
deps.py
View file

@ -58,10 +58,15 @@ def isdirty(f, depth, max_changed,
assert(mode in ('c','m')) assert(mode in ('c','m'))
if not f.csum: if not f.csum:
# f is a "normal" target: dirty f2 means f is instantly dirty # f is a "normal" target: dirty f2 means f is instantly dirty
if dirty: if dirty == DIRTY:
# if dirty==DIRTY, this means f is definitely dirty. # f2 is definitely dirty, so f definitely needs to
# if dirty==[...], it's a list of the uncertain children. # redo.
return dirty return DIRTY
elif isinstance(dirty,list):
# our child f2 might be dirty, but it's not sure yet. It's
# given us a list of targets we have to redo in order to
# be sure.
must_build += dirty
else: else:
# f is "checksummable": dirty f2 means f needs to redo, # f is "checksummable": dirty f2 means f needs to redo,
# but f might turn out to be clean after that (ie. our parent # but f might turn out to be clean after that (ie. our parent
@ -83,6 +88,7 @@ def isdirty(f, depth, max_changed,
# objects in the tree. If we build all those, we can then # objects in the tree. If we build all those, we can then
# redo-ifchange f and it won't have any uncertainty next time. # redo-ifchange f and it won't have any uncertainty next time.
return must_build return must_build
debug('%s-- CLEAN\n' % (depth,))
# if we get here, it's because the target is clean # if we get here, it's because the target is clean
if f.is_override: if f.is_override:

View file

@ -200,6 +200,9 @@ class File(object):
else: else:
return self._init_from_idname(id, name) return self._init_from_idname(id, name)
def __repr__(self):
return "File(%r)" % (self.nicename(),)
def refresh(self): def refresh(self):
self._init_from_idname(self.id, None) self._init_from_idname(self.id, None)

View file

@ -4,3 +4,9 @@
/inp /inp
/bob /bob
/usestamp2 /usestamp2
/a
/b
/ab
/doing_ab
/abc
/doing_abc

3
t/660-stamp/a.do Normal file
View file

@ -0,0 +1,3 @@
redo-always
echo a | redo-stamp
echo a > $3

4
t/660-stamp/ab.do Normal file
View file

@ -0,0 +1,4 @@
redo-ifchange a b
echo "doing ab" >&2
echo ab >$3
touch doing_ab

4
t/660-stamp/abc.do Normal file
View file

@ -0,0 +1,4 @@
redo-ifchange ab c
echo "doing abc" >&2
echo abc >$3
touch doing_abc

3
t/660-stamp/b.do Normal file
View file

@ -0,0 +1,3 @@
redo-always
echo b | redo-stamp
echo b > $3

0
t/660-stamp/c Normal file
View file

View file

@ -1 +1 @@
rm -f *.log usestamp usestamp2 stampy inp bob *~ .*~ rm -f *.log usestamp usestamp2 stampy inp bob *~ .*~ a b ab doing_ab

View file

@ -70,3 +70,16 @@ redo-ifchange usestamp usestamp2
rm -f stampy rm -f stampy
redo-ifchange stampy redo-ifchange stampy
[ "$(wc -l <stampy.log)" -eq 6 ] || exit 74 [ "$(wc -l <stampy.log)" -eq 6 ] || exit 74
# check that a target that depends on two stamped targets (that are marked as
# always built) won't be redone if neither stamped targets changes
../flush-cache
redo-ifchange abc
rm -f doing_ab doing_abc
redo-ifchange abc
[ ! -f doing_ab ] || exit 92
[ ! -f doing_abc ] || exit 93
../flush-cache
redo-ifchange abc
[ ! -f doing_ab ] || exit 94
[ ! -f doing_abc ] || exit 95