diff --git a/builder.py b/builder.py index 06ccbb3..416120f 100644 --- a/builder.py +++ b/builder.py @@ -42,6 +42,10 @@ def _try_stat(filename): raise +def warn_override(name): + warn('%s - you modified it; skipping\n' % name) + + class ImmediateReturn(Exception): def __init__(self, rv): Exception.__init__(self, "immediate return with exit code %d" % rv) @@ -69,6 +73,16 @@ class BuildJob: return self._after2(0) except ImmediateReturn, e: return self._after2(e.rv) + newstamp = sf.read_stamp() + if (sf.is_generated and + not sf.failed_runid and + newstamp != state.STAMP_MISSING and + (sf.stamp != newstamp or sf.is_override)): + warn_override(_nice(t)) + sf.set_override() + sf.set_checked() + sf.save() + return self._after2(0) if (os.path.exists(t) and not os.path.exists(t + '/.') and not sf.is_generated): # an existing source file that was not generated by us. @@ -87,7 +101,6 @@ class BuildJob: (dofile, basename, ext) = _find_do_file(sf) if not dofile: if os.path.exists(t): - sf.is_generated = False sf.set_static() sf.save() return self._after2(0) @@ -176,7 +189,7 @@ class BuildJob: else: unlink(tmpname) sf = self.sf - sf.is_generated=True + sf.is_generated = True sf.update_stamp() sf.set_changed() sf.save() diff --git a/redo-ifchange.py b/redo-ifchange.py index fb5af22..1670163 100755 --- a/redo-ifchange.py +++ b/redo-ifchange.py @@ -7,6 +7,9 @@ from helpers import debug, debug2, err, unlink def dirty_deps(f, depth, max_changed): if vars.DEBUG >= 1: debug('%s?%s\n' % (depth, f.name)) + if f.failed_runid: + debug('%s-- DIRTY (failed last time)\n' % depth) + return True if f.changed_runid == None: debug('%s-- DIRTY (never built)\n' % depth) return True @@ -35,6 +38,8 @@ def dirty_deps(f, depth, max_changed): max_changed = f.changed_runid): debug('%s-- DIRTY (sub)\n' % depth) return True + if f.is_override: + builder.warn_override(f.name) f.set_checked() f.save() return False diff --git a/state.py b/state.py index 4ecc254..d6bd56c 100644 --- a/state.py +++ b/state.py @@ -6,6 +6,10 @@ import helpers SCHEMA_VER=1 TIMEOUT=60 +STAMP_DIR='dir' # the stamp of a directory; mtime is unhelpful +STAMP_MISSING='0' # the stamp of a nonexistent file + + def _connect(dbfile): _db = sqlite3.connect(dbfile, timeout=TIMEOUT) _db.execute("pragma synchronous = off") @@ -57,6 +61,7 @@ def db(): _db.execute("create table Files " " (name not null primary key, " " is_generated int, " + " is_override int, " " checked_runid int, " " changed_runid int, " " failed_runid int, " @@ -134,19 +139,19 @@ def relpath(t, base): class File(object): # use this mostly to avoid accidentally assigning to typos - __slots__ = ['id', 'name', 'is_generated', + __slots__ = ['id', 'name', 'is_generated', 'is_override', 'checked_runid', 'changed_runid', 'failed_runid', 'stamp', 'csum'] def _init_from_cols(self, cols): - (self.id, self.name, self.is_generated, + (self.id, self.name, self.is_generated, self.is_override, self.checked_runid, self.changed_runid, self.failed_runid, self.stamp, self.csum) = cols def __init__(self, id=None, name=None, cols=None): if cols: return self._init_from_cols(cols) - q = ('select rowid, name, is_generated, ' + q = ('select rowid, name, is_generated, is_override, ' ' checked_runid, changed_runid, failed_runid, ' ' stamp, csum ' ' from Files ') @@ -177,11 +182,11 @@ class File(object): def save(self): _write('update Files set ' - ' is_generated=?, ' + ' is_generated=?, is_override=?, ' ' checked_runid=?, changed_runid=?, failed_runid=?, ' ' stamp=?, csum=? ' ' where rowid=?', - [self.is_generated, + [self.is_generated, self.is_override, self.checked_runid, self.changed_runid, self.failed_runid, self.stamp, self.csum, self.id]) @@ -192,13 +197,23 @@ class File(object): def set_changed(self): debug2('BUILT: %r (%r)\n' % (self.name, self.stamp)) self.changed_runid = vars.RUNID + self.failed_runid = None + self.is_override = False def set_failed(self): debug2('FAILED: %r\n' % self.name) + self.update_stamp() self.failed_runid = vars.RUNID + self.is_generated = True def set_static(self): self.update_stamp() + self.is_override = False + self.is_generated = False + + def set_override(self): + self.update_stamp() + self.is_override = True def update_stamp(self): newstamp = self.read_stamp() @@ -218,7 +233,7 @@ class File(object): def deps(self): q = ('select Deps.mode, Deps.source, ' - ' name, is_generated, ' + ' name, is_generated, is_override, ' ' checked_runid, changed_runid, failed_runid, ' ' stamp, csum ' ' from Files ' @@ -247,9 +262,9 @@ class File(object): try: st = os.stat(os.path.join(vars.BASE, self.name)) except OSError: - return '0' # does not exist + return STAMP_MISSING if stat.S_ISDIR(st.st_mode): - return 'dir' # the timestamp of a directory is meaningless + return STAMP_DIR else: # a "unique identifier" stamp for a regular file return str((st.st_ctime, st.st_mtime, st.st_size, st.st_ino)) diff --git a/t/flush-cache.sh b/t/flush-cache.sh index f44286d..4a28210 100755 --- a/t/flush-cache.sh +++ b/t/flush-cache.sh @@ -5,5 +5,5 @@ echo "pragma synchronous = off;" echo "update Files set checked_runid=null, " \ " changed_runid=changed_runid-1, " \ - " failed_runid=null;" + " failed_runid=failed_runid-1;" ) | sqlite3 "$REDO_BASE/.redo/db.sqlite3"