From: stevenknight Date: Mon, 4 Nov 2002 23:01:27 +0000 (+0000) Subject: Add a function to choose content signature type. (Anthony Roach) X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=e0200d482d692ee1e09c3e51f53f14cfee06d51a;p=scons.git Add a function to choose content signature type. (Anthony Roach) git-svn-id: http://scons.tigris.org/svn/scons/trunk@489 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/config b/config index 28215e75..fc04c4b3 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 6307f34f..3d7d0341 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -2420,6 +2420,16 @@ SConscriptChdir(0) 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 ) @@ -2441,6 +2451,17 @@ is that arguments to the command. 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. diff --git a/runtest.py b/runtest.py index fddcd64f..98a24ebf 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 0b1b027e..c91a59ed 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 cb20ae9f..2802e8fd 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 fd43b9a2..1403724f 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 de0600d9..997742d5 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 b6a5c25f..9a4c8469 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 00000000..f9915add --- /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(''))