summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/buildstream/_artifactelement.py8
-rw-r--r--src/buildstream/_loader/__init__.py3
-rw-r--r--src/buildstream/_loader/loadelement.pyx45
-rw-r--r--src/buildstream/_loader/loader.py157
-rw-r--r--src/buildstream/_loader/metaelement.py73
-rw-r--r--src/buildstream/_loader/metasource.py4
-rw-r--r--src/buildstream/_pluginfactory/elementfactory.py8
-rw-r--r--src/buildstream/_project.py10
-rw-r--r--src/buildstream/element.py216
-rw-r--r--src/buildstream/source.py3
-rw-r--r--tests/internals/loader.py4
11 files changed, 206 insertions, 325 deletions
diff --git a/src/buildstream/_artifactelement.py b/src/buildstream/_artifactelement.py
index 4066cef06..44e52ea90 100644
--- a/src/buildstream/_artifactelement.py
+++ b/src/buildstream/_artifactelement.py
@@ -22,7 +22,8 @@ from typing import TYPE_CHECKING
from . import Element
from . import _cachekey
from ._exceptions import ArtifactElementError
-from ._loader.metaelement import MetaElement
+from ._loader import LoadElement
+from .node import Node
from .types import Scope
if TYPE_CHECKING:
@@ -49,10 +50,9 @@ class ArtifactElement(Element):
self._key = key
project = context.get_toplevel_project()
- meta = MetaElement(project, element) # NOTE element has no .bst suffix
- plugin_conf = None
+ load_element = LoadElement(Node.from_dict({}), element, project.loader) # NOTE element has no .bst suffix
- super().__init__(context, project, meta, plugin_conf)
+ super().__init__(context, project, load_element, None)
# _new_from_artifact_ref():
#
diff --git a/src/buildstream/_loader/__init__.py b/src/buildstream/_loader/__init__.py
index fd5cac2ae..a4be9cfe5 100644
--- a/src/buildstream/_loader/__init__.py
+++ b/src/buildstream/_loader/__init__.py
@@ -17,7 +17,8 @@
# Authors:
# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
+from .types import Symbol
from .metasource import MetaSource
-from .metaelement import MetaElement
+from .loadelement import LoadElement, Dependency
from .loadcontext import LoadContext
from .loader import Loader
diff --git a/src/buildstream/_loader/loadelement.pyx b/src/buildstream/_loader/loadelement.pyx
index 6cd5b46b7..01334d124 100644
--- a/src/buildstream/_loader/loadelement.pyx
+++ b/src/buildstream/_loader/loadelement.pyx
@@ -184,9 +184,10 @@ cdef class LoadElement:
cdef readonly MappingNode node
cdef readonly str name
- cdef readonly full_name
- cdef public bint meta_done
+ cdef readonly str full_name
+ cdef readonly str kind
cdef int node_id
+ cdef readonly bint first_pass
cdef readonly object _loader
cdef readonly str link_target
cdef readonly ProvenanceInformation link_target_provenance
@@ -199,10 +200,10 @@ cdef class LoadElement:
#
# Public members
#
+ self.kind = None # The Element kind
self.node = node # The YAML node
self.name = filename # The element name
self.full_name = None # The element full name (with associated junction)
- self.meta_done = False # If the MetaElement for this LoadElement is done
self.node_id = _next_synthetic_counter()
self.link_target = None # The target of a link element
self.link_target_provenance = None # The provenance of the link target
@@ -233,13 +234,15 @@ cdef class LoadElement:
'build-depends', 'runtime-depends',
])
+ self.kind = node.get_str(Symbol.KIND, default=None)
+ self.first_pass = self.kind in ("junction", "link")
+
#
# If this is a link, resolve it right away and just
# store the link target and provenance
#
- if self.node.get_str(Symbol.KIND, default=None) == 'link':
- meta_element = self._loader.collect_element_no_deps(self)
- element = Element._new_from_meta(meta_element)
+ if self.kind == 'link':
+ element = Element._new_from_load_element(self)
element._initialize_state()
# Custom error for link dependencies, since we don't completely
@@ -254,6 +257,36 @@ cdef class LoadElement:
self.link_target = element.target
self.link_target_provenance = element.target_provenance
+ # We don't count progress for junction elements or link
+ # as they do not represent real elements in the build graph.
+ #
+ # We check for a `None` kind, to avoid reporting progress for
+ # the virtual toplevel element used to load the pipeline.
+ #
+ if self._loader.load_context.task and self.kind is not None and not self.first_pass:
+ self._loader.load_context.task.add_current_progress()
+
+ # provenance
+ #
+ # A property reporting the ProvenanceInformation of the element
+ #
+ @property
+ def provenance(self):
+ return self.node.get_provenance()
+
+ # project
+ #
+ # A property reporting the Project in which this element resides.
+ #
+ @property
+ def project(self):
+ return self._loader.project
+
+ # junction
+ #
+ # A property reporting the junction element accessing this
+ # element, if any.
+ #
@property
def junction(self):
return self._loader.project.junction
diff --git a/src/buildstream/_loader/loader.py b/src/buildstream/_loader/loader.py
index b0f4a4a07..94ee9078b 100644
--- a/src/buildstream/_loader/loader.py
+++ b/src/buildstream/_loader/loader.py
@@ -32,8 +32,6 @@ from ._loader import valid_chars_name
from .types import Symbol
from . import loadelement
from .loadelement import LoadElement, Dependency, extract_depends_from_node
-from .metaelement import MetaElement
-from .metasource import MetaSource
from ..types import CoreWarnings, _KeyStrength
from .._message import Message, MessageType
@@ -41,8 +39,8 @@ from .._message import Message, MessageType
# Loader():
#
# The Loader class does the heavy lifting of parsing target
-# bst files and ultimately transforming them into a list of MetaElements
-# with their own MetaSources, ready for instantiation by the core.
+# bst files and ultimately transforming them into a list of LoadElements
+# ready for instantiation by the core.
#
# Args:
# project (Project): The toplevel Project object
@@ -112,7 +110,8 @@ class Loader:
#
# Raises: LoadError
#
- # Returns: The toplevel LoadElement
+ # Returns:
+ # (list): The corresponding LoadElement instances matching the `targets`
#
def load(self, targets):
@@ -154,7 +153,6 @@ class Loader:
with PROFILER.profile(Topics.CIRCULAR_CHECK, "_".join(targets)):
self._check_circular_deps(dummy_target)
- ret = []
#
# Sort direct dependencies of elements by their dependency ordering
#
@@ -167,18 +165,13 @@ class Loader:
with PROFILER.profile(Topics.SORT_DEPENDENCIES, element.name):
loadelement.sort_dependencies(element, visited_elements)
- # Finally, wrap what we have into LoadElements and return the target
- #
- ret.append(loader._collect_element(element))
-
self._clean_caches()
# Cache how many Elements have just been loaded
if self.load_context.task:
- # Workaround for task potentially being None (because no State object)
self.loaded = self.load_context.task.current_progress
- return ret
+ return target_elements
# get_loader():
#
@@ -252,83 +245,6 @@ class Loader:
for parent in self._alternative_parents:
yield from foreach_parent(parent)
- # collect_element_no_deps()
- #
- # Collect a single element, without its dependencies, into a meta_element
- #
- # NOTE: This is declared public in order to share with the LoadElement
- # and should not be used outside of that `_loader` module.
- #
- # Args:
- # element (LoadElement): The element for which to load a MetaElement
- # report_progress (bool): Whether to report progress for this element, this is
- # because we ignore junctions and links when counting
- # how many elements we load.
- #
- # Returns:
- # (MetaElement): A partially loaded MetaElement
- #
- def collect_element_no_deps(self, element, *, report_progress=False):
- # Return the already built one, if we already built it
- meta_element = self._meta_elements.get(element.name)
- if meta_element:
- return meta_element
-
- node = element.node
- elt_provenance = node.get_provenance()
- meta_sources = []
-
- element_kind = node.get_str(Symbol.KIND)
-
- # if there's a workspace for this element then just append a dummy workspace
- # metasource.
- workspace = self.load_context.context.get_workspaces().get_workspace(element.full_name)
- skip_workspace = True
- if workspace:
- workspace_node = {"kind": "workspace"}
- workspace_node["path"] = workspace.get_absolute_path()
- workspace_node["last_build"] = str(workspace.to_dict().get("last_build", ""))
- node[Symbol.SOURCES] = [workspace_node]
- skip_workspace = False
-
- sources = node.get_sequence(Symbol.SOURCES, default=[])
- for index, source in enumerate(sources):
- kind = source.get_str(Symbol.KIND)
- # the workspace source plugin cannot be used unless the element is workspaced
- if kind == "workspace" and skip_workspace:
- continue
-
- del source[Symbol.KIND]
-
- # Directory is optional
- directory = source.get_str(Symbol.DIRECTORY, default=None)
- if directory:
- del source[Symbol.DIRECTORY]
- meta_source = MetaSource(element.name, index, element_kind, kind, source, directory)
- meta_sources.append(meta_source)
-
- meta_element = MetaElement(
- self.project,
- element.name,
- element_kind,
- elt_provenance,
- meta_sources,
- node.get_mapping(Symbol.CONFIG, default={}),
- node.get_mapping(Symbol.VARIABLES, default={}),
- node.get_mapping(Symbol.ENVIRONMENT, default={}),
- node.get_str_list(Symbol.ENV_NOCACHE, default=[]),
- node.get_mapping(Symbol.PUBLIC, default={}),
- node.get_mapping(Symbol.SANDBOX, default={}),
- element_kind in ("junction", "link"),
- )
-
- # Cache it now, make sure it's already there before recursing
- self._meta_elements[element.name] = meta_element
- if self.load_context.task and report_progress:
- self.load_context.task.add_current_progress()
-
- return meta_element
-
###########################################
# Private Methods #
###########################################
@@ -553,52 +469,6 @@ class Loader:
check_elements.remove(this_element)
validated.add(this_element)
- # _collect_element()
- #
- # Collect the toplevel elements we have
- #
- # Args:
- # top_element (LoadElement): The element for which to load a MetaElement
- #
- # Returns:
- # (MetaElement): A fully loaded MetaElement
- #
- def _collect_element(self, top_element):
- element_queue = [top_element]
- meta_element_queue = [self.collect_element_no_deps(top_element, report_progress=True)]
-
- while element_queue:
- element = element_queue.pop()
- meta_element = meta_element_queue.pop()
-
- if element.meta_done:
- # This can happen if there are multiple top level targets
- # in which case, we simply skip over this element.
- continue
-
- for dep in element.dependencies:
-
- loader = dep.element._loader
- name = dep.element.name
-
- try:
- meta_dep = loader._meta_elements[name]
- except KeyError:
- meta_dep = loader.collect_element_no_deps(dep.element, report_progress=True)
- element_queue.append(dep.element)
- meta_element_queue.append(meta_dep)
-
- if dep.dep_type != "runtime":
- meta_element.build_dependencies.append(meta_dep)
- if dep.dep_type != "build":
- meta_element.dependencies.append(meta_dep)
- if dep.strict:
- meta_element.strict_dependencies.append(meta_dep)
-
- element.meta_done = True
-
- return self._meta_elements[top_element.name]
-
# _search_for_override():
#
# Search parent projects for an overridden subproject to replace this junction.
@@ -711,20 +581,9 @@ class Loader:
if not load_subprojects:
return None
- # meta junction element
- #
- # Note that junction elements are not allowed to have
- # dependencies, so disabling progress reporting here should
- # have no adverse effects - the junction element itself cannot
- # be depended on, so it would be confusing for its load to
- # show up in logs.
- #
- # Any task counting *inside* the junction will be handled by
- # its loader.
- meta_element = self.collect_element_no_deps(self._elements[filename])
- if meta_element.kind != "junction":
+ if load_element.kind != "junction":
raise LoadError(
- "{}{}: Expected junction but element kind is {}".format(provenance_str, filename, meta_element.kind),
+ "{}{}: Expected junction but element kind is {}".format(provenance_str, filename, load_element.kind),
LoadErrorReason.INVALID_DATA,
)
@@ -748,7 +607,7 @@ class Loader:
"{}: Dependencies are forbidden for 'junction' elements".format(p), LoadErrorReason.INVALID_JUNCTION
)
- element = Element._new_from_meta(meta_element)
+ element = Element._new_from_load_element(load_element)
element._initialize_state()
# Handle the case where a subproject has no ref
diff --git a/src/buildstream/_loader/metaelement.py b/src/buildstream/_loader/metaelement.py
deleted file mode 100644
index 1c1f6feb2..000000000
--- a/src/buildstream/_loader/metaelement.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#
-# Copyright (C) 2016 Codethink Limited
-#
-# This program is free software; you can redistribute it and/or
-# modify it under the terms of the GNU Lesser General Public
-# License as published by the Free Software Foundation; either
-# version 2 of the License, or (at your option) any later version.
-#
-# This library is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# Lesser General Public License for more details.
-#
-# You should have received a copy of the GNU Lesser General Public
-# License along with this library. If not, see <http://www.gnu.org/licenses/>.
-#
-# Authors:
-# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk>
-
-from ..node import Node
-
-
-class MetaElement:
-
- # MetaElement()
- #
- # An abstract object holding data suitable for constructing an Element
- #
- # Args:
- # project: The project that contains the element
- # name: The resolved element name
- # kind: The element kind
- # provenance: The provenance of the element
- # sources: An array of MetaSource objects
- # config: The configuration data for the element
- # variables: The variables declared or overridden on this element
- # environment: The environment variables declared or overridden on this element
- # env_nocache: List of environment vars which should not be considered in cache keys
- # public: Public domain data dictionary
- # sandbox: Configuration specific to the sandbox environment
- # first_pass: The element is to be loaded with first pass configuration (junction)
- #
- def __init__(
- self,
- project,
- name,
- kind=None,
- provenance=None,
- sources=None,
- config=None,
- variables=None,
- environment=None,
- env_nocache=None,
- public=None,
- sandbox=None,
- first_pass=False,
- ):
- self.project = project
- self.name = name
- self.kind = kind
- self.provenance = provenance
- self.sources = sources
- self.config = config or Node.from_dict({})
- self.variables = variables or Node.from_dict({})
- self.environment = environment or Node.from_dict({})
- self.env_nocache = env_nocache or []
- self.public = public or Node.from_dict({})
- self.sandbox = sandbox or Node.from_dict({})
- self.build_dependencies = []
- self.dependencies = []
- self.strict_dependencies = []
- self.first_pass = first_pass
- self.is_junction = kind in ("junction", "link")
diff --git a/src/buildstream/_loader/metasource.py b/src/buildstream/_loader/metasource.py
index ddaa538f5..d49ae3d82 100644
--- a/src/buildstream/_loader/metasource.py
+++ b/src/buildstream/_loader/metasource.py
@@ -32,12 +32,12 @@ class MetaSource:
# config: The configuration data for the source
# first_pass: This source will be used with first project pass configuration (used for junctions).
#
- def __init__(self, element_name, element_index, element_kind, kind, config, directory):
+ def __init__(self, element_name, element_index, element_kind, kind, config, directory, first_pass):
self.element_name = element_name
self.element_index = element_index
self.element_kind = element_kind
self.kind = kind
self.config = config
self.directory = directory
- self.first_pass = False
+ self.first_pass = first_pass
self.provenance = config.get_provenance()
diff --git a/src/buildstream/_pluginfactory/elementfactory.py b/src/buildstream/_pluginfactory/elementfactory.py
index 9854c1a5c..7d94c2541 100644
--- a/src/buildstream/_pluginfactory/elementfactory.py
+++ b/src/buildstream/_pluginfactory/elementfactory.py
@@ -39,7 +39,7 @@ class ElementFactory(PluginFactory):
# Args:
# context (object): The Context object for processing
# project (object): The project object
- # meta (object): The loaded MetaElement
+ # load_element (object): The LoadElement
#
# Returns: A newly created Element object of the appropriate kind
#
@@ -47,7 +47,7 @@ class ElementFactory(PluginFactory):
# PluginError (if the kind lookup failed)
# LoadError (if the element itself took issue with the config)
#
- def create(self, context, project, meta):
- element_type, default_config = self.lookup(context.messenger, meta.kind, meta.provenance)
- element = element_type(context, project, meta, default_config)
+ def create(self, context, project, load_element):
+ element_type, default_config = self.lookup(context.messenger, load_element.kind, load_element.provenance)
+ element = element_type(context, project, load_element, default_config)
return element
diff --git a/src/buildstream/_project.py b/src/buildstream/_project.py
index 3562ea5d4..87772995a 100644
--- a/src/buildstream/_project.py
+++ b/src/buildstream/_project.py
@@ -345,13 +345,13 @@ class Project:
# Instantiate and return an element
#
# Args:
- # meta (MetaElement): The loaded MetaElement
+ # load_element (LoadElement): The LoadElement
#
# Returns:
# (Element): A newly created Element object of the appropriate kind
#
- def create_element(self, meta):
- return self.element_factory.create(self._context, self, meta)
+ def create_element(self, load_element):
+ return self.element_factory.create(self._context, self, load_element)
# create_source()
#
@@ -426,13 +426,13 @@ class Project:
with self._context.messenger.simple_task("Loading elements", silent_nested=True) as task:
self.load_context.set_task(task)
- meta_elements = self.loader.load(targets)
+ load_elements = self.loader.load(targets)
self.load_context.set_task(None)
with self._context.messenger.simple_task("Resolving elements") as task:
if task:
task.set_maximum_progress(self.loader.loaded)
- elements = [Element._new_from_meta(meta, task) for meta in meta_elements]
+ elements = [Element._new_from_load_element(load_element, task) for load_element in load_elements]
Element._clear_meta_elements_cache()
diff --git a/src/buildstream/element.py b/src/buildstream/element.py
index f1e909bce..f7d49d57f 100644
--- a/src/buildstream/element.py
+++ b/src/buildstream/element.py
@@ -80,7 +80,7 @@ import copy
import warnings
from collections import OrderedDict
import contextlib
-from contextlib import contextmanager
+from contextlib import contextmanager, suppress
from functools import partial
from itertools import chain
import string
@@ -106,6 +106,7 @@ from .sandbox._sandboxremote import SandboxRemote
from .types import CoreWarnings, Scope, _CacheBuildTrees, _KeyStrength
from ._artifact import Artifact
from ._elementsources import ElementSources
+from ._loader import Symbol, MetaSource
from .storage.directory import Directory
from .storage._filebaseddirectory import FileBasedDirectory
@@ -120,7 +121,7 @@ if TYPE_CHECKING:
from .sandbox import Sandbox
from .source import Source
from ._context import Context
- from ._loader.metaelement import MetaElement
+ from ._loader import LoadElement
from ._project import Project
# pylint: enable=cyclic-import
@@ -157,8 +158,8 @@ class Element(Plugin):
# The defaults from the yaml file and project
__defaults = None
- # A hash of Element by MetaElement
- __instantiated_elements = {} # type: Dict[MetaElement, Element]
+ # A hash of Element by LoadElement
+ __instantiated_elements = {} # type: Dict[LoadElement, Element]
# A list of (source, ref) tuples which were redundantly specified
__redundant_source_refs = [] # type: List[Tuple[Source, SourceRef]]
@@ -197,15 +198,17 @@ class Element(Plugin):
"""Whether the element produces an artifact when built.
"""
- def __init__(self, context: "Context", project: "Project", meta: "MetaElement", plugin_conf: Dict[str, Any]):
+ def __init__(
+ self, context: "Context", project: "Project", load_element: "LoadElement", plugin_conf: Dict[str, Any]
+ ):
self.__cache_key_dict = None # Dict for cache key calculation
self.__cache_key = None # Our cached cache key
- super().__init__(meta.name, context, project, meta.provenance, "element")
+ super().__init__(load_element.name, context, project, load_element.provenance, "element")
# Ensure the project is fully loaded here rather than later on
- if not meta.is_junction:
+ if not load_element.first_pass:
project.ensure_fully_loaded()
self.project_name = self._get_project().name
@@ -270,44 +273,44 @@ class Element(Plugin):
self.__resolved_initial_state = False # Whether the initial state of the Element has been resolved
# Ensure we have loaded this class's defaults
- self.__init_defaults(project, plugin_conf, meta.kind, meta.is_junction)
+ self.__init_defaults(project, plugin_conf, load_element.kind, load_element.first_pass)
# Collect the composited variables and resolve them
- variables = self.__extract_variables(project, meta)
+ variables = self.__extract_variables(project, load_element)
variables["element-name"] = self.name
self.__variables = Variables(variables)
- if not meta.is_junction:
+ if not load_element.first_pass:
self.__variables.check()
# Collect the composited environment now that we have variables
- unexpanded_env = self.__extract_environment(project, meta)
+ unexpanded_env = self.__extract_environment(project, load_element)
self.__variables.expand(unexpanded_env)
self.__environment = unexpanded_env.strip_node_info()
# Collect the environment nocache blacklist list
- nocache = self.__extract_env_nocache(project, meta)
+ nocache = self.__extract_env_nocache(project, load_element)
self.__env_nocache = nocache
# Grab public domain data declared for this instance
- self.__public = self.__extract_public(meta)
+ self.__public = self.__extract_public(load_element)
self.__variables.expand(self.__public)
self.__dynamic_public = None
# Collect the composited element configuration and
# ask the element to configure itself.
- self.__config = self.__extract_config(meta)
+ self.__config = self.__extract_config(load_element)
self.__variables.expand(self.__config)
self._configure(self.__config)
# Extract remote execution URL
- if meta.is_junction:
+ if load_element.first_pass:
self.__remote_execution_specs = None
else:
self.__remote_execution_specs = project.remote_execution_specs
# Extract Sandbox config
- sandbox_config = self.__extract_sandbox_config(project, meta)
+ sandbox_config = self.__extract_sandbox_config(project, load_element)
self.__variables.expand(sandbox_config)
self.__sandbox_config = SandboxConfig(sandbox_config, context.platform)
@@ -874,61 +877,56 @@ class Element(Plugin):
# Private Methods used in BuildStream #
#############################################################
- # _new_from_meta():
+ # _new_from_load_element():
#
# Recursively instantiate a new Element instance, its sources
- # and its dependencies from a meta element.
+ # and its dependencies from a LoadElement.
+ #
+ # FIXME: Need to use an iterative algorithm here since recursion
+ # will limit project dependency depth.
#
# Args:
- # meta (MetaElement): The meta element
+ # load_element (LoadElement): The LoadElement
# task (Task): A task object to report progress to
#
# Returns:
# (Element): A newly created Element instance
#
@classmethod
- def _new_from_meta(cls, meta, task=None):
+ def _new_from_load_element(cls, load_element, task=None):
- if not meta.first_pass:
- meta.project.ensure_fully_loaded()
+ if not load_element.first_pass:
+ load_element.project.ensure_fully_loaded()
- if meta in cls.__instantiated_elements:
- return cls.__instantiated_elements[meta]
+ with suppress(KeyError):
+ return cls.__instantiated_elements[load_element]
- element = meta.project.create_element(meta)
- cls.__instantiated_elements[meta] = element
+ element = load_element.project.create_element(load_element)
+ cls.__instantiated_elements[load_element] = element
- # Instantiate sources and generate their keys
- for meta_source in meta.sources:
- meta_source.first_pass = meta.is_junction
- source = meta.project.create_source(meta_source, variables=element.__variables)
+ # Load the sources from the LoadElement
+ element.__load_sources(load_element)
- redundant_ref = source._load_ref()
+ # Instantiate dependencies
+ for dep in load_element.dependencies:
+ dependency = Element._new_from_load_element(dep.element, task)
- element.__sources.add_source(source)
+ if dep.dep_type != "runtime":
+ element.__build_dependencies.append(dependency)
+ dependency.__reverse_build_deps.add(element)
- # Collect redundant refs which occurred at load time
- if redundant_ref is not None:
- cls.__redundant_source_refs.append((source, redundant_ref))
+ if dep.dep_type != "build":
+ element.__runtime_dependencies.append(dependency)
+ dependency.__reverse_runtime_deps.add(element)
+
+ if dep.strict:
+ element.__strict_dependencies.append(dependency)
- # Instantiate dependencies
- for meta_dep in meta.dependencies:
- dependency = Element._new_from_meta(meta_dep, task)
- element.__runtime_dependencies.append(dependency)
- dependency.__reverse_runtime_deps.add(element)
no_of_runtime_deps = len(element.__runtime_dependencies)
element.__runtime_deps_without_strict_cache_key = no_of_runtime_deps
element.__runtime_deps_without_cache_key = no_of_runtime_deps
element.__runtime_deps_uncached = no_of_runtime_deps
- for meta_dep in meta.build_dependencies:
- dependency = Element._new_from_meta(meta_dep, task)
- element.__build_dependencies.append(dependency)
- dependency.__reverse_build_deps.add(element)
-
- if meta_dep in meta.strict_dependencies:
- element.__strict_dependencies.append(dependency)
-
no_of_build_deps = len(element.__build_dependencies)
element.__build_deps_without_strict_cache_key = no_of_build_deps
element.__build_deps_without_cache_key = no_of_build_deps
@@ -2203,6 +2201,63 @@ class Element(Plugin):
# Private Local Methods #
#############################################################
+ # __load_sources()
+ #
+ # Load the Source objects from the LoadElement
+ #
+ def __load_sources(self, load_element):
+ project = self._get_project()
+ workspace = self._get_workspace()
+ meta_sources = []
+
+ # If there's a workspace for this element then we just load a workspace
+ # source plugin instead of the real plugins
+ if workspace:
+ workspace_node = {"kind": "workspace"}
+ workspace_node["path"] = workspace.get_absolute_path()
+ workspace_node["last_build"] = str(workspace.to_dict().get("last_build", ""))
+ meta = MetaSource(
+ self.name,
+ 0,
+ self.get_kind(),
+ "workspace",
+ Node.from_dict(workspace_node),
+ None,
+ load_element.first_pass,
+ )
+ meta_sources.append(meta)
+ else:
+ sources = load_element.node.get_sequence(Symbol.SOURCES, default=[])
+ for index, source in enumerate(sources):
+ kind = source.get_scalar(Symbol.KIND)
+
+ # The workspace source plugin is only valid for internal use
+ if kind.as_str() == "workspace":
+ raise LoadError(
+ "{}: Invalid usage of workspace source kind".format(kind.get_provenance()),
+ LoadErrorReason.INVALID_DATA,
+ )
+ del source[Symbol.KIND]
+
+ # Directory is optional
+ directory = source.get_str(Symbol.DIRECTORY, default=None)
+ if directory:
+ del source[Symbol.DIRECTORY]
+ meta_source = MetaSource(
+ self.name, index, self.get_kind(), kind.as_str(), source, directory, load_element.first_pass
+ )
+ meta_sources.append(meta_source)
+
+ for meta_source in meta_sources:
+ source = project.create_source(meta_source, variables=self.__variables)
+ redundant_ref = source._load_ref()
+
+ self.__sources.add_source(source)
+
+ # Collect redundant refs which occurred at load time
+ if redundant_ref is not None:
+ self.__redundant_source_refs.append((source, redundant_ref))
+
# __get_dependency_refs()
#
# Retrieve the artifact refs of the element's dependencies
@@ -2433,13 +2488,13 @@ class Element(Plugin):
yield sandbox
@classmethod
- def __compose_default_splits(cls, project, defaults, is_junction):
+ def __compose_default_splits(cls, project, defaults, first_pass):
- element_public = defaults.get_mapping("public", default={})
+ element_public = defaults.get_mapping(Symbol.PUBLIC, default={})
element_bst = element_public.get_mapping("bst", default={})
element_splits = element_bst.get_mapping("split-rules", default={})
- if is_junction:
+ if first_pass:
splits = element_splits.clone()
else:
assert project._splits is not None
@@ -2450,10 +2505,10 @@ class Element(Plugin):
element_bst["split-rules"] = splits
element_public["bst"] = element_bst
- defaults["public"] = element_public
+ defaults[Symbol.PUBLIC] = element_public
@classmethod
- def __init_defaults(cls, project, plugin_conf, kind, is_junction):
+ def __init_defaults(cls, project, plugin_conf, kind, first_pass):
# Defaults are loaded once per class and then reused
#
if cls.__defaults is None:
@@ -2468,11 +2523,11 @@ class Element(Plugin):
raise e
# Special case; compose any element-wide split-rules declarations
- cls.__compose_default_splits(project, defaults, is_junction)
+ cls.__compose_default_splits(project, defaults, first_pass)
# Override the element's defaults with element specific
# overrides from the project.conf
- if is_junction:
+ if first_pass:
elements = project.first_pass_config.element_overrides
else:
elements = project.element_overrides
@@ -2488,29 +2543,30 @@ class Element(Plugin):
# creating sandboxes for this element
#
@classmethod
- def __extract_environment(cls, project, meta):
- default_env = cls.__defaults.get_mapping("environment", default={})
+ def __extract_environment(cls, project, load_element):
+ default_env = cls.__defaults.get_mapping(Symbol.ENVIRONMENT, default={})
+ element_env = load_element.node.get_mapping(Symbol.ENVIRONMENT, default={}) or Node.from_dict({})
- if meta.is_junction:
+ if load_element.first_pass:
environment = Node.from_dict({})
else:
environment = project.base_environment.clone()
default_env._composite(environment)
- meta.environment._composite(environment)
+ element_env._composite(environment)
environment._assert_fully_composited()
return environment
@classmethod
- def __extract_env_nocache(cls, project, meta):
- if meta.is_junction:
+ def __extract_env_nocache(cls, project, load_element):
+ if load_element.first_pass:
project_nocache = []
else:
project_nocache = project.base_env_nocache
- default_nocache = cls.__defaults.get_str_list("environment-nocache", default=[])
- element_nocache = meta.env_nocache
+ default_nocache = cls.__defaults.get_str_list(Symbol.ENV_NOCACHE, default=[])
+ element_nocache = load_element.node.get_str_list(Symbol.ENV_NOCACHE, default=[])
# Accumulate values from the element default, the project and the element
# itself to form a complete list of nocache env vars.
@@ -2523,16 +2579,17 @@ class Element(Plugin):
# substituting command strings to be run in the sandbox
#
@classmethod
- def __extract_variables(cls, project, meta):
- default_vars = cls.__defaults.get_mapping("variables", default={})
+ def __extract_variables(cls, project, load_element):
+ default_vars = cls.__defaults.get_mapping(Symbol.VARIABLES, default={})
+ element_vars = load_element.node.get_mapping(Symbol.VARIABLES, default={}) or Node.from_dict({})
- if meta.is_junction:
+ if load_element.first_pass:
variables = project.first_pass_config.base_variables.clone()
else:
variables = project.base_variables.clone()
default_vars._composite(variables)
- meta.variables._composite(variables)
+ element_vars._composite(variables)
variables._assert_fully_composited()
for var in ("project-name", "element-name", "max-jobs"):
@@ -2554,13 +2611,14 @@ class Element(Plugin):
# off to element.configure()
#
@classmethod
- def __extract_config(cls, meta):
+ def __extract_config(cls, load_element):
+ element_config = load_element.node.get_mapping(Symbol.CONFIG, default={}) or Node.from_dict({})
# The default config is already composited with the project overrides
- config = cls.__defaults.get_mapping("config", default={})
+ config = cls.__defaults.get_mapping(Symbol.CONFIG, default={})
config = config.clone()
- meta.config._composite(config)
+ element_config._composite(config)
config._assert_fully_composited()
return config
@@ -2568,18 +2626,20 @@ class Element(Plugin):
# Sandbox-specific configuration data, to be passed to the sandbox's constructor.
#
@classmethod
- def __extract_sandbox_config(cls, project, meta):
- if meta.is_junction:
+ def __extract_sandbox_config(cls, project, load_element):
+ element_sandbox = load_element.node.get_mapping(Symbol.SANDBOX, default={}) or Node.from_dict({})
+
+ if load_element.first_pass:
sandbox_config = Node.from_dict({})
else:
sandbox_config = project._sandbox.clone()
# The default config is already composited with the project overrides
- sandbox_defaults = cls.__defaults.get_mapping("sandbox", default={})
+ sandbox_defaults = cls.__defaults.get_mapping(Symbol.SANDBOX, default={})
sandbox_defaults = sandbox_defaults.clone()
sandbox_defaults._composite(sandbox_config)
- meta.sandbox._composite(sandbox_config)
+ element_sandbox._composite(sandbox_config)
sandbox_config._assert_fully_composited()
return sandbox_config
@@ -2588,14 +2648,16 @@ class Element(Plugin):
# elements may extend but whos defaults are defined in the project.
#
@classmethod
- def __extract_public(cls, meta):
- base_public = cls.__defaults.get_mapping("public", default={})
+ def __extract_public(cls, load_element):
+ element_public = load_element.node.get_mapping(Symbol.PUBLIC, default={}) or Node.from_dict({})
+
+ base_public = cls.__defaults.get_mapping(Symbol.PUBLIC, default={})
base_public = base_public.clone()
base_bst = base_public.get_mapping("bst", default={})
base_splits = base_bst.get_mapping("split-rules", default={})
- element_public = meta.public.clone()
+ element_public = element_public.clone()
element_bst = element_public.get_mapping("bst", default={})
element_splits = element_bst.get_mapping("split-rules", default={})
diff --git a/src/buildstream/source.py b/src/buildstream/source.py
index dc87c35de..ea77a6537 100644
--- a/src/buildstream/source.py
+++ b/src/buildstream/source.py
@@ -1213,10 +1213,9 @@ class Source(Plugin):
self.get_kind(),
self.__config,
self.__directory,
+ self.__first_pass,
)
- meta.first_pass = self.__first_pass
-
clone = source_kind(
context, project, meta, self.__variables, alias_override=(alias, uri), unique_id=self._unique_id
)
diff --git a/tests/internals/loader.py b/tests/internals/loader.py
index bdce428f0..2da01723b 100644
--- a/tests/internals/loader.py
+++ b/tests/internals/loader.py
@@ -5,7 +5,7 @@ import pytest
from buildstream.exceptions import LoadErrorReason
from buildstream._exceptions import LoadError
from buildstream._project import Project
-from buildstream._loader import MetaElement
+from buildstream._loader import LoadElement
from tests.testutils import dummy_context
@@ -30,7 +30,7 @@ def test_one_file(datafiles):
with make_loader(basedir) as loader:
element = loader.load(["elements/onefile.bst"])[0]
- assert isinstance(element, MetaElement)
+ assert isinstance(element, LoadElement)
assert element.kind == "pony"