Add a --diskcheck option to control looking on-disk for things.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 10 Jun 2005 11:59:43 +0000 (11:59 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Fri, 10 Jun 2005 11:59:43 +0000 (11:59 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1311 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/CHANGES.txt
src/engine/SCons/Node/FS.py
src/engine/SCons/Script/Main.py
test/RCS/diskcheck.py [new file with mode: 0644]
test/SCCS/diskcheck.py [new file with mode: 0644]
test/diskcheck.py [new file with mode: 0644]

index 072f80ab0dcb6f4db82e6234f89e886c874efe16..8ac56819893eda0a9b6758349033b818a97e8048 100644 (file)
@@ -578,7 +578,6 @@ This only works when run under Python 2.1 or later.
 Re-run SCons under the control of the
 .RI pdb
 Python debugger.
-.EE
 
 .TP
 --debug=presub
@@ -618,6 +617,47 @@ after each top-level target is built. This prints out the complete
 dependency tree including implicit dependencies and ignored
 dependencies.
 
+.TP
+.RI --diskcheck= types
+Enable specific checks for
+whether or not there is a file on disk
+where the SCons configuration expects a directory
+(or vice versa),
+and whether or not RCS or SCCS sources exist
+when searching for source and include files.
+The
+.I types
+argument can be set to:
+.BR all ,
+to enable all checks explicitly
+(the default behavior);
+.BR none ,
+to disable all such checks;
+.BR match ,
+to check that files and directories on disk
+match SCons' expected configuration;
+.BR rcs ,
+to check for the existence of an RCS source
+for any missing source or include files;
+.BR sccs ,
+to check for the existence of an SCCS source
+for any missing source or include files.
+Multiple checks can be specified separated by commas;
+for example,
+.B --diskcheck=sccs,rcs
+would still check for SCCS and RCS sources,
+but disable the check for on-disk matches of files and directories.
+Disabling some or all of these checks
+can provide a performance boost for large configurations,
+or when the configuration will check for files and/or directories
+across networked or shared file systems,
+at the slight increased risk of an incorrect build
+or of not handling errors gracefully
+(if include files really should be
+found in SCCS or RCS, for example,
+or if a file really does exist
+where the SCons configuration expects a directory).
+
 .\" .TP
 .\" -e, --environment-overrides
 .\" Variables from the execution environment override construction
index d246daebd331b977040de2fc383ec63babc1bdf4..6a3e259b9547719b1255a7dfd6cca09524377416 100644 (file)
@@ -296,6 +296,11 @@ RELEASE 0.97 - XXX
 
   - Remove support for conversion from old (pre 0.96) .sconsign formats.
 
+  - Add support for a --diskcheck option to enable or disable various
+    on-disk checks:  that File and Dir nodes match on-disk entries;
+    whether an RCS file exists for a missing source file; whether an
+    SCCS file exists for a missing source file.
+
   From Wayne Lee:
 
   - Avoid "maximum recursion limit" errors when removing $(-$) pairs
index 3b4e77ff41a9d624c24eab706f5c131f6551d89b..a1cadf093c01d599612e47cbc8b2ccba86ec28fb 100644 (file)
@@ -288,6 +288,65 @@ else:
     def _my_normcase(x):
         return string.upper(x)
 
+
+
+class DiskChecker:
+    def __init__(self, type, do, ignore):
+        self.type = type
+        self.do = do
+        self.ignore = ignore
+        self.set_do()
+    def set_do(self):
+        self.__call__ = self.do
+    def set_ignore(self):
+        self.__call__ = self.ignore
+    def set(self, list):
+        if self.type in list:
+            self.set_do()
+        else:
+            self.set_ignore()
+
+def do_diskcheck_match(node, predicate, errorfmt):
+    path = node.abspath
+    if predicate(path):
+        raise TypeError, errorfmt % path
+
+def ignore_diskcheck_match(node, predicate, errorfmt):
+    pass
+
+def do_diskcheck_rcs(node, name):
+    rcspath = 'RCS' + os.sep + name+',v'
+    return node.entry_exists_on_disk(rcspath)
+
+def ignore_diskcheck_rcs(node, name):
+    return None
+
+def do_diskcheck_sccs(node, name):
+    sccspath = 'SCCS' + os.sep + 's.'+name
+    return node.entry_exists_on_disk(sccspath)
+
+def ignore_diskcheck_sccs(node, name):
+    return None
+
+diskcheck_match = DiskChecker('match', do_diskcheck_match, ignore_diskcheck_match)
+diskcheck_rcs = DiskChecker('rcs', do_diskcheck_rcs, ignore_diskcheck_rcs)
+diskcheck_sccs = DiskChecker('sccs', do_diskcheck_sccs, ignore_diskcheck_sccs)
+
+diskcheckers = [
+    diskcheck_match,
+    diskcheck_rcs,
+    diskcheck_sccs,
+]
+
+def set_diskcheck(list):
+    for dc in diskcheckers:
+        dc.set(list)
+
+def diskcheck_types():
+    return map(lambda dc: dc.type, diskcheckers)
+
+
+
 class EntryProxy(SCons.Util.Proxy):
     def __get_abspath(self):
         entry = self.get()
@@ -597,6 +656,9 @@ class Entry(Base):
     time comes, and then call the same-named method in the transformed
     class."""
 
+    def diskcheck_match(self):
+        pass
+
     def disambiguate(self):
         if self.isdir():
             self.__class__ = Dir
@@ -852,14 +914,12 @@ class FS(LocalFS):
                 if not create:
                     raise SCons.Errors.UserError
 
-                # look at the actual filesystem and make sure there isn't
-                # a file already there
-                path = directory.entry_abspath(orig)
-                if self.isfile(path):
-                    raise TypeError, \
-                          "File %s found where directory expected." % path
-
                 d = Dir(orig, directory, self)
+
+                # Check the file system (or not, as configured) to make
+                # sure there isn't already a file there.
+                d.diskcheck_match()
+
                 directory.entries[norm] = d
                 directory.add_wkid(d)
                 directory = d
@@ -878,19 +938,13 @@ class FS(LocalFS):
             if not create:
                 raise SCons.Errors.UserError
 
-            # make sure we don't create File nodes when there is actually
-            # a directory at that path on the disk, and vice versa
-            path = directory.entry_abspath(last_orig)
-            if fsclass == File:
-                if self.isdir(path):
-                    raise TypeError, \
-                          "Directory %s found where file expected." % path
-            elif fsclass == Dir:
-                if self.isfile(path):
-                    raise TypeError, \
-                          "File %s found where directory expected." % path
-            
             result = fsclass(last_orig, directory, self)
+
+            # Check the file system (or not, as configured) to make
+            # sure there isn't already a directory at the path on
+            # disk where we just created a File node, and vice versa.
+            result.diskcheck_match()
+
             directory.entries[last_norm] = result 
             directory.add_wkid(result)
         else:
@@ -1080,6 +1134,10 @@ class Dir(Base):
         self.builder = get_MkdirBuilder()
         self.get_executor().set_action_list(self.builder.action)
 
+    def diskcheck_match(self):
+        diskcheck_match(self, self.fs.isfile,
+                           "File %s found where directory expected.")
+
     def disambiguate(self):
         return self
 
@@ -1342,14 +1400,6 @@ class Dir(Base):
         """__cacheable__"""
         return self.fs.exists(self.entry_abspath(name))
 
-    def rcs_on_disk(self, name):
-        rcspath = 'RCS' + os.sep + name+',v'
-        return self.entry_exists_on_disk(rcspath)
-
-    def sccs_on_disk(self, name):
-        sccspath = 'SCCS' + os.sep + 's.'+name
-        return self.entry_exists_on_disk(sccspath)
-
     def srcdir_list(self):
         """__cacheable__"""
         result = []
@@ -1417,8 +1467,8 @@ class Dir(Base):
 
     def file_on_disk(self, name):
         if self.entry_exists_on_disk(name) or \
-           self.sccs_on_disk(name) or \
-           self.rcs_on_disk(name):
+           diskcheck_rcs(self, name) or \
+           diskcheck_sccs(self, name):
             try: return self.File(name)
             except TypeError: pass
         return self.srcdir_duplicate(name)
@@ -1532,6 +1582,10 @@ class BuildInfo(SCons.Node.BuildInfo):
 class File(Base):
     """A class for files in a file system.
     """
+    def diskcheck_match(self):
+        diskcheck_match(self, self.fs.isdir,
+                           "Directory %s found where file expected.")
+
     def __init__(self, name, directory, fs):
         if __debug__: logInstanceCreation(self, 'Node.FS.File')
         Base.__init__(self, name, directory, fs)
@@ -1703,9 +1757,9 @@ class File(Base):
             else:
                 scb = self.dir.src_builder()
                 if scb is _null:
-                    if self.dir.sccs_on_disk(self.name):
+                    if diskcheck_sccs(self.dir, self.name):
                         scb = get_DefaultSCCSBuilder()
-                    elif self.dir.rcs_on_disk(self.name):
+                    elif diskcheck_rcs(self.dir, self.name):
                         scb = get_DefaultRCSBuilder()
                     else:
                         scb = None
index d5be3ebac382276bdb4cc341784ff0dc9bf35fdf..a6b4f88a3b8d04d67956db96c1fc518979341aa2 100644 (file)
@@ -258,6 +258,26 @@ exit_status = 0 # exit status, assume success by default
 repositories = []
 num_jobs = 1 # this is modifed by SConscript.SetJobs()
 
+diskcheck_all = SCons.Node.FS.diskcheck_types()
+diskcheck_option_set = None
+
+def diskcheck_convert(value):
+    if value is None:
+        return []
+    if not SCons.Util.is_List(value):
+        value = string.split(value, ',')
+    result = []
+    for v in map(string.lower, value):
+        if v == 'all':
+            result = diskcheck_all
+        elif v == 'none':
+            result = []
+        elif v in diskcheck_all:
+            result.append(v)
+        else:
+            raise ValueError, v
+    return result
+
 #
 class Stats:
     def __init__(self):
@@ -613,6 +633,20 @@ class OptParser(OptionParser):
                         help="Print various types of debugging information: "
                              "%s." % string.join(debug_options, ", "))
 
+        def opt_diskcheck(option, opt, value, parser):
+            try:
+                global diskcheck_option_set
+                diskcheck_option_set = diskcheck_convert(value)
+                SCons.Node.FS.set_diskcheck(diskcheck_option_set)
+            except ValueError, e:
+                raise OptionValueError("Warning: `%s' is not a valid diskcheck type" % e)
+
+            
+        self.add_option('--diskcheck', action="callback", type="string",
+                        callback=opt_diskcheck, dest='diskcheck',
+                        metavar="TYPE",
+                        help="Enable specific on-disk checks.")
+
         def opt_duplicate(option, opt, value, parser):
             if not value in SCons.Node.FS.Valid_Duplicates:
                 raise OptionValueError("`%s' is not a valid duplication style." % value)
@@ -799,7 +833,8 @@ class SConscriptSettableOptions:
                          'max_drift':SCons.Sig.default_max_drift,
                          'implicit_cache':0,
                          'clean':0,
-                         'duplicate':'hard-soft-copy'}
+                         'duplicate':'hard-soft-copy',
+                         'diskcheck':diskcheck_all}
 
     def get(self, name):
         if not self.settable.has_key(name):
@@ -835,6 +870,13 @@ class SConscriptSettableOptions:
             # Set the duplicate stye right away so it can affect linking
             # of SConscript files.
             SCons.Node.FS.set_duplicate(value)
+        elif name == 'diskcheck':
+            try:
+                value = diskcheck_convert(value)
+            except ValueError, v:
+                raise SCons.Errors.UserError, "Not a valid diskcheck value: %s"%v
+            if not diskcheck_option_set:
+                SCons.Node.FS.set_diskcheck(value)
 
         self.settable[name] = value
     
diff --git a/test/RCS/diskcheck.py b/test/RCS/diskcheck.py
new file mode 100644 (file)
index 0000000..c1d5cca
--- /dev/null
@@ -0,0 +1,187 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test transparent RCS checkouts from an RCS subdirectory.
+"""
+
+import os.path
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+rcs = test.where_is('rcs')
+if not rcs:
+    print "Could not find RCS, skipping test(s)."
+    test.pass_test(1)
+
+ci = test.where_is('ci')
+if not ci:
+    print "Could not find `ci' command, skipping test(s)."
+    test.pass_test(1)
+
+
+
+sub_RCS = os.path.join('sub', 'RCS')
+sub_SConscript = os.path.join('sub', 'SConscript')
+sub_all = os.path.join('sub', 'all')
+sub_ddd_in = os.path.join('sub', 'ddd.in')
+sub_ddd_out = os.path.join('sub', 'ddd.out')
+sub_eee_in = os.path.join('sub', 'eee.in')
+sub_eee_out = os.path.join('sub', 'eee.out')
+sub_fff_in = os.path.join('sub', 'fff.in')
+sub_fff_out = os.path.join('sub', 'fff.out')
+
+test.subdir('RCS', 'sub', ['sub', 'RCS'])
+
+for f in ['aaa.in', 'bbb.in', 'ccc.in']:
+    test.write(f, "%s\n" % f)
+    args = "-f -t%s %s" % (f, f)
+    test.run(program = ci, arguments = args, stderr = None)
+
+for f in ['ddd.in', 'eee.in', 'fff.in']:
+    test.write(['sub', f], "sub/%s\n" % f)
+    args = "-f -tsub/%s sub/%s" % (f, f)
+    test.run(program = ci, arguments = args, stderr = None)
+
+test.write(['sub', 'SConscript'], """\
+Import("env")
+env.Cat('ddd.out', 'ddd.in')
+env.Cat('eee.out', 'eee.in')
+env.Cat('fff.out', 'fff.in')
+env.Cat('all', ['ddd.out', 'eee.out', 'fff.out'])
+""")
+args = "-f -tsub/SConscript sub/SConscript"
+test.run(program = ci, arguments = args, stderr = None)
+
+test.no_result(os.path.exists(test.workpath('aaa.in')))
+test.no_result(os.path.exists(test.workpath('bbb.in')))
+test.no_result(os.path.exists(test.workpath('ccc.in')))
+
+test.no_result(os.path.exists(test.workpath('sub', 'SConscript')))
+
+test.no_result(os.path.exists(test.workpath('sub', 'aaa.in')))
+test.no_result(os.path.exists(test.workpath('sub', 'bbb.in')))
+test.no_result(os.path.exists(test.workpath('sub', 'ccc.in')))
+
+test.write('SConstruct', """
+import os
+for key in ['LOGNAME', 'USERNAME', 'USER']:
+    logname = os.environ.get(key)
+    if logname: break
+ENV = {'PATH' : os.environ['PATH'],
+       'LOGNAME' : logname}
+def cat(env, source, target):
+    target = str(target[0])
+    source = map(str, source)
+    f = open(target, "wb")
+    for src in source:
+        f.write(open(src, "rb").read())
+    f.close()
+SetOption('diskcheck', None)
+DefaultEnvironment()['ENV'] = ENV
+DefaultEnvironment()['RCS_COFLAGS'] = '-l'
+env = Environment(ENV=ENV, BUILDERS={'Cat':Builder(action=cat)})
+env.Cat('aaa.out', 'aaa.in')
+env.Cat('bbb.out', 'bbb.in')
+env.Cat('ccc.out', 'ccc.in')
+env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out'])
+SConscript('sub/SConscript', "env")
+""")
+
+test.write('bbb.in', "checked-out bbb.in\n")
+
+test.write(['sub', 'eee.in'], "checked-out sub/eee.in\n")
+
+expect = """\
+
+scons: warning: Ignoring missing SConscript 'sub/SConscript'
+File "SConstruct", line 23, in ?
+scons: *** Source `aaa.in' not found, needed by target `aaa.out'.  Stop.
+"""
+
+test.run(status=2, stderr=expect)
+
+test.run(arguments = '--diskcheck=match,sccs', status=2, stderr=expect)
+
+test.run(arguments = '--diskcheck=rcs',
+         stdout = test.wrap_stdout(read_str = """\
+co -l %(sub_SConscript)s
+""" % locals(),
+                                   build_str = """\
+co -l aaa.in
+cat(["aaa.out"], ["aaa.in"])
+cat(["bbb.out"], ["bbb.in"])
+co -l ccc.in
+cat(["ccc.out"], ["ccc.in"])
+cat(["all"], ["aaa.out", "bbb.out", "ccc.out"])
+co -l %(sub_ddd_in)s
+cat(["%(sub_ddd_out)s"], ["%(sub_ddd_in)s"])
+cat(["%(sub_eee_out)s"], ["%(sub_eee_in)s"])
+co -l %(sub_fff_in)s
+cat(["%(sub_fff_out)s"], ["%(sub_fff_in)s"])
+cat(["%(sub_all)s"], ["%(sub_ddd_out)s", "%(sub_eee_out)s", "%(sub_fff_out)s"])
+""" % locals()),
+         stderr = """\
+%(sub_RCS)s/SConscript,v  -->  %(sub_SConscript)s
+revision 1.1 (locked)
+done
+RCS/aaa.in,v  -->  aaa.in
+revision 1.1 (locked)
+done
+RCS/ccc.in,v  -->  ccc.in
+revision 1.1 (locked)
+done
+%(sub_RCS)s/ddd.in,v  -->  %(sub_ddd_in)s
+revision 1.1 (locked)
+done
+%(sub_RCS)s/fff.in,v  -->  %(sub_fff_in)s
+revision 1.1 (locked)
+done
+""" % locals())
+
+# Checking things back out of RCS apparently messes with the line
+# endings, so read the result files in non-binary mode.
+
+test.must_match('all',
+                "aaa.in\nchecked-out bbb.in\nccc.in\n",
+                mode='r')
+
+test.must_match(['sub', 'all'],
+                "sub/ddd.in\nchecked-out sub/eee.in\nsub/fff.in\n",
+                mode='r')
+
+test.must_be_writable(test.workpath('sub', 'SConscript'))
+test.must_be_writable(test.workpath('aaa.in'))
+test.must_be_writable(test.workpath('ccc.in'))
+test.must_be_writable(test.workpath('sub', 'ddd.in'))
+test.must_be_writable(test.workpath('sub', 'fff.in'))
+
+
+
+#
+test.pass_test()
diff --git a/test/SCCS/diskcheck.py b/test/SCCS/diskcheck.py
new file mode 100644 (file)
index 0000000..691f09c
--- /dev/null
@@ -0,0 +1,148 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test transparent checkouts from SCCS files in an SCCS subdirectory.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+sccs = test.where_is('sccs')
+if not sccs:
+    print "Could not find SCCS, skipping test(s)."
+    test.pass_test(1)
+
+
+
+test.subdir('SCCS', 'sub', ['sub', 'SCCS'])
+
+for f in ['aaa.in', 'bbb.in', 'ccc.in']:
+    test.write(f, "%%F%% %s\n" % f)
+    args = "create %s" % f
+    test.run(program = sccs, arguments = args, stderr = None)
+    test.unlink(f)
+    test.unlink(','+f)
+
+test.write(['sub', 'SConscript'], """\
+# %%F%%
+Import("env")
+env.Cat('ddd.out', 'ddd.in')
+env.Cat('eee.out', 'eee.in')
+env.Cat('fff.out', 'fff.in')
+env.Cat('all', ['ddd.out', 'eee.out', 'fff.out'])
+""")
+args = "create SConscript"
+test.run(chdir = 'sub', program = sccs, arguments = args, stderr = None)
+test.unlink(['sub', 'SConscript'])
+test.unlink(['sub', ',SConscript'])
+
+for f in ['ddd.in', 'eee.in', 'fff.in']:
+    test.write(['sub', f], "%%F%% sub/%s\n" % f)
+    args = "create %s" % f
+    test.run(chdir = 'sub', program = sccs, arguments = args, stderr = None)
+    test.unlink(['sub', f])
+    test.unlink(['sub', ','+f])
+
+test.write(['SConstruct'], """
+DefaultEnvironment()['SCCSCOM'] = 'cd ${TARGET.dir} && $SCCS get ${TARGET.file}'
+def cat(env, source, target):
+    target = str(target[0])
+    source = map(str, source)
+    f = open(target, "wb")
+    for src in source:
+        f.write(open(src, "rb").read())
+    f.close()
+SetOption('diskcheck', ['match', 'rcs'])
+env = Environment(BUILDERS={'Cat':Builder(action=cat)},
+                  SCCSFLAGS='-k')
+env.Cat('aaa.out', 'aaa.in')
+env.Cat('bbb.out', 'bbb.in')
+env.Cat('ccc.out', 'ccc.in')
+env.Cat('all', ['aaa.out', 'bbb.out', 'ccc.out'])
+SConscript('sub/SConscript', "env")
+""")
+
+test.write(['bbb.in'], "checked-out bbb.in\n")
+
+test.write(['sub', 'eee.in'], "checked-out sub/eee.in\n")
+
+expect = """\
+
+scons: warning: Ignoring missing SConscript 'sub/SConscript'
+File "SConstruct", line 17, in ?
+scons: *** Source `aaa.in' not found, needed by target `aaa.out'.  Stop.
+"""
+
+test.run(status=2, stderr=expect)
+
+test.run(arguments = '--diskcheck=none', status=2, stderr=expect)
+
+test.run(arguments = '--diskcheck=sccs', stderr = None)
+
+lines = string.split("""
+sccs get SConscript
+sccs get aaa.in
+cat(["aaa.out"], ["aaa.in"])
+cat(["bbb.out"], ["bbb.in"])
+sccs get ccc.in
+cat(["ccc.out"], ["ccc.in"])
+cat(["all"], ["aaa.out", "bbb.out", "ccc.out"])
+sccs get ddd.in
+cat(["sub/ddd.out"], ["sub/ddd.in"])
+cat(["sub/eee.out"], ["sub/eee.in"])
+sccs get fff.in
+cat(["sub/fff.out"], ["sub/fff.in"])
+cat(["sub/all"], ["sub/ddd.out", "sub/eee.out", "sub/fff.out"])
+""", '\n')
+
+stdout = test.stdout()
+missing = filter(lambda l, s=stdout: string.find(s, l) == -1, lines)
+if missing:
+    print "Missing the following output lines:"
+    print string.join(missing, '\n')
+    print "Actual STDOUT =========="
+    print stdout
+    test.fail_test(1)
+
+test.must_match('all', """\
+s.aaa.in aaa.in
+checked-out bbb.in
+s.ccc.in ccc.in
+""")
+
+test.must_not_be_writable(test.workpath('sub', 'SConscript'))
+test.must_not_be_writable(test.workpath('aaa.in'))
+test.must_not_be_writable(test.workpath('ccc.in'))
+test.must_not_be_writable(test.workpath('sub', 'ddd.in'))
+test.must_not_be_writable(test.workpath('sub', 'fff.in'))
+
+
+
+test.pass_test()
diff --git a/test/diskcheck.py b/test/diskcheck.py
new file mode 100644 (file)
index 0000000..b8ef2fe
--- /dev/null
@@ -0,0 +1,81 @@
+#!/usr/bin/env python
+#
+# __COPYRIGHT__
+#
+# 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__"
+
+"""
+Test that the --diskcheck option and SetOption('diskcheck') correctly
+control where or not we look for on-disk matches files and directories
+that we look up.
+"""
+
+import string
+
+import TestSCons
+
+test = TestSCons.TestSCons()
+
+test.subdir('subdir')
+
+test.write('file', "file\n")
+
+
+
+test.write('SConstruct', """
+SetOption('diskcheck', 'none')
+File('subdir')
+""")
+
+test.run()
+
+test.run(arguments='--diskcheck=match', status=2, stderr=None)
+test.fail_test(string.find(test.stderr(), "found where file expected") == -1)
+
+
+
+test.write('SConstruct', """
+SetOption('diskcheck', ['rcs', 'sccs'])
+Dir('file')
+""")
+
+test.run()
+
+test.run(arguments='--diskcheck=match', status=2, stderr=None)
+test.fail_test(string.find(test.stderr(), "found where directory expected") == -1)
+
+
+
+test.write('SConstruct', """
+SetOption('diskcheck', 'rcs,sccs')
+Dir('file/subdir')
+""")
+
+test.run()
+
+test.run(arguments='--diskcheck=match', status=2, stderr=None)
+test.fail_test(string.find(test.stderr(), "found where directory expected") == -1)
+
+
+
+test.pass_test()