Use a single .redo dir for the entire build.

This commit is contained in:
Avery Pennarun 2010-11-12 22:47:03 -08:00
commit 425a295d6f
4 changed files with 42 additions and 28 deletions

13
TODO
View file

@ -1,13 +0,0 @@
.gitignore
jwack jobserver
make compatibility
sockety interface
sqlite .redo database?
rename --ifchange/--ifcreate to separate programs
rewrite ifchange/ifcreate in C
always update database atomically?
find the right .repo dir automatically
cd into subdir automatically
'redo clean' should work
aggressively mark stuff as done in the .redo database

46
redo.py
View file

@ -17,6 +17,23 @@ o = options.Options('redo', optspec)
targets = extra or ['it'] targets = extra or ['it']
def sname(typ, t):
# FIXME: t.replace(...) is non-reversible and non-unique here!
t = os.path.abspath(t)
tparts = t.split('/')
bparts = REDO_BASE.split('/')
for tp,bp in zip(tparts,bparts):
if tp != bp:
break
tparts.pop(0)
bparts.pop(0)
while bparts:
tparts.insert(0, '..')
bparts.pop(0)
tnew = '/'.join(tparts)
return REDO_BASE + ('/.redo/%s^%s' % (typ, tnew.replace('/', '^')))
def log(s): def log(s):
sys.stdout.flush() sys.stdout.flush()
sys.stderr.write('redo: %s%s' % (REDO_DEPTH, s)) sys.stderr.write('redo: %s%s' % (REDO_DEPTH, s))
@ -29,7 +46,7 @@ def debug(s):
def add_dep(t, mode, dep): def add_dep(t, mode, dep):
open('.redo/dep.%s' % t, 'a').write('%s %s\n' % (mode, dep)) open(sname('dep', t), 'a').write('%s %s\n' % (mode, dep))
def find_do_file(t): def find_do_file(t):
@ -46,11 +63,11 @@ def find_do_file(t):
def _dirty_deps(t, depth): def _dirty_deps(t, depth):
debug('%s?%s\n' % (depth, t)) debug('%s?%s\n' % (depth, t))
if not os.path.exists('.redo/stamp.%s' % t): if not os.path.exists(sname('stamp', t)):
debug('%s-- DIRTY (no stamp)\n' % depth) debug('%s-- DIRTY (no stamp)\n' % depth)
return True return True
stamptime = os.stat('.redo/stamp.%s' % t).st_mtime stamptime = os.stat(sname('stamp', t)).st_mtime
try: try:
realtime = os.stat(t).st_mtime realtime = os.stat(t).st_mtime
except OSError: except OSError:
@ -60,7 +77,7 @@ def _dirty_deps(t, depth):
debug('%s-- DIRTY (mtime)\n' % depth) debug('%s-- DIRTY (mtime)\n' % depth)
return True return True
for sub in open('.redo/dep.%s' % t).readlines(): for sub in open(sname('dep', t)).readlines():
assert(sub[0] in ('c','m')) assert(sub[0] in ('c','m'))
assert(sub[1] == ' ') assert(sub[1] == ' ')
assert(sub[-1] == '\n') assert(sub[-1] == '\n')
@ -79,13 +96,13 @@ def _dirty_deps(t, depth):
def dirty_deps(t, depth): def dirty_deps(t, depth):
if _dirty_deps(t, depth): if _dirty_deps(t, depth):
unlink('.redo/stamp.%s' % t) # short circuit future checks unlink(sname('stamp', t)) # short circuit future checks
return True return True
return False return False
def stamp(t): def stamp(t):
stampfile = '.redo/stamp.%s' % t stampfile = sname('stamp', t)
open(stampfile, 'w').close() open(stampfile, 'w').close()
try: try:
mtime = os.stat(t).st_mtime mtime = os.stat(t).st_mtime
@ -100,8 +117,8 @@ def _preexec(t):
def build(t): def build(t):
unlink('.redo/dep.%s' % t) unlink(sname('dep', t))
open('.redo/dep.%s' % t, 'w').close() open(sname('dep', t), 'w').close()
dofile = find_do_file(t) dofile = find_do_file(t)
if not dofile: if not dofile:
if os.path.exists(t): # an existing source file if os.path.exists(t): # an existing source file
@ -121,7 +138,7 @@ def build(t):
stdout=f.fileno()) stdout=f.fileno())
st = os.stat(tmpname) st = os.stat(tmpname)
#log('rv: %d (%d bytes) (%r)\n' % (rv, st.st_size, dofile)) #log('rv: %d (%d bytes) (%r)\n' % (rv, st.st_size, dofile))
stampfile = '.redo/stamp.%s' % t stampfile = sname('stamp', t)
if rv==0: if rv==0:
if st.st_size: if st.st_size:
os.rename(tmpname, t) os.rename(tmpname, t)
@ -142,12 +159,13 @@ if opt.verbose:
os.putenv('REDO_VERBOSE', '1') os.putenv('REDO_VERBOSE', '1')
assert(not (opt.ifchange and opt.ifcreate)) assert(not (opt.ifchange and opt.ifcreate))
REDO_TARGET = os.getenv('REDO_TARGET', '') if not os.getenv('REDO_BASE', ''):
REDO_DEPTH = os.getenv('REDO_DEPTH', '') base = os.path.commonprefix([os.path.abspath(os.path.dirname(t))
REDO_DEBUG = os.getenv('REDO_DEBUG', '') and 1 or 0 for t in targets])
REDO_VERBOSE = os.getenv('REDO_VERBOSE', '') and 1 or 0 os.putenv('REDO_BASE', base)
mkdirp('%s/.redo' % base)
mkdirp('.redo') from vars import *
if not REDO_DEPTH: if not REDO_DEPTH:
# toplevel call to redo # toplevel call to redo

View file

@ -1,2 +1,2 @@
redo --ifchange CC hello.c redo --ifchange CC hello.c /usr/include/stdio.h
./CC hello.c ./CC hello.c

9
vars.py Normal file
View file

@ -0,0 +1,9 @@
import os
REDO_TARGET = os.getenv('REDO_TARGET', '')
REDO_DEPTH = os.getenv('REDO_DEPTH', '')
REDO_DEBUG = os.getenv('REDO_DEBUG', '') and 1 or 0
REDO_VERBOSE = os.getenv('REDO_VERBOSE', '') and 1 or 0
REDO_BASE = os.path.abspath(os.getenv('REDO_BASE', ''))
while REDO_BASE.endswith('/'):
REDO_BASE = REDO_BASE[:-1]