#1359 frontend: add WorkList helper
Merged 3 years ago by frostyx. Opened 3 years ago by praiskup.
Unknown source worklist-for-pr-1265  into  master

@@ -42,6 +42,55 @@

  FINISHED_STATUSES = ["succeeded", "forked", "canceled", "skipped", "failed"]

  

  

+ class WorkList:

+     """

+     WorkList (TODO list) abstraction

+ 

+     This is useful if we want to process some dynamically changing TODO list

+     (directed graph traversal) and we want to make sure that each task is

+     processed only once.  E.g. to check all (even transitive) dependencies:

+ 

+         wl = WorkList(["dep A", "dep B"]

+         while not wl.empty:

+             dep = wl.pop()

+             if not dep_available(dep):

+                 print(dep + " not found")  # problem found

+                 continue

+             for dep in get_2nd_level_deps(dep):

+                 wl.schedule(dep)

+ 

+     Note that (a) each task, even if it is scheduled multiple times, is

+     processed only once - so subsequent schedule() calls are no-ops, (b) tasks

+     can be scheduled while the WorkList is being processed and (c) tasks need to

+     be hashable objects.

+ 

+     Implementation inspired by Predator project:

+     http://www.fit.vutbr.cz/research/groups/verifit/tools/predator/api/classWorkList.html

+     """

+     def __init__(self, initial_tasks):

+         self._tasks = []

+         self._seen = set()

+         for task in initial_tasks:

+             self.schedule(task)

+ 

+     def schedule(self, task):

+         """ Add task to queue, if it is not already there or processed """

+         if task in self._seen:

+             return False

+         self._tasks.insert(0, task)

+         self._seen.add(task)

+         return True

+ 

+     @property

+     def empty(self):

+         """ True if there's nothing to do """

+         return not bool(len(self._tasks))

+ 

+     def pop(self):

+         """ Get task (the oldest one) """

+         return self._tasks.pop()

+ 

+ 

  class CounterStatType(object):

      REPO_DL = "repo_dl"

  

@@ -6,7 +6,8 @@

  from coprs import app

  from coprs.helpers import parse_package_name, generate_repo_url, \

      fix_protocol_for_frontend, fix_protocol_for_backend, pre_process_repo_url, \

-     parse_repo_params, pagure_html_diff_changed, SubdirMatch, raw_commit_changes

+     parse_repo_params, pagure_html_diff_changed, SubdirMatch, \

+     raw_commit_changes, WorkList

  

  from tests.coprs_test_case import CoprsTestCase

  
@@ -224,3 +225,33 @@

          assert pagure_html_diff_changed('<html></html>') == set([])

          assert pagure_html_diff_changed('some-dust-ajablůňka>isdf/#~<--') == set([])

          assert pagure_html_diff_changed(b'091213114151deadbeaf') == set([])

+ 

+ 

+ def test_worklist_class():

+     """ test that all tasks are processed only once """

+ 

+     class _Task:

+         # pylint: disable=too-few-public-methods

+         def __init__(self, name, depends_on=None):

+             self.name = name

+             self.depends_on = depends_on or []

+ 

+     task_a = _Task("a")

+     task_b = _Task("b", [task_a])

+     task_c = _Task("c", [task_b])

+     # cycle

+     task_a.depends_on = [task_c]

+ 

+     def _get_list(start_with):

+         wlist = WorkList([start_with])

+         result = []

+         while not wlist.empty:

+             task = wlist.pop()

+             result.append(task.name)

+             for dep in task.depends_on:

+                 wlist.schedule(dep)

+         return result

+ 

+     assert _get_list(task_a) == ["a", "c", "b"]

+     assert _get_list(task_b) == ["b", "a", "c"]

+     assert _get_list(task_c) == ["c", "b", "a"]

rebased onto 78798dcabff81776a52e607a940d352c2b94ea30

3 years ago

rebased onto 1aa3efcab4df7720bf0a06526f9900a7a2405795

3 years ago

rebased onto f680bd6e5ed35a9b6315767add14356cd5021c08

3 years ago

rebased onto 66c88be4532e02e642b3696301bb8795190f94e7

3 years ago

Upon request, I added an example and better documentation.

rebased onto fec7fe0

3 years ago

Thank you for the improved docstring, it makes much more sense now.
+1, I am merging it.

Pull-Request has been merged by frostyx

3 years ago