Commits

Anonymous committed 26c2757

Use the Node Walker to build dependencies in order.

Comments (0)

Files changed (6)

src/engine/MANIFEST

 SCons/Sig/__init__.py
 SCons/Sig/MD5.py
 SCons/Sig/TimeStamp.py
+SCons/Taskmaster.py
 SCons/Util.py
 setup.py

src/engine/SCons/Node/NodeTests.py

     def test_build(self):
 	"""Test building a node
 	"""
+	# Make sure it doesn't blow up if no builder is set.
+	node = SCons.Node.Node()
+	node.build()
+	assert built_it == None
+
 	node = SCons.Node.Node()
 	node.builder_set(Builder())
 	node.env_set(Environment())

src/engine/SCons/Node/__init__.py

 	self.env = None
 
     def build(self):
+	if not hasattr(self, "builder"):
+	    return None
 	sources_str = string.join(map(lambda x: str(x), self.sources))
 	stat = self.builder.execute(ENV = self.env.Dictionary('ENV'),
 				    target = str(self), source = sources_str)

src/engine/SCons/Taskmaster.py

+"""SCons.Taskmaster
+
+Generic Taskmaster.
+
+"""
+
+#
+# Copyright (c) 2001 Steven Knight
+#
+# 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__"
+
+
+
+
+import SCons.Node
+
+
+
+class Task:
+    """Default SCons build engine task."""
+    def __init__(self,target):
+        self.target = target
+
+    def execute(self):
+        self.target.build()
+
+
+
+def current(node):
+    """Default SCons build engine is-it-current function.
+
+    This returns "always out of date," so every node is always
+    built/visited.
+    """
+    return None
+
+
+
+class Taskmaster:
+    """A generic Taskmaster for handling a bunch of targets.
+    """
+
+    def __init__(self, targets=[], tasker=Task, current=current):
+        self.targets = targets
+        self.tasker = tasker
+        self.current = current
+        self.num_iterated = 0
+        self.walker = None
+
+    def next_node(self):
+        t = None
+        if self.walker:
+            t = self.walker.next()
+        if t == None and self.num_iterated < len(self.targets):
+            t = self.targets[self.num_iterated]
+            self.num_iterated = self.num_iterated + 1
+            t.top_target = 1
+            self.walker = SCons.Node.Walker(t)
+            t = self.walker.next()
+        top = None
+        if hasattr(t, "top_target"):
+            top = 1
+        return t, top
+
+    def next_task(self):
+        n, top = self.next_node()
+        while n != None:
+            if self.current(n):
+                self.up_to_date(n)
+            else:
+                return self.tasker(n)
+            n, top = self.next_node()
+        return None
+
+    def is_blocked(self):
+        return 0
+
+    def up_to_date(self, node):
+        pass
+
+    def executed(self, task):
+        pass
+
+    def failed(self, task):
+        self.walker = None
+        self.num_iterated = len(self.targets)

src/engine/SCons/TaskmasterTests.py

