You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@buildstream.apache.org by ro...@apache.org on 2020/12/29 13:38:55 UTC

[buildstream] 03/05: sandbox/_config.py, element.py: Refactor SandboxConfig

This is an automated email from the ASF dual-hosted git repository.

root pushed a commit to branch tristan/artifact-extensions
in repository https://gitbox.apache.org/repos/asf/buildstream.git

commit 679bacf779b85f749009f508dbaf1efddd8ae7c6
Author: Tristan van Berkom <tr...@codethink.co.uk>
AuthorDate: Tue Dec 1 17:14:08 2020 +0900

    sandbox/_config.py, element.py: Refactor SandboxConfig
    
    This commit changes SandboxConfig such that it now has a simple constructor
    and a new SandboxConfig.new_from_node() classmethod to load it from a YAML
    configuration node. The new version of SandboxConfig now uses type annotations.
    
    SandboxConfig also now sports a to_dict() method to help in serialization in
    artifacts.
    
    The element.py code has been updated to use the classmethod.
    
    This refactor is meant to allow instantiating a SandboxConfig without
    any MappingNode, such that we can later load a SandboxConfig from an
    Artifact instead of from an parsed Element.
---
 src/buildstream/element.py         |   2 +-
 src/buildstream/sandbox/_config.py | 126 +++++++++++++++++++++++++++++--------
 2 files changed, 102 insertions(+), 26 deletions(-)

diff --git a/src/buildstream/element.py b/src/buildstream/element.py
index ac16e31..4a03e1c 100644
--- a/src/buildstream/element.py
+++ b/src/buildstream/element.py
@@ -347,7 +347,7 @@ class Element(Plugin):
         # Extract Sandbox config
         sandbox_config = self.__extract_sandbox_config(project, load_element)
         self.__variables.expand(sandbox_config)
-        self.__sandbox_config = SandboxConfig(sandbox_config, context.platform)
+        self.__sandbox_config = SandboxConfig.new_from_node(sandbox_config, platform=context.platform)
 
     def __lt__(self, other):
         return self.name < other.name
diff --git a/src/buildstream/sandbox/_config.py b/src/buildstream/sandbox/_config.py
index 1142741..0e389ad 100644
--- a/src/buildstream/sandbox/_config.py
+++ b/src/buildstream/sandbox/_config.py
@@ -1,5 +1,5 @@
 #
-#  Copyright (C) 2018 Codethink Limited
+#  Copyright (C) 2020 Codethink Limited
 #
 #  This program is free software; you can redistribute it and/or
 #  modify it under the terms of the GNU Lesser General Public
@@ -16,35 +16,44 @@
 #
 #  Authors:
 #        Jim MacArthur <ji...@codethink.co.uk>
+#        Tristan Van Berkom <tr...@codethink.co.uk>
+#
 
+from typing import TYPE_CHECKING, Dict, Optional, Union
 from .._platform import Platform
 
+if TYPE_CHECKING:
+    from ..node import Node, MappingNode
+
 
 # SandboxConfig
 #
-# A container for sandbox configuration data. We want the internals
-# of this to be opaque, hence putting it in its own private file.
+# The Sandbox configuration parameters, this object carries configuration
+# required to instantiate the correct type of sandbox, and assert that
+# the local or remote worker sandbox has the capabilities required.
+#
+# Args:
+#    build_os: The build OS name
+#    build_arch: A canonical machine architecture name, as defined by Platform.canonicalize_arch()
+#    build_uid: The UID for the sandbox process
+#    build_gid: The GID for the sandbox process
+#
+# If the build_uid or build_gid is unspecified, then the underlying sandbox implementation
+# does not guarantee what UID/GID will be used, but generally UID/GID 0 will be used in a
+# sandbox implementation which supports UID/GID control.
+#
+# If the build_uid or build_gid is specified, then the UID/GID is guaranteed to match
+# the specified UID/GID, if the underlying sandbox implementation does not support UID/GID
+# control, then an error will be raised when attempting to configure the sandbox.
+#
 class SandboxConfig:
