From c57de820fba03f474b24060ab918a129567b52af Mon Sep 17 00:00:00 2001 From: Avery Pennarun Date: Sat, 13 Nov 2010 00:45:49 -0800 Subject: [PATCH] Move 'redo --ifchange' into 'redo-ifchange' to match djb's style. It does simplify the logic of both redo.py and redo-ifchange.py, I suppose. --- libdo.py | 27 +++++++++++++++ redo-ifchange | 1 + redo-ifchange.py | 61 ++++++++++++++++++++++++++++++++++ redo.py | 85 ++++-------------------------------------------- t/bellow.do | 2 +- t/hello.do | 2 +- t/hello.o.do | 2 +- t/it.do | 2 +- t/runtests.do | 2 +- t/yellow.do | 2 +- t/yellow.o.do | 2 +- test.do | 2 +- 12 files changed, 103 insertions(+), 87 deletions(-) create mode 100644 libdo.py create mode 120000 redo-ifchange create mode 100755 redo-ifchange.py diff --git a/libdo.py b/libdo.py new file mode 100644 index 0000000..0cd859a --- /dev/null +++ b/libdo.py @@ -0,0 +1,27 @@ +import sys, os +import vars + +def relpath(t, base): + t = os.path.abspath(t) + tparts = t.split('/') + bparts = 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) + return '/'.join(tparts) + + +def sname(typ, t): + # FIXME: t.replace(...) is non-reversible and non-unique here! + tnew = relpath(t, vars.BASE) + #log('sname: (%r) %r -> %r\n' % (vars.BASE, t, tnew)) + return vars.BASE + ('/.redo/%s^%s' % (typ, tnew.replace('/', '^'))) + + +def add_dep(t, mode, dep): + open(sname('dep', t), 'a').write('%s %s\n' % (mode, dep)) diff --git a/redo-ifchange b/redo-ifchange new file mode 120000 index 0000000..28bfe24 --- /dev/null +++ b/redo-ifchange @@ -0,0 +1 @@ +redo-ifchange.py \ No newline at end of file diff --git a/redo-ifchange.py b/redo-ifchange.py new file mode 100755 index 0000000..07a9a39 --- /dev/null +++ b/redo-ifchange.py @@ -0,0 +1,61 @@ +#!/usr/bin/python +import sys, os +import vars +from helpers import * +from log import * +from libdo import * + + +def _dirty_deps(t, depth): + debug('%s?%s\n' % (depth, t)) + if not os.path.exists(sname('stamp', t)): + debug('%s-- DIRTY (no stamp)\n' % depth) + return True + + stamptime = os.stat(sname('stamp', t)).st_mtime + try: + realtime = os.stat(t).st_mtime + except OSError: + realtime = 0 + + if stamptime != realtime: + debug('%s-- DIRTY (mtime)\n' % depth) + return True + + for sub in open(sname('dep', t)).readlines(): + assert(sub[0] in ('c','m')) + assert(sub[1] == ' ') + assert(sub[-1] == '\n') + mode = sub[0] + name = sub[2:-1] + if mode == 'c': + if os.path.exists(name): + debug('%s-- DIRTY (created)\n' % depth) + return True + elif mode == 'm': + if dirty_deps(name, depth + ' '): + #debug('%s-- DIRTY (sub)\n' % depth) + return True + return False + + +def dirty_deps(t, depth): + if _dirty_deps(t, depth): + unlink(sname('stamp', t)) # short circuit future checks + return True + return False + + +if not vars.TARGET: + sys.stderr.write('redo-ifchange: error: must be run from inside a .do\n') + sys.exit(1) + +want_build = [] +for t in sys.argv[1:]: + mkdirp('%s/.redo' % vars.BASE) + add_dep(vars.TARGET, 'm', t) + if dirty_deps(t, depth = ''): + want_build.append(t) + +if want_build: + os.execvp('redo', ['redo', '--'] + want_build) diff --git a/redo.py b/redo.py index 09aca04..e1bdb92 100755 --- a/redo.py +++ b/redo.py @@ -8,8 +8,6 @@ redo [targets...] -- d,debug print dependency checks as they happen v,verbose print commands as they are run -ifchange only redo if the file is modified or deleted -ifcreate only redo if the file is created """ o = options.Options('redo', optspec) (opt, flags, extra) = o.parse(sys.argv[1:]) @@ -17,90 +15,24 @@ o = options.Options('redo', optspec) targets = extra or ['it'] -def relpath(t, base): - t = os.path.abspath(t) - tparts = t.split('/') - bparts = 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) - return '/'.join(tparts) - - -def sname(typ, t): - # FIXME: t.replace(...) is non-reversible and non-unique here! - tnew = relpath(t, vars.BASE) - #log('sname: (%r) %r -> %r\n' % (vars.BASE, t, tnew)) - return vars.BASE + ('/.redo/%s^%s' % (typ, tnew.replace('/', '^'))) - - -def add_dep(t, mode, dep): - open(sname('dep', t), 'a').write('%s %s\n' % (mode, dep)) - - def find_do_file(t): dofile = '%s.do' % t if os.path.exists(dofile): add_dep(t, 'm', dofile) - if dirty_deps(dofile, depth = ''): - build(dofile) return dofile else: add_dep(t, 'c', dofile) return None -def _dirty_deps(t, depth): - debug('%s?%s\n' % (depth, t)) - if not os.path.exists(sname('stamp', t)): - debug('%s-- DIRTY (no stamp)\n' % depth) - return True - - stamptime = os.stat(sname('stamp', t)).st_mtime - try: - realtime = os.stat(t).st_mtime - except OSError: - realtime = 0 - - if stamptime != realtime: - debug('%s-- DIRTY (mtime)\n' % depth) - return True - - for sub in open(sname('dep', t)).readlines(): - assert(sub[0] in ('c','m')) - assert(sub[1] == ' ') - assert(sub[-1] == '\n') - mode = sub[0] - name = sub[2:-1] - if mode == 'c': - if os.path.exists(name): - debug('%s-- DIRTY (created)\n' % depth) - return True - elif mode == 'm': - if dirty_deps(name, depth + ' '): - #debug('%s-- DIRTY (sub)\n' % depth) - return True - return False - - -def dirty_deps(t, depth): - if _dirty_deps(t, depth): - unlink(sname('stamp', t)) # short circuit future checks - return True - return False - - def stamp(t): stampfile = sname('stamp', t) + depfile = sname('dep', t) if not os.path.exists(vars.BASE + '/.redo'): # .redo might not exist in a 'make clean' target return open(stampfile, 'w').close() + open(depfile, 'a').close() try: mtime = os.stat(t).st_mtime except OSError: @@ -126,6 +58,7 @@ def build(t): return # success else: raise Exception('no rule to make %r' % t) + stamp(dofile) unlink(t) tmpname = '%s.redo.tmp' % t unlink(tmpname) @@ -158,7 +91,6 @@ if opt.debug: os.environ['REDO_DEBUG'] = '1' if opt.verbose: os.environ['REDO_VERBOSE'] = '1' -assert(not (opt.ifchange and opt.ifcreate)) if not os.environ.get('REDO_BASE', ''): base = os.path.commonprefix([os.path.abspath(os.path.dirname(t)) @@ -173,6 +105,7 @@ if not os.environ.get('REDO_BASE', ''): import vars from log import * +from libdo import * if not vars.DEPTH: # toplevel call to redo @@ -188,11 +121,5 @@ for t in targets: os.chdir(startdir) if vars.TARGET: - add_dep(vars.TARGET, opt.ifcreate and 'c' or 'm', t) - if opt.ifcreate: - pass # just adding the dependency (above) is enough - elif opt.ifchange: - if dirty_deps(t, depth = ''): - build(t) - else: - build(t) + add_dep(vars.TARGET, 'm', t) + build(t) diff --git a/t/bellow.do b/t/bellow.do index 9ab2cf2..748ef62 100644 --- a/t/bellow.do +++ b/t/bellow.do @@ -1,2 +1,2 @@ -redo --ifchange LD yellow.o +redo-ifchange LD yellow.o ./LD bellow yellow.o diff --git a/t/hello.do b/t/hello.do index 8398122..e2c2bb9 100644 --- a/t/hello.do +++ b/t/hello.do @@ -1,2 +1,2 @@ -redo --ifchange LD hello.o +redo-ifchange LD hello.o ./LD hello hello.o diff --git a/t/hello.o.do b/t/hello.o.do index deac360..543adfa 100644 --- a/t/hello.o.do +++ b/t/hello.o.do @@ -1,2 +1,2 @@ -redo --ifchange CC hello.c /usr/include/stdio.h +redo-ifchange CC hello.c /usr/include/stdio.h ./CC hello.c diff --git a/t/it.do b/t/it.do index 9489b33..da328b3 100644 --- a/t/it.do +++ b/t/it.do @@ -1,2 +1,2 @@ -redo --ifchange hello yellow bellow +redo-ifchange hello yellow bellow diff --git a/t/runtests.do b/t/runtests.do index 3ef758a..a6be69e 100644 --- a/t/runtests.do +++ b/t/runtests.do @@ -1,2 +1,2 @@ -redo --ifchange it +redo-ifchange it ./hello >&2 diff --git a/t/yellow.do b/t/yellow.do index 7faac8f..69d6689 100644 --- a/t/yellow.do +++ b/t/yellow.do @@ -1,2 +1,2 @@ -redo --ifchange LD yellow.o +redo-ifchange LD yellow.o ./LD yellow yellow.o diff --git a/t/yellow.o.do b/t/yellow.o.do index 331c775..14bc756 100644 --- a/t/yellow.o.do +++ b/t/yellow.o.do @@ -1,2 +1,2 @@ -redo --ifchange CC hello.c +redo-ifchange CC hello.c gcc -o $3 -c hello.c diff --git a/test.do b/test.do index 41f6f02..fc4e03e 100644 --- a/test.do +++ b/test.do @@ -1,4 +1,4 @@ -redo --ifchange t/it +redo-ifchange t/it wvtestrun redo runtests >&2