Author: William ML Leslie <[email protected]>
Branch: taskengine-sorted-optionals
Changeset: r84337:cb82010dadbc
Date: 2016-05-10 02:02 +1000
http://bitbucket.org/pypy/pypy/changeset/cb82010dadbc/
Log: Optional dependencies should take part in ordering even if they
become non-optional 'later'
diff --git a/rpython/translator/tool/taskengine.py
b/rpython/translator/tool/taskengine.py
--- a/rpython/translator/tool/taskengine.py
+++ b/rpython/translator/tool/taskengine.py
@@ -13,7 +13,7 @@
tasks[task_name] = task, task_deps
- def _plan(self, goals, skip=[]):
+ def _plan(self, goals, skip=()):
skip = [toskip for toskip in skip if toskip not in goals]
key = (tuple(goals), tuple(skip))
@@ -21,64 +21,46 @@
return self._plan_cache[key]
except KeyError:
pass
- constraints = []
-
- def subgoals(task_name):
- taskcallable, deps = self.tasks[task_name]
- for dep in deps:
- if dep.startswith('??'): # optional
- dep = dep[2:]
- if dep not in goals:
- continue
- if dep.startswith('?'): # suggested
- dep = dep[1:]
- if dep in skip:
- continue
- yield dep
-
- seen = {}
-
- def consider(subgoal):
- if subgoal in seen:
- return
- else:
- seen[subgoal] = True
- constraints.append([subgoal])
- deps = subgoals(subgoal)
- for dep in deps:
- constraints.append([subgoal, dep])
- consider(dep)
-
- for goal in goals:
- consider(goal)
-
- #sort
plan = []
+ goal_walker = goals[::-1]
+ flattened_goals = []
+ for base_goal in goals[::-1]:
+ goal_walker = [base_goal]
+ dep_walker = [iter(self.tasks[base_goal.lstrip('?')][1])]
+ while goal_walker:
+ for subgoal in dep_walker[-1]:
+ break
+ else:
+ # all dependencies are in flattened_goals. record
+ # this goal.
+ dep_walker.pop()
+ goal = goal_walker.pop()
+ if goal not in flattened_goals:
+ flattened_goals.append(goal)
+ continue
+ if subgoal in goal_walker:
+ raise RuntimeException('circular dependency')
- while True:
- cands = dict.fromkeys([constr[0] for constr in constraints if
constr])
- if not cands:
- break
+ # subgoal must be at least as optional as its parent
+ qs = goal_walker[-1].count('?')
+ if subgoal.count('?') < qs:
+ subgoal = '?' * qs + subgoal.lstrip('?')
- for cand in cands:
- for constr in constraints:
- if cand in constr[1:]:
- break
- else:
- break
- else:
- raise RuntimeError("circular dependecy")
+ # we'll add this goal once we have its dependencies.
+ goal_walker.append(subgoal)
+ dep_walker.append(iter(self.tasks[subgoal.lstrip('?')][1]))
- plan.append(cand)
- for constr in constraints:
- if constr and constr[0] == cand:
- del constr[0]
-
- plan.reverse()
-
+ plan = []
+ for name in flattened_goals:
+ name = name.lstrip('?')
+ if name in plan:
+ continue
+ will_run = name in flattened_goals or (
+ '?' + name in flattened_goals and name not in skip)
+ if will_run:
+ plan.append(name)
self._plan_cache[key] = plan
-
return plan
def _depending_on(self, goal):
diff --git a/rpython/translator/tool/test/test_taskengine.py
b/rpython/translator/tool/test/test_taskengine.py
--- a/rpython/translator/tool/test/test_taskengine.py
+++ b/rpython/translator/tool/test/test_taskengine.py
@@ -148,3 +148,29 @@
assert drv._plan(['D', 'T', 'R']) == ['A', 'R', 'b', 'H', 'T', 'B', 'D']
assert drv._plan(['D', 'T']) == ['A', 'R', 'b', 'H', 'T', 'B', 'D']
assert drv._plan(['D', 'T'], skip=['B']) == ['A', 'R', 'b', 'H', 'T', 'D']
+
+
+def test_can_be_optional():
+ class Drv(SimpleTaskEngine):
+ def task_A():
+ pass
+
+ def task_B():
+ pass
+
+ task_B.task_deps = ['??A']
+
+ def task_C():
+ pass
+
+ task_C.task_deps = ['??B']
+
+ def task_D():
+ pass
+
+ task_D.task_deps = ['B', 'C']
+
+ drv = Drv()
+ assert drv._plan(['D']) == ['B', 'C', 'D']
+ assert drv._plan(['B', 'D']) == ['B', 'C', 'D']
+ assert drv._plan(['A', 'D']) == ['A', 'B', 'C', 'D']
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit