Faster/leaner tree dumping. (Kevin Quick)
authorstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 11 Nov 2004 13:55:32 +0000 (13:55 +0000)
committerstevenknight <stevenknight@fdb21ef1-2011-0410-befe-b5e4ea1792b1>
Thu, 11 Nov 2004 13:55:32 +0000 (13:55 +0000)
git-svn-id: http://scons.tigris.org/svn/scons/trunk@1156 fdb21ef1-2011-0410-befe-b5e4ea1792b1

src/CHANGES.txt
src/engine/SCons/Script/__init__.py
src/engine/SCons/Util.py
src/engine/SCons/UtilTests.py

index 4c23967e8418ea0582fd23b6a4a9d2338c77ed08..1bd5e014aba4d2f883d0d24421dde03c50c6e9d0 100644 (file)
@@ -273,6 +273,8 @@ RELEASE 0.97 - XXX
   - Handle Python stack traces consistently (stop at the SConscript stack
     frame, by default) even if the Python source code isn't available.
 
+  - Improve the performance of the --debug={tree,dtree} options.
+
   From Levi Stephen:
 
   - Allow $JARCHDIR to be expanded to other construction variables.
index 712b4babefa115e4ef623723efec305c8d511522..a3d933d78fa0911d9275e94e39b44299d4390a46 100644 (file)
@@ -125,10 +125,10 @@ class BuildTask(SCons.Taskmaster.Task):
         # this method is serialized, but execute isn't:
         if print_tree and self.top:
             print
-            print SCons.Util.render_tree(self.targets[0], get_all_children)
+            SCons.Util.print_tree(self.targets[0], get_all_children)
         if print_dtree and self.top:
             print
-            print SCons.Util.render_tree(self.targets[0], get_derived_children)
+            SCons.Util.print_tree(self.targets[0], get_derived_children)
         if print_includes and self.top:
             t = self.targets[0]
             tree = t.render_include_tree()
index b2bae65e593740a2022472db73ca3dbd45e75aae..ec809b9ffb0944c343230d6e38cc84934d6f2262 100644 (file)
@@ -1018,7 +1018,9 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
        or in the whole tree if prune.
     """
 
-    if visited.has_key(root):
+    rname = str(root)
+
+    if visited.has_key(rname):
         return ""
 
     children = child_func(root)
@@ -1029,10 +1031,10 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
         else:
             retval = retval + "  "
 
-    retval = retval + "+-" + str(root) + "\n"
+    retval = retval + "+-" + rname + "\n"
     if not prune:
         visited = copy.copy(visited)
-    visited[root] = 1
+    visited[rname] = 1
 
     for i in range(len(children)):
         margin.append(i<len(children)-1)
@@ -1042,6 +1044,44 @@ def render_tree(root, child_func, prune=0, margin=[0], visited={}):
 
     return retval
 
+def print_tree(root, child_func, prune=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,
+    so that huge trees can be printed.
+
+    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
+    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,
+       or in the whole tree if prune.
+    """
+
+    rname = str(root)
+
+    if visited.has_key(rname):
+        return
+
+    def MMM(m):
+        return ["  ","| "][m]
+    print string.join(map(MMM, margin[:-1]), '') + "+-" + 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),
+            children[:-1])
+        margin[-1] = 0
+        print_tree(children[-1], child_func, prune, margin, visited)
+        margin.pop()
+                  
+
 def is_Dict(e):
     return type(e) is types.DictType or isinstance(e, UserDict)
 
index cec89e1d258f5f894d0312400109e7ca12696390..18fd3c2b888eef397998b6ca051c51402fd47aeb 100644 (file)
@@ -26,6 +26,7 @@ __revision__ = "__FILE__ __REVISION__ __DATE__ __DEVELOPER__"
 import os
 import os.path
 import string
+import StringIO
 import sys
 import types
 import unittest
@@ -941,7 +942,8 @@ class UtilTestCase(unittest.TestCase):
         q = quote_spaces('x\tx')
         assert q == '"x\tx"', q
 
-    def test_render_tree(self):
+    def tree_case_1(self):
+        """Fixture for the render_tree() and print_tree() tests."""
         class Node:
             def __init__(self, name, children=[]):
                 self.children = children
@@ -949,9 +951,6 @@ class UtilTestCase(unittest.TestCase):
             def __str__(self):
                 return self.name
 
-        def get_children(node):
-            return node.children
-
         windows_h = Node("windows.h")
         stdlib_h = Node("stdlib.h")
         stdio_h = Node("stdio.h")
@@ -972,9 +971,18 @@ class UtilTestCase(unittest.TestCase):
       +-windows.h
 """
 
-        actual = render_tree(foo, get_children)
-        assert expect == actual, (expect, actual)
+        return foo, expect
+
+    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])
@@ -988,9 +996,43 @@ class UtilTestCase(unittest.TestCase):
     +-bar.h
 """
 
-        actual = render_tree(blat_o, get_children, 1)
+        return blat_o, expect
+
+    def test_render_tree(self):
+        """Test the render_tree() function"""
+        def get_children(node):
+            return node.children
+
+        node, expect = self.tree_case_1()
+        actual = render_tree(node, get_children)
         assert expect == actual, (expect, actual)
 
+        node, expect = self.tree_case_2()
+        actual = render_tree(node, get_children, 1)
+        assert expect == actual, (expect, actual)
+
+    def test_print_tree(self):
+        """Test the print_tree() function"""
+        def get_children(node):
+            return node.children
+
+        save_stdout = sys.stdout
+
+        try:
+            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, 1)
+            actual = sys.stdout.getvalue()
+            assert expect == actual, (expect, actual)
+        finally:
+            sys.stdout = save_stdout
+
     def test_is_Dict(self):
         assert is_Dict({})
         assert is_Dict(UserDict())
@@ -1585,8 +1627,6 @@ class UtilTestCase(unittest.TestCase):
 
     def test_LogicalLines(self):
         """Test the LogicalLines class"""
-        import StringIO
-
         fobj = StringIO.StringIO(r"""
 foo \
 bar \