If a user manually changes a generated file, don't ever overwrite it.
That way the user can modify an auto-generated 'compile' script, for example, and it'll stay modified. If they delete the file, we can then generate it for them again. Also, we have to warn whenever we're doing this, or people might think it's a bug.
This commit is contained in:
parent
0126f6be1e
commit
f6d11d5411
4 changed files with 44 additions and 11 deletions
15
builder.py
15
builder.py
|
|
@ -42,6 +42,10 @@ 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)
|
||||||
|
|
@ -69,6 +73,16 @@ class BuildJob:
|
||||||
return self._after2(0)
|
return self._after2(0)
|
||||||
except ImmediateReturn, e:
|
except ImmediateReturn, e:
|
||||||
return self._after2(e.rv)
|
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 + '/.')
|
if (os.path.exists(t) and not os.path.exists(t + '/.')
|
||||||
and not sf.is_generated):
|
and not sf.is_generated):
|
||||||
# an existing source file that was not generated by us.
|
# an existing source file that was not generated by us.
|
||||||
|
|
@ -87,7 +101,6 @@ class BuildJob:
|
||||||
(dofile, basename, ext) = _find_do_file(sf)
|
(dofile, basename, ext) = _find_do_file(sf)
|
||||||
if not dofile:
|
if not dofile:
|
||||||
if os.path.exists(t):
|
if os.path.exists(t):
|
||||||
sf.is_generated = False
|
|
||||||
sf.set_static()
|
sf.set_static()
|
||||||
sf.save()
|
sf.save()
|
||||||
return self._after2(0)
|
return self._after2(0)
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,9 @@ from helpers import debug, debug2, err, unlink
|
||||||
def dirty_deps(f, depth, max_changed):
|
def dirty_deps(f, depth, max_changed):
|
||||||
if vars.DEBUG >= 1: debug('%s?%s\n' % (depth, f.name))
|
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:
|
if f.changed_runid == None:
|
||||||
debug('%s-- DIRTY (never built)\n' % depth)
|
debug('%s-- DIRTY (never built)\n' % depth)
|
||||||
return True
|
return True
|
||||||
|
|
@ -35,6 +38,8 @@ def dirty_deps(f, depth, max_changed):
|
||||||
max_changed = f.changed_runid):
|
max_changed = f.changed_runid):
|
||||||
debug('%s-- DIRTY (sub)\n' % depth)
|
debug('%s-- DIRTY (sub)\n' % depth)
|
||||||
return True
|
return True
|
||||||
|
if f.is_override:
|
||||||
|
builder.warn_override(f.name)
|
||||||
f.set_checked()
|
f.set_checked()
|
||||||
f.save()
|
f.save()
|
||||||
return False
|
return False
|
||||||
|
|
|
||||||
31
state.py
31
state.py
|
|
@ -6,6 +6,10 @@ import helpers
|
||||||
SCHEMA_VER=1
|
SCHEMA_VER=1
|
||||||
TIMEOUT=60
|
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):
|
def _connect(dbfile):
|
||||||
_db = sqlite3.connect(dbfile, timeout=TIMEOUT)
|
_db = sqlite3.connect(dbfile, timeout=TIMEOUT)
|
||||||
_db.execute("pragma synchronous = off")
|
_db.execute("pragma synchronous = off")
|
||||||
|
|
@ -57,6 +61,7 @@ def db():
|
||||||
_db.execute("create table Files "
|
_db.execute("create table Files "
|
||||||
" (name not null primary key, "
|
" (name not null primary key, "
|
||||||
" is_generated int, "
|
" is_generated int, "
|
||||||
|
" is_override int, "
|
||||||
" checked_runid int, "
|
" checked_runid int, "
|
||||||
" changed_runid int, "
|
" changed_runid int, "
|
||||||
" failed_runid int, "
|
" failed_runid int, "
|
||||||
|
|
@ -134,19 +139,19 @@ def relpath(t, base):
|
||||||
|
|
||||||
class File(object):
|
class File(object):
|
||||||
# use this mostly to avoid accidentally assigning to typos
|
# 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',
|
'checked_runid', 'changed_runid', 'failed_runid',
|
||||||
'stamp', 'csum']
|
'stamp', 'csum']
|
||||||
|
|
||||||
def _init_from_cols(self, cols):
|
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.checked_runid, self.changed_runid, self.failed_runid,
|
||||||
self.stamp, self.csum) = cols
|
self.stamp, self.csum) = cols
|
||||||
|
|
||||||
def __init__(self, id=None, name=None, cols=None):
|
def __init__(self, id=None, name=None, cols=None):
|
||||||
if cols:
|
if cols:
|
||||||
return self._init_from_cols(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, '
|
' checked_runid, changed_runid, failed_runid, '
|
||||||
' stamp, csum '
|
' stamp, csum '
|
||||||
' from Files ')
|
' from Files ')
|
||||||
|
|
@ -177,11 +182,11 @@ class File(object):
|
||||||
|
|
||||||
def save(self):
|
def save(self):
|
||||||
_write('update Files set '
|
_write('update Files set '
|
||||||
' is_generated=?, '
|
' is_generated=?, is_override=?, '
|
||||||
' checked_runid=?, changed_runid=?, failed_runid=?, '
|
' checked_runid=?, changed_runid=?, failed_runid=?, '
|
||||||
' stamp=?, csum=? '
|
' stamp=?, csum=? '
|
||||||
' where rowid=?',
|
' where rowid=?',
|
||||||
[self.is_generated,
|
[self.is_generated, self.is_override,
|
||||||
self.checked_runid, self.changed_runid, self.failed_runid,
|
self.checked_runid, self.changed_runid, self.failed_runid,
|
||||||
self.stamp, self.csum,
|
self.stamp, self.csum,
|
||||||
self.id])
|
self.id])
|
||||||
|
|
@ -192,13 +197,23 @@ class File(object):
|
||||||
def set_changed(self):
|
def set_changed(self):
|
||||||
debug2('BUILT: %r (%r)\n' % (self.name, self.stamp))
|
debug2('BUILT: %r (%r)\n' % (self.name, self.stamp))
|
||||||
self.changed_runid = vars.RUNID
|
self.changed_runid = vars.RUNID
|
||||||
|
self.failed_runid = None
|
||||||
|
self.is_override = False
|
||||||
|
|
||||||
def set_failed(self):
|
def set_failed(self):
|
||||||
debug2('FAILED: %r\n' % self.name)
|
debug2('FAILED: %r\n' % self.name)
|
||||||
|
self.update_stamp()
|
||||||
self.failed_runid = vars.RUNID
|
self.failed_runid = vars.RUNID
|
||||||
|
self.is_generated = True
|
||||||
|
|
||||||
def set_static(self):
|
def set_static(self):
|
||||||
self.update_stamp()
|
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):
|
def update_stamp(self):
|
||||||
newstamp = self.read_stamp()
|
newstamp = self.read_stamp()
|
||||||
|
|
@ -218,7 +233,7 @@ class File(object):
|
||||||
|
|
||||||
def deps(self):
|
def deps(self):
|
||||||
q = ('select Deps.mode, Deps.source, '
|
q = ('select Deps.mode, Deps.source, '
|
||||||
' name, is_generated, '
|
' name, is_generated, is_override, '
|
||||||
' checked_runid, changed_runid, failed_runid, '
|
' checked_runid, changed_runid, failed_runid, '
|
||||||
' stamp, csum '
|
' stamp, csum '
|
||||||
' from Files '
|
' from Files '
|
||||||
|
|
@ -247,9 +262,9 @@ class File(object):
|
||||||
try:
|
try:
|
||||||
st = os.stat(os.path.join(vars.BASE, self.name))
|
st = os.stat(os.path.join(vars.BASE, self.name))
|
||||||
except OSError:
|
except OSError:
|
||||||
return '0' # does not exist
|
return STAMP_MISSING
|
||||||
if stat.S_ISDIR(st.st_mode):
|
if stat.S_ISDIR(st.st_mode):
|
||||||
return 'dir' # the timestamp of a directory is meaningless
|
return STAMP_DIR
|
||||||
else:
|
else:
|
||||||
# a "unique identifier" stamp for a regular file
|
# a "unique identifier" stamp for a regular file
|
||||||
return str((st.st_ctime, st.st_mtime, st.st_size, st.st_ino))
|
return str((st.st_ctime, st.st_mtime, st.st_size, st.st_ino))
|
||||||
|
|
|
||||||
|
|
@ -5,5 +5,5 @@
|
||||||
echo "pragma synchronous = off;"
|
echo "pragma synchronous = off;"
|
||||||
echo "update Files set checked_runid=null, " \
|
echo "update Files set checked_runid=null, " \
|
||||||
" changed_runid=changed_runid-1, " \
|
" changed_runid=changed_runid-1, " \
|
||||||
" failed_runid=null;"
|
" failed_runid=failed_runid-1;"
|
||||||
) | sqlite3 "$REDO_BASE/.redo/db.sqlite3"
|
) | sqlite3 "$REDO_BASE/.redo/db.sqlite3"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue