From ef4eb5b3ae186653fd53fe9f825fed06cdb64861 Mon Sep 17 00:00:00 2001
From: Richard Maw <richard.maw@codethink.co.uk>
Date: Mon, 29 Oct 2018 13:07:44 +0000
Subject: [PATCH] element: Add BST_STAGE_INTEGRATES Element flag

This commit introduces BST_STAGE_INTEGRATES as a compatibility flag,
so Elements can set it to false
to signal that integrate_dependency_artifacts should be called.

This will be needed to implement staging multiple elements,
since the integration commands for all elements need to be called
after all dependencies are staged.
---
 buildstream/element.py | 38 +++++++++++++++++++++++++++++++++++---
 1 file changed, 35 insertions(+), 3 deletions(-)

diff --git a/buildstream/element.py b/buildstream/element.py
index 7c647b3237..2e9572ff5c 100644
--- a/buildstream/element.py
+++ b/buildstream/element.py
@@ -176,6 +176,15 @@ class Element(Plugin):
     *Since: 1.4*
     """
 
+    BST_STAGE_INTEGRATES = True
+    """Whether Element.stage calls integration commands, or whether callers are
+    expected to call Element.integrate_dependency_artifacts.
+
+    If this is the case then multi-element sandboxes can't include this element.
+
+    *Since: 1.4*
+    """
+
     def __init__(self, context, project, meta, plugin_conf):
 
         self.__cache_key_dict = None            # Dict for cache key calculation
@@ -291,11 +300,12 @@ class Element(Plugin):
         raise ImplError("element plugin '{kind}' does not implement configure_sandbox()".format(
             kind=self.get_kind()))
 
-    def stage(self, sandbox):
+    def stage(self, sandbox, *, visited=None):
         """Stage inputs into the sandbox directories
 
         Args:
            sandbox (:class:`.Sandbox`): The build sandbox
+           visited (dict or None): Skip Elements included here and add any traversed
 
         Raises:
            (:class:`.ElementError`): When the element raises an error
@@ -308,6 +318,27 @@ class Element(Plugin):
         raise ImplError("element plugin '{kind}' does not implement stage()".format(
             kind=self.get_kind()))
 
+    def integrate_dependency_artifacts(self, sandbox, scope, *, visited=None):
+        """Integrate element dependencies in scope
+
+        This is primarily a convenience wrapper around
+        :func:`Element.integrate() <buildstream.element.Element.stage_artifact>`
+        which takes care of integrating all the dependencies in `scope`.
+
+        Args:
+           sandbox (:class:`.Sandbox`): The build sandbox
+           scope (:class:`.Scope`): The scope to stage dependencies in
+           visited (dict or None): Skip Elements included here and add any traversed
+
+        *Since: 1.4*
+        """
+        if visited is None:
+            visited = {}
+
+        with sandbox.batch(SandboxFlags.NONE, label="Integrating sandbox"):
+            for dep in self.dependencies(scope, visited=visited):
+                dep.integrate(sandbox)
+
     def prepare(self, sandbox):
         """Run one-off preparation commands.
 
@@ -656,7 +687,7 @@ class Element(Plugin):
         return link_result.combine(copy_result)
 
     def stage_dependency_artifacts(self, sandbox, scope, *, path=None,
-                                   include=None, exclude=None, orphans=True):
+                                   include=None, exclude=None, orphans=True, visited=None):
         """Stage element dependencies in scope
 
         This is primarily a convenience wrapper around
@@ -671,6 +702,7 @@ class Element(Plugin):
            include (list): An optional list of domains to include files from
            exclude (list): An optional list of domains to exclude files from
            orphans (bool): Whether to include files not spoken for by split domains
+           visited (dict or None): Skip Elements included here and add any traversed
 
         Raises:
            (:class:`.ElementError`): If any of the dependencies in `scope` have not
@@ -686,7 +718,7 @@ class Element(Plugin):
         if self.__can_build_incrementally() and workspace.last_successful:
             old_dep_keys = self.__get_artifact_metadata_dependencies(workspace.last_successful)
 
-        for dep in self.dependencies(scope):
+        for dep in self.dependencies(scope, visited=visited):
             # If we are workspaced, and we therefore perform an
             # incremental build, we must ensure that we update the mtimes
             # of any files created by our dependencies since the last
-- 
GitLab