diff options
author | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2018-02-20 18:39:36 +0900 |
---|---|---|
committer | Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> | 2018-03-20 17:46:41 +0900 |
commit | a39927a8ffb3a86489cfca5bc4953dfeab4b9fee (patch) | |
tree | 3fb9965520cd12c1d647189ee007c46e8a7b0515 /buildstream/_projectrefs.py | |
parent | 1fbedea8ce1a32e5e9bb86479add3c24ba8b1f36 (diff) | |
download | buildstream-a39927a8ffb3a86489cfca5bc4953dfeab4b9fee.tar.gz |
_projectrefs.py: Adding the ProjectRefs refs management object
This object manages the project.refs file in a project directory.
Diffstat (limited to 'buildstream/_projectrefs.py')
-rw-r--r-- | buildstream/_projectrefs.py | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/buildstream/_projectrefs.py b/buildstream/_projectrefs.py new file mode 100644 index 000000000..bf58e1e81 --- /dev/null +++ b/buildstream/_projectrefs.py @@ -0,0 +1,165 @@ +#!/usr/bin/env python3 +# +# 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: +# Tristan Van Berkom <tristan.vanberkom@codethink.co.uk> +import os +from collections import Mapping + +from . import _yaml +from ._exceptions import LoadError, LoadErrorReason + + +# ProjectRefStorage() +# +# Indicates the type of ref storage +class ProjectRefStorage(): + + # Source references are stored inline + # + INLINE = 'inline' + + # Source references are stored in a central project.refs file + # + PROJECT_REFS = 'project.refs' + + +# ProjectRefs() +# +# The project.refs file management +# +class ProjectRefs(): + + def __init__(self, directory): + + self.directory = os.path.abspath(directory) + self.fullpath = os.path.join(self.directory, "project.refs") + + self.toplevel_node = None + self.toplevel_save = None + + # load() + # + # Load the project.refs file + # + # Args: + # options (OptionPool): To resolve conditional statements + # + def load(self, options): + + try: + self.toplevel_node = _yaml.load(self.fullpath, shortname='project.refs', copy_tree=True) + provenance = _yaml.node_get_provenance(self.toplevel_node) + self.toplevel_save = provenance.toplevel + + # Process any project options immediately + options.process_node(self.toplevel_node) + + # Run any final assertions on the project.refs, just incase there + # are list composition directives or anything left unprocessed. + _yaml.node_final_assertions(self.toplevel_node) + + except LoadError as e: + if e.reason != LoadErrorReason.MISSING_FILE: + raise + + # Ignore failure if the file doesnt exist, it'll be created and + # for now just assumed to be empty + self.toplevel_node = {} + self.toplevel_save = self.toplevel_node + + _yaml.node_validate(self.toplevel_node, ['projects']) + + # Ensure we create our toplevel entry point on the fly here + for node in [self.toplevel_node, self.toplevel_save]: + if 'projects' not in node: + node['projects'] = {} + + # save() + # + # Save the project.refs file with any local changes + # + def save(self): + _yaml.dump(self.toplevel_save, self.fullpath) + + # lookup_ref() + # + # Fetch the ref node for a given Source. If the ref node does not + # exist and `write` is specified, it will be automatically created. + # + # Args: + # project (str): The project to lookup + # element (str): The element name to lookup + # source_index (int): The index of the Source in the specified element + # write (bool): Whether we want to read the node or write to it + # + # Returns: + # (node): The YAML dictionary where the ref is stored + # + def lookup_ref(self, project, element, source_index, *, write=False): + + node = self._lookup(self.toplevel_node, project, element, source_index) + + if write: + + if node is not None: + provenance = _yaml.node_get_provenance(node) + if provenance: + node = provenance.node + + # If we couldnt find the orignal, create a new one. + # + if node is None: + node = self._lookup(self.toplevel_save, project, element, source_index, ensure=True) + + return node + + # _lookup() + # + # Looks up a ref node in the project.refs file, creates one if ensure is True. + # + def _lookup(self, toplevel, project, element, source_index, *, ensure=False): + + # Fetch the project + try: + project_node = toplevel['projects'][project] + except KeyError: + if not ensure: + return None + project_node = toplevel['projects'][project] = {} + + # Fetch the element + try: + element_list = project_node[element] + except KeyError: + if not ensure: + return None + element_list = project_node[element] = [] + + # Fetch the source index + try: + node = element_list[source_index] + except IndexError: + if not ensure: + return None + + # Pad the list with empty newly created dictionaries + element_list.extend({} for _ in range(len(element_list), source_index + 1)) + + node = element_list[source_index] + + return node |