summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--config16
-rw-r--r--doc/man/scons.121
-rw-r--r--runtest.py10
-rw-r--r--src/CHANGES.txt3
-rw-r--r--src/engine/SCons/Script/SConscript.py15
-rw-r--r--src/engine/SCons/Script/__init__.py13
-rw-r--r--src/engine/SCons/Sig/TimeStamp.py9
-rw-r--r--src/engine/SCons/Sig/__init__.py22
-rw-r--r--test/SetContentSignatureType.py131
9 files changed, 214 insertions, 26 deletions
diff --git a/config b/config
index 28215e7..fc04c4b 100644
--- a/config
+++ b/config
@@ -234,14 +234,20 @@ diff_command =
test $? -le 1";
/*
- * We use an intermediary test.pl script to execute tests.
- * This serves as glue between the tests themselves (which are
- * written to conform to Perl conventions) and Aegis' expectations.
- * See the comments in the test.pl script itself for details.
+ * We use a runtest.pl script to execute tests. This takes care of
+ * massaging environment variables and the like to test agains the
+ * unpacked package in the current directory.
+ *
+ * Note that we must include $spe in the batch_test_command line (so
+ * that Aegis thinks we're smart about testing ourselves against the
+ * baseline) but we don't actually need it. Our tests always run
+ * relative to the package built under the current directory, which
+ * is set appropriately during a baseline test. So we just use the
+ * proper aesub variable to comment out the expanded $spe.
*/
test_command = "python ${Source runtest.py Absolute} -p tar-gz -q ${File_Name}";
-batch_test_command = "python ${Source runtest.py Absolute} -p tar-gz -o ${Output} ${File_Names}";
+batch_test_command = "python ${Source runtest.py Absolute} -p tar-gz -o ${Output} ${File_Names} ${COMment $spe}";
new_test_filename = "test/CHANGETHIS.py";
diff --git a/doc/man/scons.1 b/doc/man/scons.1
index 6307f34..3d7d034 100644
--- a/doc/man/scons.1
+++ b/doc/man/scons.1
@@ -2421,6 +2421,16 @@ SConscript('bar/SConscript') # will not chdir to bar
.EE
.TP
+.RI SetBuildSignatureType( type )
+
+This function tells SCons what type of build signature to use: "build" or
+"content". "build" means to concatenate the signatures of all source files
+of a derived file to make its signature, and "content" means to use
+the derived files content signature as its signature. "build" signatures
+are usually faster to compute, but "content" signatures can prevent
+redundant rebuilds. The default is "build".
+
+.TP
.RI SetCommandHandler( function )
This registers a user
@@ -2442,6 +2452,17 @@ is a dictionary of the environment variables
in which the command should be executed.
.TP
+.RI SetContentSignatureType( type )
+
+This function tells SCons what type of content signature to use: "MD5" or
+"timestamp". "MD5" means to use the MD5 checksum of a files contents as
+its signature, and "timestamp" means to use a files timestamp as its
+signature. When using "timestamp" signatures, changes in the
+command line will not cause files to be rebuilt. "MD5" signatures take
+longer to compute, but "timestamp" signatures are less accurate. The
+default is "MD5".
+
+.TP
.RI Split( arg )
Returns a list of file names or other objects.
If arg is a string,
diff --git a/runtest.py b/runtest.py
index fddcd64..98a24eb 100644
--- a/runtest.py
+++ b/runtest.py
@@ -246,5 +246,11 @@ if output:
f.write(' exit_status = %d; },\n' % t.status)
f.write("];\n")
f.close()
-
-sys.exit(len(fail) + len(no_result))
+ sys.exit(0)
+else:
+ if len(fail):
+ sys.exit(1)
+ elif len(no_result):
+ sys.exit(2)
+ else:
+ sys.exit(0)
diff --git a/src/CHANGES.txt b/src/CHANGES.txt
index 0b1b027..c91a59e 100644
--- a/src/CHANGES.txt
+++ b/src/CHANGES.txt
@@ -96,6 +96,9 @@ RELEASE 0.09 -
- Fix the overly-verbose stack trace on ListBuilder build errors.
+ - Add a SetContentSignatureType() function, allowing use of file
+ timestamps instead of MD5 signatures.
+
From sam th:
- Dynamically check for the existence of utilities with which to
diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py
index cb20ae9..2802e8f 100644
--- a/src/engine/SCons/Script/SConscript.py
+++ b/src/engine/SCons/Script/SConscript.py
@@ -39,7 +39,6 @@ import SCons.Node.FS
import SCons.Platform
import SCons.Tool
import SCons.Util
-import SCons.Sig
import SCons.Options
import SCons
@@ -258,6 +257,7 @@ def GetLaunchDir():
return launch_dir
def SetBuildSignatureType(type):
+ import SCons.Sig
if type == 'build':
SCons.Sig.build_signature = 1
elif type == 'content':
@@ -265,6 +265,18 @@ def SetBuildSignatureType(type):
else:
raise SCons.Errors.UserError, "Unknown build signature type '%s'"%type
+def SetContentSignatureType(type):
+ import SCons.Script
+ if type == 'MD5':
+ import SCons.Sig.MD5
+ SCons.Script.sig_module = SCons.Sig.MD5
+ elif type == 'timestamp':
+ import SCons.Sig.TimeStamp
+ SCons.Script.sig_module = SCons.Sig.TimeStamp
+ else:
+ raise SCons.Errors.UserError, "Unknown content signature type '%s'"%type
+
+
class Options(SCons.Options.Options):
def Update(self, env):
return SCons.Options.Options.Update(self, env, arguments)
@@ -321,6 +333,7 @@ def BuildDefaultGlobals():
globals['Object'] = SCons.Defaults.StaticObject
globals['Repository'] = SCons.Node.FS.default_fs.Repository
globals['SetBuildSignatureType'] = SetBuildSignatureType
+ globals['SetContentSignatureType'] = SetContentSignatureType
globals['StaticLibrary'] = SCons.Defaults.StaticLibrary
globals['StaticObject'] = SCons.Defaults.StaticObject
globals['SharedLibrary'] = SCons.Defaults.SharedLibrary
diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py
index fd43b9a..1403724 100644
--- a/src/engine/SCons/Script/__init__.py
+++ b/src/engine/SCons/Script/__init__.py
@@ -61,7 +61,6 @@ import SCons.Node.FS
import SCons.Job
from SCons.Errors import *
import SCons.Sig
-import SCons.Sig.MD5
from SCons.Taskmaster import Taskmaster
import SCons.Builder
import SCons.Script.SConscript
@@ -178,6 +177,7 @@ exit_status = 0 # exit status, assume success by default
profiling = 0
max_drift = None
repositories = []
+sig_module = None
#
def print_it(text):
@@ -1040,9 +1040,14 @@ def _main():
if not calc:
if max_drift is not None:
- SCons.Sig.default_calc = SCons.Sig.Calculator(SCons.Sig.MD5,
- max_drift)
-
+ if sig_module is not None:
+ SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module,
+ max_drift=max_drift)
+ else:
+ SCons.Sig.default_calc = SCons.Sig.Calculator(max_drift=max_drift)
+ elif sig_module is not None:
+ SCons.Sig.default_calc = SCons.Sig.Calculator(module=sig_module)
+
calc = SCons.Sig.default_calc
display("scons: Building targets ...")
diff --git a/src/engine/SCons/Sig/TimeStamp.py b/src/engine/SCons/Sig/TimeStamp.py
index de0600d..997742d 100644
--- a/src/engine/SCons/Sig/TimeStamp.py
+++ b/src/engine/SCons/Sig/TimeStamp.py
@@ -63,6 +63,13 @@ def to_string(signature):
def from_string(string):
"""Convert a string to a timestamp"""
- return int(string)
+ try:
+ return int(string)
+ except ValueError:
+ # if the signature isn't an int, then
+ # the user probably just switched from
+ # MD5 signatures to timestamp signatures,
+ # so ignore the error:
+ return None
diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py
index b6a5c25..9a4c846 100644
--- a/src/engine/SCons/Sig/__init__.py
+++ b/src/engine/SCons/Sig/__init__.py
@@ -36,6 +36,13 @@ import SCons.Node
import time
import SCons.Warnings
+try:
+ import MD5
+ default_module = MD5
+except ImportError:
+ import TimeStamp
+ default_module = TimeStamp
+
#XXX Get rid of the global array so this becomes re-entrant.
sig_files = []
@@ -265,14 +272,13 @@ class SConsignFile:
except:
pass
-
class Calculator:
"""
Encapsulates signature calculations and .sconsign file generating
for the build engine.
"""
- def __init__(self, module=None, max_drift=2*24*60*60):
+ def __init__(self, module=default_module, max_drift=2*24*60*60):
"""
Initialize the calculator.
@@ -281,17 +287,7 @@ class Calculator:
cache content signatures. A negative value means to never cache
content signatures. (defaults to 2 days)
"""
- if module is None:
- try:
- import MD5
- self.module = MD5
- except ImportError:
- # fallback on timestamp signatures if MD5 is not available
- # XXX add a warning message here
- import TimeStamp
- self.module = TimeStamp
- else:
- self.module = module
+ self.module = module
self.max_drift = max_drift
def bsig(self, node):
diff --git a/test/SetContentSignatureType.py b/test/SetContentSignatureType.py
new file mode 100644
index 0000000..f9915ad
--- /dev/null
+++ b/test/SetContentSignatureType.py
@@ -0,0 +1,131 @@
+#!/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 imp
+import os
+import os.path
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.write('SConstruct', """
+def build(env, target, source):
+ open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
+B = Builder(action = build)
+env = Environment(BUILDERS = { 'B' : 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')
+env.B(target = 'f4.out', source = 'f4.in')
+
+SetContentSignatureType('timestamp')
+""")
+
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+
+test.run(arguments = 'f1.out f3.out')
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f3.out" is up to date.\n'))
+
+os.utime(test.workpath('f1.in'),
+ (os.path.getatime(test.workpath('f1.in')),
+ os.path.getmtime(test.workpath('f1.in'))+10))
+os.utime(test.workpath('f3.in'),
+ (os.path.getatime(test.workpath('f3.in')),
+ os.path.getmtime(test.workpath('f3.in'))+10))
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout('scons: "f2.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+
+test.write('SConstruct', """
+def build(env, target, source):
+ open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
+B = Builder(action = build)
+env = Environment(BUILDERS = { 'B' : 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')
+env.B(target = 'f4.out', source = 'f4.in')
+
+SetContentSignatureType('MD5')
+""")
+
+test.write('f1.in', "f1.in\n")
+test.write('f2.in', "f2.in\n")
+test.write('f3.in', "f3.in\n")
+test.write('f4.in', "f4.in\n")
+
+test.run(arguments = 'f1.out f3.out')
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f3.out" is up to date.\n'))
+
+os.utime(test.workpath('f1.in'),
+ (os.path.getatime(test.workpath('f1.in')),
+ os.path.getmtime(test.workpath('f1.in'))+10))
+os.utime(test.workpath('f3.in'),
+ (os.path.getatime(test.workpath('f3.in')),
+ os.path.getmtime(test.workpath('f3.in'))+10))
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f2.out" is up to date.\nscons: "f3.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+
+test.write('SConstruct', """
+def build(env, target, source):
+ open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
+B = Builder(action = build)
+env = Environment(BUILDERS = { 'B' : 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')
+env.B(target = 'f4.out', source = 'f4.in')
+""")
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout('scons: "f1.out" is up to date.\nscons: "f2.out" is up to date.\nscons: "f3.out" is up to date.\nscons: "f4.out" is up to date.\n'))
+
+test.pass_test()
+
+test.write('SConstruct', """
+def build(env, target, source):
+ open(str(target[0]), 'wt').write(open(str(source[0]), 'rt').read())
+B = Builder(action = build)
+env = Environment(BUILDERS = { 'B' : 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')
+env.B(target = 'f4.out', source = 'f4.in')
+
+SetContentSignatureType('timestamp')
+""")
+
+test.run(arguments = 'f1.out f2.out f3.out f4.out',
+ stdout = test.wrap_stdout(''))