summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bin/files1
-rw-r--r--doc/man/scons.121
-rw-r--r--src/CHANGES.txt2
-rw-r--r--src/engine/MANIFEST.in1
-rw-r--r--src/engine/SCons/Node/Python.py76
-rw-r--r--src/engine/SCons/Node/PythonTests.py52
-rw-r--r--src/engine/SCons/Script/SConscript.py2
-rw-r--r--test/Value.py103
8 files changed, 258 insertions, 0 deletions
diff --git a/bin/files b/bin/files
index ccb6089..3af1572 100644
--- a/bin/files
+++ b/bin/files
@@ -6,6 +6,7 @@
./SCons/Job.py
./SCons/Node/Alias.py
./SCons/Node/FS.py
+./SCons/Node/Python.py
./SCons/Node/__init__.py
./SCons/Options.py
./SCons/Platform/__init__.py
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index c96c8b8..14a2e50 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -4064,6 +4064,27 @@ env = Environment(tools = [ Tool('msvc') ])
.EE
.TP
+.RI Value( value )
+Returns a Node object representing the specified Python value. Value
+nodes can be used as dependencies of targets. If the result of
+calling
+.BR str( value )
+changes between SCons runs, any targets depending on
+.BR Value( value )
+will be rebuilt.
+
+.ES
+def create(target, source, env):
+ f = open(str(target[0]), 'wb')
+ f.write('prefix=' + source[0].get_contents())
+
+prefix = ARGUMENTS.get('prefix', '/usr/local')
+env = Environment()
+env['BUILDERS']['Config'] = Builder(action = create)
+env.Config(target = 'package-config', source = Value(prefix))
+.EE
+
+.TP
.RI WhereIs( program ", [" path ", [" pathext ]])
Searches for the specified executable
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index f6bdee0..196c28d 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -28,6 +28,8 @@ RELEASE 0.14 - XXX
- Portability fixes for a lot of tests.
+ - Add a Value Node class for dependencies on in-core Python values.
+
From Allen Bierbaum:
- Pass an Environment to the Options validator method, and
diff --git a/src/engine/MANIFEST.in b/src/engine/MANIFEST.in
index ca713ff..c028989 100644
--- a/src/engine/MANIFEST.in
+++ b/src/engine/MANIFEST.in
@@ -9,6 +9,7 @@ SCons/exitfuncs.py
SCons/Node/__init__.py
SCons/Node/Alias.py
SCons/Node/FS.py
+SCons/Node/Python.py
SCons/Optik/__init__.py
SCons/Optik/errors.py
SCons/Optik/option.py
diff --git a/src/engine/SCons/Node/Python.py b/src/engine/SCons/Node/Python.py
new file mode 100644
index 0000000..9348b83
--- /dev/null
+++ b/src/engine/SCons/Node/Python.py
@@ -0,0 +1,76 @@
+"""scons.Node.Python
+
+Python nodes.
+
+"""
+
+#
+# __COPYRIGHT__
+#
+# 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 SCons.Node
+
+class Value(SCons.Node.Node):
+ """A class for Python variables, typically passed on the command line
+ or generated by a script, but not from a file or some other source.
+ """
+ def __init__(self, value):
+ SCons.Node.Node.__init__(self)
+ self.value = value
+
+ def __str__(self):
+ return repr(self.value)
+
+ def build(self):
+ """A "builder" for Values."""
+ pass
+
+ def current(self, calc):
+ """If all of our children were up-to-date, then this
+ Value was up-to-date, too."""
+ # Allow the children to calculate their signatures.
+ calc.bsig(self)
+ 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 is_under(self, dir):
+ # Make Value nodes get built regardless of
+ # what directory scons was run from. Value nodes
+ # are outside the filesystem:
+ return 1
+
+ def get_contents(self):
+ """The contents of a Value are the concatenation
+ of all the contents of its sources with the node's value itself."""
+ contents = str(self.value)
+ for kid in self.children(None):
+ contents = contents + kid.get_contents()
+ return contents
diff --git a/src/engine/SCons/Node/PythonTests.py b/src/engine/SCons/Node/PythonTests.py
new file mode 100644
index 0000000..0befa25
--- /dev/null
+++ b/src/engine/SCons/Node/PythonTests.py
@@ -0,0 +1,52 @@
+#
+# __COPYRIGHT__
+#
+# 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 unittest
+
+import SCons.Errors
+import SCons.Node.Python
+
+class ValueTestCase(unittest.TestCase):
+
+ def test_Value(self):
+ """Test creating a Value() object
+ """
+ v1 = SCons.Node.Python.Value('a')
+ assert v1.value == 'a', v1.value
+
+ value2 = 'a'
+ v2 = SCons.Node.Python.Value(value2)
+ assert v2.value == value2, v2.value
+ assert v2.value is value2, v2.value
+
+ assert not v1 is v2
+ assert v1.value == v2.value
+
+
+if __name__ == "__main__":
+ suite = unittest.makeSuite(ValueTestCase, 'test_')
+ if not unittest.TextTestRunner().run(suite).wasSuccessful():
+ sys.exit(1)
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index 6b28b92..af8cc79 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -37,6 +37,7 @@ import SCons.Environment
import SCons.Errors
import SCons.Node
import SCons.Node.FS
+import SCons.Node.Python
import SCons.Platform
import SCons.SConf
import SCons.Script
@@ -561,5 +562,6 @@ def BuildDefaultGlobals():
globals['StaticObject'] = SCons.Defaults.StaticObject
globals['TargetSignatures'] = TargetSignatures
globals['Tool'] = SCons.Tool.Tool
+ globals['Value'] = SCons.Node.Python.Value
globals['WhereIs'] = SCons.Util.WhereIs
return globals
diff --git a/test/Value.py b/test/Value.py
new file mode 100644
index 0000000..f3df6fe
--- /dev/null
+++ b/test/Value.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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 re
+import string
+import sys
+import TestSCons
+import TestCmd
+
+test = TestSCons.TestSCons(match=TestCmd.match_re)
+
+test.write('SConstruct', """
+class Custom:
+ def __init__(self, value): self.value = value
+ def __str__(self): return "C=" + str(self.value)
+
+P = ARGUMENTS.get('prefix', '/usr/local')
+L = len(P)
+C = Custom(P)
+
+def create(target, source, env):
+ open(str(target[0]), 'wb').write(source[0].get_contents())
+
+env = Environment()
+env['BUILDERS']['B'] = Builder(action = create)
+env.B('f1.out', Value(P))
+env.B('f2.out', Value(L))
+env.B('f3.out', Value(C))
+""")
+
+
+test.run()
+out1 = """create("f1.out", "'/usr/local'")"""
+out2 = """create("f2.out", "10")"""
+out3 = """create\\("f3.out", "<.*.Custom instance at """
+test.fail_test(string.find(test.stdout(), out1) == -1)
+test.fail_test(string.find(test.stdout(), out2) == -1)
+test.fail_test(re.search(out3, test.stdout()) == None)
+
+test.fail_test(not os.path.exists(test.workpath('f1.out')))
+test.fail_test(open(test.workpath('f1.out'), 'rb').read() != '/usr/local')
+test.fail_test(not os.path.exists(test.workpath('f2.out')))
+test.fail_test(open(test.workpath('f2.out'), 'rb').read() != '10')
+test.fail_test(not os.path.exists(test.workpath('f3.out')))
+test.fail_test(open(test.workpath('f3.out'), 'rb').read() != 'C=/usr/local')
+
+test.up_to_date(arguments = ".")
+
+test.run(arguments = 'prefix=/usr')
+out4 = """create("f1.out", "'/usr'")"""
+out5 = """create("f2.out", "4")"""
+out6 = """create\\("f3.out", "<.*.Custom instance at """
+test.fail_test(string.find(test.stdout(), out4) == -1)
+test.fail_test(string.find(test.stdout(), out5) == -1)
+test.fail_test(re.search(out6, test.stdout()) == None)
+
+test.fail_test(not os.path.exists(test.workpath('f1.out')))
+test.fail_test(open(test.workpath('f1.out'), 'rb').read() != '/usr')
+test.fail_test(not os.path.exists(test.workpath('f2.out')))
+test.fail_test(open(test.workpath('f2.out'), 'rb').read() != '4')
+test.fail_test(not os.path.exists(test.workpath('f3.out')))
+test.fail_test(open(test.workpath('f3.out'), 'rb').read() != 'C=/usr')
+
+test.unlink('f3.out')
+
+test.run(arguments = 'prefix=/var')
+out4 = """create("f1.out", "'/var'")"""
+test.fail_test(string.find(test.stdout(), out4) == -1)
+test.fail_test(string.find(test.stdout(), out5) != -1)
+test.fail_test(re.search(out6, test.stdout()) == None)
+
+test.fail_test(not os.path.exists(test.workpath('f1.out')))
+test.fail_test(open(test.workpath('f1.out'), 'rb').read() != '/var')
+test.fail_test(not os.path.exists(test.workpath('f2.out')))
+test.fail_test(open(test.workpath('f2.out'), 'rb').read() != '4')
+test.fail_test(not os.path.exists(test.workpath('f3.out')))
+test.fail_test(open(test.workpath('f3.out'), 'rb').read() != 'C=/var')
+
+test.pass_test()