summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChandan Singh <csingh43@bloomberg.net>2019-04-12 20:00:46 +0100
committerChandan Singh <csingh43@bloomberg.net>2019-04-18 15:45:19 +0100
commitefe5547f1fecc8076d3d769ae5468a1935dac10b (patch)
treee4c9e0169a184f88aa9cc8a699760f1110ce9046
parente570c681a44cf86d22a93e6893e122d97d4b51ff (diff)
downloadbuildstream-efe5547f1fecc8076d3d769ae5468a1935dac10b.tar.gz
Add support for defining target for junction elements
Add support for specifying target of a junction element to be a sub-sub-project as a configuration option. When such a target is defined, the junction element is not allowed to have any sources. This was discussed in the following mailing list thread: https://mail.gnome.org/archives/buildstream-list/2019-April/msg00025.html Since this adds new configuration, also bump `BST_FORMAT_VERSION`.
-rw-r--r--buildstream/_loader/loader.py12
-rw-r--r--buildstream/_versions.py2
-rw-r--r--buildstream/plugins/elements/junction.py64
3 files changed, 75 insertions, 3 deletions
diff --git a/buildstream/_loader/loader.py b/buildstream/_loader/loader.py
index 6d8310cfa..31d721b07 100644
--- a/buildstream/_loader/loader.py
+++ b/buildstream/_loader/loader.py
@@ -519,6 +519,18 @@ class Loader():
element = Element._new_from_meta(meta_element)
element._preflight()
+ # If this junction element points to a sub-sub-project, we need to
+ # find loader for that project.
+ if element.target:
+ subproject_loader = self._get_loader(element.target_junction, rewritable=rewritable, ticker=ticker,
+ level=level, fetch_subprojects=fetch_subprojects,
+ provenance=provenance)
+ loader = subproject_loader._get_loader(element.target_element, rewritable=rewritable, ticker=ticker,
+ level=level, fetch_subprojects=fetch_subprojects,
+ provenance=provenance)
+ self._loaders[filename] = loader
+ return loader
+
sources = list(element.sources())
if not element._source_cached():
for idx, source in enumerate(sources):
diff --git a/buildstream/_versions.py b/buildstream/_versions.py
index 56fd95223..c439f59fb 100644
--- a/buildstream/_versions.py
+++ b/buildstream/_versions.py
@@ -23,7 +23,7 @@
# This version is bumped whenever enhancements are made
# to the `project.conf` format or the core element format.
#
-BST_FORMAT_VERSION = 23
+BST_FORMAT_VERSION = 24
# The base BuildStream artifact version
diff --git a/buildstream/plugins/elements/junction.py b/buildstream/plugins/elements/junction.py
index ec7832bc6..15ef115d9 100644
--- a/buildstream/plugins/elements/junction.py
+++ b/buildstream/plugins/elements/junction.py
@@ -48,6 +48,18 @@ Overview
# Optionally look in a subpath of the source repository for the project
path: projects/hello
+ # Optionally specify another junction element to serve as a target for
+ # this element. Target should be defined using the syntax
+ # ``{junction-name}:{element-name}``.
+ #
+ # Note that this option cannot be used in conjunction with sources.
+ target: sub-project.bst:sub-sub-project.bst
+
+.. note::
+
+ The configuration option to allow specifying junction targets is available
+ since :ref:`format version 24 <project_format_version>`.
+
.. note::
Junction elements may not specify any dependencies as they are simply
@@ -124,10 +136,34 @@ As the junctions may differ in source version and options, BuildStream cannot
simply use one junction and ignore the others. Due to this, BuildStream requires
the user to resolve possibly conflicting nested junctions by creating a junction
with the same name in the top-level project, which then takes precedence.
+
+Targeting other junctions
+~~~~~~~~~~~~~~~~~~~~~~~~~
+When working with nested junctions, you can also create a junction element that
+targets another junction element in the sub-project. This can be useful if you
+need to ensure that both the top-level project and the sub-project are using
+the same version of the sub-sub-project.
+
+This can be done using the ``target`` configuration option. See below for an
+example:
+
+.. code:: yaml
+
+ kind: junction
+
+ config:
+ target: subproject.bst:subsubproject.bst
+
+In the above example, this junction element would be targeting the junction
+element named ``subsubproject.bst`` in the subproject referred to by
+``subproject.bst``.
+
+Note that when targeting another junction, the names of the junction element
+must not be the same as the name of the target.
"""
from collections.abc import Mapping
-from buildstream import Element
+from buildstream import Element, ElementError
from buildstream._pipeline import PipelineError
@@ -142,9 +178,33 @@ class JunctionElement(Element):
def configure(self, node):
self.path = self.node_get_member(node, str, 'path', default='')
self.options = self.node_get_member(node, Mapping, 'options', default={})
+ self.target = self.node_get_member(node, str, 'target', default=None)
+ self.target_element = None
+ self.target_junction = None
def preflight(self):
- pass
+ # "target" cannot be used in conjunction with:
+ # 1. sources
+ # 2. config['options']
+ # 3. config['path']
+ if self.target and any(self.sources()):
+ raise ElementError("junction elements cannot define both 'sources' and 'target' config option")
+ if self.target and any(self.node_items(self.options)):
+ raise ElementError("junction elements cannot define both 'options' and 'target'")
+ if self.target and self.path:
+ raise ElementError("junction elements cannot define both 'path' and 'target'")
+
+ # Validate format of target, if defined
+ if self.target:
+ try:
+ self.target_junction, self.target_element = self.target.split(":")
+ except ValueError:
+ raise ElementError("'target' option must be in format '{junction-name}:{element-name}'")
+
+ # We cannot target a junction that has the same name as us, since that
+ # will cause an infinite recursion while trying to load it.
+ if self.name == self.target_element:
+ raise ElementError("junction elements cannot target an element with the same name")
def get_unique_key(self):
# Junctions do not produce artifacts. get_unique_key() implementation