From cc7be86c788a5337ebce16365b9b51341b7cddc2 Mon Sep 17 00:00:00 2001 From: Adam Coldrick Date: Sun, 12 Apr 2015 11:33:32 +0000 Subject: Add a `morph get-repo` command to clone repositories from the cache Change-Id: I0c175649bd98067ea69d471ebe6880aac5a25598 --- morphlib/plugins/get_repo_plugin.py | 149 ++++++++++++++++++++++++++++++++++++ without-test-modules | 1 + 2 files changed, 150 insertions(+) create mode 100644 morphlib/plugins/get_repo_plugin.py diff --git a/morphlib/plugins/get_repo_plugin.py b/morphlib/plugins/get_repo_plugin.py new file mode 100644 index 00000000..63e75237 --- /dev/null +++ b/morphlib/plugins/get_repo_plugin.py @@ -0,0 +1,149 @@ +# -*- coding: utf-8 -*- +# Copyright © 2015 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program 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 General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program. If not, see . + + +import os + +import cliapp + +import morphlib + + +class DirectoryAlreadyExistsError(morphlib.Error): + + def __init__(self, chunk, dirname): + self.msg = ('Failed to clone repo for %s, destination directory %s ' + 'already exists.' % (chunk, dirname)) + + +class GetRepoPlugin(cliapp.Plugin): + + def enable(self): + self.app.add_subcommand( + 'get-repo', self.get_repo, arg_synopsis='CHUNK [PATH]') + self.app.settings.string(['ref', 'r'], + 'ref to checkout in the cloned repo', + metavar='REF', default='', + group='get-repo options') + + def disable(self): + pass + + def _clone_repo(self, cached_repo, dirname, checkout_ref): + '''Clone a cached git repository into the directory given by path.''' + # Do the clone. + gd = morphlib.gitdir.clone_from_cached_repo( + cached_repo, dirname, checkout_ref) + + # Configure the "origin" remote to use the upstream git repository, + # and not the locally cached copy. + resolver = morphlib.repoaliasresolver.RepoAliasResolver( + cached_repo.app.settings['repo-alias']) + remote = gd.get_remote('origin') + remote.set_fetch_url(resolver.pull_url(cached_repo.url)) + remote.set_push_url(resolver.push_url(cached_repo.original_name)) + + gd.update_submodules(self.app) + gd.update_remotes() + + def _get_chunk_dirname(self, path, sb, spec): + if path: + return path + else: + return sb.get_git_directory_name(spec['repo']) + + def get_repo(self, args): + '''Checkout a component repository. + + Command line arguments: + + * `CHUNK` is the name of a chunk + * `PATH` is the path at which the checkout will be located. + * `REF` is the ref to checkout. By default this is the ref defined in + the stratum containing the chunk. + + This makes a local checkout of CHUNK in PATH (or in the current system + branch if PATH isn't given). + + ''' + + if len(args) < 1: + raise cliapp.AppException('morph get-repo needs a chunk ' + 'as parameter: `morph get-repo ' + 'CHUNK [PATH]') + + chunk_name = args[0] + path = None + if len(args) > 1: + path = os.path.abspath(args[1]) + ref = self.app.settings['ref'] + + ws = morphlib.workspace.open('.') + sb = morphlib.sysbranchdir.open_from_within('.') + loader = morphlib.morphloader.MorphologyLoader() + + def checkout_chunk(morph, chunk_spec): + dirname = self._get_chunk_dirname(path, sb, chunk_spec) + if not os.path.exists(dirname): + self.app.status( + msg='Checking out ref %(ref)s of %(chunk)s in ' + '%(stratum)s stratum', + ref=ref or chunk_spec['ref'], chunk=chunk_spec['name'], + stratum=morph['name']) + lrc, rrc = morphlib.util.new_repo_caches(self.app) + cached_repo = lrc.get_updated_repo(chunk_spec['repo'], + chunk_spec['ref']) + + self._clone_repo(cached_repo, dirname, + ref or chunk_spec['ref']) + else: + raise DirectoryAlreadyExistsError(chunk_spec['name'], dirname) + + return dirname + + strata = set() + found = 0 + + self.app.status(msg='Loading in all morphologies') + for morph in sb.load_all_morphologies(loader): + if morph['kind'] == 'stratum': + for chunk in morph['chunks']: + if chunk['name'] == chunk_name: + if found >= 1: + self.app.status( + msg='Chunk %(chunk)s also found in ' + '%(stratum)s stratum.', + chunk=chunk_name, stratum=morph['name'], + chatty=True) + else: + chunk_dirname = checkout_chunk(morph, chunk) + strata.add(morph['name']) + found = found + 1 + + if found == 0: + self.app.status( + msg="No chunk %(chunk)s found. If you want to create one, add " + "an entry to a stratum morph file.", chunk=chunk_name) + + if found >= 1: + self.app.status( + msg="Chunk %(chunk)s source is available at %(dir)s", + chunk=chunk_name, dir=chunk_dirname) + + if found > 1: + self.app.status( + msg="Note that this chunk appears in more than one stratum: " + "%(strata)s", + strata=', '.join(strata)) diff --git a/without-test-modules b/without-test-modules index fb66ff69..f80a6caf 100644 --- a/without-test-modules +++ b/without-test-modules @@ -33,6 +33,7 @@ morphlib/plugins/add_binary_plugin.py morphlib/plugins/push_pull_plugin.py morphlib/plugins/distbuild_plugin.py morphlib/plugins/certify_plugin.py +morphlib/plugins/get_repo_plugin.py distbuild/__init__.py distbuild/build_controller.py distbuild/connection_machine.py -- cgit v1.2.1