diff options
author | Steven Knight <knight@baldmt.com> | 2002-03-25 05:40:36 (GMT) |
---|---|---|
committer | Steven Knight <knight@baldmt.com> | 2002-03-25 05:40:36 (GMT) |
commit | df70fbb73a1b644373002ebe3c9bc206b256744b (patch) | |
tree | 08c005a22d974cae5ce36fedbc4858a7f377005d /src | |
parent | 94d7ac89ad998937fbbc3c896dffc88cece8e925 (diff) | |
download | SCons-df70fbb73a1b644373002ebe3c9bc206b256744b.zip SCons-df70fbb73a1b644373002ebe3c9bc206b256744b.tar.gz SCons-df70fbb73a1b644373002ebe3c9bc206b256744b.tar.bz2 |
Add support for target Aliases.
Diffstat (limited to 'src')
-rw-r--r-- | src/CHANGES.txt | 2 | ||||
-rw-r--r-- | src/engine/MANIFEST.in | 1 | ||||
-rw-r--r-- | src/engine/SCons/Builder.py | 16 | ||||
-rw-r--r-- | src/engine/SCons/BuilderTests.py | 27 | ||||
-rw-r--r-- | src/engine/SCons/Defaults.py | 16 | ||||
-rw-r--r-- | src/engine/SCons/Node/Alias.py | 93 | ||||
-rw-r--r-- | src/engine/SCons/Node/AliasTests.py | 87 | ||||
-rw-r--r-- | src/engine/SCons/Node/FS.py | 6 | ||||
-rw-r--r-- | src/engine/SCons/Node/FSTests.py | 8 | ||||
-rw-r--r-- | src/engine/SCons/Node/NodeTests.py | 34 | ||||
-rw-r--r-- | src/engine/SCons/Node/__init__.py | 12 | ||||
-rw-r--r-- | src/engine/SCons/Script/__init__.py | 8 |
12 files changed, 295 insertions, 15 deletions
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: |