From df70fbb73a1b644373002ebe3c9bc206b256744b Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Mon, 25 Mar 2002 05:40:36 +0000 Subject: Add support for target Aliases. --- SConstruct | 36 ++++++++---- doc/man/scons.1 | 16 +++++- rpm/scons.spec | 2 + src/CHANGES.txt | 2 + src/engine/MANIFEST.in | 1 + src/engine/SCons/Builder.py | 16 ++++-- src/engine/SCons/BuilderTests.py | 27 ++++++++- src/engine/SCons/Defaults.py | 16 +++++- src/engine/SCons/Node/Alias.py | 93 ++++++++++++++++++++++++++++++ src/engine/SCons/Node/AliasTests.py | 87 ++++++++++++++++++++++++++++ src/engine/SCons/Node/FS.py | 6 ++ src/engine/SCons/Node/FSTests.py | 8 ++- src/engine/SCons/Node/NodeTests.py | 34 +++++++++++ src/engine/SCons/Node/__init__.py | 12 +++- src/engine/SCons/Script/__init__.py | 8 ++- test/Alias.py | 110 ++++++++++++++++++++++++++++++++++++ 16 files changed, 446 insertions(+), 28 deletions(-) create mode 100644 src/engine/SCons/Node/Alias.py create mode 100644 src/engine/SCons/Node/AliasTests.py create mode 100644 test/Alias.py diff --git a/SConstruct b/SConstruct index 5303c70..1d97f10 100644 --- a/SConstruct +++ b/SConstruct @@ -69,6 +69,7 @@ fakeroot = whereis('fakeroot') gzip = whereis('gzip') rpm = whereis('rpm') unzip = whereis('unzip') +zip = whereis('zip') # My installation on Red Hat doesn't like any debhelper version # beyond 2, so let's use 2 as the default on any non-Debian build. @@ -174,24 +175,33 @@ try: import zipfile def zipit(env, target, source): - print "Zipping %s:" % target + print "Zipping %s:" % str(target[0]) def visit(arg, dirname, names): for name in names: - arg.write(os.path.join(dirname, name)) + path = os.path.join(dirname, name) + if os.path.isfile(path): + arg.write(path) + zf = zipfile.ZipFile(str(target[0]), 'w') os.chdir('build') - zf = zipfile.ZipFile(target, 'w') os.path.walk(env['PSV'], visit, zf) os.chdir('..') + zf.close() def unzipit(env, target, source): - print "Unzipping %s:" % source[0] - zf = zipfile.ZipFile(source[0], 'r') + print "Unzipping %s:" % str(source[0]) + zf = zipfile.ZipFile(str(source[0]), 'r') for name in zf.namelist(): dest = os.path.join(env['UNPACK_ZIP_DIR'], name) + dir = os.path.dirname(dest) + try: + os.makedirs(dir) + except: + pass + print dest,name open(dest, 'w').write(zf.read(name)) except: - if unzip: + if unzip and zip: zipit = "cd build && $ZIP $ZIPFLAGS dist/${TARGET.file} $PSV" unzipit = "$UNZIP $UNZIPFLAGS $SOURCES" @@ -237,7 +247,7 @@ env = Environment( TAR_HFLAG = tar_hflag, - ZIP = whereis('zip'), + ZIP = zip, ZIPFLAGS = '-r', UNZIP = unzip, UNZIPFLAGS = '-o -d $UNPACK_ZIP_DIR', @@ -441,6 +451,8 @@ for p in [ scons ]: open(os.path.join(src, 'MANIFEST.in')).readlines()) dst_files = src_files[:] + MANIFEST_in_list = [] + if p.has_key('subpkgs'): # # This package includes some sub-packages. Read up their @@ -451,8 +463,9 @@ for p in [ scons ]: for sp in p['subpkgs']: ssubdir = sp['src_subdir'] isubdir = p['subinst_dirs'][sp['pkg']] - f = map(lambda x: x[:-1], - open(os.path.join(src, ssubdir, 'MANIFEST.in')).readlines()) + MANIFEST_in = os.path.join(src, ssubdir, 'MANIFEST.in') + MANIFEST_in_list.append(MANIFEST_in) + f = map(lambda x: x[:-1], open(MANIFEST_in).readlines()) src_files.extend(map(lambda x, s=ssubdir: os.path.join(s, x), f)) if isubdir: f = map(lambda x, i=isubdir: os.path.join(i, x), f) @@ -486,6 +499,7 @@ for p in [ scons ]: # MANIFEST itself to the array, of course. # src_files.append("MANIFEST") + MANIFEST_in_list.append(os.path.join(src, 'MANIFEST.in')) def copy(target, source, **kw): global src_files @@ -495,9 +509,7 @@ for p in [ scons ]: f.write(file + "\n") f.close() return 0 - env.Command(os.path.join(build, 'MANIFEST'), - os.path.join(src, 'MANIFEST.in'), - copy) + env.Command(os.path.join(build, 'MANIFEST'), MANIFEST_in_list, copy) # # Now go through and arrange to create whatever packages we can. diff --git a/doc/man/scons.1 b/doc/man/scons.1 index cee4e65..e49008f 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -767,6 +767,20 @@ Multiple targets can be passed in to a single call to .BR Precious (). .TP +.RI Alias( alias ", " targets ) +Creates a phony target that +expands to one or more other targets. +Returns the Node object representing the alias, +which exists outside of any file system. +This Node object, or the alias name, +may be used as a dependency of any other target, +including another alias. + +.ES +env.Alias('install', ['/usr/local/bin', '/usr/local/lib']) +.EE + +.TP .RI Update( key = val ", [...])" Updates the contents of an environment with the specified keyword arguments. @@ -795,7 +809,7 @@ The command line used to generate a static library from object files. .IP BUILDERS A list of the available builders. -[CFile, CXXFile, Object, Program, Library] by default. +[Alias, CFile, CXXFile, DVI, Library, Object, Program] by default. .IP CC The C compiler. diff --git a/rpm/scons.spec b/rpm/scons.spec index 5953842..77fe187 100644 --- a/rpm/scons.spec +++ b/rpm/scons.spec @@ -62,6 +62,8 @@ rm -rf $RPM_BUILD_ROOT /usr/lib/scons/SCons/Errors.pyc /usr/lib/scons/SCons/Job.py /usr/lib/scons/SCons/Job.pyc +/usr/lib/scons/SCons/Node/Alias.py +/usr/lib/scons/SCons/Node/Alias.pyc /usr/lib/scons/SCons/Node/FS.py /usr/lib/scons/SCons/Node/FS.pyc /usr/lib/scons/SCons/Node/__init__.py diff --git a/src/CHANGES.txt b/src/CHANGES.txt index b53da0f..1ffca34 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -55,6 +55,8 @@ RELEASE 0.06 - - Modify the new DVI builder to create .dvi files from LaTeX (.ltx and .latex) files. + - Add support for Aliases (phony targets). + From Steve Leblanc: - Add support for the -U option. diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in index 100abcb..e86d601 100644 --- a/src/engine/MANIFEST.in +++ b/src/engine/MANIFEST.in @@ -7,6 +7,7 @@ SCons/Errors.py SCons/Job.py SCons/exitfuncs.py SCons/Node/__init__.py +SCons/Node/Alias.py SCons/Node/FS.py SCons/Scanner/__init__.py SCons/Scanner/C.py diff --git a/src/engine/SCons/Builder.py b/src/engine/SCons/Builder.py index 46fe9cb..bc90e19 100644 --- a/src/engine/SCons/Builder.py +++ b/src/engine/SCons/Builder.py @@ -94,6 +94,8 @@ class BuilderBase: suffix = '', src_suffix = '', node_factory = SCons.Node.FS.default_fs.File, + target_factory = None, + source_factory = None, scanner = None): if name is None: raise UserError, "You must specify a name for the builder." @@ -103,7 +105,8 @@ class BuilderBase: self.prefix = prefix self.suffix = suffix self.src_suffix = src_suffix - self.node_factory = node_factory + self.target_factory = target_factory or node_factory + self.source_factory = source_factory or node_factory self.scanner = scanner if self.suffix and self.suffix[0] not in '.$': self.suffix = '.' + self.suffix @@ -136,12 +139,12 @@ class BuilderBase: tlist = SCons.Node.arg2nodes(adjustixes(target, env.subst(self.prefix), env.subst(self.suffix)), - self.node_factory) + self.target_factory) slist = SCons.Node.arg2nodes(adjustixes(source, None, env.subst(self.src_suffix)), - self.node_factory) + self.source_factory) return tlist, slist def __call__(self, env, target = None, source = None): @@ -243,13 +246,16 @@ class MultiStepBuilder(BuilderBase): suffix = '', src_suffix = '', node_factory = SCons.Node.FS.default_fs.File, + target_factory = None, + source_factory = None, scanner=None): BuilderBase.__init__(self, name, action, prefix, suffix, src_suffix, - node_factory, scanner) + node_factory, target_factory, source_factory, + scanner) self.src_builder = src_builder def __call__(self, env, target = None, source = None): - slist = SCons.Node.arg2nodes(source, self.node_factory) + slist = SCons.Node.arg2nodes(source, self.source_factory) final_sources = [] src_suffix = env.subst(self.src_suffix) sdict = {} diff --git a/src/engine/SCons/BuilderTests.py b/src/engine/SCons/BuilderTests.py index 9363631..16c87a4 100644 --- a/src/engine/SCons/BuilderTests.py +++ b/src/engine/SCons/BuilderTests.py @@ -398,7 +398,32 @@ class BuilderTestCase(unittest.TestCase): global Foo return Foo(target) builder = SCons.Builder.Builder(name = "builder", node_factory = FooFactory) - assert builder.node_factory is FooFactory + assert builder.target_factory is FooFactory + assert builder.source_factory is FooFactory + + def test_target_factory(self): + """Test a Builder that creates target nodes of a specified class + """ + class Foo: + pass + def FooFactory(target): + global Foo + return Foo(target) + builder = SCons.Builder.Builder(name = "builder", target_factory = FooFactory) + assert builder.target_factory is FooFactory + assert not builder.source_factory is FooFactory + + def test_source_factory(self): + """Test a Builder that creates source nodes of a specified class + """ + class Foo: + pass + def FooFactory(source): + global Foo + return Foo(source) + builder = SCons.Builder.Builder(name = "builder", source_factory = FooFactory) + assert not builder.target_factory is FooFactory + assert builder.source_factory is FooFactory def test_prefix(self): """Test Builder creation with a specified target prefix diff --git a/src/engine/SCons/Defaults.py b/src/engine/SCons/Defaults.py index 26c59a6..36a6aa1 100644 --- a/src/engine/SCons/Defaults.py +++ b/src/engine/SCons/Defaults.py @@ -43,9 +43,11 @@ import sys import SCons.Action import SCons.Builder +import SCons.Errors +import SCons.Node.Alias +import SCons.Node.FS import SCons.Scanner.C import SCons.Scanner.Prog -import SCons.Errors import SCons.Util @@ -121,6 +123,14 @@ DVI = SCons.Builder.Builder(name = 'DVI', CScan = SCons.Scanner.C.CScan() +def alias_builder(env, target, source): + pass + +Alias = SCons.Builder.Builder(name = 'Alias', + action = alias_builder, + target_factory = SCons.Node.Alias.default_ans.Alias, + source_factory = SCons.Node.FS.default_fs.Entry) + def get_devstudio_versions (): """ Get list of devstudio versions from the Windows registry. Return a @@ -248,7 +258,7 @@ def make_win32_env_from_paths(include, lib, path): 'LATEXFLAGS' : '', 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES', 'DVISUFFIX' : '.dvi', - 'BUILDERS' : [CFile, CXXFile, Object, Program, Library, DVI], + 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Object, Program, Library], 'SCANNERS' : [CScan], 'OBJPREFIX' : '', 'OBJSUFFIX' : '.obj', @@ -318,7 +328,7 @@ if os.name == 'posix': 'LATEXFLAGS' : '', 'LATEXCOM' : '$LATEX $LATEXFLAGS $SOURCES', 'DVISUFFIX' : '.dvi', - 'BUILDERS' : [CFile, CXXFile, Object, Program, Library, DVI], + 'BUILDERS' : [Alias, CFile, CXXFile, DVI, Object, Program, Library], 'SCANNERS' : [CScan], 'OBJPREFIX' : '', 'OBJSUFFIX' : '.o', diff --git a/src/engine/SCons/Node/Alias.py b/src/engine/SCons/Node/Alias.py new file mode 100644 index 0000000..31f0a9b --- /dev/null +++ b/src/engine/SCons/Node/Alias.py @@ -0,0 +1,93 @@ + +"""scons.Node.Alias + +Alias nodes. + +This creates a hash of global Aliases (dummy targets). + +""" + +# +# Copyright (c) 2001, 2002 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __USER__" + +import UserDict + +import SCons.Errors +import SCons.Node +import SCons.Util + +class AliasNameSpace(UserDict.UserDict): + def Alias(self, name): + if self.has_key(name): + raise SCons.Errors.UserError + self[name] = SCons.Node.Alias.Alias(name) + return self[name] + + def lookup(self, name): + try: + return self[name] + except KeyError: + return None + +class Alias(SCons.Node.Node): + def __init__(self, name): + SCons.Node.Node.__init__(self) + self.name = name + + def __str__(self): + return self.name + + def build(self): + """A "builder" for aliases.""" + pass + + def set_bsig(self, bsig): + """An alias has no signature.""" + pass + + def set_csig(self, csig): + """An alias has no signature.""" + pass + + def current(self): + """If all of our children were up-to-date, then this + Alias was up-to-date, too.""" + state = 0 + for kid in self.children(None): + s = kid.get_state() + if s and (not state or s > state): + state = s + if state == 0 or state == SCons.Node.up_to_date: + return 1 + else: + return 0 + + def sconsign(self): + """An Alias is not recorded in .sconsign files""" + pass + +default_ans = AliasNameSpace() + +SCons.Node.arg2nodes_lookups.append(default_ans.lookup) diff --git a/src/engine/SCons/Node/AliasTests.py b/src/engine/SCons/Node/AliasTests.py new file mode 100644 index 0000000..a14bc57 --- /dev/null +++ b/src/engine/SCons/Node/AliasTests.py @@ -0,0 +1,87 @@ +# +# Copyright (c) 2001, 2002 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __USER__" + +import sys +import unittest + +import SCons.Errors +import SCons.Node.Alias + +class AliasTestCase(unittest.TestCase): + + def test_AliasNameSpace(self): + """Test creating an Alias name space + """ + ans = SCons.Node.Alias.AliasNameSpace() + assert not ans is None, ans + + def test_ANS_Alias(self): + """Test the Alias() factory + """ + ans = SCons.Node.Alias.AliasNameSpace() + + a = ans.Alias('a1') + assert a.name == 'a1', a.name + + try: + ans.Alias('a1') + except SCons.Errors.UserError: + pass + else: + raise TestFailed, "did not catch expected UserError" + + def test_lookup(self): + """Test the lookup() method + """ + ans = SCons.Node.Alias.AliasNameSpace() + + ans.Alias('a1') + a = ans.lookup('a1') + assert a.name == 'a1', a.name + + a1 = ans.lookup('a1') + assert a is a1, a1 + + a = ans.lookup('a2') + assert a == None, a + + def test_Alias(self): + """Test creating an Alias() object + """ + a1 = SCons.Node.Alias.Alias('a') + assert a1.name == 'a', a1.name + + a2 = SCons.Node.Alias.Alias('a') + assert a2.name == 'a', a2.name + + assert not a1 is a2 + assert a1.name == a2.name + + + +if __name__ == "__main__": + suite = unittest.makeSuite(AliasTestCase, 'test_') + if not unittest.TextTestRunner().run(suite).wasSuccessful(): + sys.exit(1) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 362559c..1be5e81 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -336,6 +336,12 @@ class Entry(SCons.Node.Node): self.exists_flag = self.exists() return self.exists_flag + def get_parents(self): + parents = SCons.Node.Node.get_parents(self) + if self.dir and not isinstance(self.dir, ParentOfRoot): + parents.append(self.dir) + return parents + def current(self): """If the underlying path doesn't exist, we know the node is not current without even checking the signature, so return 0. diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 6cf8f1a..bea1499 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -290,8 +290,6 @@ class FSTestCase(unittest.TestCase): d1.build() assert not built_it - assert d1.get_parents() == [] - built_it = None assert not built_it f1.add_source([SCons.Node.Node()]) # XXX FAKE SUBCLASS ATTRIBUTE @@ -480,6 +478,12 @@ class FSTestCase(unittest.TestCase): assert fs.File('foo.x').scanner_key() == '.x' assert fs.File('foo.xyz').scanner_key() == '.xyz' + d1 = fs.Dir('dir') + f1 = fs.File('dir/file') + assert f1.dir == d1, f1.dir + parents = f1.get_parents() + assert parents == [ d1 ], parents + class find_fileTestCase(unittest.TestCase): def runTest(self): diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 1c92476..16c5548 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -740,6 +740,40 @@ class NodeTestCase(unittest.TestCase): assert len(nodes) == 1, nodes assert isinstance(nodes[0], OtherNode), node + def lookup_a(str, F=Factory): + if str[0] == 'a': + n = F(str) + n.a = 1 + return n + else: + return None + + def lookup_b(str, F=Factory): + if str[0] == 'b': + n = F(str) + n.b = 1 + return n + else: + return None + + SCons.Node.arg2nodes_lookups.append(lookup_a) + SCons.Node.arg2nodes_lookups.append(lookup_b) + + nodes = SCons.Node.arg2nodes(['aaa', 'bbb', 'ccc'], Factory) + assert len(nodes) == 3, nodes + + assert nodes[0].name == 'aaa', nodes[0] + assert nodes[0].a == 1, nodes[0] + assert not hasattr(nodes[0], 'b'), nodes[0] + + assert nodes[1].name == 'bbb' + assert not hasattr(nodes[1], 'a'), nodes[1] + assert nodes[1].b == 1, nodes[1] + + assert nodes[2].name == 'ccc' + assert not hasattr(nodes[2], 'a'), nodes[1] + assert not hasattr(nodes[2], 'b'), nodes[1] + if __name__ == "__main__": diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index a7c8521..98b2d50 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -322,6 +322,9 @@ class Walker: return not self.stack +arg2nodes_lookups = [] + + def arg2nodes(arg, node_factory=None): """This function converts a string or list into a list of Node instances. It follows the rules outlined in the SCons design document by accepting @@ -342,7 +345,14 @@ def arg2nodes(arg, node_factory=None): nodes = [] for v in narg: if SCons.Util.is_String(v): - if node_factory: + n = None + for l in arg2nodes_lookups: + n = l(v) + if not n is None: + break + if not n is None: + nodes.append(n) + elif node_factory: nodes.append(node_factory(v)) # Do we enforce the following restriction? Maybe, but it # would also restrict what we can do to allow people to diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 055dbbc..6866e35 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -753,9 +753,11 @@ def _main(): node = x else: try: - node = SCons.Node.FS.default_fs.Entry(x, - directory = top, - create = 0) + node = SCons.Node.Alias.default_ans.lookup(x) + if node is None: + node = SCons.Node.FS.default_fs.Entry(x, + directory = top, + create = 0) except UserError: string = "scons: *** Do not know how to make target `%s'." % x if not keep_going_on_error: diff --git a/test/Alias.py b/test/Alias.py new file mode 100644 index 0000000..e6de2c0 --- /dev/null +++ b/test/Alias.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001, 2002 Steven Knight +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY +# KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +# WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# + +__revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" + +import os +import sys +import TestSCons + +python = sys.executable + +test = TestSCons.TestSCons() + +test.subdir('sub1', 'sub2') + +test.write('build.py', r""" +import sys +open(sys.argv[1], 'wb').write(open(sys.argv[2], 'rb').read()) +sys.exit(0) +""") + +test.write('SConstruct', """ +B = Builder(name = "B", action = r"%s build.py $TARGET $SOURCES") +builders = Environment().Dictionary('BUILDERS') +env = Environment(BUILDERS = builders + [ B ]) +env.B(target = 'f1.out', source = 'f1.in') +env.B(target = 'f2.out', source = 'f2.in') +env.B(target = 'f3.out', source = 'f3.in') +SConscript('sub1/SConscript', "env") +SConscript('sub2/SConscript', "env") +env.Alias('foo', ['f2.out', 'sub1']) +env.Alias('bar', ['sub2', 'f3.out']) +env.Depends('f1.out', 'bar') +""" % python) + +test.write(['sub1', 'SConscript'], """ +Import("env") +env.B(target = 'f4.out', source = 'f4.in') +env.B(target = 'f5.out', source = 'f5.in') +env.B(target = 'f6.out', source = 'f6.in') +""") + +test.write(['sub2', 'SConscript'], """ +Import("env") +env.B(target = 'f7.out', source = 'f7.in') +env.B(target = 'f8.out', source = 'f8.in') +env.B(target = 'f9.out', source = 'f9.in') +""") + +test.write('f1.in', "f1.in\n") +test.write('f2.in', "f2.in\n") +test.write('f3.in', "f3.in\n") + +test.write(['sub1', 'f4.in'], "sub1/f4.in\n") +test.write(['sub1', 'f5.in'], "sub1/f5.in\n") +test.write(['sub1', 'f6.in'], "sub1/f6.in\n") + +test.write(['sub2', 'f7.in'], "sub2/f7.in\n") +test.write(['sub2', 'f8.in'], "sub2/f8.in\n") +test.write(['sub2', 'f9.in'], "sub2/f9.in\n") + +test.run(arguments = 'foo') + +test.fail_test(os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f2.out'))) +test.fail_test(os.path.exists(test.workpath('f3.out'))) + +test.fail_test(not os.path.exists(test.workpath('sub1', 'f4.out'))) +test.fail_test(not os.path.exists(test.workpath('sub1', 'f5.out'))) +test.fail_test(not os.path.exists(test.workpath('sub1', 'f6.out'))) + +test.fail_test(os.path.exists(test.workpath('sub2', 'f7.out'))) +test.fail_test(os.path.exists(test.workpath('sub2', 'f8.out'))) +test.fail_test(os.path.exists(test.workpath('sub2', 'f9.out'))) + +test.up_to_date(arguments = 'foo') + +test.run(arguments = 'f1.out') + +test.fail_test(not os.path.exists(test.workpath('f1.out'))) +test.fail_test(not os.path.exists(test.workpath('f3.out'))) + +test.fail_test(not os.path.exists(test.workpath('sub2', 'f7.out'))) +test.fail_test(not os.path.exists(test.workpath('sub2', 'f8.out'))) +test.fail_test(not os.path.exists(test.workpath('sub2', 'f9.out'))) + +test.up_to_date(arguments = 'f1.out') + +test.pass_test() -- cgit v0.12