.EE
to remove target files under build and export.
+Additional files or directories to remove can be specified using the
+Clean() function.
A subset of a hierarchical tree may be built by
remaining at the top-level directory (where the
-c, --clean, --remove
Clean up by removing all target files for which a construction
command is specified.
+Also remove any files or directories associated to the construction command
+using the Clean() function.
.\" .TP
.\" --cache-disable, --no-cache
is usually safe, and is always more efficient than
.IR duplicate =1.
+.TP
+.RI Clean ( target, files_or_dirs )
+This specifies a list of files or directories which should be removed
+whenever the target is specified with the
+.B -c
+command line option.
+Multiple calls to
+.BR Clean ()
+are legal,
+and create a new target or add files and directories to the
+clean list for the specified target.
+
+Multiple files or directories should be specified
+either as separate arguments to the
+.BR Clean ()
+method, or as a list.
+.BR Clean ()
+will also accept the return value of any of the construction environment
+Builder methods.
+Examples:
+
+.ES
+Clean('foo', ['bar', 'baz'])
+Clean('dist', env.Program('hello', 'hello.c'))
+.EE
+
.TP
.RI Default( targets )
This specifies a list of default targets,
- Remove Python bytecode (*.pyc) files from the scons-local packages.
+ From Steve Leblanc:
+
+ - Add a Clean() method to support removing user-specified targets
+ when using the -c option.
+
From Anthony Roach:
- Add SetJobs() and GetJobs() methods to allow configuration of the
HelpFunction = do_nothing
default_targets = []
+clean_targets = {}
arguments = {}
launch_dir = os.path.abspath(os.curdir)
except ValueError, x:
raise SCons.Errors.UserError, "A positive integer is required: %s"%repr(num)
+def Clean(target, files):
+ target = str(target)
+ if not SCons.Util.is_List(files):
+ files = [files]
+ nodes = []
+ for f in files:
+ if isinstance(f, SCons.Node.Node):
+ nodes.append(f)
+ else:
+ nodes.extend(SCons.Node.arg2nodes(f, SCons.Node.FS.default_fs.Entry))
+ if clean_targets.has_key(target):
+ clean_targets[target].extend(nodes)
+ else:
+ clean_targets[target] = nodes
+
def BuildDefaultGlobals():
"""
Create a dictionary containing all the default globals for
globals['ARGUMENTS'] = arguments
globals['BuildDir'] = BuildDir
globals['Builder'] = SCons.Builder.Builder
+ globals['Clean'] = Clean
globals['CScan'] = SCons.Defaults.CScan
globals['Default'] = Default
globals['Dir'] = SCons.Node.FS.default_fs.Dir
import SCons.Script.SConscript
import SCons.Warnings
from SCons.Optik import OptionParser, SUPPRESS_HELP, OptionValueError
+from SCons.Util import display
#
def show(self):
if self.targets[0].builder or self.targets[0].side_effect:
display("Removed " + str(self.targets[0]))
+ if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])):
+ files = SCons.Script.SConscript.clean_targets[str(self.targets[0])]
+ for f in files:
+ SCons.Utils.fs_delete(str(f), 0)
def remove(self):
if self.targets[0].builder or self.targets[0].side_effect:
else:
if removed:
display("Removed " + str(t))
+ if SCons.Script.SConscript.clean_targets.has_key(str(self.targets[0])):
+ files = SCons.Script.SConscript.clean_targets[str(self.targets[0])]
+ for f in files:
+ SCons.Util.fs_delete(str(f))
execute = remove
sig_module = None
num_jobs = 1 # this is modifed by SConscript.SetJobs()
-def print_it(text):
- print text
-
-display = print_it
-
# Exceptions for this module
class PrintHelp(Exception):
pass
"--touch", action="callback", callback=opt_ignore,
help="Ignored for compatibility.")
- def opt_c(option, opt, value, parser):
- setattr(parser.values, 'clean', 1)
- self.add_option('-c', '--clean', '--remove', action="callback",
- callback=opt_c,
+ self.add_option('-c', '--clean', '--remove', action="store_true",
+ default=0, dest="clean",
help="Remove specified targets and dependencies.")
self.add_option('-C', '--directory', type="string", action = "append",
SCons.Node.FS.execute_actions = None
CleanTask.execute = CleanTask.show
if options.no_progress or options.silent:
- global display
- def dont_print_it(text):
- pass
- display = dont_print_it
+ display.set_mode(0)
if options.silent:
SCons.Action.print_actions = None
if options.directory:
def __cmp__(self, rhs):
return cmp(self.flatdata, str(rhs))
+class DisplayEngine:
+ def __init__(self):
+ self.__call__ = self.print_it
+
+ def print_it(self, text):
+ print text
+
+ def dont_print(self, text):
+ pass
+
+ def set_mode(self, mode):
+ if mode:
+ self.__call__ = self.print_it
+ else:
+ self.__call__ = self.dont_print
+
def scons_subst_list(strSubst, globals, locals, remove=None):
"""
if type(command) is type([]):
command = string.join(command)
return function(env, os.popen(command).read())
+
+def dir_index(directory):
+ files = []
+ for file in os.listdir(directory):
+ fullname = os.path.join(directory, file)
+ files.append(fullname)
+ return files
+
+def fs_delete(path, remove=1):
+ try:
+ if os.path.exists(path):
+ if os.path.isfile(path):
+ if remove: os.unlink(path)
+ display("Removed " + path)
+ elif os.path.isdir(path) and not os.path.islink(path):
+ # delete everything in the dir
+ for p in dir_index(path):
+ if os.path.isfile(p):
+ if remove: os.unlink(p)
+ display("Removed " + p)
+ else:
+ fs_delete(p, remove)
+ # then delete dir itself
+ if remove: os.rmdir(path)
+ display("Removed directory " + path)
+ except OSError, e:
+ print "scons: Could not remove '%s':" % str(t), e.strerror
+
+display = DisplayEngine()
from SCons.Util import *
import TestCmd
+
+class OutBuffer:
+ def __init__(self):
+ self.buffer = ""
+
+ def write(self, str):
+ self.buffer = self.buffer + str
+
+
class UtilTestCase(unittest.TestCase):
def test_subst(self):
"""Test the subst function."""
env=DummyEnv()
res=mapPaths('bleh', dir, env)
assert res[0] == os.path.normpath('foo/bar'), res[1]
-
+
+ def test_display(self):
+ old_stdout = sys.stdout
+ sys.stdout = OutBuffer()
+ SCons.Util.display("line1")
+ display.set_mode(0)
+ SCons.Util.display("line2")
+ display.set_mode(1)
+ SCons.Util.display("line3")
+
+ assert sys.stdout.buffer == "line1\nline3\n"
+ sys.stdout = old_stdout
+
+ def test_fs_delete(self):
+ test = TestCmd.TestCmd(workdir = '')
+ base = test.workpath('')
+ xxx = test.workpath('xxx.xxx')
+ sub1_yyy = test.workpath('sub1', 'yyy.yyy')
+ test.subdir('sub1')
+ test.write(xxx, "\n")
+ test.write(sub1_yyy, "\n")
+
+ old_stdout = sys.stdout
+ sys.stdout = OutBuffer()
+
+ exp = "Removed " + os.path.join(base, sub1_yyy) + '\n' + \
+ "Removed directory " + os.path.join(base, 'sub1') + '\n' + \
+ "Removed " + os.path.join(base, xxx) + '\n' + \
+ "Removed directory " + base + '\n'
+
+ SCons.Util.fs_delete(base, remove=0)
+ assert sys.stdout.buffer == exp
+ assert os.path.exists(sub1_yyy)
+
+ sys.stdout.buffer = ""
+ SCons.Util.fs_delete(base, remove=1)
+ assert sys.stdout.buffer == exp
+ assert not os.path.exists(base)
+
+ test._dirlist = None
+ sys.stdout = old_stdout
+
if __name__ == "__main__":
suite = unittest.makeSuite(UtilTestCase, 'test_')
test.writable('.', 0)
f = open(test.workpath('foo1.out'))
-
test.run(arguments = '-c foo1.out',
stdout = test.wrap_stdout("scons: Could not remove 'foo1.out': Permission denied\n"))
-
test.fail_test(not os.path.exists(test.workpath('foo1.out')))
-
f.close()
+test.writable('.', 1)
+
+test.subdir('subd')
+test.write(['subd', 'foon.in'], "foon.in\n")
+test.write('aux1.x', "aux1.x\n")
+test.write('aux2.x', "aux2.x\n")
+test.write('SConstruct', """
+B = Builder(action = r'%s build.py $TARGETS $SOURCES')
+env = Environment(BUILDERS = { 'B' : B })
+env.B(target = 'foo1.out', source = 'foo1.in')
+env.B(target = 'foo2.out', source = 'foo2.xxx')
+env.B(target = 'foo2.xxx', source = 'foo2.in')
+env.B(target = 'foo3.out', source = 'foo3.in')
+Clean('foo2.xxx', ['aux1.x'])
+Clean('foo2.xxx', ['aux2.x'])
+Clean('.', ['subd'])
+""" % python)
+
+expect = test.wrap_stdout("""Removed foo2.xxx
+Removed aux1.x
+Removed aux2.x
+""")
+test.run(arguments = '-c foo2.xxx', stdout=expect)
+test.fail_test(test.read(test.workpath('foo1.out')) != "foo1.in\n")
+test.fail_test(os.path.exists(test.workpath('foo2.xxx')))
+test.fail_test(test.read(test.workpath('foo2.out')) != "foo2.in\n")
+test.fail_test(test.read(test.workpath('foo3.out')) != "foo3.in\n")
+
+expect = test.wrap_stdout("""Removed foo1.out
+Removed foo2.out
+Removed foo3.out
+Removed %s
+Removed directory subd
+""" % os.path.join('subd','foon.in'))
+test.run(arguments = '-c .', stdout=expect)
+test.fail_test(os.path.exists(test.workpath('subdir', 'foon.in')))
+test.fail_test(os.path.exists(test.workpath('subdir')))
test.pass_test()