Repository support (first cut).
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 17 Jul 2002 23:12:12 +0000 (23:12 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Wed, 17 Jul 2002 23:12:12 +0000 (23:12 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@418 fdb21ef1-2011-0410-befe-b5e4ea1792b1

17 files changed:
doc/man/scons.1
src/RELEASE.txt
src/engine/SCons/Action.py
src/engine/SCons/ActionTests.py
src/engine/SCons/Environment.py
src/engine/SCons/EnvironmentTests.py
src/engine/SCons/Node/FS.py
src/engine/SCons/Node/FSTests.py
src/engine/SCons/Node/NodeTests.py
src/engine/SCons/Node/__init__.py
src/engine/SCons/Script/SConscript.py
src/engine/SCons/Script/__init__.py
test/Repository/.aeignore [new file with mode: 0644]
test/Repository/Program.py [new file with mode: 0644]
test/Repository/include.py [new file with mode: 0644]
test/Repository/no-repository.py [new file with mode: 0644]
test/option--Y.py

index d32b7ff189beb8bb6c51a1e4eca07d5e4d7c4b8e..f574fb3cfab794586c5a176ae7dc87fc3f00c492 100644 (file)
@@ -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
index 7124eff6b4b5feb5557341f90a921520cb280e93..0dab6ce6f9f7d482d9ece2d9a20281a66dbdf64d 100644 (file)
@@ -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.
index c222d26ebef6dceecc2d0ed799be6fde78da1783..79fdd2cffb6bbda04af875611836c68e7c8d1410 100644 (file)
@@ -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
index c1425efe95c77b55640d44629df4e72f5d2fc2f2..5fa1b8bd7aec7f44f102eab54f8dd1d7838e194e 100644 (file)
@@ -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):
index 42aa326fc101e4ca34f1e6d237536541900c6ef2..da7c15ab22aa3de5567c7cc6964f60f051409864 100644 (file)
@@ -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:
index 75e5e83c7569629f55289013c857e22527714e0f..418d89166f6ac7f2b2a92f7bba7c2a4d996bebf5 100644 (file)
@@ -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):
index 771ac5624d33a95fe7d66905cb88e075e247b23a..2645cea0725b1a3bb2b4eceabfe297a0f5d25dec 100644 (file)
@@ -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()
 
index 1ae121567567b61bccb97fc3da92df148f3147c9..595396a6199d58cca3b354d966afa809621e035f 100644 (file)
@@ -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)
index 03b06bd0c6887a99a8ec7f81cac3e8dfc5baf06d..cbd54730acd78f7087a467915a7e0b205be00395 100644 (file)
@@ -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 = {}
index 90cd122e8cc3d9e01cfc2b079f088a93d801c636..2a5e5bc684db1ab714abb3128c821798392bc35b 100644 (file)
@@ -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
index 48c4046dc05ad4ca522def211344ab138ee8bb2f..e088c991dec2bd58969e27a4a59b9b7aac354248 100644 (file)
@@ -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
index 66b4fd76bbe11ff984827e19aea77fb4f28fa688..10794f5103871d9e700ee627813d08b2ea09da9b 100644 (file)
@@ -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 (file)
index 0000000..877ac53
--- /dev/null
@@ -0,0 +1,4 @@
+*,D
+.*.swp
+.consign
+.sconsign
diff --git a/test/Repository/Program.py b/test/Repository/Program.py
new file mode 100644 (file)
index 0000000..854ede2
--- /dev/null
@@ -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 (file)
index 0000000..1538e1a
--- /dev/null
@@ -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 <bar.h>
+""")
+
+test.write(['repository', 'bar.h'], r"""
+#define        STRING2 "repository/bar.h"
+""")
+
+test.write(['repository', 'foo.c'], r"""
+#include <foo.h>
+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 <bar.h>
+""")
+
+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 <foo.h>
+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 (file)
index 0000000..8659c00
--- /dev/null
@@ -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()
index b201bbd6f5ea9f9771a82f87160bc6bb5824d7da..c675e9ba5eb738c3d67c299c094655a2b119765b 100644 (file)
 
 __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()