Fix --debug=explain when the action is a Python function.
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 18 Sep 2004 23:02:56 +0000 (23:02 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sat, 18 Sep 2004 23:02:56 +0000 (23:02 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1085 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Action.py
src/engine/SCons/Executor.py
src/engine/SCons/ExecutorTests.py
src/engine/SCons/Node/__init__.py
test/explain.py
test/symlink.py

index d7b66937a2153750179f5724fab50dd82acd2630..ee2c546a1db50e33db30dd2b95c58f64416264cc 100644 (file)
@@ -53,6 +53,10 @@ RELEASE 0.97 - XXX
     (already supported by Conftest.py) to specify text at the top of
     the compiled test file.
 
+  - Fix the --debug=explain output when a Python function action changed
+    so it prints a meaningful string, not the binary representation of
+    the function contents.
+
   From Elliot Murphy:
 
   - Enhance the tests to guarantee persistence of ListOption
index e110d6095c7566e839652c0d52672e8d50181f0c..c131693354b3592570039d4aa2d3ac4c99d5d217 100644 (file)
@@ -37,6 +37,11 @@ other modules:
         to compare the actions used to build a target last time and
         this time.
 
+    strfunction()
+        Returns a substituted string representation of the Action.
+        This is used by the ActionBase.show() command to display the
+        command/function that will be executed to generate the target(s).
+
 Subclasses also supply the following methods for internal use within
 this module:
 
@@ -46,11 +51,6 @@ this module:
         the pre-substitution command whenever the --debug=presub option
         is used.
 
-    strfunction()
-        Returns a substituted string representation of the Action.
-        This is used by the ActionBase.show() command to display the
-        command/function that will be executed to generate the target(s).
-
     execute()
         The internal method that really, truly, actually handles the
         execution of a command or Python function.  This is used so
index b3e6f888b00ff02f4e80b5d6c12c343f29cef1c1..bfb1a6568a11f85ac357c49e7d2ee9af4a4ba59f 100644 (file)
@@ -137,6 +137,26 @@ class Executor:
                                            self.get_build_env())
             return self.string
 
+    def strfunction(self):
+        try:
+            return self.string
+        except AttributeError:
+            action = self.action
+            build_env = self.get_build_env()
+            if action.strfunction is None:
+                # This instance has strfunction set to None to suppress
+                # printing of the action.  Call the method directly
+                # through the class instead.
+                self._strfunc = action.__class__.strfunction(action,
+                                                             self.targets,
+                                                             self.sources,
+                                                             build_env)
+            else:
+                self._strfunc = action.strfunction(self.targets,
+                                                   self.sources,
+                                                   build_env)
+            return self._strfunc
+
     def get_raw_contents(self):
         """Fetch the raw signature contents.  This, along with
         get_contents(), is the real reason this class exists, so we can
index c4a5552b27d042558dd33530d000315485e150cf..c391543c7f2e704c713af31276e21f2883348b45 100644 (file)
@@ -48,6 +48,8 @@ class MyAction:
         self.actions = actions
     def get_actions(self):
         return self.actions
+    def strfunction(self, target, source, env):
+        return string.join(['STRFUNCTION'] + self.actions + target + source)
     def genstring(self, target, source, env):
         return string.join(['GENSTRING'] + self.actions + target + source)
     def get_raw_contents(self, target, source, env):
@@ -195,6 +197,14 @@ class ExecutorTestCase(unittest.TestCase):
         c = str(x)
         assert c == 'GENSTRING action1 action2 t s', c
 
+    def test_strfunction(self):
+        """Test the strfunction() method"""
+        env = MyEnvironment(S='string')
+
+        x = SCons.Executor.Executor(MyAction(), env, [], ['t'], ['s'])
+        s = x.strfunction()
+        assert s == 'STRFUNCTION action1 action2 t s', s
+
     def test_get_raw_contents(self):
         """Test fetching the raw signatures contents"""
         env = MyEnvironment(RC='raw contents')
index 063837539061c51c760e8db1d17017437fea4ac6..47139fcd1b32fa8345e19e9e4d2a5bbc8f5fe661 100644 (file)
@@ -545,7 +545,7 @@ class Node:
 
         if self.has_builder():
             executor = self.get_executor()
-            binfo.bact = executor.get_contents()
+            binfo.bact = executor.strfunction()
             binfo.bactsig = calc.module.signature(executor)
             sigs.append(binfo.bactsig)
 
@@ -899,10 +899,13 @@ class Node:
 
         if len(lines) == 0:
             newact, newactsig = self.binfo.bact, self.binfo.bactsig
-            if old.bact != newact:
-                lines.append("the build action changed:\n" +
-                             "%sold: %s\n" % (' '*15, old.bact) +
-                             "%snew: %s\n" % (' '*15, newact))
+            if old.bactsig != newactsig:
+                if old.bact == newact:
+                    lines.append("the contents of the build action changed\n")
+                else:
+                    lines.append("the build action changed:\n" +
+                                 "%sold: %s\n" % (' '*15, old.bact) +
+                                 "%snew: %s\n" % (' '*15, newact))
 
         if len(lines) == 0:
             return "rebuilding `%s' for unknown reasons" % self
index ae4a33a095179bb643824a2342a07a71f68fd14d..be966c0cec8faafb8177f25e72962222a7c510a9 100644 (file)
@@ -38,7 +38,8 @@ python = TestSCons.python
 test = TestSCons.TestSCons()
 
 test.subdir('work1', ['work1', 'src'], ['work1', 'src', 'subdir'],
-            'work4', ['work4', 'src'], ['work4', 'src', 'subdir'])
+            'work4', ['work4', 'src'], ['work4', 'src', 'subdir'],
+            'work5')
 
 subdir_file6 = os.path.join('subdir', 'file6')
 subdir_file6_in = os.path.join('subdir', 'file6.in')
@@ -442,4 +443,59 @@ ccc 1
 file5.k 1 line 4
 """)
 
