diff options
author | Tristan Maat <tristan.maat@codethink.com> | 2017-08-02 17:59:30 +0100 |
---|---|---|
committer | Tristan Maat <tristan.maat@codethink.co.uk> | 2017-09-28 11:30:50 +0100 |
commit | 620006f2c3e6271e56743edc129c4fb19eab241a (patch) | |
tree | 166c1fc53ff6883acbd345df7cd7d11f549dc794 /buildstream | |
parent | 32be8c7b78a80534d75648448221cac5eccd993b (diff) | |
download | buildstream-620006f2c3e6271e56743edc129c4fb19eab241a.tar.gz |
Add platform factories
Diffstat (limited to 'buildstream')
-rw-r--r-- | buildstream/__init__.py | 2 | ||||
-rw-r--r-- | buildstream/_pipeline.py | 10 | ||||
-rw-r--r-- | buildstream/_platform/__init__.py | 21 | ||||
-rw-r--r-- | buildstream/_platform/linux.py | 43 | ||||
-rwxr-xr-x | buildstream/_platform/platform.py | 92 | ||||
-rw-r--r-- | buildstream/_platform/unix.py | 49 | ||||
-rw-r--r-- | buildstream/context.py | 1 | ||||
-rw-r--r-- | buildstream/element.py | 23 | ||||
-rw-r--r-- | buildstream/exceptions.py | 6 | ||||
-rw-r--r-- | buildstream/sandbox/sandbox.py | 7 |
10 files changed, 231 insertions, 23 deletions
diff --git a/buildstream/__init__.py b/buildstream/__init__.py index cda2808d3..f8a2db354 100644 --- a/buildstream/__init__.py +++ b/buildstream/__init__.py @@ -20,7 +20,7 @@ # Exceptions and utilities first from .exceptions import PluginError, LoadError, LoadErrorReason, \ - SourceError, ElementError, ImplError, ProgramNotFoundError + SourceError, ElementError, ImplError, ProgramNotFoundError, PlatformError # Core components from .context import Context diff --git a/buildstream/_pipeline.py b/buildstream/_pipeline.py index 03646ff81..3a72de7ed 100644 --- a/buildstream/_pipeline.py +++ b/buildstream/_pipeline.py @@ -31,7 +31,6 @@ from pluginbase import PluginBase from .exceptions import _BstError, _ArtifactError from ._message import Message, MessageType -from ._artifactcache import ArtifactCache from ._elementfactory import ElementFactory from ._loader import Loader from ._sourcefactory import SourceFactory @@ -39,6 +38,7 @@ from . import Consistency, ImplError, LoadError from . import Scope from . import _site from . import _yaml, utils +from ._platform import Platform from ._scheduler import SchedStatus, TrackQueue, FetchQueue, BuildQueue, PullQueue, PushQueue @@ -146,8 +146,8 @@ class Pipeline(): # Resolve project variant now that we've decided on one project._resolve(loader.project_variant) - - self.artifacts = ArtifactCache(self.context, self.project) + self.platform = Platform.get_platform(context, project) + self.artifacts = self.platform.artifactcache # Create the factories after resolving the project pluginbase = PluginBase(package='buildstream.plugins') @@ -178,7 +178,7 @@ class Pipeline(): if self.artifacts.can_fetch(): try: if remote_ticker: - remote_ticker(self.artifacts.artifact_pull) + remote_ticker(context.artifact_pull) self.artifacts.fetch_remote_refs() except _ArtifactError: self.message(self.target, MessageType.WARN, "Failed to fetch remote refs") @@ -686,8 +686,6 @@ class Pipeline(): if not self.artifacts.can_push(): raise PipelineError("Not configured for pushing artifacts") - if not self.can_push_remote_artifact_cache(): - raise PipelineError("Unable to push to the configured remote artifact cache") plan = elements self.assert_consistent(plan) diff --git a/buildstream/_platform/__init__.py b/buildstream/_platform/__init__.py new file mode 100644 index 000000000..49400c3f2 --- /dev/null +++ b/buildstream/_platform/__init__.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 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 Maat <tristan.maat@codethink.co.uk> + +from .platform import Platform diff --git a/buildstream/_platform/linux.py b/buildstream/_platform/linux.py new file mode 100644 index 000000000..38afc5423 --- /dev/null +++ b/buildstream/_platform/linux.py @@ -0,0 +1,43 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 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 Maat <tristan.maat@codethink.co.uk> + +import os +import sys + +from .. import utils +from ..sandbox import SandboxBwrap +from .._artifactcache.ostreecache import OSTreeCache + +from . import Platform + + +class Linux(Platform): + + def __init__(self, context, project): + + super().__init__(context, project) + self._artifact_cache = OSTreeCache(context, project) + + @property + def artifactcache(self): + return self._artifact_cache + + def create_sandbox(self, *args, **kwargs): + return SandboxBwrap(*args, **kwargs) diff --git a/buildstream/_platform/platform.py b/buildstream/_platform/platform.py new file mode 100755 index 000000000..920fddbde --- /dev/null +++ b/buildstream/_platform/platform.py @@ -0,0 +1,92 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 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 Maat <tristan.maat@codethink.co.uk> + +import os +import sys +import platform + +from .. import utils +from .. import PlatformError, ProgramNotFoundError, ImplError + + +class Platform(): + + # Platform() + # + # A class to manage platform-specific details. Currently holds the + # sandbox factory, the artifact cache and staging operations, as + # well as platform helpers. + # + # Args: + # context (context): The project context + # + def __init__(self, context, project): + self.context = context + self.project = project + + @classmethod + def get_platform(cls, *args, **kwargs): + + if sys.platform.startswith('linux'): + backend = 'linux' + else: + backend = 'unix' + + # Meant for testing purposes and therefore hidden in the + # deepest corners of the source code. Try not to abuse this, + # please? + if os.getenv('BST_FORCE_BACKEND'): + backend = os.getenv('BST_FORCE_BACKEND') + + if backend == 'linux': + from .linux import Linux as PlatformImpl + elif backend == 'unix': + from .unix import Unix as PlatformImpl + else: + raise PlatformError("No such platform: '{}'".format(backend)) + + return PlatformImpl(*args, **kwargs) + + ################################################################## + # Platform properties # + ################################################################## + @property + def artifactcache(self): + raise ImplError("Platform {platform} does not implement an artifactcache" + .format(platform=type(self).__name__)) + + ################################################################## + # Sandbox functions # + ################################################################## + + # create_sandbox(): + # + # Create a build sandbox suitable for the environment + # + # Args: + # args (dict): The arguments to pass to the sandbox constructor + # kwargs (file): The keyword arguments to pass to the sandbox constructor + # + # Returns: + # (Sandbox) A sandbox + # + def create_sandbox(self, *args, **kwargs): + raise ImplError("Platform {platform} does not implement create_sandbox()" + .format(platform=type(self).__name__)) diff --git a/buildstream/_platform/unix.py b/buildstream/_platform/unix.py new file mode 100644 index 000000000..752386bdf --- /dev/null +++ b/buildstream/_platform/unix.py @@ -0,0 +1,49 @@ +#!/usr/bin/env python3 +# +# Copyright (C) 2017 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 Maat <tristan.maat@codethink.co.uk> + +import os +import sys +import pathlib + +from .. import utils +from .. import PlatformError +from ..sandbox import SandboxChroot +from .._artifactcache.tarcache import TarCache + +from . import Platform + + +class Unix(Platform): + + def __init__(self, context, project): + + super().__init__(context, project) + self._artifact_cache = TarCache(context, project) + + # Not necessarily 100% reliable, but we want to fail early. + if os.geteuid() != 0: + raise PlatformError("Root privileges are required to run without bubblewrap.") + + @property + def artifactcache(self): + return self._artifact_cache + + def create_sandbox(self, *args, **kwargs): + return SandboxChroot(*args, **kwargs) diff --git a/buildstream/context.py b/buildstream/context.py index 6f378f700..4ac1adc7a 100644 --- a/buildstream/context.py +++ b/buildstream/context.py @@ -128,6 +128,7 @@ class Context(): self._cache_key = None self._message_handler = None self._message_depth = deque() + self._platform = None def load(self, config=None): """Loads the configuration files diff --git a/buildstream/element.py b/buildstream/element.py index 7029acd7e..efb499be0 100644 --- a/buildstream/element.py +++ b/buildstream/element.py @@ -38,15 +38,15 @@ import shutil from . import _yaml from ._yaml import CompositePolicy from ._variables import Variables -from .exceptions import _BstError, _ArtifactError +from .exceptions import _BstError from . import LoadError, LoadErrorReason, ElementError, ImplError -from ._sandboxbwrap import SandboxBwrap -from . import Sandbox, SandboxFlags from . import Plugin, Consistency from .project import BST_ARTIFACT_VERSION as BST_CORE_ARTIFACT_VERSION +from . import SandboxFlags from . import utils from . import _signals from . import _site +from ._platform import Platform class Scope(Enum): @@ -456,7 +456,7 @@ class Element(Plugin): for i in range(len(commands)): cmd = self.node_subst_list_element(bstdata, 'integration-commands', [i]) self.status("Running integration command", detail=cmd) - exitcode = sandbox.run(['sh', '-c', '-e', cmd], 0, env=environment, cwd='/') + exitcode = sandbox.run(['sh', '-e', '-c', cmd], 0, env=environment, cwd='/') if exitcode != 0: raise ElementError("Command '{}' failed with exitcode {}".format(cmd, exitcode)) @@ -866,7 +866,8 @@ class Element(Plugin): 'environment': cache_env, 'sources': [s._get_unique_key() for s in self.__sources], 'dependencies': dependencies, - 'public': self.__public + 'public': self.__public, + 'cache': type(self.__artifacts).__name__ }) # _get_cache_key(): @@ -1403,15 +1404,13 @@ class Element(Plugin): def __sandbox(self, directory, stdout=None, stderr=None): context = self.get_context() project = self.get_project() + platform = Platform.get_platform(context, project) if directory is not None and os.path.exists(directory): - - # We'll want a factory function and some decision making about - # which sandbox implementation to use, when we have more than - # one sandbox implementation. - # - sandbox = SandboxBwrap(context, project, directory, stdout=stdout, stderr=stderr) - + sandbox = platform.create_sandbox(context, project, + directory, + stdout=stdout, + stderr=stderr) yield sandbox else: diff --git a/buildstream/exceptions.py b/buildstream/exceptions.py index 68e43ec37..b23a88506 100644 --- a/buildstream/exceptions.py +++ b/buildstream/exceptions.py @@ -141,5 +141,11 @@ class ProgramNotFoundError(_BstError): pass +class PlatformError(_BstError): + """Raised if the current platform is not supported. + """ + pass + + class _ArtifactError(_BstError): pass diff --git a/buildstream/sandbox/sandbox.py b/buildstream/sandbox/sandbox.py index fe69eae94..ff7dc8762 100644 --- a/buildstream/sandbox/sandbox.py +++ b/buildstream/sandbox/sandbox.py @@ -180,12 +180,11 @@ class Sandbox(): Sandbox programming interface for :class:`.Element` plugins. """ - def __init__(self, context, project, directory, - stdout=None, stderr=None): + def __init__(self, context, project, directory, **kwargs): self.__context = context self.__project = project - self.__stdout = stdout - self.__stderr = stderr + self.__stdout = kwargs['stdout'] + self.__stderr = kwargs['stderr'] self.__directories = [] self.__cwd = None self.__env = None |