| # |
| # Copyright Bloomberg Finance LP |
| # Copyright (C) 2018 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: |
| # Chandan Singh <csingh43@bloomberg.net> |
| # Tiago Gomes <tiago.gomes@codethink.co.uk> |
| |
| """ |
| patch - apply locally stored patches |
| ==================================== |
| |
| **Host dependencies:** |
| |
| * patch |
| |
| **Usage:** |
| |
| .. code:: yaml |
| |
| # Specify the local source kind |
| kind: patch |
| |
| # Specify the project relative path to a patch file |
| path: files/somefile.diff |
| |
| # Optionally specify the strip level, defaults to 1 |
| strip-level: 1 |
| |
| See :ref:`built-in functionality doumentation <core_source_builtins>` for |
| details on common configuration options for sources. |
| """ |
| |
| import os |
| from buildstream import Source, SourceError |
| from buildstream import utils |
| |
| |
| class PatchSource(Source): |
| # pylint: disable=attribute-defined-outside-init |
| |
| BST_MIN_VERSION = "2.0" |
| |
| BST_REQUIRES_PREVIOUS_SOURCES_STAGE = True |
| |
| def configure(self, node): |
| node.validate_keys(["path", "strip-level", *Source.COMMON_CONFIG_KEYS]) |
| self.path = self.node_get_project_path(node.get_scalar("path"), check_is_file=True) |
| self.strip_level = node.get_int("strip-level", default=1) |
| self.fullpath = os.path.join(self.get_project_directory(), self.path) |
| |
| def preflight(self): |
| # Check if patch is installed, get the binary at the same time |
| self.host_patch = utils.get_host_tool("patch") |
| |
| def get_unique_key(self): |
| return [self.path, utils.sha256sum(self.fullpath), self.strip_level] |
| |
| def is_resolved(self): |
| return True |
| |
| def is_cached(self): |
| return True |
| |
| def load_ref(self, node): |
| pass |
| |
| def get_ref(self): |
| return None # pragma: nocover |
| |
| def set_ref(self, ref, node): |
| pass # pragma: nocover |
| |
| def fetch(self): # pylint: disable=arguments-differ |
| # Nothing to do here for a local source |
| pass # pragma: nocover |
| |
| def stage(self, directory): |
| with self.timed_activity("Applying local patch: {}".format(self.path)): |
| |
| # Bail out with a comprehensive message if the target directory is empty |
| if not os.listdir(directory): |
| raise SourceError("Nothing to patch in directory '{}'".format(directory), reason="patch-no-files") |
| |
| strip_level_option = "-p{}".format(self.strip_level) |
| self.call( |
| [self.host_patch, strip_level_option, "-i", self.fullpath, "-d", directory], |
| fail="Failed to apply patch {}".format(self.path), |
| ) |
| |
| |
| # Plugin entry point |
| def setup(): |
| return PatchSource |