diff options
Diffstat (limited to 'buildstream')
-rw-r--r-- | buildstream/_loader.py | 95 |
1 files changed, 60 insertions, 35 deletions
diff --git a/buildstream/_loader.py b/buildstream/_loader.py index 3c90e4364..17db17f43 100644 --- a/buildstream/_loader.py +++ b/buildstream/_loader.py @@ -61,12 +61,14 @@ class Symbol(): # A simple dependency object # class Dependency(): - def __init__(self, owner_name, name, variant_name=None, filename=None, dep_type=None): + def __init__(self, owner_name, name, variant_name=None, filename=None, + dep_type=None, provenance=None): self.owner = owner_name self.name = name self.variant_name = variant_name self.filename = filename self.dep_type = dep_type + self.provenance = provenance # Holds a variant dictionary and normalized Dependency list @@ -81,6 +83,34 @@ class Variant(): del self.data[Symbol.VARIANT] +# VariantDisagreement is raised to indicate that 2 elements +# depend on a given element in a way that conflicts +# +class VariantDisagreement(Exception): + def __init__(self, element_config, dependency): + super(VariantDisagreement, self).__init__( + "Variant disagreement occurred.\n" + "Element '%s' requested element '%s (%s)'\n" + "Element '%s' requested element '%s (%s)" % + (element_config.dependency.owner, element_config.filename, + element_config.dependency.variant_name, + dependency.owner, element_config.filename, + dependency.variant_name)) + + +# VariantInvalid is raised to indicate that a nonexisting +# variant name on an element was requested +# +class VariantInvalid(Exception): + def __init__(self, dependency, element, variant_name): + message = "Variant '{}' is invalid for element {}" \ + .format(variant_name, element.name) + if dependency: + message = "{}: {}".format(dependency.provenance, message) + + super(VariantInvalid, self).__init__(message) + + # A utility object wrapping the LoadElement, this represents # a hypothetical configuration of an element, it describes: # @@ -97,21 +127,6 @@ class LoadElementConfig(): self.deps = element.deps_for_variant(variant_name) -# VariantError is raised to indicate that 2 elements -# depend on a given element in a way that conflicts -# -class VariantError(Exception): - def __init__(self, element_config, dependency): - super(VariantError, self).__init__( - "Variant disagreement occurred.\n" - "Element '%s' requested element '%s (%s)'\n" - "Element '%s' requested element '%s (%s)" % - (element_config.dependency.owner, element_config.filename, - element_config.dependency.variant_name, - dependency.owner, element_config.filename, - dependency.variant_name)) - - # resolve_arch() # # Composites the data node with the active arch dict and discards @@ -316,9 +331,10 @@ def extract_depends_from_node(owner, data): output_deps = [] for dep in depends: + dep_provenance = _yaml.node_get_provenance(data, key=Symbol.DEPENDS, indices=[depends.index(dep)]) if isinstance(dep, str): - dependency = Dependency(owner, dep, filename=dep) + dependency = Dependency(owner, dep, filename=dep, provenance=dep_provenance) elif isinstance(dep, Mapping): # Make variant optional, for this we set it to None after @@ -337,7 +353,8 @@ def extract_depends_from_node(owner, data): (str(provenance), dep_type)) filename = _yaml.node_get(dep, str, Symbol.FILENAME) - dependency = Dependency(owner, filename, variant_name=variant, filename=filename, dep_type=dep_type) + dependency = Dependency(owner, filename, variant_name=variant, filename=filename, + dep_type=dep_type, provenance=dep_provenance) else: index = depends.index(dep) @@ -392,7 +409,6 @@ class Loader(): self.host_arch = host_arch self.target_arch = target_arch - self.loaded_files = {} # Table of files we've already loaded self.meta_elements = {} # Dict of resolved meta elements by name self.elements = {} # Dict of elements @@ -417,7 +433,14 @@ class Loader(): # First pass, recursively load files and populate our table of LoadElements # profile_start(Topics.LOAD_PROJECT, self.target_filename) - self.load_file(self.target_filename, rewritable, ticker) + + try: + target = self.load_file(self.target_filename, rewritable, ticker) + if self.target_variant and target.lookup_variant(self.target_variant) is None: + raise VariantInvalid(None, target, self.target_variant) + except VariantInvalid as e: + raise LoadError(LoadErrorReason.INVALID_VARIANT, str(e)) from e + profile_end(Topics.LOAD_PROJECT, self.target_filename) # @@ -454,16 +477,8 @@ class Loader(): def load_file(self, filename, rewritable, ticker): # Silently ignore already loaded files - if filename in self.loaded_files: - return - self.loaded_files[filename] = True - - # Raise error if two files claim the same name if filename in self.elements: - element = self.elements[filename] - raise LoadError(LoadErrorReason.INVALID_DATA, - "Tried to load file '%s' but existing file '%s' has the same name" % - (filename, element.filename)) + return self.elements[filename] # Call the ticker if ticker: @@ -479,11 +494,21 @@ class Loader(): # Load all possible dependency files for the new LoadElement for dep in element.base_deps: - self.load_file(dep.filename, rewritable, ticker) + self.load_dependency_file(dep, rewritable, ticker) for variant in element.variants: for dep in variant.dependencies: - self.load_file(dep.filename, rewritable, ticker) + self.load_dependency_file(dep, rewritable, ticker) + + return element + + def load_dependency_file(self, dependency, rewritable, ticker): + + element = self.load_file(dependency.filename, rewritable, ticker) + + # Check for invalid variant dependencies + if dependency.variant_name and element.lookup_variant(dependency.variant_name) is None: + raise VariantInvalid(dependency, element, dependency.variant_name) ######################################## # Resolving Variants # @@ -531,7 +556,7 @@ class Loader(): toplevel_config = LoadElementConfig(None, target_element, target_variant) try: pool = self.configure_variants(toplevel_config, []) - except VariantError as e: + except VariantDisagreement as e: raise LoadError(LoadErrorReason.VARIANT_DISAGREEMENT, str(e)) from e # Now apply the chosen variant configurations @@ -573,7 +598,7 @@ class Loader(): else: # Two different variants of the same element should be reached # on a path of variant agreement. - raise VariantError(element_config, config.dependency) + raise VariantDisagreement(element_config, config.dependency) # Now add ourselves to the pool and recurse into the dependency list new_pool = pool + [element_config] @@ -621,7 +646,7 @@ class Loader(): # ... Then recurse into sibling elements accum_pool = self.configure_dependency_variants(deps[1:], try_pool) - except VariantError as e: + except VariantDisagreement as e: # Hold onto the error last_error = e @@ -630,7 +655,7 @@ class Loader(): # element configurations continue - # If unable to find any valid configuration, raise a VariantError + # If unable to find any valid configuration, raise a VariantDisagreement if not accum_pool: raise last_error |