... |
... |
@@ -112,7 +112,7 @@ class Loader(): |
112
|
112
|
|
113
|
113
|
# First pass, recursively load files and populate our table of LoadElements
|
114
|
114
|
#
|
115
|
|
- deps = []
|
|
115
|
+ target_elements = []
|
116
|
116
|
|
117
|
117
|
# XXX This will need to be changed to the context's top-level project if this method
|
118
|
118
|
# is ever used for subprojects
|
... |
... |
@@ -124,8 +124,8 @@ class Loader(): |
124
|
124
|
profile_start(Topics.LOAD_PROJECT, target)
|
125
|
125
|
junction, name, loader = self._parse_name(target, rewritable, ticker,
|
126
|
126
|
fetch_subprojects=fetch_subprojects)
|
127
|
|
- loader._load_file(name, rewritable, ticker, fetch_subprojects, yaml_cache)
|
128
|
|
- deps.append(Dependency(name, junction=junction))
|
|
127
|
+ element = loader._load_file(name, rewritable, ticker, fetch_subprojects, yaml_cache)
|
|
128
|
+ target_elements.append(element)
|
129
|
129
|
profile_end(Topics.LOAD_PROJECT, target)
|
130
|
130
|
|
131
|
131
|
#
|
... |
... |
@@ -134,24 +134,29 @@ class Loader(): |
134
|
134
|
|
135
|
135
|
# Set up a dummy element that depends on all top-level targets
|
136
|
136
|
# to resolve potential circular dependencies between them
|
|
137
|
+ dummy_target = LoadElement("", "", self)
|
|
138
|
+ dummy_target.dependencies.extend(
|
|
139
|
+ LoadElement.Dependency(element, Symbol.RUNTIME)
|
|
140
|
+ for element in target_elements
|
|
141
|
+ )
|
|
142
|
+
|
137
|
143
|
profile_key = "_".join(t for t in targets)
|
138
|
144
|
profile_start(Topics.CIRCULAR_CHECK, profile_key)
|
139
|
|
- self._check_circular_deps(LoadElement("", "", self))
|
|
145
|
+ self._check_circular_deps(dummy_target)
|
140
|
146
|
profile_end(Topics.CIRCULAR_CHECK, profile_key)
|
141
|
147
|
|
142
|
148
|
ret = []
|
143
|
149
|
#
|
144
|
150
|
# Sort direct dependencies of elements by their dependency ordering
|
145
|
151
|
#
|
146
|
|
- for target in targets:
|
147
|
|
- profile_start(Topics.SORT_DEPENDENCIES, target)
|
148
|
|
- junction, name, loader = self._parse_name(target, rewritable, ticker,
|
149
|
|
- fetch_subprojects=fetch_subprojects)
|
150
|
|
- loader._sort_dependencies(name)
|
151
|
|
- profile_end(Topics.SORT_DEPENDENCIES, target)
|
|
152
|
+ for element in target_elements:
|
|
153
|
+ profile_start(Topics.SORT_DEPENDENCIES, element.name)
|
|
154
|
+ loader._sort_dependencies(element)
|
|
155
|
+ profile_end(Topics.SORT_DEPENDENCIES, element.name)
|
152
|
156
|
# Finally, wrap what we have into LoadElements and return the target
|
153
|
157
|
#
|
154
|
|
- ret.append(loader._collect_element(name))
|
|
158
|
+ # TODO: we could pass element directly
|
|
159
|
+ ret.append(loader._collect_element(element.name))
|
155
|
160
|
|
156
|
161
|
return ret
|
157
|
162
|
|
... |
... |
@@ -282,11 +287,12 @@ class Loader(): |
282
|
287
|
# dependencies already resolved.
|
283
|
288
|
#
|
284
|
289
|
# Args:
|
285
|
|
- # element_name (str): The element-path relative element name to check
|
|
290
|
+ # element (str): The element to check
|
286
|
291
|
#
|
287
|
292
|
# Raises:
|
288
|
293
|
# (LoadError): In case there was a circular dependency error
|
289
|
294
|
#
|
|
295
|
+ # TODO: this would be nicer in the LoadElement directly
|
290
|
296
|
def _check_circular_deps(self, element, check_elements=None, validated=None, sequence=None):
|
291
|
297
|
|
292
|
298
|
if check_elements is None:
|
... |
... |
@@ -304,18 +310,18 @@ class Loader(): |
304
|
310
|
# Create `chain`, the loop of element dependencies from this
|
305
|
311
|
# element back to itself, by trimming everything before this
|
306
|
312
|
# element from the sequence under consideration.
|
307
|
|
- chain = sequence[sequence.index(element):]
|
308
|
|
- chain.append(element)
|
|
313
|
+ chain = sequence[sequence.index(element.full_name):]
|
|
314
|
+ chain.append(element.full_name)
|
309
|
315
|
raise LoadError(LoadErrorReason.CIRCULAR_DEPENDENCY,
|
310
|
316
|
("Circular dependency detected at element: {}\n" +
|
311
|
317
|
"Dependency chain: {}")
|
312
|
|
- .format(element.name, " -> ".join(chain)))
|
|
318
|
+ .format(element.full_name, " -> ".join(chain)))
|
313
|
319
|
|
314
|
320
|
# Push / Check each dependency / Pop
|
315
|
321
|
check_elements[element] = True
|
316
|
|
- sequence.append(element)
|
|
322
|
+ sequence.append(element.full_name)
|
317
|
323
|
for dep in element.dependencies:
|
318
|
|
- dep._loader._check_circular_deps(element, check_elements, validated, sequence)
|
|
324
|
+ dep.element._loader._check_circular_deps(dep.element, check_elements, validated, sequence)
|
319
|
325
|
del check_elements[element]
|
320
|
326
|
sequence.pop()
|
321
|
327
|
|
... |
... |
@@ -333,23 +339,17 @@ class Loader(): |
333
|
339
|
# sorts throughout the build process.
|
334
|
340
|
#
|
335
|
341
|
# Args:
|
336
|
|
- # element_name (str): The element-path relative element name to sort
|
|
342
|
+ # element_name (str): The element to sort
|
337
|
343
|
#
|
338
|
|
- def _sort_dependencies(self, element_name, visited=None):
|
|
344
|
+ def _sort_dependencies(self, element, visited=None):
|
339
|
345
|
if visited is None:
|
340
|
|
- visited = {}
|
341
|
|
-
|
342
|
|
- element = self._elements[element_name]
|
343
|
|
-
|
344
|
|
- # element name must be unique across projects
|
345
|
|
- # to be usable as key for the visited dict
|
346
|
|
- element_name = element.full_name
|
|
346
|
+ visited = set()
|
347
|
347
|
|
348
|
|
- if visited.get(element_name) is not None:
|
|
348
|
+ if element in visited:
|
349
|
349
|
return
|
350
|
350
|
|
351
|
351
|
for dep in element.dependencies:
|
352
|
|
- dep.element._loader._sort_dependencies(dep.element.name, visited=visited)
|
|
352
|
+ dep.element._loader._sort_dependencies(dep.element, visited=visited)
|
353
|
353
|
|
354
|
354
|
def dependency_cmp(dep_a, dep_b):
|
355
|
355
|
element_a = dep_a.element
|
... |
... |
@@ -395,7 +395,7 @@ class Loader(): |
395
|
395
|
# it is found later in the list.
|
396
|
396
|
element.dependencies.sort(key=cmp_to_key(dependency_cmp))
|
397
|
397
|
|
398
|
|
- visited[element_name] = True
|
|
398
|
+ visited.add(element)
|
399
|
399
|
|
400
|
400
|
# _collect_element()
|
401
|
401
|
#
|