From: stevenknight Date: Sat, 18 Oct 2003 19:22:25 +0000 (+0000) Subject: Allow SConsignFile() to take a dbm module argument; portability fixes. (Ralf W.... X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=af769da57fe1dcae109a366756167cbe9b89fec6;p=scons.git Allow SConsignFile() to take a dbm module argument; portability fixes. (Ralf W. Grosse-Kunstleve) Make ParseConfig() and env.Append() work regardless of initial construction variable values. Make new Dir() support work with empty directories and timestamps. Make the new Queue-based Job implementation portable to Python 1.5.2. git-svn-id: http://scons.tigris.org/svn/scons/trunk@821 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/CHANGES.txt b/src/CHANGES.txt index 1ab7499c..6e81a3e3 100644 --- a/src/CHANGES.txt +++ b/src/CHANGES.txt @@ -56,6 +56,9 @@ RELEASE X.XX - XXX - Accomodate anydbm modules that don't have a sync() method. + - Allow SConsignFile() to take an argument specifying the DBM + module to be used. + From Stephen Kennedy: - Add support for a configurable global .sconsign.dbm file which @@ -118,6 +121,11 @@ RELEASE X.XX - XXX - Remove the long-obsolete {Get,Set}CommandHandler() functions. + - Enhance env.Append() to suppress null values when appropriate. + + - Fix ParseConfig() so it works regardless of initial construction + variable values. + From Clark McGrew: - Generalize the action for .tex files so that it will decide whether diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index f8ff6c35..e320f058 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -427,10 +427,14 @@ class Base: self._dict[key] = kw[key] elif SCons.Util.is_List(self._dict[key]) and not \ SCons.Util.is_List(kw[key]): - self._dict[key] = self._dict[key] + [ kw[key] ] + if not kw[key] is None and kw[key] != '': + self._dict[key] = self._dict[key] + [ kw[key] ] elif SCons.Util.is_List(kw[key]) and not \ SCons.Util.is_List(self._dict[key]): - self._dict[key] = [ self._dict[key] ] + kw[key] + if self._dict[key] is None or self._dict[key] == '': + self._dict[key] = kw[key] + else: + self._dict[key] = [ self._dict[key] ] + kw[key] elif SCons.Util.is_Dict(self._dict[key]) and \ SCons.Util.is_Dict(kw[key]): self._dict[key].update(kw[key]) @@ -549,34 +553,30 @@ class Base: # the default parse function def parse_conf(env, output): - env_dict = env.Dictionary() + dict = { + 'CPPPATH' : [], + 'LIBPATH' : [], + 'LIBS' : [], + 'CCFLAGS' : [], + } static_libs = [] - # setup all the dictionary options - if not env_dict.has_key('CPPPATH'): - env_dict['CPPPATH'] = [] - if not env_dict.has_key('LIBPATH'): - env_dict['LIBPATH'] = [] - if not env_dict.has_key('LIBS'): - env_dict['LIBS'] = [] - if not env_dict.has_key('CCFLAGS') or env_dict['CCFLAGS'] == "": - env_dict['CCFLAGS'] = [] - params = string.split(output) for arg in params: switch = arg[0:1] opt = arg[1:2] if switch == '-': if opt == 'L': - env_dict['LIBPATH'].append(arg[2:]) + dict['LIBPATH'].append(arg[2:]) elif opt == 'l': - env_dict['LIBS'].append(arg[2:]) + dict['LIBS'].append(arg[2:]) elif opt == 'I': - env_dict['CPPPATH'].append(arg[2:]) + dict['CPPPATH'].append(arg[2:]) else: - env_dict['CCFLAGS'].append(arg) + dict['CCFLAGS'].append(arg) else: static_libs.append(arg) + apply(env.Append, (), dict) return static_libs if function is None: @@ -940,11 +940,11 @@ class Base: nkw = self.subst_kw(kw) return apply(SCons.Scanner.Base, nargs, nkw) - def SConsignFile(self, name=".sconsign.dbm"): + def SConsignFile(self, name=".sconsign.dbm", dbm_module=None): name = self.subst(name) if not os.path.isabs(name): name = os.path.join(str(self.fs.SConstruct_dir), name) - SCons.Sig.SConsignFile(name) + SCons.Sig.SConsignFile(name, dbm_module) def SideEffect(self, side_effect, target): """Tell scons that side_effects are built as side diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 49d6ac72..2ad0a329 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -724,20 +724,58 @@ class EnvironmentTestCase(unittest.TestCase): import UserList UL = UserList.UserList - env1 = Environment(AAA = 'a', BBB = 'b', CCC = 'c', DDD = 'd', - EEE = ['e'], FFF = ['f'], GGG = ['g'], HHH = ['h'], - III = UL(['i']), JJJ = UL(['j']), - KKK = UL(['k']), LLL = UL(['l'])) - env1.Append(BBB = 'B', CCC = ['C'], DDD = UL(['D']), - FFF = 'F', GGG = ['G'], HHH = UL(['H']), - JJJ = 'J', KKK = ['K'], LLL = UL(['L'])) - env2 = Environment(AAA = 'a', BBB = 'bB', - CCC = ['c', 'C'], DDD = UL(['d', 'D']), - EEE = ['e'], FFF = ['f', 'F'], - GGG = ['g', 'G'], HHH = UL(['h', 'H']), - III = UL(['i']), JJJ = UL(['j', 'J']), - KKK = UL(['k', 'K']), LLL = UL(['l', 'L'])) - assert env1 == env2, diff_env(env1, env2) + env1 = Environment(AAA = 'a', + AAA1 = 'a1', AAA2 = 'a2', AAA3 = 'a3', + EEE = ['e'], + EEE1 = ['e1'], EEE2 = ['e2'], EEE3 = ['e3'], + III = UL(['i']), + III1 = UL(['i1']), III2 = UL(['i2']), III3 = UL(['i3']), + MMM = '', + MMM1 = '', MMM2 = '', MMM3 = '', + NNN = [], + NNN1 = [], NNN2 = [], NNN3 = [], + OOO = UL([]), + OOO1 = UL([]), OOO2 = UL([]), OOO3 = UL([]), + PPP = [''], + PPP1 = [''], PPP2 = [''], PPP3 = [''], + QQQ = UL(['']), + QQQ1 = UL(['']), QQQ2 = UL(['']), QQQ3 = UL([''])) + env1.Append(AAA1 = 'A1', AAA2 = ['A2'], AAA3 = UL(['A3']), + EEE1 = 'E1', EEE2 = ['E2'], EEE3 = UL(['E3']), + III1 = 'I1', III2 = ['I2'], III3 = UL(['I3']), + MMM1 = 'M1', MMM2 = ['M2'], MMM3 = UL(['M3']), + NNN1 = 'N1', NNN2 = ['N2'], NNN3 = UL(['N3']), + OOO1 = 'O1', OOO2 = ['O2'], OOO3 = UL(['O3']), + PPP1 = 'P1', PPP2 = ['P2'], PPP3 = UL(['P3']), + QQQ1 = 'Q1', QQQ2 = ['Q2'], QQQ3 = UL(['Q3'])) + assert env1['AAA'] == 'a', env1['AAA'] + assert env1['AAA1'] == 'a1A1', env1['AAA1'] + assert env1['AAA2'] == ['a2', 'A2'], env1['AAA2'] + assert env1['AAA3'] == UL(['a3', 'A3']), env1['AAA3'] + assert env1['EEE'] == ['e'], env1['EEE'] + assert env1['EEE1'] == ['e1', 'E1'], env1['EEE1'] + assert env1['EEE2'] == ['e2', 'E2'], env1['EEE2'] + assert env1['EEE3'] == UL(['e3', 'E3']), env1['EEE3'] + assert env1['III'] == UL(['i']), env1['III'] + assert env1['III1'] == UL(['i1', 'I1']), env1['III1'] + assert env1['III2'] == UL(['i2', 'I2']), env1['III2'] + assert env1['III3'] == UL(['i3', 'I3']), env1['III3'] + assert env1['MMM'] == '', env1['MMM'] + assert env1['MMM1'] == 'M1', env1['MMM1'] + assert env1['MMM2'] == ['M2'], env1['MMM2'] + assert env1['MMM3'] == UL(['M3']), env1['MMM3'] + assert env1['NNN1'] == ['N1'], env1['NNN1'] + assert env1['NNN2'] == ['N2'], env1['NNN2'] + assert env1['NNN3'] == UL(['N3']), env1['NNN3'] + assert env1['OOO1'] == ['O1'], env1['OOO1'] + assert env1['OOO2'] == ['O2'], env1['OOO2'] + assert env1['OOO3'] == UL(['O3']), env1['OOO3'] + assert env1['PPP1'] == ['', 'P1'], env1['PPP1'] + assert env1['PPP2'] == ['', 'P2'], env1['PPP2'] + assert env1['PPP3'] == UL(['', 'P3']), env1['PPP3'] + assert env1['QQQ1'] == UL(['', 'Q1']), env1['QQQ1'] + assert env1['QQQ2'] == UL(['', 'Q2']), env1['QQQ2'] + assert env1['QQQ3'] == UL(['', 'Q3']), env1['QQQ3'] env3 = Environment(X = {'x1' : 7}) env3.Append(X = {'x1' : 8, 'x2' : 9}, Y = {'y1' : 10}) @@ -946,7 +984,11 @@ class EnvironmentTestCase(unittest.TestCase): def test_ParseConfig(self): """Test the ParseConfig() method""" - env = Environment(COMMAND='command') + env = Environment(COMMAND='command', + CPPPATH='string', + LIBPATH=['list'], + LIBS='', + CCFLAGS=['']) save_command = [] orig_popen = os.popen def my_popen(command, save_command=save_command): @@ -961,10 +1003,10 @@ class EnvironmentTestCase(unittest.TestCase): libs = env.ParseConfig("fake $COMMAND") assert save_command == ['fake command'], save_command assert libs == ['abc'], libs - assert env['CPPPATH'] == ['/usr/include/fum', 'bar'], env['CPPPATH'] - assert env['LIBPATH'] == ['/usr/fax', 'foo'], env['LIBPATH'] + assert env['CPPPATH'] == ['string', '/usr/include/fum', 'bar'], env['CPPPATH'] + assert env['LIBPATH'] == ['list', '/usr/fax', 'foo'], env['LIBPATH'] assert env['LIBS'] == ['xxx'], env['LIBS'] - assert env['CCFLAGS'] == ['-X'], env['CCFLAGS'] + assert env['CCFLAGS'] == ['', '-X'], env['CCFLAGS'] finally: os.popen = orig_popen @@ -1723,27 +1765,34 @@ class EnvironmentTestCase(unittest.TestCase): env.fs = MyFS() try: - save = [] - def capture(name, save=save): - save.append(name) + fnames = [] + dbms = [] + def capture(name, dbm_module, fnames=fnames, dbms=dbms): + fnames.append(name) + dbms.append(dbm_module) save_Sig_SConsignFile = SCons.Sig.SConsignFile SCons.Sig.SConsignFile = capture env.SConsignFile('foo') - assert save[0] == os.path.join(os.sep, 'dir', 'foo'), save + assert fnames[0] == os.path.join(os.sep, 'dir', 'foo'), fnames + assert dbms[0] == None, dbms env.SConsignFile('$FOO') - assert save[1] == os.path.join(os.sep, 'dir', 'SConsign'), save + assert fnames[1] == os.path.join(os.sep, 'dir', 'SConsign'), fnames + assert dbms[1] == None, dbms env.SConsignFile('/$FOO') - assert save[2] == '/SConsign', save + assert fnames[2] == '/SConsign', fnames + assert dbms[2] == None, dbms - env.SConsignFile('$BAR') - assert save[3] == os.path.join(os.sep, 'File'), save + env.SConsignFile('$BAR', 'x') + assert fnames[3] == os.path.join(os.sep, 'File'), fnames + assert dbms[3] == 'x', dbms - env.SConsignFile('__$BAR') - assert save[4] == os.path.join(os.sep, 'dir', '__', 'File'), save + env.SConsignFile('__$BAR', 7) + assert fnames[4] == os.path.join(os.sep, 'dir', '__', 'File'), fnames + assert dbms[4] == 7, dbms finally: SCons.Sig.SConsignFile = save_Sig_SConsignFile diff --git a/src/engine/SCons/Executor.py b/src/engine/SCons/Executor.py index 2b4e634f..12dfcc7e 100644 --- a/src/engine/SCons/Executor.py +++ b/src/engine/SCons/Executor.py @@ -138,4 +138,4 @@ class Executor: course (only files do), but this is the interface used by the timestamp module. """ - return None + return 0 diff --git a/src/engine/SCons/ExecutorTests.py b/src/engine/SCons/ExecutorTests.py index 6af5794f..6ead3068 100644 --- a/src/engine/SCons/ExecutorTests.py +++ b/src/engine/SCons/ExecutorTests.py @@ -160,7 +160,7 @@ class ExecutorTestCase(unittest.TestCase): """Test fetching the "timestamp" """ x = SCons.Executor.Executor('b', 'e', 'o', 't', ['s1', 's2']) ts = x.get_timestamp() - assert ts is None, ts + assert ts == 0, ts if __name__ == "__main__": diff --git a/src/engine/SCons/Job.py b/src/engine/SCons/Job.py index 0c01b852..b5296dc8 100644 --- a/src/engine/SCons/Job.py +++ b/src/engine/SCons/Job.py @@ -136,9 +136,9 @@ class Worker(threading.Thread): try: task.execute() except: - ok = False + ok = 0 else: - ok = True + ok = 1 self.resultsQueue.put((task, ok)) @@ -147,8 +147,8 @@ class ThreadPool: def __init__(self, num): """Create the request and reply queues, and 'num' worker threads.""" - self.requestQueue = Queue.Queue() - self.resultsQueue = Queue.Queue() + self.requestQueue = Queue.Queue(0) + self.resultsQueue = Queue.Queue(0) # Create worker threads for i in range(num): @@ -165,7 +165,7 @@ class ThreadPool: def get_nowait(self): """Remove and result a result tuple from the results queue without blocking.""" - return self.get(False) + return self.get(0) class Parallel: """This class is used to execute tasks in parallel, and is somewhat diff --git a/src/engine/SCons/JobTests.py b/src/engine/SCons/JobTests.py index 2c840285..1b09fd64 100644 --- a/src/engine/SCons/JobTests.py +++ b/src/engine/SCons/JobTests.py @@ -172,9 +172,9 @@ class Taskmaster: def is_blocked(self): if self.stop or self.all_tasks_are_executed(): - return False + return 0 if self.all_tasks_are_iterated(): - return True + return 1 # simulate blocking tasks return self.num_iterated - self.num_executed >= max(num_jobs/2, 2) diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index d93a6a49..b183a881 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -912,7 +912,7 @@ class DummyExecutor: def get_contents(self): return '' def get_timestamp(self): - return None + return 0 class Dir(Base): """A class for directories in a file system. @@ -1148,7 +1148,7 @@ class Dir(Base): def get_timestamp(self): """Return the latest timestamp from among our children""" - stamp = None + stamp = 0 for kid in self.children(None): if kid.get_timestamp() > stamp: stamp = kid.get_timestamp() diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 53e2013b..2237959e 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -985,6 +985,27 @@ class FSTestCase(unittest.TestCase): finally: test.unlink("tstamp") + test.subdir('tdir1') + d = fs.Dir('tdir1') + t = d.get_timestamp() + assert t == 0, "expected 0, got %s" % str(t) + + test.subdir('tdir2') + d = fs.Dir('tdir2') + f1 = test.workpath('tdir2', 'file1') + f2 = test.workpath('tdir2', 'file2') + test.write(f1, 'file1\n') + test.write(f2, 'file2\n') + fs.File(f1) + fs.File(f2) + current_time = float(int(time.time() / 2) * 2) + t1 = current_time - 4.0 + t2 = current_time - 2.0 + os.utime(f1, (t1 - 2.0, t1)) + os.utime(f2, (t2 - 2.0, t2)) + t = d.get_timestamp() + assert t == t2, "expected %f, got %f" % (t2, t) + #XXX test get_prevsiginfo() skey = fs.Entry('eee.x').scanner_key() diff --git a/src/engine/SCons/Sig/SigTests.py b/src/engine/SCons/Sig/SigTests.py index c82d2c5f..f297464d 100644 --- a/src/engine/SCons/Sig/SigTests.py +++ b/src/engine/SCons/Sig/SigTests.py @@ -490,6 +490,41 @@ class SConsignDirFileTestCase(unittest.TestCase): assert f.get('foo') == (3, 1, 2) assert f.get_implicit('foo') == ['bar'] +class SConsignFileTestCase(unittest.TestCase): + + def runTest(self): + test = TestCmd.TestCmd(workdir = '') + file = test.workpath('sconsign_file') + + assert SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db + + SCons.Sig.SConsignFile(file) + + assert not SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db + + class Fake_DBM: + def open(self, name, mode): + self.name = name + self.mode = mode + return self + + fake_dbm = Fake_DBM() + + SCons.Sig.SConsignFile(file, fake_dbm) + + assert not SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db + assert not hasattr(fake_dbm, 'name'), fake_dbm + assert not hasattr(fake_dbm, 'mode'), fake_dbm + + SCons.Sig.SConsign_db = None + + SCons.Sig.SConsignFile(file, fake_dbm) + + assert not SCons.Sig.SConsign_db is None, SCons.Sig.SConsign_db + assert fake_dbm.name == file, fake_dbm.name + assert fake_dbm.mode == "c", fake_dbm.mode + + def suite(): suite = unittest.TestSuite() @@ -500,6 +535,7 @@ def suite(): suite.addTest(_SConsignTestCase()) suite.addTest(SConsignDBTestCase()) suite.addTest(SConsignDirFileTestCase()) + suite.addTest(SConsignFileTestCase()) return suite if __name__ == "__main__": diff --git a/src/engine/SCons/Sig/__init__.py b/src/engine/SCons/Sig/__init__.py index 4898f29e..dfddf341 100644 --- a/src/engine/SCons/Sig/__init__.py +++ b/src/engine/SCons/Sig/__init__.py @@ -301,15 +301,17 @@ class SConsignDirFile(SConsignDir): SConsignForDirectory = SConsignDirFile -def SConsignFile(name): +def SConsignFile(name, dbm_module=None): """ Arrange for all signatures to be stored in a global .sconsign.dbm file. """ global SConsign_db if SConsign_db is None: - import anydbm - SConsign_db = anydbm.open(name, "c") + if dbm_module is None: + import anydbm + dbm_module = anydbm + SConsign_db = dbm_module.open(name, "c") global SConsignForDirectory SConsignForDirectory = SConsignDB