Ronny Pfannschmidt avatar Ronny Pfannschmidt committed 3505f1e

fix dependency tracking bug with repeaded task occurences

Comments (0)

Files changed (5)

         self.depends = {}
         self.completed = set()
         self.runnable = set()
-        self.taken = set()
+        self.failed = set()
         self.running = set()
 
-    def find_and_add_new_runnable(self):
-        found = set()
-
-        for k, v in  self.depends.items():
+    def _run_canidates(self):
+        for k, v in self.depends.iteritems():
             if k in self.completed:
                 continue
             if k in self.running:
                 continue
-            if hasattr(k, '__iter__'):
-                new_item = next(k, None)
-                if new_item is not None:
-                    new_item = self.add(new_item, parent=k)
-                    found.add(new_item)
-            if not v - self.completed:
+            if v - self.completed:
+                continue
+            yield k, v
+
+
+    def find_and_add_new_runnable(self):
+        for k, v in  self._run_canidates():
+            try:
+                new_item = next(k)
+                new_item = self.add(new_item, parent=k)
+                return True
+            except (TypeError, StopIteration):
                 self.runnable.add(k)
-        return bool(found)
+                return False
+
 
     def report_failure(self, task):
-        #XXX: evil
+        self.failed.add(task)
         task_failed.send(task)
         self.completed.add(task)
         self.running.remove(task)
 
-    def report_sucess(self, task):
+    def report_success(self, task):
         task_succeeded.send(task)
         self.completed.add(task)
         self.running.remove(task)
 
     def next(self):
+        #XXX: expensive
         if not self.runnable:
-            #XXX: expensive
-            f = self.find_and_add_new_runnable()
-            while f and not self.runnable:
-                f = self.find_and_add_new_runnable()
+            retry = True
+            while retry:
+                retry = self.find_and_add_new_runnable()
+
 
         if not self.runnable:
             raise StopIteration
             self._key_to_identity[task] = task
         else:
             task = self._key_to_identity[task]
+
         if parent:
             self.depends[parent].add(task)
             task_succeeded.connect(parent._requirement_succeeded, sender=task)
             task_failed.connect(parent._requirement_failed, sender=task)
+
+            # directly resignal on already completed signals
+            if task in self.completed:
+                print 'completed, but reasked', task
+                if task in self.failed:
+                    task_failed.send(task)
+                else:
+                    task_succeeded.send(task)
         return task
 
     def run_all_possible(self):
             print 'trying to run', item
             try:
                 item()
-                self.report_sucess(item)
+                self.report_success(item)
             except RuntimeError:
                 #reraise if report_failure tells us to do so
                 if self.report_failure(item):
         """
         self.run_all_possible()
         if len(self.completed) < len(self.depends):
-            print 'completed: \n ', '\n  '.join(str(x)
+
+            def sanestr(x):
+                for a in 'match package'.split():
+                    if hasattr(x, a):
+                        return '%s %s=%s' % (
+                                x.__class__.__name__,
+                                a,
+                                getattr(x, a))
+
+                return x.__class__.__name__
+
+            def depspec(x):
+                if not self.depends[x]:
+                    return sanestr(x)
+                return '%s -> %s' % (
+                        sanestr(x),
+                        ', '.join(sanestr(v)
+                                  for v in sorted(self.depends[x])),
+                        )
+
+            print 'completed: \n ', '\n  '.join(sanestr(x)
                                                 for x in sorted(self.completed))
-            print 'depends', '\n  '.join(str(x)
+            print 'depends', '\n  '.join(depspec(x) 
                                          for x in sorted(self.depends))
             raise RuntimeError('not all tasks are executable')

pu/tasks/metadata.py

 
     def on_readyamlmetadata_success(self, item):
         self.result = []
+        print 'got yaml for', self
+        print item.result.packages
         for package in item.result.packages:
             task = FindSubPackages(
                 match=package,

tests/tasks/test_build.py

 
     queue = Queue()
     queue.add(task)
+
     queue.run_all()
     assert len(tmpdir.join('scripts').listdir()) == 2
     assert tmpdir.join('lib/testpkg/__init__.py').check()

tests/tasks/test_metadata.py

     queue.run_all_possible()
     for k, v in queue.depends.items():
         print k, 'depends on', v
-    assert task.result == ['foo', 'bar']
+    assert sorted(task.result) == ['bar', 'foo']
 

tests/test_task_queue.py

 
     assert isinstance(first_task, SimpleTask)
 
-    queue.report_sucess(first_task)
+    queue.report_success(first_task)
     next_task = next(queue)
     assert next_task.number == 1
-    queue.report_sucess(next_task)
+    queue.report_success(next_task)
     py.test.raises(StopIteration, next, queue)
 
 
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.