diff options
author | Darius Makovsky <traveltissues@protonmail.com> | 2019-09-05 14:22:19 +0100 |
---|---|---|
committer | Darius Makovsky <traveltissues@protonmail.com> | 2019-09-20 16:38:24 +0100 |
commit | 46cb41e71ece062f8ee4d80ee17154146f197c7f (patch) | |
tree | 0536ec92949c481f271821477f53aab3211aa57b | |
parent | fc0136c62bf065a94e7fe192a673e708dc0778c7 (diff) | |
download | buildstream-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.py | 138 |
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 |