+
+
+test.write(['work5', 'SConstruct'], """\
+import shutil
+
+env = Environment()
+mode = int(ARGUMENTS.get('mode'))
+if mode:
+    def DifferentCopy(target, source, env):
+        tgt = str(target[0])
+        src = str(source[0])
+        shutil.copy(src, tgt)
+    MyCopy = Builder(action = DifferentCopy)
+
+    def ChangingCopy(target, source, env):
+        tgt = str(target[0])
+        src = str(source[0])
+        shutil.copy(src, tgt)
+    ChangingCopy = Builder(action = ChangingCopy)
+else:
+    MyCopy = Builder(action = Copy('$TARGET', '$SOURCE'))
+    def ChangingCopy(target, source, env):
+        tgt = str(target[0].abspath)
+        src = str(source[0].abspath)
+        shutil.copy(src, tgt)
+    ChangingCopy = Builder(action = ChangingCopy)
+
+env['BUILDERS']['MyCopy'] = MyCopy
+env['BUILDERS']['ChangingCopy'] = ChangingCopy
+
+env.MyCopy('f1.out', 'f1.in')
+env.ChangingCopy('f2.out', 'f2.in')
+""")
+
+test.write(['work5', 'f1.in'], "work5/f1.in\n")
+test.write(['work5', 'f2.in'], "work5/f2.in\n")
+
+test.run(chdir = 'work5', arguments = "mode=0 .")
+
+test.must_match(['work5', 'f1.out'], "work5/f1.in\n")
+test.must_match(['work5', 'f2.out'], "work5/f2.in\n")
+
+test.run(chdir = 'work5',
+         arguments = "--debug=explain mode=1 .",
+         stdout = test.wrap_stdout("""\
+scons: rebuilding `f1.out' because the build action changed:
+               old: Copy("f1.out", "f1.in")
+               new: DifferentCopy(["f1.out"], ["f1.in"])
+DifferentCopy(["f1.out"], ["f1.in"])
+scons: rebuilding `f2.out' because the contents of the build action changed
+ChangingCopy(["f2.out"], ["f2.in"])
+"""))
+
+
+
 test.pass_test()
index 62ce75b53d433956981276f6398e4a6e115b55a4..889c7a0c67da07acdc17320a5038c6cc14405b27 100644 (file)
@@ -59,7 +59,7 @@ expect = "scons: *** [%s] Error 1\n" % foo_obj
 test.fail_test(string.find(test.stderr(), expect) == -1)
 
 test.write('SConstruct', """
-Command('file.out', 'file.in', Copy())
+Command('file.out', 'file.in', Copy('$TARGET', '$SOURCE'))
 """)
 
 test.symlink('nonexistent', 'file.in')