summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDarius Makovsky <traveltissues@protonmail.com>2019-09-05 14:22:19 +0100
committerDarius Makovsky <traveltissues@protonmail.com>2019-09-20 16:38:24 +0100
commit46cb41e71ece062f8ee4d80ee17154146f197c7f (patch)
tree0536ec92949c481f271821477f53aab3211aa57b
parentfc0136c62bf065a94e7fe192a673e708dc0778c7 (diff)
downloadbuildstream-46cb41e71ece062f8ee4d80ee17154146f197c7f.tar.gz
workspace.py: add workspace source plugin
The `workspace.init_workspace()` call should wrap `source._init_workspace` for held sources to support those sources not publishing `BST_VIRTUAL_DIRECTORY` This object owns a directory digest attribute used inplace of the source ref.
-rw-r--r--src/buildstream/plugins/sources/workspace.py138
1 files changed, 138 insertions, 0 deletions
diff --git a/src/buildstream/plugins/sources/workspace.py b/src/buildstream/plugins/sources/workspace.py
new file mode 100644
index 000000000..f696410e0
--- /dev/null
+++ b/src/buildstream/plugins/sources/workspace.py
@@ -0,0 +1,138 @@
+#
+# Copyright (C) 2019 Bloomberg Finance LP
+#
+# 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/>.
+
+"""
+:orphan:
+
+workspace - stage an opened workspace directory
+===============================================
+
+**Usage:**
+
+The workspace plugin must not be directly used. This plugin is used as the
+kind for a synthetic node representing the sources of an element with an open
+workspace. The node constructed would be specified as follows:
+
+.. code:: yaml
+
+ # Specify the workspace source kind
+ kind: workspace
+
+ # Specify the absolute path to the directory
+ path: /path/to/workspace
+"""
+
+import os
+from buildstream.storage.directory import Directory
+from buildstream import Source, SourceError, Consistency
+from buildstream import utils
+from buildstream.types import SourceRef
+
+
+class WorkspaceSource(Source):
+ # pylint: disable=attribute-defined-outside-init
+
+ BST_STAGE_VIRTUAL_DIRECTORY = True
+
+ def __init__(self, context, project, meta):
+ super().__init__(context, project, meta)
+
+ # Cached unique key to avoid multiple file system traversal if the unique key is requested multiple times.
+ self.__unique_key = None
+ self.__element_sources = []
+ self.__source_digest = None
+
+ def set_element_sources(self, _element_sources):
+ self.__element_sources = _element_sources
+
+ def get_element_sources(self):
+ return self.__element_sources
+
+ def track(self) -> SourceRef:
+ return self.__source_digest
+
+ def configure(self, node):
+ node.validate_keys(['path', 'ref', 'kind'])
+ self.path = node.get_str('path')
+ self.__source_digest = node.get_str('ref')
+
+ def preflight(self):
+ return
+
+ def get_ref(self) -> None:
+ return None
+
+ def load_ref(self, node) -> None:
+ pass # pragma: nocover
+
+ def set_ref(self, ref, node) -> None:
+ pass # pragma: nocover
+
+ def get_unique_key(self):
+ return (self.path, self.__source_digest)
+
+ def init_workspace(self, directory):
+ # for each source held by the workspace we must call init_workspace
+ # those sources may override `init_workspace` expecting str or Directory
+ # and this will need to be extracted from the directory passed to this method
+ assert isinstance(directory, Directory)
+ directory = directory.external_directory
+ for source in self.get_element_sources():
+ source._init_workspace(directory)
+
+ def get_consistency(self):
+ if self.__source_digest is None:
+ return Consistency.INCONSISTENT
+ return Consistency.RESOLVED
+
+ def fetch(self):
+ pass # pragma: nocover
+
+ def stage(self, directory):
+ # directory should always be a Directory object
+ assert isinstance(directory, Directory)
+ with self.timed_activity("Staging local files into CAS"):
+ if os.path.isdir(self.path) and not os.path.islink(self.path):
+ result = directory.import_files(self.path)
+ else:
+ result = directory.import_single_file(self.path)
+
+ if result.overwritten or result.ignored:
+ raise SourceError(
+ "Failed to stage source: files clash with existing directory",
+ reason='ensure-stage-dir-fail')
+
+ def _get_local_path(self):
+ return self.path
+
+
+# Create a unique key for a file
+def unique_key(filename):
+
+ # Return some hard coded things for files which
+ # have no content to calculate a key for
+ if os.path.islink(filename):
+ # For a symbolic link, use the link target as its unique identifier
+ return os.readlink(filename)
+ elif os.path.isdir(filename):
+ return "0"
+
+ return utils.sha256sum(filename)
+
+
+# Plugin entry point
+def setup():
+ return WorkspaceSource