From 3ba9cd5c59be33f2ad31edc06995e754dcd9e35f Mon Sep 17 00:00:00 2001 From: stevenknight Date: Thu, 24 Jan 2002 06:29:31 +0000 Subject: [PATCH] Add the Ignore() method. git-svn-id: http://scons.tigris.org/svn/scons/trunk@220 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- doc/man/scons.1 | 11 ++++ src/CHANGES.txt | 4 ++ src/engine/SCons/Environment.py | 11 ++++ src/engine/SCons/EnvironmentTests.py | 11 ++++ src/engine/SCons/Node/NodeTests.py | 32 ++++++++++ src/engine/SCons/Node/__init__.py | 12 +++- test/Ignore.py | 96 ++++++++++++++++++++++++++++ 7 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 test/Ignore.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index dfb96c7d..9a2e9a0f 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -647,6 +647,17 @@ dict = env.Dictionary() cc_dict = env.Dictionary('CC', 'CCFLAGS', 'CCCOM') .EE +.TP +.RI Ignore( target ", " dependency ) +The specified dependency file(s) +will be ignored when deciding if +the target file(s) need to be rebuilt. + +.ES +env.Ignore('foo', 'foo.c') +env.Ignore('bar', ['bar1.h', 'bar2.h']) +.EE + .TP .RI Install( dir ", " source ) Installs one or more files in a destination directory. diff --git a/src/CHANGES.txt b/src/CHANGES.txt index ea9bf431..a2467110 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -19,6 +19,8 @@ RELEASE 0.04 - - Allow LIBS and LIBPATH to be strings, not just arrays. + - Print a traceback if a Python-function builder throws an exception. + From Steven Knight: - Fix using a directory as a Default(), and allow Default() to @@ -46,6 +48,8 @@ RELEASE 0.04 - surround $_INCDIRS and $_LIBDIRS so we don't rebuild in response to changes to -I or -L options. + - Add the Ignore() method to ignore dependencies. + From Steve Leblanc: - Add var=value command-line arguments. diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 612ae9ac..3c1ee430 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -174,6 +174,17 @@ class Environment: tlist = tlist[0] return tlist + def Ignore(self, target, dependency): + """Ignore a dependency.""" + tlist = SCons.Util.scons_str2nodes(target) + dlist = SCons.Util.scons_str2nodes(dependency) + for t in tlist: + t.add_ignore(dlist) + + if len(tlist) == 1: + tlist = tlist[0] + return tlist + def Dictionary(self, *args): if not args: return self._dict diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index a65cc33e..59f3c78b 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -258,6 +258,17 @@ class EnvironmentTestCase(unittest.TestCase): assert d.__class__.__name__ == 'File' assert d.path == 'Environment.py' + def test_Ignore(self): + """Test the explicit Ignore method.""" + env = Environment() + t = env.Ignore(target='targ.py', dependency='dep.py') + assert t.__class__.__name__ == 'File' + assert t.path == 'targ.py' + assert len(t.ignore) == 1 + i = t.ignore[0] + assert i.__class__.__name__ == 'File' + assert i.path == 'dep.py' + def test_Command(self): """Test the Command() method.""" env = Environment() diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 10507679..aa9dccb1 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -312,6 +312,38 @@ class NodeTestCase(unittest.TestCase): assert node.implicit[3] == [two, three] assert node.implicit[4] == [three, four, one] + def test_add_ignore(self): + """Test adding files whose dependencies should be ignored. + """ + node = SCons.Node.Node() + assert node.ignore == [] + + zero = SCons.Node.Node() + try: + node.add_ignore(zero) + except TypeError: + pass + else: + assert 0 + + one = SCons.Node.Node() + two = SCons.Node.Node() + three = SCons.Node.Node() + four = SCons.Node.Node() + + node.add_ignore([one]) + assert node.ignore == [one] + node.add_ignore([two, three]) + assert node.ignore == [one, two, three] + node.add_ignore([three, four, one]) + assert node.ignore == [one, two, three, four] + + assert zero.get_parents() == [] + assert one.get_parents() == [node] + assert two.get_parents() == [node] + assert three.get_parents() == [node] + assert four.get_parents() == [node] + def test_scan(self): """Test Scanner functionality""" class DummyScanner: diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index c6418951..03705f71 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -59,6 +59,7 @@ class Node: self.sources = [] # source files used to build node self.depends = [] # explicit dependencies (from Depends) self.implicit = {} # implicit (scanned) dependencies + self.ignore = [] # dependencies to ignore self.parents = [] self.wkids = None # Kids yet to walk, when it's an array self.builder = None @@ -167,6 +168,10 @@ class Node: """Adds dependencies. The depend argument must be a list.""" self._add_child(self.depends, depend) + def add_ignore(self, depend): + """Adds dependencies to ignore. The depend argument must be a list.""" + self._add_child(self.ignore, depend) + def add_source(self, source): """Adds sources. The source argument must be a list.""" self._add_child(self.sources, source) @@ -201,9 +206,10 @@ class Node: def children(self): #XXX Need to remove duplicates from this - return self.sources \ - + self.depends \ - + reduce(lambda x, y: x + y, self.implicit.values(), []) + return filter(lambda x, i=self.ignore: x not in i, + self.sources \ + + self.depends \ + + reduce(lambda x, y: x + y, self.implicit.values(), [])) def get_parents(self): return self.parents diff --git a/test/Ignore.py b/test/Ignore.py new file mode 100644 index 00000000..32e66373 --- /dev/null +++ b/test/Ignore.py @@ -0,0 +1,96 @@ +#!/usr/bin/env python +# +# Copyright (c) 2001 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 sys +import TestSCons + +python = sys.executable + +test = TestSCons.TestSCons() + +test.subdir('subdir') + +test.write('build.py', r""" +import sys +contents = open(sys.argv[2], 'rb').read() + open(sys.argv[3], 'rb').read() +file = open(sys.argv[1], 'wb') +for arg in sys.argv[2:]: + file.write(open(arg, 'rb').read()) +file.close() +""") + +test.write('SConstruct', """ +Foo = Builder(name = "Foo", + action = r"%s build.py $TARGET $SOURCES") +Bar = Builder(name = "Bar", + action = r"%s build.py $TARGET $SOURCES") +env = Environment(BUILDERS = [Foo, Bar]) +env.Foo(target = 'f1.out', source = ['f1a.in', 'f1b.in']) +env.Ignore(target = 'f1.out', dependency = 'f1b.in') +SConscript('subdir/SConscript', "env") +""" % (python, python)) + +test.write(['subdir', 'SConscript'], """ +Import("env") +env.Bar(target = 'f2.out', source = ['f2a.in', 'f2b.in']) +env.Ignore('f2.out', 'f2a.in') +""") + +test.write('f1a.in', "f1a.in\n") +test.write('f1b.in', "f1b.in\n") + +test.write(['subdir', 'f2a.in'], "subdir/f2a.in\n") +test.write(['subdir', 'f2b.in'], "subdir/f2b.in\n") + +test.run(arguments = '.') + +test.fail_test(test.read('f1.out') != "f1a.in\nf1b.in\n") +test.fail_test(test.read(['subdir', 'f2.out']) != + "subdir/f2a.in\nsubdir/f2b.in\n") + +test.up_to_date(arguments = '.') + +test.write('f1b.in', "f1b.in 2\n") +test.write(['subdir', 'f2a.in'], "subdir/f2a.in 2\n") + +test.up_to_date(arguments = '.') + +test.fail_test(test.read('f1.out') != "f1a.in\nf1b.in\n") +test.fail_test(test.read(['subdir', 'f2.out']) != + "subdir/f2a.in\nsubdir/f2b.in\n") + +test.write('f1a.in', "f1a.in 2\n") +test.write(['subdir', 'f2b.in'], "subdir/f2b.in 2\n") + +test.run(arguments = '.') + +test.fail_test(test.read('f1.out') != "f1a.in 2\nf1b.in 2\n") +test.fail_test(test.read(['subdir', 'f2.out']) != + "subdir/f2a.in 2\nsubdir/f2b.in 2\n") + +test.up_to_date(arguments = '.') + +test.pass_test() -- 2.26.2