1
1
#!/usr/bin/env python3
2
2
3
3
import argparse
4
+ import contextlib
4
5
from pathlib import Path
5
- from typing import TYPE_CHECKING , Callable , Dict , Union
6
+ from typing import TYPE_CHECKING , Callable , MutableMapping , Optional
6
7
7
8
import yaml
9
+ from element_tracking import ElementsCache , ElementsInProgress
8
10
from import_backends import FakeTracBackend , GitHubBackend , RealTracBackend
9
11
from ticket_type import Ticket
10
12
@@ -79,7 +81,13 @@ def process(element_name: str, *, year: str, handle_dep: Callable[[str], int]) -
79
81
return ticket
80
82
81
83
82
- def add (element : str , backend : 'Backend' , year : str ) -> int :
84
+ def add (
85
+ element : str ,
86
+ backend : 'Backend' ,
87
+ year : str ,
88
+ * ,
89
+ known_elements : Optional [MutableMapping [str , int ]] = None ,
90
+ ) -> int :
83
91
"""
84
92
Add 'element' into the task tracker, along with all its dependencies.
85
93
@@ -92,22 +100,19 @@ def add(element: str, backend: 'Backend', year: str) -> int:
92
100
dependencies which have already been imported at the point they are
93
101
depended upon by a new parent.
94
102
"""
95
- CYCLE = object ()
96
- elements : Dict [str , Union [int , object ]] = {}
103
+ elements = ElementsInProgress (known_elements )
97
104
98
105
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 )
106
+ previous = elements .get (element )
107
+ if previous :
104
108
return previous
105
- else :
106
- elements [ element ] = CYCLE
109
+
110
+ with elements . process ( element ) as record_id :
107
111
generated = process (element , year = year , handle_dep = _add )
108
112
ticket_id = backend .submit (generated )
109
- elements [element ] = ticket_id
110
- return ticket_id
113
+ record_id (ticket_id )
114
+
115
+ return ticket_id
111
116
112
117
return _add (element )
113
118
@@ -119,6 +124,12 @@ def parse_args() -> argparse.Namespace:
119
124
'year' ,
120
125
help = "SR year to generate for (specify as just the number part)" ,
121
126
)
127
+ parser .add_argument (
128
+ '--cache' ,
129
+ help = "Path to a JSON file in which to load/store mapping from existing tasks." ,
130
+ type = Path ,
131
+ default = None ,
132
+ )
122
133
123
134
backends_group = parser .add_mutually_exclusive_group ()
124
135
backends_group .add_argument (
@@ -143,7 +154,15 @@ def main(arguments: argparse.Namespace) -> None:
143
154
else :
144
155
backend = FakeTracBackend ()
145
156
146
- add (arguments .base , backend , arguments .year )
157
+ with contextlib .ExitStack () as stack :
158
+ if arguments .cache :
159
+ elements : MutableMapping [str , int ] = stack .enter_context (
160
+ ElementsCache (arguments .cache ),
161
+ )
162
+ else :
163
+ elements = {}
164
+
165
+ add (arguments .base , backend , arguments .year , known_elements = elements )
147
166
148
167
149
168
if __name__ == '__main__' :
0 commit comments