Move dependency checking from redo-ifchange into deps.py.
In preparation for sharing between multiple commands.
This commit is contained in:
parent
f2d34fa685
commit
df85b3d163
4 changed files with 101 additions and 96 deletions
|
|
@ -43,10 +43,6 @@ def _try_stat(filename):
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
|
||||||
def warn_override(name):
|
|
||||||
warn('%s - you modified it; skipping\n' % name)
|
|
||||||
|
|
||||||
|
|
||||||
class ImmediateReturn(Exception):
|
class ImmediateReturn(Exception):
|
||||||
def __init__(self, rv):
|
def __init__(self, rv):
|
||||||
Exception.__init__(self, "immediate return with exit code %d" % rv)
|
Exception.__init__(self, "immediate return with exit code %d" % rv)
|
||||||
|
|
@ -88,7 +84,7 @@ class BuildJob:
|
||||||
not sf.failed_runid and
|
not sf.failed_runid and
|
||||||
newstamp != state.STAMP_MISSING and
|
newstamp != state.STAMP_MISSING and
|
||||||
(sf.stamp != newstamp or sf.is_override)):
|
(sf.stamp != newstamp or sf.is_override)):
|
||||||
warn_override(_nice(t))
|
state.warn_override(_nice(t))
|
||||||
sf.set_override()
|
sf.set_override()
|
||||||
sf.set_checked()
|
sf.set_checked()
|
||||||
sf.save()
|
sf.save()
|
||||||
|
|
|
||||||
91
deps.py
Normal file
91
deps.py
Normal file
|
|
@ -0,0 +1,91 @@
|
||||||
|
import sys, os
|
||||||
|
import vars, state, builder
|
||||||
|
from log import debug
|
||||||
|
|
||||||
|
CLEAN = 0
|
||||||
|
DIRTY = 1
|
||||||
|
|
||||||
|
def isdirty(f, depth, max_changed):
|
||||||
|
if vars.DEBUG >= 1:
|
||||||
|
debug('%s?%s\n' % (depth, f.nicename()))
|
||||||
|
|
||||||
|
if f.failed_runid:
|
||||||
|
debug('%s-- DIRTY (failed last time)\n' % depth)
|
||||||
|
return DIRTY
|
||||||
|
if f.changed_runid == None:
|
||||||
|
debug('%s-- DIRTY (never built)\n' % depth)
|
||||||
|
return DIRTY
|
||||||
|
if f.changed_runid > max_changed:
|
||||||
|
debug('%s-- DIRTY (built)\n' % depth)
|
||||||
|
return DIRTY # has been built more recently than parent
|
||||||
|
if f.is_checked():
|
||||||
|
if vars.DEBUG >= 1:
|
||||||
|
debug('%s-- CLEAN (checked)\n' % depth)
|
||||||
|
return CLEAN # has already been checked during this session
|
||||||
|
if not f.stamp:
|
||||||
|
debug('%s-- DIRTY (no stamp)\n' % depth)
|
||||||
|
return DIRTY
|
||||||
|
|
||||||
|
newstamp = f.read_stamp()
|
||||||
|
if f.stamp != newstamp:
|
||||||
|
if newstamp == state.STAMP_MISSING:
|
||||||
|
debug('%s-- DIRTY (missing)\n' % depth)
|
||||||
|
else:
|
||||||
|
debug('%s-- DIRTY (mtime)\n' % depth)
|
||||||
|
if f.csum:
|
||||||
|
return [f]
|
||||||
|
else:
|
||||||
|
return DIRTY
|
||||||
|
|
||||||
|
must_build = []
|
||||||
|
for mode,f2 in f.deps():
|
||||||
|
dirty = CLEAN
|
||||||
|
if mode == 'c':
|
||||||
|
if os.path.exists(os.path.join(vars.BASE, f2.name)):
|
||||||
|
debug('%s-- DIRTY (created)\n' % depth)
|
||||||
|
dirty = DIRTY
|
||||||
|
elif mode == 'm':
|
||||||
|
sub = isdirty(f2, depth = depth + ' ',
|
||||||
|
max_changed = max(f.changed_runid,
|
||||||
|
f.checked_runid))
|
||||||
|
if sub:
|
||||||
|
debug('%s-- DIRTY (sub)\n' % depth)
|
||||||
|
dirty = sub
|
||||||
|
else:
|
||||||
|
assert(mode in ('c','m'))
|
||||||
|
if not f.csum:
|
||||||
|
# f is a "normal" target: dirty f2 means f is instantly dirty
|
||||||
|
if dirty:
|
||||||
|
# if dirty==DIRTY, this means f is definitely dirty.
|
||||||
|
# if dirty==[...], it's a list of the uncertain children.
|
||||||
|
return dirty
|
||||||
|
else:
|
||||||
|
# f is "checksummable": dirty f2 means f needs to redo,
|
||||||
|
# but f might turn out to be clean after that (ie. our parent
|
||||||
|
# might not be dirty).
|
||||||
|
if dirty == DIRTY:
|
||||||
|
# f2 is definitely dirty, so f definitely needs to
|
||||||
|
# redo. However, after that, f might turn out to be
|
||||||
|
# unchanged.
|
||||||
|
return [f]
|
||||||
|
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
|
||||||
|
|
||||||
|
if must_build:
|
||||||
|
# f is *maybe* dirty because at least one of its children is maybe
|
||||||
|
# dirty. must_build has accumulated a list of "topmost" uncertain
|
||||||
|
# objects in the tree. If we build all those, we can then
|
||||||
|
# redo-ifchange f and it won't have any uncertainty next time.
|
||||||
|
return must_build
|
||||||
|
|
||||||
|
# if we get here, it's because the target is clean
|
||||||
|
if f.is_override:
|
||||||
|
state.warn_override(f.name)
|
||||||
|
f.set_checked()
|
||||||
|
f.save()
|
||||||
|
return CLEAN
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,107 +1,21 @@
|
||||||
#!/usr/bin/python
|
#!/usr/bin/python
|
||||||
import sys, os, errno, stat
|
import sys, os
|
||||||
if not sys.argv[1:]:
|
if not sys.argv[1:]:
|
||||||
sys.exit(0) # nothing to do, so we can't possibly do it wrong
|
sys.exit(0) # nothing to do, so we can't possibly do it wrong
|
||||||
|
|
||||||
import vars_init
|
import vars_init
|
||||||
vars_init.init(sys.argv[1:])
|
vars_init.init(sys.argv[1:])
|
||||||
|
|
||||||
import vars, state, builder, jwack
|
import vars, state, builder, jwack, deps
|
||||||
from helpers import unlink
|
from helpers import unlink
|
||||||
from log import debug, debug2, err
|
from log import debug, debug2, err
|
||||||
|
|
||||||
CLEAN = 0
|
|
||||||
DIRTY = 1
|
|
||||||
def dirty_deps(f, depth, max_changed):
|
|
||||||
if vars.DEBUG >= 1:
|
|
||||||
debug('%s?%s\n' % (depth, f.nicename()))
|
|
||||||
|
|
||||||
if f.failed_runid:
|
|
||||||
debug('%s-- DIRTY (failed last time)\n' % depth)
|
|
||||||
return DIRTY
|
|
||||||
if f.changed_runid == None:
|
|
||||||
debug('%s-- DIRTY (never built)\n' % depth)
|
|
||||||
return DIRTY
|
|
||||||
if f.changed_runid > max_changed:
|
|
||||||
debug('%s-- DIRTY (built)\n' % depth)
|
|
||||||
return DIRTY # has been built more recently than parent
|
|
||||||
if f.is_checked():
|
|
||||||
if vars.DEBUG >= 1:
|
|
||||||
debug('%s-- CLEAN (checked)\n' % depth)
|
|
||||||
return CLEAN # has already been checked during this session
|
|
||||||
if not f.stamp:
|
|
||||||
debug('%s-- DIRTY (no stamp)\n' % depth)
|
|
||||||
return DIRTY
|
|
||||||
|
|
||||||
newstamp = f.read_stamp()
|
|
||||||
if f.stamp != newstamp:
|
|
||||||
if newstamp == state.STAMP_MISSING:
|
|
||||||
debug('%s-- DIRTY (missing)\n' % depth)
|
|
||||||
else:
|
|
||||||
debug('%s-- DIRTY (mtime)\n' % depth)
|
|
||||||
if f.csum:
|
|
||||||
return [f]
|
|
||||||
else:
|
|
||||||
return DIRTY
|
|
||||||
|
|
||||||
must_build = []
|
|
||||||
for mode,f2 in f.deps():
|
|
||||||
dirty = CLEAN
|
|
||||||
if mode == 'c':
|
|
||||||
if os.path.exists(os.path.join(vars.BASE, f2.name)):
|
|
||||||
debug('%s-- DIRTY (created)\n' % depth)
|
|
||||||
dirty = DIRTY
|
|
||||||
elif mode == 'm':
|
|
||||||
sub = dirty_deps(f2, depth = depth + ' ',
|
|
||||||
max_changed = max(f.changed_runid,
|
|
||||||
f.checked_runid))
|
|
||||||
if sub:
|
|
||||||
debug('%s-- DIRTY (sub)\n' % depth)
|
|
||||||
dirty = sub
|
|
||||||
else:
|
|
||||||
assert(mode in ('c','m'))
|
|
||||||
if not f.csum:
|
|
||||||
# f is a "normal" target: dirty f2 means f is instantly dirty
|
|
||||||
if dirty:
|
|
||||||
# if dirty==DIRTY, this means f is definitely dirty.
|
|
||||||
# if dirty==[...], it's a list of the uncertain children.
|
|
||||||
return dirty
|
|
||||||
else:
|
|
||||||
# f is "checksummable": dirty f2 means f needs to redo,
|
|
||||||
# but f might turn out to be clean after that (ie. our parent
|
|
||||||
# might not be dirty).
|
|
||||||
if dirty == DIRTY:
|
|
||||||
# f2 is definitely dirty, so f definitely needs to
|
|
||||||
# redo. However, after that, f might turn out to be
|
|
||||||
# unchanged.
|
|
||||||
return [f]
|
|
||||||
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
|
|
||||||
|
|
||||||
if must_build:
|
|
||||||
# f is *maybe* dirty because at least one of its children is maybe
|
|
||||||
# dirty. must_build has accumulated a list of "topmost" uncertain
|
|
||||||
# objects in the tree. If we build all those, we can then
|
|
||||||
# redo-ifchange f and it won't have any uncertainty next time.
|
|
||||||
return must_build
|
|
||||||
|
|
||||||
# if we get here, it's because the target is clean
|
|
||||||
if f.is_override:
|
|
||||||
builder.warn_override(f.name)
|
|
||||||
f.set_checked()
|
|
||||||
f.save()
|
|
||||||
return CLEAN
|
|
||||||
|
|
||||||
|
|
||||||
def should_build(t):
|
def should_build(t):
|
||||||
f = state.File(name=t)
|
f = state.File(name=t)
|
||||||
if f.is_failed():
|
if f.is_failed():
|
||||||
raise builder.ImmediateReturn(32)
|
raise builder.ImmediateReturn(32)
|
||||||
dirty = dirty_deps(f, depth = '', max_changed = vars.RUNID)
|
dirty = deps.isdirty(f, depth = '', max_changed = vars.RUNID)
|
||||||
return dirty==[f] and DIRTY or dirty
|
return dirty==[f] and deps.DIRTY or dirty
|
||||||
|
|
||||||
|
|
||||||
rv = 202
|
rv = 202
|
||||||
|
|
|
||||||
6
state.py
6
state.py
|
|
@ -1,7 +1,7 @@
|
||||||
import sys, os, errno, glob, stat, fcntl, sqlite3
|
import sys, os, errno, glob, stat, fcntl, sqlite3
|
||||||
import vars
|
import vars
|
||||||
from helpers import unlink, close_on_exec, join
|
from helpers import unlink, close_on_exec, join
|
||||||
from log import err, debug2, debug3
|
from log import warn, err, debug2, debug3
|
||||||
|
|
||||||
SCHEMA_VER=1
|
SCHEMA_VER=1
|
||||||
TIMEOUT=60
|
TIMEOUT=60
|
||||||
|
|
@ -132,6 +132,10 @@ def relpath(t, base):
|
||||||
return join('/', tparts)
|
return join('/', tparts)
|
||||||
|
|
||||||
|
|
||||||
|
def warn_override(name):
|
||||||
|
warn('%s - you modified it; skipping\n' % name)
|
||||||
|
|
||||||
|
|
||||||
_file_cols = ['rowid', 'name', 'is_generated', 'is_override',
|
_file_cols = ['rowid', 'name', 'is_generated', 'is_override',
|
||||||
'checked_runid', 'changed_runid', 'failed_runid',
|
'checked_runid', 'changed_runid', 'failed_runid',
|
||||||
'stamp', 'csum']
|
'stamp', 'csum']
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue