summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdam Coldrick <adam@sotk.co.uk>2015-04-12 11:33:32 +0000
committerBaserock Gerrit <gerrit@baserock.org>2015-04-27 15:42:40 +0000
commitcc7be86c788a5337ebce16365b9b51341b7cddc2 (patch)
tree2f3046c58db0be89884251bdf07afc414851af92
parentb0301d608ff73e6bc70d4ca700846b778c5db374 (diff)
downloadmorph-cc7be86c788a5337ebce16365b9b51341b7cddc2.tar.gz
Add a `morph get-repo` command to clone repositories from the cache
Change-Id: I0c175649bd98067ea69d471ebe6880aac5a25598
-rw-r--r--morphlib/plugins/get_repo_plugin.py149
-rw-r--r--without-test-modules1
2 files changed, 150 insertions, 0 deletions
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 <http://www.gnu.org/licenses/>.
+
+
+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