Raise an error if SConf needs to do something but -n or -q is specified. (Christoph...
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 12 Jun 2003 15:28:38 +0000 (15:28 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 12 Jun 2003 15:28:38 +0000 (15:28 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@710 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/engine/SCons/Errors.py
src/engine/SCons/ErrorsTests.py
src/engine/SCons/SConf.py
src/engine/SCons/Script/__init__.py
test/option-n.py
test/option-q.py

index 9743674726699747aa621ae045a41b0818afe6b1..cc8bb3d843c4600316d207928928c9ada1fbef61 100644 (file)
@@ -55,3 +55,9 @@ class ExplicitExit(Exception):
         self.node = node
         self.status = status
         self.args = args
+
+class ConfigureDryRunError(UserError):
+    """Raised when a file needs to be updated during a Configure process,
+    but the user requested a dry-run"""
+    def __init__(self,file):
+        UserError.__init__(self,"Cannot update configure test (%s) within a dry-run." % str(file))
index b12802658e2efd9ac3a575ba43f4d6669cf21e38..810f8402346f4e6d9f8453ac30652df36747bfa5 100644 (file)
@@ -58,6 +58,12 @@ class ErrorsTestCase(unittest.TestCase):
         except SCons.Errors.ExplicitExit, e:
             assert e.node == "node"
 
+    def test_ConfigureDryRunError(self):
+        """Test the ConfigureDryRunError."""
+        try:
+            raise SCons.Errors.ConfigureDryRunError, "FileName"
+        except SCons.Errors.UserError, e:
+            assert e.args == "Cannot update configure test (FileName) within a dry-run."
 
 
 if __name__ == "__main__":
index 7336cdeca2940b4a46bd30586030fe95ef9ef984..b62dabff83dfa11a0291f16b4338185b3272c363 100644 (file)
@@ -47,6 +47,9 @@ import SCons.Warnings
 # but it showed up that there are too many side effects in doing that.
 SConfFS=SCons.Node.FS.default_fs
 
+# to be set, if we are in dry-run mode
+dryrun = 0
+
 _ac_build_counter = 0
 _ac_config_counter = 0
 _activeSConfObjects = {}
@@ -159,6 +162,22 @@ class SConf:
             def do_failed(self, status=2):
                 pass
 
+        class SConfDryRunTask(SConfBuildTask):
+            """Raise ConfiugreDryRunErrors whenever a target is to
+            be built. Pass these Errors to the main script."""
+            def execute(self):
+                target = self.targets[0]
+                if (target.get_state() != SCons.Node.up_to_date and
+                    target.has_builder() and
+                    not hasattr(target.builder, 'status')):
+                    
+                    raise SCons.Errors.ConfigureDryRunError(target)
+                
+            def failed(self):
+                if sys.exc_type == SCons.Errors.ConfigureDryRunError:
+                    raise
+                SConfBuildTask.failed(self)
+
         if self.logstream != None:
             # override stdout / stderr to write in log file
             oldStdout = sys.stdout
@@ -176,8 +195,12 @@ class SConf:
         try:
             # ToDo: use user options for calc
             self.calc = SCons.Sig.Calculator(max_drift=0)
+            if dryrun:
+                buildTask = SConfDryRunTask
+            else:
+                buildTask = SConfBuildTask
             tm = SCons.Taskmaster.Taskmaster( nodes,
-                                              SConfBuildTask,
+                                              buildTask,
                                               self.calc )
             # we don't want to build tests in parallel
             jobs = SCons.Job.Jobs(1, tm )
@@ -365,6 +388,8 @@ class SConf:
             self.cache = {}
 
     def _dumpCache(self):
+        if dryrun:
+            return
         # try to dump build-error cache
         try:
             cacheDesc = {'scons_version' : SCons.__version__,
@@ -377,9 +402,13 @@ class SConf:
 
     def _createDir( self, node ):
         dirName = node.get_path()
-        if not os.path.isdir( dirName ):
-            os.makedirs( dirName )
-            node._exists = 1
+        if dryrun:
+            if not os.path.isdir( dirName ):
+                raise SCons.Errors.ConfigureDryRunError(dirName)
+        else:
+            if not os.path.isdir( dirName ):
+                os.makedirs( dirName )
+                node._exists = 1
 
     def _startup(self):
         """Private method. Set up logstream, and set the environment
@@ -394,7 +423,7 @@ class SConf:
         self._createDir(self.confdir)
         self.confdir.up().add_ignore( [self.confdir] )
 
-        if self.logfile != None:
+        if self.logfile != None and not dryrun:
             # truncate logfile, if SConf.Configure is called for the first time
             # in a build
             if _ac_config_counter == 0:
index 1c773f0c462f1d5ce163cf1cdfc2f6f29fe583f6..139d2964aaa653d43b57d670d7b32ad8c3bdc964 100644 (file)
@@ -723,8 +723,12 @@ def _main():
     if options.warn:
         _setup_warn(options.warn)
     if options.noexec:
+        SCons.SConf.dryrun = 1
         SCons.Action.execute_actions = None
         CleanTask.execute = CleanTask.show
+    if options.question:
+        SCons.SConf.dryrun = 1
+        
     if options.no_progress or options.silent:
         display.set_mode(0)
     if options.silent:
@@ -977,6 +981,8 @@ def main():
         _scons_syntax_error(e)
     except SCons.Errors.UserError, e:
         _scons_user_error(e)
+    except SCons.Errors.ConfigureDryRunError, e:
+        _scons_configure_dryrun_error(e)
     except:
         _scons_other_errors()
 
index bccb785b866c4c08845fb62d6fdf1f3fb46b5352..86f4c3ab8611f7e60fab4fe19458567d27e17995 100644 (file)
@@ -32,13 +32,18 @@ This test verifies:
         installed when -n is used;
     4)  that source files don't get duplicated in a BuildDir
         when -n is used.
+    5)  that Configure calls don't build any files. If a file
+        needs to be build (i.e. is not up-to-date), a ConfigureError
+        is raised.
 """
 
 __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 
+import os
 import os.path
 import string
 import sys
+import TestCmd
 import TestSCons
 
 python = TestSCons.python
@@ -155,5 +160,74 @@ test.fail_test(not os.path.exists(test.workpath('install', 'f3.in')))
 test.run(arguments = '-n build')
 test.fail_test(os.path.exists(test.workpath('build', 'f4.in')))
 
-test.pass_test()
+# test Configure-calls in conjunction with -n
+test.subdir('configure')
+test.match_func = TestCmd.match_re_dotall
+test.write('configure/SConstruct',
+"""def CustomTest(context):
+    def userAction(target,source,env):
+        import shutil
+        shutil.copyfile( str(source[0]), str(target[0]))
+    def strAction(target,source,env):
+        return "cp " + str(source[0]) + " " + str(target[0])
+    context.Message("Executing Custom Test ... " )
+    (ok, msg) = context.TryAction(Action(userAction,strAction),
+                                  "Hello World", ".in")
+    context.Result(ok)
+    return ok
+
+env = Environment()
+conf = Configure( env,
+                  custom_tests={'CustomTest':CustomTest},
+                  conf_dir="config.test",
+                  log_file="config.log" )
+if not conf.CustomTest():
+    Exit(1)
+else:
+    env = conf.Finish()
+""")
+# test that conf_dir isn't created and an error is raised
+stderr=r"""
+scons: \*\*\* Cannot update configure test \(config\.test\) within a dry-run\.
+File \S+, line \S+, in \S+
+"""
+test.run(arguments="-n",stderr=stderr,status=2,
+         chdir=test.workpath("configure"))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.log")))
+
+# test that targets are not built, if conf_dir exists.
+# verify that .cache and config.log are not created.
+# an error should be raised
+stderr=r"""
+scons: \*\*\* Cannot update configure test \(config\.test.conftest_0\.in\) within a dry-run\.
+File \S+, line \S+, in \S+
+"""
+test.subdir(['configure','config.test'])
+test.run(arguments="-n",stderr=stderr,status=2,
+         chdir=test.workpath("configure"))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            ".cache")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            "conftest_0")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            "conftest_0.in")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.log")))
+
+# test that no error is raised, if all targets are up-to-date. In this
+# case .cache and config.log shouldn't be created
+stdout=test.wrap_stdout(build_str='scons: "." is up to date.\n',
+                        read_str="""\
+Executing Custom Test ... ok
+""")
+test.run(status=0,chdir=test.workpath("configure"))
+cache1_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
+log1_mtime = os.path.getmtime(test.workpath("configure","config.log"))
+test.run(stdout=stdout,arguments="-n",status=0,
+         chdir=test.workpath("configure"))
+cache2_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
+log2_mtime = os.path.getmtime(test.workpath("configure","config.log"))
+test.fail_test( cache1_mtime != cache2_mtime )
+test.fail_test( log1_mtime != log2_mtime )
 
+test.pass_test()
index e7457600c15f040b66cebbcef85f7e14fe44e71b..449d5eb2d570d2cbdf1003964f3f6b75843870dd 100644 (file)
@@ -28,6 +28,7 @@ import os.path
 import string
 import sys
 
+import TestCmd
 import TestSCons
 
 test = TestSCons.TestSCons()
@@ -72,5 +73,82 @@ test.fail_test(test.read('bbb.out') != "bbb.in\n")
 
 test.run(arguments = '--question bbb.out', status = 0)
 
+
+# test -q in conjunction with Configure Tests
+# mostly copy&paste from test/option-n.py
+test.subdir('configure')
+test.match_func = TestCmd.match_re_dotall
+test.write('configure/aaa.in', 'Hello world')
+test.write('configure/SConstruct',
+"""def userAction(target,source,env):
+    import shutil
+    shutil.copyfile( str(source[0]), str(target[0]))
+
+def strAction(target,source,env):
+    return "cp " + str(source[0]) + " " + str(target[0])
+
+def CustomTest(context):
+    context.Message("Executing Custom Test ... " )
+    (ok, msg) = context.TryAction(Action(userAction,strAction),
+                                  "Hello World", ".in")
+    context.Result(ok)
+    return ok
+
+env = Environment(BUILDERS={'B' : Builder(action=Action(userAction,strAction))})
+
+conf = Configure( env,
+                  custom_tests={'CustomTest':CustomTest},
+                  conf_dir="config.test",
+                  log_file="config.log")
+if not conf.CustomTest():
+    Exit(1)
+else:
+    env = conf.Finish()
+
+env.B(target='aaa.out', source='aaa.in')
+""")
+# test that conf_dir isn't created and an error is raised
+stderr=r"""
+scons: \*\*\* Cannot update configure test \(config\.test\) within a dry-run\.
+File \S+, line \S+, in \S+
+"""
+test.run(arguments="-q aaa.out",stderr=stderr,status=2,
+         chdir=test.workpath("configure"))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.log")))
+
+# test that targets are not built, if conf_dir exists.
+# verify that .cache and config.log are not created.
+# an error should be raised
+stderr=r"""
+scons: \*\*\* Cannot update configure test \(config\.test.conftest_0\.in\) within a dry-run\.
+File \S+, line \S+, in \S+
+"""
+test.subdir(['configure','config.test'])
+test.run(arguments="-q aaa.out",stderr=stderr,status=2,
+         chdir=test.workpath("configure"))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            ".cache")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            "conftest_0")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.test",
+                                            "conftest_0.in")))
+test.fail_test(os.path.exists(test.workpath("configure", "config.log")))
+
+# test that no error is raised, if all targets are up-to-date. In this
+# case .cache and config.log shouldn't be created
+stdout=test.wrap_stdout(build_str='cp aaa.in aaa.out\n',
+                        read_str="""\
+Executing Custom Test ... ok
+""")
+test.run(stdout=stdout,arguments="aaa.out",status=0,chdir=test.workpath("configure"))
+cache1_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
+log1_mtime = os.path.getmtime(test.workpath("configure","config.log"))
+test.run(arguments="-q aaa.out",status=0,
+         chdir=test.workpath("configure"))
+cache2_mtime = os.path.getmtime(test.workpath("configure","config.test",".cache"))
+log2_mtime = os.path.getmtime(test.workpath("configure","config.log"))
+test.fail_test( cache1_mtime != cache2_mtime )
+test.fail_test( log1_mtime != log2_mtime )
+
 test.pass_test()