Add a --debug=stree option to show Node status. (Kevin Quick)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 21 Nov 2004 16:35:29 +0000 (16:35 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Sun, 21 Nov 2004 16:35:29 +0000 (16:35 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1173 fdb21ef1-2011-0410-befe-b5e4ea1792b1

doc/man/scons.1
src/engine/SCons/Script/__init__.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py
test/option--debug.py

index 23e646b34175f18ddc7f9cf06b18689400879ecd..e73bada0ca662f28e55d4364c1512d007a72e781 100644 (file)
@@ -573,6 +573,12 @@ Building myprog.o with action(s):
 Prints an internal Python stack trace
 when encountering an otherwise unexplained error.
 
+.TP
+--debug=stree
+Print the dependency tree along with status information.  This is the
+same as the debug=tree option, but additional status information is
+provided for each node in the tree.
+
 .TP
 --debug=time
 Prints various time profiling information: the time spent
index a3d933d78fa0911d9275e94e39b44299d4390a46..7d139a1fceaf446f65e91d1b93891ece2f4324de 100644 (file)
@@ -126,6 +126,10 @@ class BuildTask(SCons.Taskmaster.Task):
         if print_tree and self.top:
             print
             SCons.Util.print_tree(self.targets[0], get_all_children)
+        if print_stree and self.top:
+            print
+            SCons.Util.print_tree(self.targets[0], get_all_children,
+                                  showtags=2)
         if print_dtree and self.top:
             print
             SCons.Util.print_tree(self.targets[0], get_derived_children)
@@ -245,6 +249,7 @@ print_explanations = 0
 print_includes = 0
 print_objects = 0
 print_stacktrace = 0
+print_stree = 0
 print_time = 0
 print_tree = 0
 memory_stats = None
@@ -405,7 +410,7 @@ def _set_globals(options):
     global repositories, keep_going_on_error, ignore_errors
     global print_count, print_dtree
     global print_explanations, print_includes
-    global print_objects, print_stacktrace
+    global print_objects, print_stacktrace, print_stree
     global print_time, print_tree
     global memory_outf, memory_stats
 
@@ -433,6 +438,8 @@ def _set_globals(options):
                 SCons.Action.print_actions_presub = 1
             elif options.debug == "stacktrace":
                 print_stacktrace = 1
+            elif options.debug == "stree":
+                print_stree = 1
             elif options.debug == "time":
                 print_time = 1
             elif options.debug == "tree":
@@ -530,7 +537,7 @@ class OptParser(OptionParser):
 
         debug_options = ["count", "dtree", "explain", "findlibs",
                          "includes", "memory", "objects",
-                         "pdb", "presub", "stacktrace",
+                         "pdb", "presub", "stacktrace", "stree",
                          "time", "tree"]
 
         def opt_debug(option, opt, value, parser, debug_options=debug_options):
index 896abaf26176275b916cd3010624ca0af1d3ab93..87aba968e7d347f777a022cd571631e4d9241ac9 100644 (file)
@@ -1052,7 +1052,9 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
 
     return retval
 
-def print_tree(root, child_func, prune=0, margin=[0], visited={}):
+IDX = lambda N: N and 1 or 0
+
+def print_tree(root, child_func, prune=0, showtags=0, margin=[0], visited={}):
     """
     Print a tree of nodes.  This is like render_tree, except it prints
     lines directly instead of creating a string representation in memory,
@@ -1061,6 +1063,7 @@ def print_tree(root, child_func, prune=0, margin=[0], visited={}):
     root - the root node of the tree
     child_func - the function called to get the children of a node
     prune - don't visit the same node twice
+    showtags - print status information to the left of each node line
     margin - the format of the left margin to use for children of root.
        1 results in a pipe, and 0 results in no pipe.
     visited - a dictionary of visited nodes in the current branch if not prune,
@@ -1072,23 +1075,51 @@ def print_tree(root, child_func, prune=0, margin=[0], visited={}):
     if visited.has_key(rname):
         return
 
+    if showtags:
+
+        if showtags == 2:
+            print ' E       = exists'
+            print '  R      = exists in repository only'
+            print '   b     = implicit builder'
+            print '   B     = explicit builder'
+            print '    S    = side effect'
+            print '     P   = precious'
+            print '      A  = always build'
+            print '       C = current'
+            print ''
+
+        tags = ['[']
+        tags.append(' E'[IDX(root.exists())])
+        tags.append(' R'[IDX(root.rexists() and not root.exists())])
+        tags.append(' BbB'[[0,1][IDX(root.has_explicit_builder())] +
+                           [0,2][IDX(root.has_builder())]])
+        tags.append(' S'[IDX(root.side_effect)])
+        tags.append(' P'[IDX(root.precious)])
+        tags.append(' A'[IDX(root.always_build)])
+        tags.append(' C'[IDX(root.current())])
+        tags.append(']')
+
+    else:
+        tags = []
+
     def MMM(m):
         return ["  ","| "][m]
-    print string.join(map(MMM, margin[:-1]), '') + "+-" + rname
+    margins = map(MMM, margin[:-1])
+
+    print string.join(tags + margins + ['+-', rname], '')
 
     if prune:
         visited[rname] = 1
-        
+
     children = child_func(root)
     if children:
         margin.append(1)
-        map(lambda C, cf=child_func, p=prune, m=margin, v=visited:
-                   print_tree(C, cf, p, m, v),
+        map(lambda C, cf=child_func, p=prune, i=IDX(showtags), m=margin, v=visited:
+                   print_tree(C, cf, p, i, m, v),
             children[:-1])
         margin[-1] = 0
-        print_tree(children[-1], child_func, prune, margin, visited)
+        print_tree(children[-1], child_func, prune, IDX(showtags), margin, visited)
         margin.pop()
-                  
 
 def is_Dict(e):
     return type(e) is types.DictType or isinstance(e, UserDict)
index c5c5297d99ab1053ee85b06bb6eed5c8bf8b64d6..c28db37bfd79d308028ce434d3812d06edbf6f60 100644 (file)
@@ -942,23 +942,39 @@ class UtilTestCase(unittest.TestCase):
         q = quote_spaces('x\tx')
         assert q == '"x\tx"', q
 
+    class Node:
+        def __init__(self, name, children=[]):
+            self.children = children
+            self.name = name
+        def __str__(self):
+            return self.name
+        def exists(self):
+            return 1
+        def rexists(self):
+            return 1
+        def has_builder(self):
+            return 1
+        def has_explicit_builder(self):
+            return 1
+        def side_effect(self):
+            return 1
+        def precious(self):
+            return 1
+        def always_build(self):
+            return 1
+        def current(self):
+            return 1
+
     def tree_case_1(self):
         """Fixture for the render_tree() and print_tree() tests."""
-        class Node:
-            def __init__(self, name, children=[]):
-                self.children = children
-                self.name = name
-            def __str__(self):
-                return self.name
-
-        windows_h = Node("windows.h")
-        stdlib_h = Node("stdlib.h")
-        stdio_h = Node("stdio.h")
-        bar_c = Node("bar.c", [stdlib_h, windows_h])
-        bar_o = Node("bar.o", [bar_c])
-        foo_c = Node("foo.c", [stdio_h])
-        foo_o = Node("foo.o", [foo_c])
-        foo = Node("foo", [foo_o, bar_o])
+        windows_h = self.Node("windows.h")
+        stdlib_h = self.Node("stdlib.h")
+        stdio_h = self.Node("stdio.h")
+        bar_c = self.Node("bar.c", [stdlib_h, windows_h])
+        bar_o = self.Node("bar.o", [bar_c])
+        foo_c = self.Node("foo.c", [stdio_h])
+        foo_o = self.Node("foo.o", [foo_c])
+        foo = self.Node("foo", [foo_o, bar_o])
 
         expect = """\
 +-foo
@@ -971,22 +987,20 @@ class UtilTestCase(unittest.TestCase):
       +-windows.h
 """
 
-        return foo, expect
+        lines = string.split(expect, '\n')[:-1]
+        lines = map(lambda l: '[E BSPAC]'+l, lines)
+        withtags = string.join(lines, '\n') + '\n'
+
+        return foo, expect, withtags
 
     def tree_case_2(self):
         """Fixture for the render_tree() and print_tree() tests."""
-        class Node:
-            def __init__(self, name, children=[]):
-                self.children = children
-                self.name = name
-            def __str__(self):
-                return self.name
 
-        stdlib_h = Node("stdlib.h")
-        bar_h = Node('bar.h', [stdlib_h])
-        blat_h = Node('blat.h', [stdlib_h])
-        blat_c = Node('blat.c', [blat_h, bar_h])
-        blat_o = Node('blat.o', [blat_c])
+        stdlib_h = self.Node("stdlib.h")
+        bar_h = self.Node('bar.h', [stdlib_h])
+        blat_h = self.Node('blat.h', [stdlib_h])
+        blat_c = self.Node('blat.c', [blat_h, bar_h])
+        blat_o = self.Node('blat.o', [blat_c])
 
         expect = """\
 +-blat.o
@@ -996,18 +1010,22 @@ class UtilTestCase(unittest.TestCase):
     +-bar.h
 """
 
-        return blat_o, expect
+        lines = string.split(expect, '\n')[:-1]
+        lines = map(lambda l: '[E BSPAC]'+l, lines)
+        withtags = string.join(lines, '\n') + '\n'
+
+        return blat_o, expect, withtags
 
     def test_render_tree(self):
         """Test the render_tree() function"""
         def get_children(node):
             return node.children
 
-        node, expect = self.tree_case_1()
+        node, expect, withtags = self.tree_case_1()
         actual = render_tree(node, get_children)
         assert expect == actual, (expect, actual)
 
-        node, expect = self.tree_case_2()
+        node, expect, withtags = self.tree_case_2()
         actual = render_tree(node, get_children, 1)
         assert expect == actual, (expect, actual)
 
@@ -1019,17 +1037,38 @@ class UtilTestCase(unittest.TestCase):
         save_stdout = sys.stdout
 
         try:
+            node, expect, withtags = self.tree_case_1()
+
             sys.stdout = StringIO.StringIO()
-            node, expect = self.tree_case_1()
             print_tree(node, get_children)
             actual = sys.stdout.getvalue()
             assert expect == actual, (expect, actual)
 
             sys.stdout = StringIO.StringIO()
-            node, expect = self.tree_case_2()
+            print_tree(node, get_children, showtags=1)
+            actual = sys.stdout.getvalue()
+            assert withtags == actual, (withtags, actual)
+
+            node, expect, withtags = self.tree_case_2()
+
+            sys.stdout = StringIO.StringIO()
             print_tree(node, get_children, 1)
             actual = sys.stdout.getvalue()
             assert expect == actual, (expect, actual)
+
+            sys.stdout = StringIO.StringIO()
+            # The following call should work here:
+            #    print_tree(node, get_children, 1, showtags=1)
+            # For some reason I don't understand, though, *this*
+            # time that we call print_tree, the visited dictionary
+            # is still populated with the values from the last call!
+            # I can't see why this would be, short of a bug in Python,
+            # and rather than continue banging my head against the
+            # brick wall for a *test*, we're going to going with
+            # the cheap, easy workaround:
+            print_tree(node, get_children, 1, showtags=1, visited={})
+            actual = sys.stdout.getvalue()
+            assert withtags == actual, (withtags, actual)
         finally:
             sys.stdout = save_stdout
 
index 7a80647083f1ef33dfb4529eae4c45c6b60c6f2b..47bc058d9c01c2138b04b2ddc3cc7290d9173ee8 100644 (file)
@@ -84,6 +84,47 @@ test.fail_test(string.find(test.stdout(), tree) == -1)
 test.run(arguments = "--debug=tree foo.xxx")
 test.fail_test(string.find(test.stdout(), tree) == -1)
 
+stree = """
+[E B   C]+-foo.xxx
+[E B   C]  +-foo.ooo
+[E      ]  | +-foo.c
+[E      ]  | +-foo.h
+[E      ]  | +-bar.h
+[E B   C]  +-bar.ooo
+[E      ]    +-bar.c
+[E      ]    +-bar.h
+[E      ]    +-foo.h
+"""
+
+test.run(arguments = "--debug=stree foo.xxx")
+test.fail_test(string.find(test.stdout(), stree) == -1)
+
+stree2 = """
+ E       = exists
+  R      = exists in repository only
+   b     = implicit builder
+   B     = explicit builder
+    S    = side effect
+     P   = precious
+      A  = always build
+       C = current
+
+[  B    ]+-foo.xxx
+[  B    ]  +-foo.ooo
+[E      ]  | +-foo.c
+[E      ]  | +-foo.h
+[E      ]  | +-bar.h
+[  B    ]  +-bar.ooo
+[E      ]    +-bar.c
+[E      ]    +-bar.h
+[E      ]    +-foo.h
+"""
+
+test.run(arguments = '-c foo.xxx')
+test.run(arguments = "--no-exec --debug=stree foo.xxx")
+test.fail_test(string.find(test.stdout(), stree2) == -1)
+
+
 
 tree = """
 +-foo.xxx