We already printed an error at build time, but added the broken dependency anyway. If the .do script decided to succeed despite redo-ifchange aborting, the target would be successfully created and we'd end up with an infinite loop when running isdirty() later. The result was still "correct", because python helpfully aborted the infinite loop after the recursion got too deep. But let's explicitly detect it and print a better error message. (Thanks to Nils Dagsson Moskopp's redo-testcases repo for exposing this problem. If you put a #!/bin/sh header on your .do script means you need to run 'set -e' yourself if you want .do scripts to abort after an error, which you almost always do, and those testcases don't, which exposed this bug if you ran the tests twice.)
46 lines
1.2 KiB
Python
Executable file
46 lines
1.2 KiB
Python
Executable file
#!/usr/bin/env python
|
|
import sys, os
|
|
|
|
import vars_init
|
|
vars_init.init(sys.argv[1:])
|
|
|
|
import vars, state, builder, jwack, deps
|
|
from helpers import unlink
|
|
from log import debug, debug2, err
|
|
|
|
def should_build(t):
|
|
f = state.File(name=t)
|
|
if f.is_failed():
|
|
raise builder.ImmediateReturn(32)
|
|
dirty = deps.isdirty(f, depth = '', max_changed = vars.RUNID,
|
|
already_checked=[])
|
|
return dirty==[f] and deps.DIRTY or dirty
|
|
|
|
|
|
rv = 202
|
|
try:
|
|
if vars.TARGET and not vars.UNLOCKED:
|
|
me = os.path.join(vars.STARTDIR,
|
|
os.path.join(vars.PWD, vars.TARGET))
|
|
f = state.File(name=me)
|
|
debug2('TARGET: %r %r %r\n' % (vars.STARTDIR, vars.PWD, vars.TARGET))
|
|
else:
|
|
f = me = None
|
|
debug2('redo-ifchange: not adding depends.\n')
|
|
try:
|
|
targets = sys.argv[1:]
|
|
if f:
|
|
for t in targets:
|
|
f.add_dep('m', t)
|
|
f.save()
|
|
state.commit()
|
|
rv = builder.main(targets, should_build)
|
|
finally:
|
|
try:
|
|
state.rollback()
|
|
finally:
|
|
jwack.force_return_tokens()
|
|
except KeyboardInterrupt:
|
|
sys.exit(200)
|
|
state.commit()
|
|
sys.exit(rv)
|