Is there a way to emulate Make's .DELETE_ON_FAILURE
behavior? If I have a builder that executes a series of Actions to produce a target, I would expect them to operate atomically. If an earlier Action produces an (incomplete) file, and a later action fails to modify it, I would like the target file to be deleted, instead of remaining in its incomplete state.
Consider this SConstruct file:
def example(target, source, env):
raise Exception('failure')
# more processing that never happens...
action_list = [
Copy('$TARGET', '$SOURCE'),
Chmod('$TARGET', 0755),
example,
]
Command(
action = action_list,
target = 'foo.out',
source = 'foo.in',
)
If the example
action fails, foo.out
still exists, because the first two actions were successful. However, it is incomplete.
Interestingly, running scons
again causes is to again retry to build foo.out
, even though it exists in the filesystem.
Yes, what you are looking for is GetBuildFailures.
Expanding on your example to include this feature...
import atexit
import os
def delete_on_failure():
from SCons.Script import GetBuildFailures
for bf in GetBuildFailures():
if os.path.isfile(bf.node.abspath):
print 'Removing %s' % bf.node.path
os.remove(bf.node.abspath)
atexit.register(delete_on_failure)
def example(target, source, env):
raise Exception('failure')
# more processing that never happens...
action_list = [
Copy('$TARGET', '$SOURCE'),
Chmod('$TARGET', 0755),
example,
]
Command(
action = action_list,
target = 'foo.out',
source = 'foo.in',
)
Which when run produces the following...
>> scons --version
SCons by Steven Knight et al.:
script: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
engine: v2.3.4, 2014/09/27 12:51:43, by garyo on lubuntu
engine path: ['/usr/lib/scons/SCons']
Copyright (c) 2001 - 2014 The SCons Foundation
>> tree
.
├── foo.in
└── SConstruct
0 directories, 2 files
>> scons
scons: Reading SConscript files ...
scons: done reading SConscript files.
scons: Building targets ...
Copy("foo.out", "foo.in")
Chmod("foo.out", 0755)
example(["foo.out"], ["foo.in"])
scons: *** [foo.out] Exception : failure
Traceback (most recent call last):
File "/usr/lib/scons/SCons/Action.py", line 1065, in execute
result = self.execfunction(target=target, source=rsources, env=env)
File "/path/to/SConstruct", line 13, in example
raise Exception('failure')
Exception: failure
scons: building terminated because of errors.
Removing foo.out
>> tree
.
├── foo.in
└── SConstruct
0 directories, 2 files