summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2017-07-16 17:45:41 +0900
committerTristan Van Berkom <tristan.vanberkom@codethink.co.uk>2017-07-16 17:45:41 +0900
commitf7c6062b1b2fad4ea5cf5800b2c9a0553074a6fd (patch)
tree4884e3ce710de768ad30cd54d46f578d7eedd049
parent0e4efd70511c033c58fa88cde74cfbf79857fd33 (diff)
downloadbuildstream-f7c6062b1b2fad4ea5cf5800b2c9a0553074a6fd.tar.gz
Committing crazy non-functional alternative with cached code paths.
o Single configuration in o Multi configuration out o Loop over configurations
-rw-r--r--buildstream/_loader.py167
1 files changed, 118 insertions, 49 deletions
diff --git a/buildstream/_loader.py b/buildstream/_loader.py
index 0592c8ab4..db31e21df 100644
--- a/buildstream/_loader.py
+++ b/buildstream/_loader.py
@@ -87,15 +87,12 @@ class Variant():
# depend on a given element in a way that conflicts
#
class VariantDisagreement(Exception):
- def __init__(self, element_config, dependency):
+ def __init__(self, element_config1, element_config2):
+ path1 = element_config1.make_path()
+ path2 = element_config2.make_path()
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))
+ "Variant disagreement occurred.\n {}\n {}"
+ .format(path1, path2))
# VariantInvalid is raised to indicate that a nonexisting
@@ -119,13 +116,25 @@ class VariantInvalid(Exception):
# o The dependencies the element has when configured for the given variant
#
class LoadElementConfig():
- def __init__(self, dependency, element, variant_name=None):
- self.dependency = dependency
+ def __init__(self, parent_config, element, variant_name=None):
+ self.parent_config = parent_config
self.element = element
self.filename = element.filename
self.variant_name = variant_name
self.deps = element.deps_for_variant(variant_name)
+ def __str__(self):
+ if self.variant_name:
+ return "{} ({})".format(self.filename, self.variant_name)
+
+ return self.filename
+
+ def make_path(self):
+ path = str(self)
+ if self.parent_config:
+ path = self.parent_config.make_path() + ' -> ' + path
+ return path
+
# resolve_arch()
#
@@ -412,6 +421,9 @@ class Loader():
self.meta_elements = {} # Dict of resolved meta elements by name
self.elements = {} # Dict of elements
+
+ self.debug_count = 0 # XXX
+
########################################
# Main Entry Point #
########################################
@@ -555,13 +567,22 @@ class Loader():
#
toplevel_config = LoadElementConfig(None, target_element, target_variant)
try:
- pool = self.configure_variants(toplevel_config, [])
+
+ # XXX Start with self.configure_dependency_variants instead !!!
+ #
+ # pool = self.configure_dependency_variants(toplevel_config.deps, {
+ # toplevel_config.filename: toplevel_config
+ # })
+ #
+
+ pools = self.configure_variants(toplevel_config, {})
+
except VariantDisagreement as e:
raise LoadError(LoadErrorReason.VARIANT_DISAGREEMENT, str(e)) from e
# Now apply the chosen variant configurations
#
- for element_config in pool:
+ for _, element_config in pools[0].items():
element_config.element.apply_element_config(element_config)
#
@@ -569,7 +590,7 @@ class Loader():
#
# Args:
# element_config (LoadElementConfig): the element to try
- # pool (list): A list of LoadElementConfig objects
+ # pool (dict): A dict of LoadElementConfig objects
#
# Returns:
# A new configuration
@@ -580,35 +601,40 @@ class Loader():
# the given configuration and the first valid configuration of its
# dependencies
#
- def configure_variants(self, element_config, pool):
+ def configure_variants(self, element_config, pool, depth=0, visited=None, visit_count=None):
- # First, check the new element configuration to try against
- # the existing ones in the pool for conflicts.
- #
- for config in pool:
+ # print("{}TRY: {}".format(' ' * depth, element_config))
+
+ if element_config.filename in pool:
+ config = pool[element_config.filename]
# The configuration pool can have only one selected configuration
# for each element, handle intersections and conflicts.
#
if config.element is element_config.element:
- if config.variant_name == element_config.variant_name:
- # A path converges on the same element configuration,
- # this iteration can be safely discarded.
- return pool
- else:
+
+ if config.variant_name != element_config.variant_name:
+
# Two different variants of the same element should be reached
# on a path of variant agreement.
- raise VariantDisagreement(element_config, config.dependency)
+ raise VariantDisagreement(element_config, config)
+
+ else:
+ # A path converges on the same element configuration,
+ # no need to recurse as we already have a result for this.
+ return [pool]
# Now add ourselves to the pool and recurse into the dependency list
- new_pool = pool + [element_config]
- return self.configure_dependency_variants(element_config.deps, new_pool)
+ new_pool = dict(pool)
+ new_pool[element_config.filename] = element_config
- def configure_dependency_variants(self, deps, pool):
+ return self.configure_dependency_variants(element_config, element_config.deps, new_pool, depth=depth + 1, visited=visited, visit_count=visit_count)
+
+ def configure_dependency_variants(self, parent_config, deps, pool, depth=0, visited=None, visit_count=None):
# This is just the end of the list
if not deps:
- return pool
+ return [pool]
# Loop over the possible variants for this dependency
dependency = deps[0]
@@ -619,51 +645,94 @@ class Loader():
#
element_configs_to_try = []
if dependency.variant_name:
- config = LoadElementConfig(dependency, element, dependency.variant_name)
+ config = LoadElementConfig(parent_config, element, dependency.variant_name)
element_configs_to_try.append(config)
elif len(element.variants) == 0:
- config = LoadElementConfig(dependency, element, None)
+ config = LoadElementConfig(parent_config, element, None)
element_configs_to_try.append(config)
else:
for variant in element.variants:
- config = LoadElementConfig(dependency, element, variant.name)
+ config = LoadElementConfig(parent_config, element, variant.name)
element_configs_to_try.append(config)
# Loop over every possible element configuration for this dependency
#
- accum_pool = None
last_error = None
-
+ valid_pools = []
for element_config in element_configs_to_try:
- # Reset the attempted new pool for each try
- accum_pool = None
+ # XXX DEBUG START
+ if visited is None:
+ visited = {}
+ if visit_count is None:
+ visit_count = {}
+
+ iter_key = (
+ parent_config.filename, parent_config.variant_name,
+ element_config.filename, element_config.variant_name
+ )
+ count = visit_count.get(iter_key, 0)
+ if count > 0:
+ print("Visited path {} times: {}".format(count, element_config.make_path()))
+
+ visit_count[iter_key] = count + 1
+ # XXX DEBUG END
+
+ iter_result = visited.get(iter_key)
+
+ if iter_result is not None:
+ valid_pools += iter_result['pools']
+ if iter_result['error']:
+ last_error = iter_result['error']
+ print("Assigning {} valid pools with error {}".format(len(iter_result['pools']), iter_result['error']))
+ continue
+ else:
+ print("Fresh iteration")
- try:
- # If this configuration of the this element succeeds...
- try_pool = self.configure_variants(element_config, pool)
+ iter_result = {
+ 'pools': [],
+ 'error': None
+ }
- # ... Then recurse into sibling elements
- accum_pool = self.configure_dependency_variants(deps[1:], try_pool)
+ config_pools = []
+ iter_error = None
+ # Recurse into this dependency for this config first
+ try:
+ try_pools = self.configure_variants(element_config, pool, depth=depth, visited=visited, visit_count=visit_count)
except VariantDisagreement as e:
+ last_error = iter_error = e
+
+ # XXX
- # Hold onto the error
- last_error = e
+ iter_result['pools'] = config_pools
+ iter_result['error'] = iter_error
+ visited[iter_key] = iter_result
- # If this element configuration failed, then find more possible
- # element configurations
continue
- # If we've reached here without any disagreement, then we've found the
- # first valid configuration, which should take priority over any others.
- break
+ # For each valid configuration for this element
+ for try_pool in try_pools:
+
+ # Recurse into the siblings, siblings either pass of fail as a whole
+ try:
+ config_pools += self.configure_dependency_variants(parent_config, deps[1:], try_pool,
+ depth=depth + 1, visited=visited, visit_count=visit_count)
+ except VariantDisagreement as e:
+ last_error = iter_error = e
+ continue
+
+ iter_result['pools'] = config_pools
+ iter_result['error'] = iter_error
+ visited[iter_key] = iter_result
+
+ valid_pools += config_pools
# If unable to find any valid configuration, raise a VariantDisagreement
- if not accum_pool:
+ if not valid_pools:
raise last_error
- return accum_pool
+ return valid_pools
########################################
# Element Sorting #