From: stevenknight Date: Mon, 8 Dec 2008 19:04:22 +0000 (+0000) Subject: Create Taskmaster.{Always,OutOfDate}Task subclasses of Taskmaster.Task X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=7717c448f7d69064d5741d9baf86a6ac5efb1ce9;p=scons.git Create Task{Always,OutOfDate}Task subclasses of Taskmaster.Task to hold different implementations of the .needs_execute() method. git-svn-id: http://scons.tigris.org/svn/scons/trunk@3817 fdb21ef1-2011-0410-befe-b5e4ea1792b1 --- diff --git a/src/engine/SCons/JobTests.py b/src/engine/SCons/JobTests.py index b2a195ea..852cb915 100644 --- a/src/engine/SCons/JobTests.py +++ b/src/engine/SCons/JobTests.py @@ -437,7 +437,9 @@ class _SConsTaskTest(unittest.TestCase): for tnum in range(num_tasks): testnodes.append(node_seq[tnum % len(node_seq)]()) - taskmaster = SCons.Taskmaster.Taskmaster(testnodes) + taskmaster = SCons.Taskmaster.Taskmaster(testnodes, + tasker=SCons.Taskmaster.AlwaysTask) + jobs = SCons.Job.Jobs(num_jobs, taskmaster) # Exceptions thrown by tasks are not actually propagated to diff --git a/src/engine/SCons/SConf.py b/src/engine/SCons/SConf.py index 25fc2bcf..6461dda9 100644 --- a/src/engine/SCons/SConf.py +++ b/src/engine/SCons/SConf.py @@ -203,7 +203,7 @@ class Streamer: self.s.flush() -class SConfBuildTask(SCons.Taskmaster.Task): +class SConfBuildTask(SCons.Taskmaster.AlwaysTask): """ This is almost the same as SCons.Script.BuildTask. Handles SConfErrors correctly and knows about the current cache_mode. diff --git a/src/engine/SCons/Script/Main.py b/src/engine/SCons/Script/Main.py index 25e73dce..db712e6e 100644 --- a/src/engine/SCons/Script/Main.py +++ b/src/engine/SCons/Script/Main.py @@ -155,7 +155,7 @@ _BuildFailures = [] def GetBuildFailures(): return _BuildFailures -class BuildTask(SCons.Taskmaster.Task): +class BuildTask(SCons.Taskmaster.OutOfDateTask): """An SCons build task.""" progress = ProgressObject @@ -164,16 +164,14 @@ class BuildTask(SCons.Taskmaster.Task): def prepare(self): self.progress(self.targets[0]) - return SCons.Taskmaster.Task.prepare(self) + return SCons.Taskmaster.OutOfDateTask.prepare(self) def needs_execute(self): - target = self.targets[0] - if target.get_state() == SCons.Node.executing: + if SCons.Taskmaster.OutOfDateTask.needs_execute(self): return True - else: - if self.top and target.has_builder(): - display("scons: `%s' is up to date." % str(self.node)) - return False + if self.top and self.targets[0].has_builder(): + display("scons: `%s' is up to date." % str(self.node)) + return False def execute(self): if print_time: @@ -181,7 +179,7 @@ class BuildTask(SCons.Taskmaster.Task): global first_command_start if first_command_start is None: first_command_start = start_time - SCons.Taskmaster.Task.execute(self) + SCons.Taskmaster.OutOfDateTask.execute(self) if print_time: global cumulative_command_time global last_command_end @@ -195,13 +193,13 @@ class BuildTask(SCons.Taskmaster.Task): global exit_status global this_build_status if self.options.ignore_errors: - SCons.Taskmaster.Task.executed(self) + SCons.Taskmaster.OutOfDateTask.executed(self) elif self.options.keep_going: - SCons.Taskmaster.Task.fail_continue(self) + SCons.Taskmaster.OutOfDateTask.fail_continue(self) exit_status = status this_build_status = status else: - SCons.Taskmaster.Task.fail_stop(self) + SCons.Taskmaster.OutOfDateTask.fail_stop(self) exit_status = status this_build_status = status @@ -223,9 +221,9 @@ class BuildTask(SCons.Taskmaster.Task): self.do_failed() else: print "scons: Nothing to be done for `%s'." % t - SCons.Taskmaster.Task.executed(self) + SCons.Taskmaster.OutOfDateTask.executed(self) else: - SCons.Taskmaster.Task.executed(self) + SCons.Taskmaster.OutOfDateTask.executed(self) def failed(self): # Handle the failure of a build task. The primary purpose here @@ -293,17 +291,17 @@ class BuildTask(SCons.Taskmaster.Task): if tree: print print tree - SCons.Taskmaster.Task.postprocess(self) + SCons.Taskmaster.OutOfDateTask.postprocess(self) def make_ready(self): """Make a task ready for execution""" - SCons.Taskmaster.Task.make_ready(self) + SCons.Taskmaster.OutOfDateTask.make_ready(self) if self.out_of_date and self.options.debug_explain: explanation = self.out_of_date[0].explain() if explanation: sys.stdout.write("scons: " + explanation) -class CleanTask(SCons.Taskmaster.Task): +class CleanTask(SCons.Taskmaster.AlwaysTask): """An SCons clean task.""" def fs_delete(self, path, pathstr, remove=1): try: @@ -379,11 +377,11 @@ class CleanTask(SCons.Taskmaster.Task): def prepare(self): pass -class QuestionTask(SCons.Taskmaster.Task): +class QuestionTask(SCons.Taskmaster.AlwaysTask): """An SCons task for the -q (question) option.""" def prepare(self): pass - + def execute(self): if self.targets[0].get_state() != SCons.Node.up_to_date or \ (self.top and not self.targets[0].exists()): diff --git a/src/engine/SCons/Taskmaster.py b/src/engine/SCons/Taskmaster.py index eefe56bc..f3604028 100644 --- a/src/engine/SCons/Taskmaster.py +++ b/src/engine/SCons/Taskmaster.py @@ -197,14 +197,11 @@ class Task: return self.node def needs_execute(self): - """ - Called to determine whether the task's execute() method should - be run. - - This method allows one to skip the somethat costly execution - of the execute() method in a seperate thread. For example, - that would be unnecessary for up-to-date targets. - """ + # TODO(deprecate): "return True" is the old default behavior; + # change it to NotImplementedError (after running through the + # Deprecation Cycle) so the desired behavior is explicitly + # determined by which concrete subclass is used. + #raise NotImplementedError return True def execute(self): @@ -501,6 +498,30 @@ class Task: exc_traceback = None raise exc_type, exc_value, exc_traceback +class AlwaysTask(Task): + def needs_execute(self): + """ + Always returns True (indicating this Task should always + be executed). + + Subclasses that need this behavior (as opposed to the default + of only executing Nodes that are out of date w.r.t. their + dependencies) can use this as follows: + + class MyTaskSubclass(SCons.Taskmaster.Task): + needs_execute = SCons.Taskmaster.Task.execute_always + """ + return True + +class OutOfDateTask(Task): + def needs_execute(self): + """ + Returns True (indicating this Task should be executed) if this + Task's target state indicates it needs executing, which has + already been determined by an earlier up-to-date check. + """ + return self.targets[0].get_state() == SCons.Node.executing + def find_cycle(stack, visited): if stack[-1] in visited: @@ -521,11 +542,13 @@ class Taskmaster: The Taskmaster for walking the dependency DAG. """ - def __init__(self, targets=[], tasker=Task, order=None, trace=None): + def __init__(self, targets=[], tasker=None, order=None, trace=None): self.original_top = targets self.top_targets_left = targets[:] self.top_targets_left.reverse() self.candidates = [] + if tasker is None: + tasker = OutOfDateTask self.tasker = tasker if not order: order = lambda l: l