summaryrefslogtreecommitdiff
path: root/buildstream
diff options
context:
space:
mode:
authorTristan Maat <tristan.maat@codethink.com>2017-08-02 17:59:30 +0100
committerTristan Maat <tristan.maat@codethink.co.uk>2017-09-28 11:30:50 +0100
commit620006f2c3e6271e56743edc129c4fb19eab241a (patch)
tree166c1fc53ff6883acbd345df7cd7d11f549dc794 /buildstream
parent32be8c7b78a80534d75648448221cac5eccd993b (diff)
downloadbuildstream-620006f2c3e6271e56743edc129c4fb19eab241a.tar.gz
Add platform factories
Diffstat (limited to 'buildstream')
-rw-r--r--buildstream/__init__.py2
-rw-r--r--buildstream/_pipeline.py10
-rw-r--r--buildstream/_platform/__init__.py21
-rw-r--r--buildstream/_platform/linux.py43
-rwxr-xr-xbuildstream/_platform/platform.py92
-rw-r--r--buildstream/_platform/unix.py49
-rw-r--r--buildstream/context.py1
-rw-r--r--buildstream/element.py23
-rw-r--r--buildstream/exceptions.py6
-rw-r--r--buildstream/sandbox/sandbox.py7
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