SCons/Sig/__init__.py
SCons/Sig/MD5.py
SCons/Sig/TimeStamp.py
+SCons/Taskmaster.py
SCons/Util.py
setup.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())
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)
--- /dev/null
+"""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)
--- /dev/null
+#
+# 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)
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()