+#
+# Copyright (c) 2001 Steven Knight
+#
+# 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__"
+
+import sys
+import unittest
+
+import SCons.Taskmaster
+
+
+
+built = None
+
+class Node:
+    def __init__(self, name, kids = []):
+        self.name = name
+	self.kids = kids
+
+    def build(self):
+        global built
+        built = self.name + " built"
+
+    def children(self):
+	return self.kids
+
+
+
+class TaskmasterTestCase(unittest.TestCase):
+
+    def test_next_node(self):
+	"""Test fetching the next node
+	"""
+	n1 = Node("n1")
+	n2 = Node("n2")
+	n3 = Node("n3", [n1, n2])
+
+	tm = SCons.Taskmaster.Taskmaster([n3])
+	n, top = tm.next_node()
+	assert n.name == "n1"
+	assert top == None
+	n, top = tm.next_node()
+	assert n.name == "n2"
+	assert top == None
+	n, top = tm.next_node()
+	assert n.name == "n3"
+	assert top == 1
+	n, top = tm.next_node()
+	assert n == None
+	assert top == None
+
+    def test_next_task(self):
+	"""Test fetching the next task
+	"""
+	global built
+
+	n1 = Node("n1")
+	n2 = Node("n2")
+	n3 = Node("n3", [n1, n2])
+
+	tm = SCons.Taskmaster.Taskmaster([n3])
+	tm.next_task().execute()
+	assert built == "n1 built"
+
+	tm.next_task().execute()
+	assert built == "n2 built"
+
+	tm.next_task().execute()
+	assert built == "n3 built"
+
+	def current(node):
+	    return 1
+
+	built = "up to date: "
+
+	class MyTM(SCons.Taskmaster.Taskmaster):
+	    def up_to_date(self, node):
+		global built
+	        built = built + " " + node.name
+
+	tm = MyTM(targets = [n3], current = current)
+	assert tm.next_task() == None
+	assert built == "up to date:  n1 n2 n3"
+
+    def test_is_blocked(self):
+        """Test whether a task is blocked
+
+	Both default and overridden in a subclass.
+	"""
+	tm = SCons.Taskmaster.Taskmaster()
+	assert tm.is_blocked() == 0
+
+	class MyTM(SCons.Taskmaster.Taskmaster):
+	    def is_blocked(self):
+	        return 1
+	tm = MyTM()
+	assert tm.is_blocked() == 1
+
+    def test_executed(self):
+        """Test the executed() method
+
+	Both default and overridden in a subclass.
+	"""
+	tm = SCons.Taskmaster.Taskmaster()
+	tm.executed('foo')
+
+	class MyTM(SCons.Taskmaster.Taskmaster):
+	    def executed(self, task):
+	        return 'x' + task
+	tm = MyTM()
+	assert tm.executed('foo') == 'xfoo'
+
+    def test_failed(self):
+        """Test the failed() method
+
+	Both default and overridden in a subclass.
+	"""
+	tm = SCons.Taskmaster.Taskmaster()
+	#XXX
+	tm.failed('foo')
+
+	class MyTM(SCons.Taskmaster.Taskmaster):
+	    def failed(self, task):
+	        return 'y' + task
+	tm = MyTM()
+	assert tm.failed('foo') == 'yfoo'
+
+
+
+
+if __name__ == "__main__":
+    suite = unittest.makeSuite(TaskmasterTestCase, 'test_')
+    if not unittest.TextTestRunner().run(suite).wasSuccessful():
+	sys.exit(1)

src/script/scons.py

 import sys
 import traceback
 
+import SCons.Node
 import SCons.Node.FS
 import SCons.Job
 from SCons.Errors import *
 import SCons.Sig
 import SCons.Sig.MD5
+from SCons.Taskmaster import Taskmaster
 
 #
 # Modules and classes that we don't use directly in this script, but
 from SCons.Environment import Environment
 from SCons.Builder import Builder
 
+
+
+#
+# Task control.
+#
 class Task:
-    "XXX: this is here only until the build engine is implemented"
+    """An SCons build task."""
 
     def __init__(self, target):
         self.target = target
             sys.stderr.write("scons: *** [%s] Error %d\n" % (e.node, e.stat))
             raise
 
-
-
-class Taskmaster:
-    "XXX: this is here only until the build engine is implemented"
-
-    def __init__(self, targets, calc):
-        self.targets = targets
-        self.calc = calc
-        self.num_iterated = 0
-
-
+class ScriptTaskmaster(SCons.Taskmaster.Taskmaster):
+    """Controlling logic for tasks.
+    
+    This is the stock Taskmaster from the build engine, except
+    that we override the next_task() method to provide our
+    script-specific up-to-date message for command-line targets.
+    """
     def next_task(self):
-        while self.num_iterated < len(self.targets):
-            t = self.targets[self.num_iterated]
-            self.num_iterated = self.num_iterated + 1
-            if self.calc.current(t):
+        t, top = SCons.Taskmaster.Taskmaster.next_node(self)
+        while t != None:
+            if not self.current(t):
+                return self.tasker(t)
+            elif top:
                 print 'scons: "%s" is up to date.' % t
-            else:
-                return Task(t)
+            t, top = SCons.Taskmaster.Taskmaster.next_node(self)
         return None
 
-    def is_blocked(self):
-        return 0
-
-    def executed(self, task):
-        pass
-
-    def failed(self, task):
-        self.num_iterated = len(self.targets)
 
 
 # Global variables
     nodes = map(lambda x: SCons.Node.FS.default_fs.File(x), targets)
     calc = SCons.Sig.Calculator(SCons.Sig.MD5)
 
-    taskmaster = Taskmaster(nodes, calc)
+    taskmaster = ScriptTaskmaster(nodes, Task, calc.current)
 
     jobs = SCons.Job.Jobs(num_jobs, taskmaster)
     jobs.start()
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.