Skip to content

Commit 5df7661

Browse files
committed
Hoist cyclic dependency tracking and support merging with known tasks
1 parent 6ba11b6 commit 5df7661

File tree

2 files changed

+54
-13
lines changed

2 files changed

+54
-13
lines changed

scripts/element_tracking.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import contextlib
2+
from typing import Callable, Iterator, MutableMapping, Optional, Set
3+
4+
5+
class ElementsInProgress:
6+
"""
7+
Keep track of the tasks as they're being imported.
8+
9+
This checks for cyclic dependencies and provides a way to consume existing
10+
mappings of tasks that are known to be equivalent to those in this repo.
11+
"""
12+
13+
def __init__(self, known_elements: Optional[MutableMapping[str, int]]) -> None:
14+
self.known_elements = known_elements or {}
15+
self._current: Set[str] = set()
16+
17+
def get(self, key: str) -> Optional[int]:
18+
if key in self._current:
19+
raise RuntimeError(f"Cyclic dependency on {key}")
20+
21+
return self.known_elements.get(key)
22+
23+
@contextlib.contextmanager
24+
def process(self, key: str) -> Iterator[Callable[[int], None]]:
25+
if key in self._current:
26+
raise RuntimeError(
27+
f"Re-entrant processing not supported (attempted {key})",
28+
)
29+
30+
def done(x: int) -> None:
31+
self.known_elements[key] = x
32+
33+
self._current.add(key)
34+
try:
35+
yield done
36+
finally:
37+
self._current.remove(key)

scripts/import.py

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22

33
import argparse
44
from pathlib import Path
5-
from typing import TYPE_CHECKING, Callable, Dict, Union
5+
from typing import TYPE_CHECKING, Callable, MutableMapping, Optional
66

77
import yaml
8+
from element_tracking import ElementsInProgress
89
from import_backends import FakeTracBackend, GitHubBackend, RealTracBackend
910
from ticket_type import Ticket
1011

@@ -79,7 +80,13 @@ def process(element_name: str, *, year: str, handle_dep: Callable[[str], int]) -
7980
return ticket
8081

8182

82-
def add(element: str, backend: 'Backend', year: str) -> int:
83+
def add(
84+
element: str,
85+
backend: 'Backend',
86+
year: str,
87+
*,
88+
known_elements: Optional[MutableMapping[str, int]] = None,
89+
) -> int:
8390
"""
8491
Add 'element' into the task tracker, along with all its dependencies.
8592
@@ -92,22 +99,19 @@ def add(element: str, backend: 'Backend', year: str) -> int:
9299
dependencies which have already been imported at the point they are
93100
depended upon by a new parent.
94101
"""
95-
CYCLE = object()
96-
elements: Dict[str, Union[int, object]] = {}
102+
elements = ElementsInProgress(known_elements)
97103

98104
def _add(element: str) -> int:
99-
if element in elements:
100-
previous = elements[element]
101-
if previous is CYCLE:
102-
raise RuntimeError(f"cyclic dependency on {element}")
103-
assert isinstance(previous, int)
105+
previous = elements.get(element)
106+
if previous:
104107
return previous
105-
else:
106-
elements[element] = CYCLE
108+
109+
with elements.process(element) as record_id:
107110
generated = process(element, year=year, handle_dep=_add)
108111
ticket_id = backend.submit(generated)
109-
elements[element] = ticket_id
110-
return ticket_id
112+
record_id(ticket_id)
113+
114+
return ticket_id
111115

112116
return _add(element)
113117

0 commit comments

Comments
 (0)