diff --git a/TODO b/TODO index 992851bd..5ae3f578 100644 --- a/TODO +++ b/TODO @@ -4,3 +4,19 @@ Waf 1.6.x * fix the remaining bugs * provide more extensions + +Can be useful: + +def bld_command(*k): + fun = k[0] + name = fun.__name__ + from waflib.Build import BuildContext + class tmp(BuildContext): + cmd = name + fun = name + return fun + +@bld_command +def foo(ctx): + print ctx.env + diff --git a/waflib/Runner.py b/waflib/Runner.py index bca936d2..ee288d31 100644 --- a/waflib/Runner.py +++ b/waflib/Runner.py @@ -312,6 +312,7 @@ class Parallel(object): st = tsk.runnable_status() except Exception: self.processed += 1 + # TODO waf 1.7 this piece of code should go in the error_handler tsk.err_msg = Utils.ex_stack() if not self.stop and self.bld.keep: tsk.hasrun = Task.SKIPPED @@ -320,6 +321,9 @@ class Parallel(object): if Logs.verbose > 1 or not self.error: self.error.append(tsk) self.stop = True + else: + if Logs.verbose > 1: + self.error.append(tsk) continue tsk.hasrun = Task.EXCEPTION self.error_handler(tsk) diff --git a/waflib/extras/smart_continue.py b/waflib/extras/smart_continue.py new file mode 100644 index 00000000..3af7b1f5 --- /dev/null +++ b/waflib/extras/smart_continue.py @@ -0,0 +1,81 @@ +#! /usr/bin/env python +# Thomas Nagy, 2011 + +# Try to cancel the tasks that cannot run with the option -k when an error occurs: +# 1 direct file dependencies +# 2 tasks listed in the before/after/ext_in/ext_out attributes + +from waflib import Task, Runner + +Task.CANCELED = 4 + +def cancel_next(self, tsk): + if not isinstance(tsk, Task.TaskBase): + return + if tsk.hasrun >= Task.SKIPPED: + # normal execution, no need to do anything here + return + + try: + canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes + except AttributeError: + canceled_tasks = self.canceled_tasks = set([]) + canceled_nodes = self.canceled_nodes = set([]) + + try: + canceled_nodes.update(tsk.outputs) + except AttributeError: + pass + + try: + canceled_tasks.add(tsk) + except AttributeError: + pass + +def get_out(self): + tsk = self.out.get() + if not self.stop: + self.add_more_tasks(tsk) + self.count -= 1 + self.dirty = True + self.cancel_next(tsk) # new code + +def error_handler(self, tsk): + if not self.bld.keep: + self.stop = True + self.error.append(tsk) + self.cancel_next(tsk) # new code + +Runner.Parallel.cancel_next = cancel_next +Runner.Parallel.get_out = get_out +Runner.Parallel.error_handler = error_handler + +def get_next_task(self): + tsk = self.get_next_task_smart_continue() + if not tsk: + return tsk + + try: + canceled_tasks, canceled_nodes = self.canceled_tasks, self.canceled_nodes + except AttributeError: + pass + else: + # look in the tasks that this one is waiting on + # if one of them was canceled, cancel this one too + for x in tsk.run_after: + if x in canceled_tasks: + tsk.hasrun = Task.CANCELED + self.cancel_next(tsk) + break + else: + # so far so good, now consider the nodes + for x in getattr(tsk, 'inputs', []) + getattr(tsk, 'deps', []): + if x in canceled_nodes: + tsk.hasrun = Task.CANCELED + self.cancel_next(tsk) + break + return tsk + +Runner.Parallel.get_next_task_smart_continue = Runner.Parallel.get_next_task +Runner.Parallel.get_next_task = get_next_task +