-    def __init__(self, sandbox_config, platform):
-        host_arch = platform.get_host_arch()
-        host_os = platform.get_host_os()
-
-        sandbox_config.validate_keys(["build-uid", "build-gid", "build-os", "build-arch"])
-
-        build_os = sandbox_config.get_str("build-os", default=None)
-        if build_os:
-            self.build_os = build_os.lower()
-        else:
-            self.build_os = host_os
-
-        build_arch = sandbox_config.get_str("build-arch", default=None)
-        if build_arch:
-            self.build_arch = Platform.canonicalize_arch(build_arch)
-        else:
-            self.build_arch = host_arch
-
-        self.build_uid = sandbox_config.get_int("build-uid", None)
-        self.build_gid = sandbox_config.get_int("build-gid", None)
+    def __init__(
+        self, *, build_os: str, build_arch: str, build_uid: Optional[int] = None, build_gid: Optional[int] = None
+    ):
+        self.build_os = build_os
+        self.build_arch = build_arch
+        self.build_uid = build_uid
+        self.build_gid = build_gid
 
     # get_unique_key():
     #
@@ -54,9 +63,9 @@ class SandboxConfig:
     # Returns:
     #    (dict): A dictionary to add to an element's cache key
     #
-    def get_unique_key(self):
+    def get_unique_key(self) -> dict:
 
-        unique_key = {"os": self.build_os, "arch": self.build_arch}
+        unique_key: Dict[str, Union[str, int]] = {"os": self.build_os, "arch": self.build_arch}
 
         if self.build_uid is not None:
             unique_key["build-uid"] = self.build_uid
@@ -65,3 +74,70 @@ class SandboxConfig:
             unique_key["build-gid"] = self.build_gid
 
         return unique_key
+
+    # to_dict():
+    #
+    # Represent the SandboxConfig as a dictionary.
+    #
+    # This dictionary will be stored in the corresponding artifact
+    # whenever an artifact is cached. When loading an element from
+    # an artifact, then this dict will be loaded as a MappingNode
+    # and interpreted by SandboxConfig.new_from_node().
+    #
+    # Returns:
+    #    A dictionary representation of this SandboxConfig
+    #
+    def to_dict(self) -> Dict[str, Union[str, int]]:
+        sandbox_dict: Dict[str, Union[str, int]] = {"build-os": self.build_os, "build-arch": self.build_arch}
+
+        if self.build_uid is not None:
+            sandbox_dict["build-uid"] = self.build_uid
+        if self.build_gid is not None:
+            sandbox_dict["build-gid"] = self.build_gid
+
+        return sandbox_dict
+
+    # new_from_node():
+    #
+    # Instantiate a new SandboxConfig from YAML configuration.
+    #
+    # If the Platform is specified, then we expect to be loading
+    # from project definitions, and some defaults will be derived
+    # from the Platform. Otherwise, we expect to be loading from
+    # a cached artifact, and values are expected to exist on the
+    # given node.
+    #
+    # Args:
+    #    config: The YAML configuration node
+    #    platform: The host Platform instance, or None
+    #
+    # Returns:
+    #    A new SandboxConfig instance
+    #
+    @classmethod
+    def new_from_node(cls, config: "MappingNode[Node]", *, platform: Optional[Platform] = None) -> "SandboxConfig":
+        config.validate_keys(["build-uid", "build-gid", "build-os", "build-arch"])
+
+        build_os: str
+        build_arch: str
+
+        if platform:
+            tmp = config.get_str("build-os", default=None)
+            if tmp:
+                build_os = tmp.lower()
+            else:
+                build_os = platform.get_host_os()
+
+            tmp = config.get_str("build-arch", default=None)
+            if tmp:
+                build_arch = Platform.canonicalize_arch(tmp)
+            else:
+                build_arch = platform.get_host_arch()
+        else:
+            build_os = config.get_str("build-os")
+            build_arch = config.get_str("build-arch")
+
+        build_uid = config.get_int("build-uid", None)
+        build_gid = config.get_int("build-gid", None)
+
+        return cls(build_os=build_os, build_arch=build_arch, build_uid=build_uid, build_gid=build_gid)