From 64a0553a81deaa7cab0158d9f533a1f460ad2c8b Mon Sep 17 00:00:00 2001 From: Steven Knight Date: Wed, 17 Jul 2002 23:12:12 +0000 Subject: Repository support (first cut). --- doc/man/scons.1 | 16 +- src/RELEASE.txt | 2 - src/engine/SCons/Action.py | 14 +- src/engine/SCons/ActionTests.py | 14 ++ src/engine/SCons/Environment.py | 13 +- src/engine/SCons/EnvironmentTests.py | 48 ++++++ src/engine/SCons/Node/FS.py | 44 +++++- src/engine/SCons/Node/FSTests.py | 50 +++++++ src/engine/SCons/Node/NodeTests.py | 12 +- src/engine/SCons/Node/__init__.py | 3 + src/engine/SCons/Script/SConscript.py | 7 +- src/engine/SCons/Script/__init__.py | 16 +- test/Repository/.aeignore | 4 + test/Repository/Program.py | 169 +++++++++++++++++++++ test/Repository/include.py | 186 ++++++++++++++++++++++++ test/Repository/no-repository.py | 91 ++++++++++++ test/option--Y.py | 266 +++++++++++++++++++++++++++++++++- 17 files changed, 918 insertions(+), 37 deletions(-) create mode 100644 test/Repository/.aeignore create mode 100644 test/Repository/Program.py create mode 100644 test/Repository/include.py create mode 100644 test/Repository/no-repository.py diff --git a/doc/man/scons.1 b/doc/man/scons.1 index d32b7ff..f574fb3 100644 --- a/doc/man/scons.1 +++ b/doc/man/scons.1 @@ -634,14 +634,14 @@ Turn off -w, even if it was turned on implicitly. .\" .TP .\" --warn-undefined-variables .\" Warn when an undefined variable is referenced. -.\" -.\" .TP -.\" .RI -Y " repository" ", --repository=" repository -.\" Search the specified repository for any input and target -.\" files not found in the local directory hierarchy. Multiple -.\" .B -Y -.\" options may specified, in which case the -.\" repositories are searched in the order specified. + +.TP +.RI -Y " repository" ", --repository=" repository +Search the specified repository for any input and target +files not found in the local directory hierarchy. Multiple +.B -Y +options may specified, in which case the +repositories are searched in the order specified. .SH CONFIGURATION FILE REFERENCE .\" .SS Python Basics diff --git a/src/RELEASE.txt b/src/RELEASE.txt index 7124eff..0dab6ce 100644 --- a/src/RELEASE.txt +++ b/src/RELEASE.txt @@ -177,8 +177,6 @@ RELEASE 0.08 - Mon, 15 Jul 2002 12:08:51 -0500 - No support yet for the following future features: - - Repository search paths (-Y) - - Configurable signature calculation - No support for caching built files. diff --git a/src/engine/SCons/Action.py b/src/engine/SCons/Action.py index c222d26..79fdd2c 100644 --- a/src/engine/SCons/Action.py +++ b/src/engine/SCons/Action.py @@ -266,11 +266,17 @@ class ActionBase: try: cwd = kw['dir'] - except: + except KeyError: cwd = None else: del kw['dir'] + def rstr(x): + try: + return x.rstr() + except AttributeError: + return str(x) + if kw.has_key('target'): t = kw['target'] del kw['target'] @@ -280,7 +286,7 @@ class ActionBase: cwd = t[0].cwd except (IndexError, AttributeError): pass - dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(str, t))) + dict['TARGETS'] = SCons.Util.PathList(map(os.path.normpath, map(rstr, t))) if dict['TARGETS']: dict['TARGET'] = dict['TARGETS'][0] @@ -289,7 +295,7 @@ class ActionBase: del kw['source'] if not SCons.Util.is_List(s): s = [s] - dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(str, s))) + dict['SOURCES'] = SCons.Util.PathList(map(os.path.normpath, map(rstr, s))) if dict['SOURCES']: dict['SOURCE'] = dict['SOURCES'][0] @@ -357,7 +363,7 @@ class CommandAction(ActionBase): if execute_actions: try: ENV = kw['env']['ENV'] - except: + except KeyError: global default_ENV if not default_ENV: import SCons.Environment diff --git a/src/engine/SCons/ActionTests.py b/src/engine/SCons/ActionTests.py index c1425ef..5fa1b8b 100644 --- a/src/engine/SCons/ActionTests.py +++ b/src/engine/SCons/ActionTests.py @@ -114,6 +114,20 @@ class ActionBaseTestCase(unittest.TestCase): assert SOURCES == ['s1', 's2'], d['SOURCES'] assert str(d['SOURCE']) == 's1', d['SOURCE'] + class N: + def __init__(self, name): + self.name = name + def rstr(self): + return 'rstr-' + self.name + + d = a.subst_dict(target = [N('t3'), 't4'], source = ['s3', N('s4')]) + TARGETS = map(lambda x: str(x), d['TARGETS']) + TARGETS.sort() + assert TARGETS == ['rstr-t3', 't4'], d['TARGETS'] + SOURCES = map(lambda x: str(x), d['SOURCES']) + SOURCES.sort() + assert SOURCES == ['rstr-s4', 's3'], d['SOURCES'] + class CommandActionTestCase(unittest.TestCase): def test_init(self): diff --git a/src/engine/SCons/Environment.py b/src/engine/SCons/Environment.py index 42aa326..da7c15a 100644 --- a/src/engine/SCons/Environment.py +++ b/src/engine/SCons/Environment.py @@ -492,13 +492,18 @@ class DirVarInterp(VarInterpolator): def prepare(x, self=self): if isinstance(x, SCons.Node.Node): - return x + return [x] elif str(x): - return self.fs.Dir(str(x), directory=self.dir) + if os.path.isabs(str(x)): + return [self.fs.Dir(str(x), directory=self.dir)] + else: + return map(lambda d, s=str(x), fs=self.fs: + fs.Dir(s, directory=d), + [self.dir] + self.fs.Repositories) else: - return None + return [] - return map(prepare, src) + return reduce(lambda x, y: x+y, map(prepare, src), []) def instance(self, dir, fs): try: diff --git a/src/engine/SCons/EnvironmentTests.py b/src/engine/SCons/EnvironmentTests.py index 75e5e83..418d891 100644 --- a/src/engine/SCons/EnvironmentTests.py +++ b/src/engine/SCons/EnvironmentTests.py @@ -507,6 +507,54 @@ class EnvironmentTestCase(unittest.TestCase): assert len(dict['_F77INCFLAGS']) == 0, dict['_F77INCFLAGS'] assert len(dict['_LIBDIRFLAGS']) == 0, dict['_LIBDIRFLAGS'] + blat = SCons.Node.FS.default_fs.File('blat') + SCons.Node.FS.default_fs.Repository('/rep1') + SCons.Node.FS.default_fs.Repository('/rep2') + env = Environment(CPPPATH = [ 'foo', '/a/b', '$FOO/bar', blat], + INCPREFIX = '-I ', + INCSUFFIX = 'XXX', + FOO = 'baz') + dict = env.autogenerate(dir = SCons.Node.FS.default_fs.Dir('/xx')) + assert len(dict['_CPPINCFLAGS']) == 18, dict['_CPPINCFLAGS'] + assert dict['_CPPINCFLAGS'][0] == '$(', \ + dict['_CPPINCFLAGS'][0] + assert dict['_CPPINCFLAGS'][1] == '-I', \ + dict['_CPPINCFLAGS'][1] + assert dict['_CPPINCFLAGS'][2] == os.path.normpath('/xx/fooXXX'), \ + dict['_CPPINCFLAGS'][2] + assert dict['_CPPINCFLAGS'][3] == '-I', \ + dict['_CPPINCFLAGS'][3] + assert dict['_CPPINCFLAGS'][4] == os.path.normpath('/rep1/fooXXX'), \ + dict['_CPPINCFLAGS'][4] + assert dict['_CPPINCFLAGS'][5] == '-I', \ + dict['_CPPINCFLAGS'][5] + assert dict['_CPPINCFLAGS'][6] == os.path.normpath('/rep2/fooXXX'), \ + dict['_CPPINCFLAGS'][6] + assert dict['_CPPINCFLAGS'][7] == '-I', \ + dict['_CPPINCFLAGS'][7] + assert dict['_CPPINCFLAGS'][8] == os.path.normpath('/a/bXXX'), \ + dict['_CPPINCFLAGS'][8] + assert dict['_CPPINCFLAGS'][9] == '-I', \ + dict['_CPPINCFLAGS'][9] + assert dict['_CPPINCFLAGS'][10] == os.path.normpath('/xx/baz/barXXX'), \ + dict['_CPPINCFLAGS'][10] + assert dict['_CPPINCFLAGS'][11] == '-I', \ + dict['_CPPINCFLAGS'][11] + assert dict['_CPPINCFLAGS'][12] == os.path.normpath('/rep1/baz/barXXX'), \ + dict['_CPPINCFLAGS'][12] + assert dict['_CPPINCFLAGS'][13] == '-I', \ + dict['_CPPINCFLAGS'][13] + assert dict['_CPPINCFLAGS'][14] == os.path.normpath('/rep2/baz/barXXX'), \ + dict['_CPPINCFLAGS'][14] + assert dict['_CPPINCFLAGS'][15] == '-I', \ + dict['_CPPINCFLAGS'][15] + assert dict['_CPPINCFLAGS'][16] == os.path.normpath('blatXXX'), \ + dict['_CPPINCFLAGS'][16] + assert dict['_CPPINCFLAGS'][17] == '$)', \ + dict['_CPPINCFLAGS'][17] + + + def test_platform(self): """Test specifying a platform callable when instantiating.""" def p(env): diff --git a/src/engine/SCons/Node/FS.py b/src/engine/SCons/Node/FS.py index 771ac56..2645cea 100644 --- a/src/engine/SCons/Node/FS.py +++ b/src/engine/SCons/Node/FS.py @@ -99,6 +99,7 @@ class FS: self.pathTop = path self.Root = {} self.Top = None + self.Repositories = [] def set_toplevel_dir(self, path): assert not self.Top, "You can only set the top-level path on an FS object that has not had its File, Dir, or Entry methods called yet." @@ -152,9 +153,9 @@ class FS: drive, path_first = os.path.splitdrive(path_comp[0]) if not path_first: # Absolute path - drive = _my_normcase(drive) + drive_path = _my_normcase(drive) try: - directory = self.Root[drive] + directory = self.Root[drive_path] except KeyError: if not create: raise UserError @@ -162,7 +163,7 @@ class FS: dir.path = dir.path + os.sep dir.abspath = dir.abspath + os.sep dir.srcpath = dir.srcpath + os.sep - self.Root[drive] = dir + self.Root[drive_path] = dir directory = dir path_comp = path_comp[1:] else: @@ -209,6 +210,7 @@ class FS: "File %s found where directory expected." % path ret = fsclass(path_comp[-1], directory) + ret.fs = self directory.entries[file_name] = ret directory.add_wkid(ret) return ret @@ -295,6 +297,20 @@ class FS: raise UserError, "Source directory cannot be under build directory." build_dir.link(src_dir, duplicate) + def Repository(self, *dirs): + """Specify repository directories to search.""" + for d in dirs: + self.Repositories.append(self.Dir(d)) + + def Rsearch(self, path, func = os.path.exists): + """Search for something in a repository.""" + for dir in self.Repositories: + t = os.path.join(dir.path, path) + if func(t): + return t + return None + + class Entry(SCons.Node.Node): """A generic class for file system entries. This class if for when we don't know yet whether the entry being looked up is a file @@ -334,6 +350,7 @@ class Entry(SCons.Node.Node): self.__doSrcpath(self.duplicate) self.srcpath_ = self.srcpath self.cwd = None # will hold the SConscript directory for target nodes + self._rfile = None def get_dir(self): return self.dir @@ -372,7 +389,7 @@ class Entry(SCons.Node.Node): raise AttributeError def exists(self): - return os.path.exists(str(self)) + return os.path.exists(self.rstr()) def cached_exists(self): try: @@ -420,6 +437,7 @@ class Dir(Entry): def __init__(self, name, directory): Entry.__init__(self, name, directory) self._morph() + self._rfile = None def _morph(self): """Turn a file system node (either a freshly initialized @@ -573,11 +591,11 @@ class File(Entry): def get_contents(self): if not self.exists(): return '' - return open(str(self), "rb").read() + return open(self.rstr(), "rb").read() def get_timestamp(self): if self.exists(): - return os.path.getmtime(str(self)) + return os.path.getmtime(self.rstr()) else: return 0 @@ -594,6 +612,8 @@ class File(Entry): self.dir.sconsign().set_timestamp(self.name, self.get_timestamp()) def get_prevsiginfo(self): + """Fetch the previous signature information from the + .sconsign entry.""" return self.dir.sconsign().get(self.name) def get_stored_implicit(self): @@ -650,6 +670,18 @@ class File(Entry): else: self.__createDir() + def rfile(self): + if not self._rfile: + self._rfile = self + if not os.path.isabs(self.path) and not os.path.isfile(self.path): + t = self.fs.Rsearch(self.path, os.path.isfile) + if t: + self._rfile = self.fs.File(t) + return self._rfile + + def rstr(self): + return os.path.normpath(str(self.rfile())) + default_fs = FS() diff --git a/src/engine/SCons/Node/FSTests.py b/src/engine/SCons/Node/FSTests.py index 1ae1215..595396a 100644 --- a/src/engine/SCons/Node/FSTests.py +++ b/src/engine/SCons/Node/FSTests.py @@ -530,6 +530,55 @@ class FSTestCase(unittest.TestCase): exc_caught = 1 assert exc_caught, "Should have caught a TypeError" +class RepositoryTestCase(unittest.TestCase): + def runTest(self): + """Test FS (file system) Repository operations + + """ + fs = SCons.Node.FS.FS() + + fs.Repository('foo') + fs.Repository(os.path.join('foo', 'bar')) + fs.Repository(os.path.join('bar', 'foo')) + fs.Repository('bar') + + assert len(fs.Repositories) == 4, fs.Repositories + r = map(lambda x, np=os.path.normpath: np(str(x)), fs.Repositories) + assert r == ['foo', 'foo/bar', 'bar/foo', 'bar'], r + + test = TestCmd(workdir = '') + test.subdir('rep1', 'rep2', 'rep3', 'work') + + rep1 = test.workpath('rep1') + rep2 = test.workpath('rep2') + rep3 = test.workpath('rep3') + + os.chdir(test.workpath('work')) + + fs = SCons.Node.FS.FS() + fs.Repository(rep1, rep2, rep3) + + wf = fs.File(os.path.join('f1')) + assert wf.rfile() is wf + + test.write([rep1, 'f2'], "") + + wf = fs.File('f2') + assert not wf.rfile() is wf, wf.rfile() + assert str(wf.rfile()) == os.path.join(rep1, 'f2'), str(wf.rfile()) + + test.subdir([rep2, 'f3']) + test.write([rep3, 'f3'], "") + + wf = fs.File('f3') + assert not wf.rfile() is wf, wf.rfile() + assert wf.rstr() == os.path.join(rep3, 'f3'), wf.rstr() + + assert not fs.Rsearch('f1', os.path.exists) + assert fs.Rsearch('f2', os.path.exists) + assert fs.Rsearch('f3', os.path.exists) + + class find_fileTestCase(unittest.TestCase): def runTest(self): """Testing find_file function""" @@ -553,6 +602,7 @@ if __name__ == "__main__": suite = unittest.TestSuite() suite.addTest(FSTestCase()) suite.addTest(BuildDirTestCase()) + suite.addTest(RepositoryTestCase()) suite.addTest(find_fileTestCase()) if not unittest.TextTestRunner().run(suite).wasSuccessful(): sys.exit(1) diff --git a/src/engine/SCons/Node/NodeTests.py b/src/engine/SCons/Node/NodeTests.py index 03b06bd..cbd5473 100644 --- a/src/engine/SCons/Node/NodeTests.py +++ b/src/engine/SCons/Node/NodeTests.py @@ -41,7 +41,7 @@ cycle_detected = None class Builder: def execute(self, **kw): global built_it, built_target, built_source, built_args - built_it = 1 + built_it = 1 built_target = kw['target'] built_source = kw['source'] built_args = kw @@ -555,6 +555,16 @@ class NodeTestCase(unittest.TestCase): n = nw.next() assert nw.next() == None + def test_rstr(self): + """Test the rstr() method.""" + class MyNode(SCons.Node.Node): + def __init__(self, name): + self.name = name + def __str__(self): + return self.name + n1 = MyNode("n1") + assert n1.rstr() == 'n1', n1.rstr() + def test_arg2nodes(self): """Test the arg2nodes function.""" dict = {} diff --git a/src/engine/SCons/Node/__init__.py b/src/engine/SCons/Node/__init__.py index 90cd122..2a5e5bc 100644 --- a/src/engine/SCons/Node/__init__.py +++ b/src/engine/SCons/Node/__init__.py @@ -356,6 +356,9 @@ class Node: def current(self): return None + def rstr(self): + return str(self) + def get_children(node, parent): return node.children() def ignore_cycle(node, stack): pass def do_nothing(node, parent): pass diff --git a/src/engine/SCons/Script/SConscript.py b/src/engine/SCons/Script/SConscript.py index 48c4046..e088c99 100644 --- a/src/engine/SCons/Script/SConscript.py +++ b/src/engine/SCons/Script/SConscript.py @@ -167,7 +167,7 @@ def SConscript(*ls, **kw): else: f = SCons.Node.FS.default_fs.File(str(fn)) if f.exists(): - file = open(str(f), "r") + file = open(f.rstr(), "r") SCons.Node.FS.default_fs.chdir(f.dir) if sconscript_chdir: old_dir = os.getcwd() @@ -276,10 +276,13 @@ def BuildDefaultGlobals(): globals['FindFile'] = FindFile globals['GetBuildPath'] = GetBuildPath globals['GetCommandHandler'] = SCons.Action.GetCommandHandler + globals['GetLaunchDir'] = GetLaunchDir globals['Help'] = Help globals['Import'] = Import globals['Library'] = SCons.Defaults.StaticLibrary globals['Object'] = SCons.Defaults.StaticObject + globals['Repository'] = SCons.Node.FS.default_fs.Repository + globals['SetBuildSignatureType'] = SetBuildSignatureType globals['StaticLibrary'] = SCons.Defaults.StaticLibrary globals['StaticObject'] = SCons.Defaults.StaticObject globals['SharedLibrary'] = SCons.Defaults.SharedLibrary @@ -294,6 +297,4 @@ def BuildDefaultGlobals(): globals['Split'] = SCons.Util.Split globals['Tool'] = SCons.Tool.Tool globals['WhereIs'] = SCons.Util.WhereIs - globals['GetLaunchDir'] = GetLaunchDir - globals['SetBuildSignatureType'] = SetBuildSignatureType return globals diff --git a/src/engine/SCons/Script/__init__.py b/src/engine/SCons/Script/__init__.py index 66b4fd7..10794f5 100644 --- a/src/engine/SCons/Script/__init__.py +++ b/src/engine/SCons/Script/__init__.py @@ -185,6 +185,7 @@ target_top = None exit_status = 0 # exit status, assume success by default profiling = 0 max_drift = None +repositories = [] # utility functions @@ -792,7 +793,11 @@ def options_init(): # long = ['warn-undefined-variables'], # help = "Warn when an undefined variable is referenced.") - Option(func = opt_not_yet, future = 1, + def opt_Y(opt, arg): + global repositories + repositories.append(arg) + + Option(func = opt_Y, short = 'Y', long = ['repository'], arg = 'REPOSITORY', help = "Search REPOSITORY for source and target files.") @@ -825,10 +830,15 @@ def _SConstruct_exists(dirname=''): If so, it returns the path of the file. By default, it checks the current directory. """ + global repositories for file in ['SConstruct', 'Sconstruct', 'sconstruct']: sfile = os.path.join(dirname, file) if os.path.isfile(sfile): return sfile + if not os.path.isabs(file): + for rep in repositories: + if os.path.isfile(os.path.join(rep, sfile)): + return sfile return None @@ -932,6 +942,10 @@ def _main(): sys.path = include_dirs + sys.path + global repositories + for rep in repositories: + SCons.Node.FS.default_fs.Repository(rep) + start_time = time.time() for script in scripts: SCons.Script.SConscript.SConscript(script) diff --git a/test/Repository/.aeignore b/test/Repository/.aeignore new file mode 100644 index 0000000..877ac53 --- /dev/null +++ b/test/Repository/.aeignore @@ -0,0 +1,4 @@ +*,D +.*.swp +.consign +.sconsign diff --git a/test/Repository/Program.py b/test/Repository/Program.py new file mode 100644 index 0000000..854ede2 --- /dev/null +++ b/test/Repository/Program.py @@ -0,0 +1,169 @@ +#!/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 sys +import TestSCons + +if sys.platform == 'win32': + _exe = '.exe' +else: + _exe = '' + +test = TestSCons.TestSCons() + +test.subdir('repository', 'work') + +repository = test.workpath('repository') +repository_foo_c = test.workpath('repository', 'foo.c') +work_foo = test.workpath('work', 'foo' + _exe) +work_foo_c = test.workpath('work', 'foo.c') + +test.write(['work', 'SConstruct'], r""" +Repository('%s') +env = Environment() +env.Program(target= 'foo', source = Split('aaa.c bbb.c foo.c')) +""" % repository) + +test.write(['repository', 'aaa.c'], r""" +void +aaa(void) +{ + printf("repository/aaa.c\n"); +} +""") + +test.write(['repository', 'bbb.c'], r""" +void +bbb(void) +{ + printf("repository/bbb.c\n"); +} +""") + +test.write(['repository', 'foo.c'], r""" +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("repository/foo.c\n"); + exit (0); +} +""") + +# Make the entire repository non-writable, so we'll detect +# if we try to write into it accidentally. +test.writable('repository', 0) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """repository/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.write(['work', 'bbb.c'], r""" +void +bbb(void) +{ + printf("work/bbb.c\n"); +} +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """repository/aaa.c +work/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.write(['work', 'aaa.c'], r""" +void +aaa(void) +{ + printf("work/aaa.c\n"); +} +""") + +test.write(['work', 'foo.c'], r""" +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("work/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """work/aaa.c +work/bbb.c +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.unlink(['work', 'aaa.c']) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """repository/aaa.c +work/bbb.c +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.unlink(['work', 'bbb.c']) +test.unlink(['work', 'foo.c']) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """repository/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.pass_test() diff --git a/test/Repository/include.py b/test/Repository/include.py new file mode 100644 index 0000000..1538e1a --- /dev/null +++ b/test/Repository/include.py @@ -0,0 +1,186 @@ +#!/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 sys +import TestSCons + +if sys.platform == 'win32': + _exe = '.exe' +else: + _exe = '' + +test = TestSCons.TestSCons() + +test.subdir('repository', 'work') + +repository = test.workpath('repository') +work_foo = test.workpath('work', 'foo' + _exe) +work_foo_h = test.workpath('work', 'foo.h') + +test.write(['work', 'SConstruct'], """ +Repository('%s') +env = Environment(CPPPATH = ['.']) +env.Program(target = 'foo', source = 'foo.c') +""" % repository) + +test.write(['repository', 'foo.h'], r""" +#define STRING1 "repository/foo.h" +#include +""") + +test.write(['repository', 'bar.h'], r""" +#define STRING2 "repository/bar.h" +""") + +test.write(['repository', 'foo.c'], r""" +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("%s\n", STRING1); + printf("%s\n", STRING2); + printf("repository/foo.c\n"); + exit (0); +} +""") + +# Make the entire repository non-writable, so we'll detect +# if we try to write into it accidentally. +test.writable('repository', 0) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""repository/foo.h +repository/bar.h +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.write(['work', 'foo.h'], r""" +#define STRING1 "work/foo.h" +#include +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""work/foo.h +repository/bar.h +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.write(['work', 'foo.c'], r""" +#include +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("%s\n", STRING1); + printf("%s\n", STRING2); + printf("work/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""work/foo.h +repository/bar.h +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.write(['work', 'bar.h'], r""" +#define STRING2 "work/bar.h" +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""work/foo.h +work/bar.h +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.writable('repository', 1) +test.unlink(['work', 'foo.h']) +test.writable('repository', 0) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""repository/foo.h +work/bar.h +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.writable('repository', 1) +test.unlink(['work', 'foo.c']) +test.writable('repository', 0) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""repository/foo.h +work/bar.h +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.writable('repository', 1) +test.unlink(['work', 'bar.h']) +test.writable('repository', 0) + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = +"""repository/foo.h +repository/bar.h +repository/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +# +test.pass_test() diff --git a/test/Repository/no-repository.py b/test/Repository/no-repository.py new file mode 100644 index 0000000..8659c00 --- /dev/null +++ b/test/Repository/no-repository.py @@ -0,0 +1,91 @@ +#!/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 os +import string +import sys +import TestSCons + +python = sys.executable + +if sys.platform == 'win32': + _exe = '.exe' +else: + _exe = '' + +test = TestSCons.TestSCons() + +test.subdir('work') + +no_repository = test.workpath('no_repository') +work_foo = test.workpath('work', 'foo' + _exe) + +test.write(['work', 'SConstruct'], """ +Repository('%s') +env = Environment() +env.Program(target = 'foo', source = Split('aaa.c bbb.c foo.c')) +""" % no_repository) + +test.write(['work', 'aaa.c'], r""" +void +aaa(void) +{ + printf("work/aaa.c\n"); +} +""") + +test.write(['work', 'bbb.c'], r""" +void +bbb(void) +{ + printf("work/bbb.c\n"); +} +""") + +test.write(['work', 'foo.c'], r""" +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("work/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work', arguments = '.') + +test.run(program = work_foo, stdout = """work/aaa.c +work/bbb.c +work/foo.c +""") + +test.up_to_date(chdir = 'work', arguments = '.') + +test.pass_test() diff --git a/test/option--Y.py b/test/option--Y.py index b201bbd..c675e9b 100644 --- a/test/option--Y.py +++ b/test/option--Y.py @@ -24,19 +24,269 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__" -import TestSCons -import string import sys +import TestSCons + +if sys.platform == 'win32': + _exe = '.exe' +else: + _exe = '' + + test = TestSCons.TestSCons() -test.write('SConstruct', "") +test.subdir('repository', 'work1') + +repository = test.workpath('repository') +repository_foo_c = test.workpath('repository', 'foo.c') +work1_foo = test.workpath('work1', 'foo' + _exe) +work1_foo_c = test.workpath('work1', 'foo.c') + +test.write(['repository', 'SConstruct'], r""" +env = Environment() +env.Program(target= 'foo', source = Split('aaa.c bbb.c foo.c')) +""") + +test.write(['repository', 'aaa.c'], r""" +void +aaa(void) +{ + printf("repository/aaa.c\n"); +} +""") + +test.write(['repository', 'bbb.c'], r""" +void +bbb(void) +{ + printf("repository/bbb.c\n"); +} +""") + +test.write(['repository', 'foo.c'], r""" +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("repository/foo.c\n"); + exit (0); +} +""") + +opts = '-Y ' + repository + +# Make the entire repository non-writable, so we'll detect +# if we try to write into it accidentally. +test.writable('repository', 0) + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """repository/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.write(['work1', 'bbb.c'], r""" +void +bbb(void) +{ + printf("work1/bbb.c\n"); +} +""") + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """repository/aaa.c +work1/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.write(['work1', 'aaa.c'], r""" +void +aaa(void) +{ + printf("work1/aaa.c\n"); +} +""") + +test.write(['work1', 'foo.c'], r""" +extern void aaa(void); +extern void bbb(void); +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + aaa(); + bbb(); + printf("work1/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """work1/aaa.c +work1/bbb.c +work1/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + +# +test.unlink(['work1', 'bbb.c']) +test.unlink(['work1', 'foo.c']) + +test.run(chdir = 'work1', options = opts, arguments = '.') + +test.run(program = work1_foo, stdout = """work1/aaa.c +repository/bbb.c +repository/foo.c +""") + +test.up_to_date(chdir = 'work1', options = opts, arguments = '.') + + + +# +test.subdir('r.NEW', 'r.OLD', 'work2') + +workpath_r_NEW = test.workpath('r.NEW') +workpath_r_OLD = test.workpath('r.OLD') +work2_foo = test.workpath('work2', 'foo' + _exe) + +SConstruct = """ +env = Environment() +env.Program(target = 'foo', source = 'foo.c') +""" + +test.write(['r.OLD', 'SConstruct'], SConstruct) -test.run(arguments = '-Y foo', - stderr = "Warning: the -Y option is not yet implemented\n") +test.write(['r.NEW', 'SConstruct'], SConstruct) -test.run(arguments = '--repository=foo', - stderr = "Warning: the --repository option is not yet implemented\n") +test.write(['r.OLD', 'foo.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.OLD/foo.c\n"); + exit (0); +} +""") +opts = '-Y %s -Y %s' % (workpath_r_NEW, workpath_r_OLD) + +# Make the repositories non-writable, so we'll detect +# if we try to write into them accidentally. +test.writable('r.OLD', 0) +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.OLD/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.NEW', 1) + +test.write(['r.NEW', 'foo.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.NEW/foo.c\n"); + exit (0); +} +""") + +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.NEW/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.write(['work2', 'foo.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("work2/foo.c\n"); + exit (0); +} +""") + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "work2/foo.c\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.OLD', 1) +test.writable('r.NEW', 1) + +test.write(['r.OLD', 'foo.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.OLD/foo.c 2\n"); + exit (0); +} +""") + +test.write(['r.NEW', 'foo.c'], r""" +int +main(int argc, char *argv[]) +{ + argv[argc++] = "--"; + printf("r.NEW/foo.c 2\n"); + exit (0); +} +""") + +test.writable('r.OLD', 0) +test.writable('r.NEW', 0) + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.unlink(['work2', 'foo.c']) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.NEW/foo.c 2\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + +# +test.writable('r.NEW', 1) + +test.unlink(['r.NEW', 'foo.c']) + +test.writable('r.NEW', 0) + +test.run(chdir = 'work2', options = opts, arguments = '.') + +test.run(program = work2_foo, stdout = "r.OLD/foo.c 2\n") + +test.up_to_date(chdir = 'work2', options = opts, arguments = '.') + + + +# test.pass_test() - -- cgit v0.12