summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Gomes <tiago.gomes@codethink.co.uk>2015-11-23 14:20:41 +0000
committerTiago Gomes <tiago.gomes@codethink.co.uk>2015-11-24 09:56:17 +0000
commit66860eb41001a8497375aad8b4ad592934eacb33 (patch)
tree1ae927fb6e3787b00f4fba433be49efec07e325d
parentcbc3d789a4573704863de3a0247f55eda8b28638 (diff)
downloadmorph-66860eb41001a8497375aad8b4ad592934eacb33.tar.gz
Remove branch-and-merge plugin
RIP. Change-Id: I6aac995415c5d67c60687367697173be52cd2bde
-rw-r--r--doc/branching-merging-systems.mdwn316
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py482
2 files changed, 0 insertions, 798 deletions
diff --git a/doc/branching-merging-systems.mdwn b/doc/branching-merging-systems.mdwn
deleted file mode 100644
index 3bc19aab..00000000
--- a/doc/branching-merging-systems.mdwn
+++ /dev/null
@@ -1,316 +0,0 @@
-Branching and merging at the system level in Baserock
-=====================================================
-
-NOTE: This is a spec. The code does not yet match it.
-
-As I write this, Baserock consists of just under 70 upstream projects,
-each of which we keep in their own git repository. We need a way to
-manage changes to them in a sensible manner, particularly when things
-touch more than one repository. What we need is a way to do branch
-and merge the whole system, across all our git repositories, with
-similar ease and efficiency as what git provides for an individual
-project. Where possible we need to allow the use of raw git so that
-we do not constrain our developers unnecessarily.
-
-There are other things we will want to do across all the Baserock git
-repositories, but that is outside the scope of this document, and will
-be dealt with later.
-
-A couple of use cases:
-
-* I have a problem on a particular device, and want to make changes to
- analyze and fix it. I need to branch the specific version of everything
- that was using the system image version that the device was running.
- I then want to be able to make changes to selected components and build
- the system with those changes. Everything I do not explicitly touch should
- stay at the same version.
-* I am developing Baserock and I want to fix something, or add a new
- feature, or other such change. I want to take the current newest
- version of everything (the mainline development branch, whatever it
- might be named), and make changes to some components, and build and
- test those changes. While I'm doing that, I don't want to get random
- other changes by other people, except when I explicitly ask for them
- (e.g. "git pull" on an individual repository.), to avoid unnecessary
- conflicts and building changes that don't affect my changes.
-
-In both users cases, when I'm done, I want to get my changes into the
-relevant branches. This might happen by merging my changes directly,
-by generating a pull request on a git server, or by generating a patch
-series for each affected repository to be mailed to people who can do
-the merging.
-
-Overview
---------
-
-We want a clear, convenient, and efficient way of working with multiple
-repositories and multiple projects at the same time. To manage this,
-we introduce the following concepts (FIXME: naming needs attention):
-
-* **git repository** is exactly the same as usually with git, as are
- all other concepts related to git
-* **system branch** is a collection of branches in individual git
- repositories that together form a particular line of development of
- the whole system; in other words, given all the git repositories
- that are part of Baserock, system branch `foo` consists of branch
- `foo` in each git repository that has a branch with that name
-* **system branch directory** contains git repositories relevant to
- a system branch; it need not contain all the repositories, just the
- ones that are being worked on by the user, or that the user for
- other reasons have checked out
-* **morph workspace** is where all Morph keeps global
- state and shared caches, so that creating a system branch directory
- is a fairly cheap operation; all the system branch directories are
- inside the morph workspace directory
-
-As a picture:
-
- /home/liw/ -- user's home directory
- baserock/ -- morph workspace
- .morph/ -- morph shared state, cache, etc
- unstable/ -- system branch directory: mainline devel
- morphs/ -- git repository for system, stratum morphs
- magnetic-frobbles/ -- system branch directory: new feature
- morphs/ -- system branch specific changes to morphs
- linux/ -- ditto for linux
-
-To use the system branching and merging, you do the following (which we'll
-cover in more detail later):
-
-1. Initialize the morph workspace. This creates the `.morph` directory and
- populates it with some initial stuff. You can have as many workspaces as
- you want, but you don't have to have more than one, and you only
- need to initialize it once.
-2. Branch the system from some version of it (e.g., `master`) to work
- on a new feature or bug fix.
- This creates a system branch directory under the workspace directory.
- The system branch directory initially contains a clone of the `morphs`
- git repository, with some changes specific to this system branch.
- (See petrification, below.)
-3. Edit one or more components (chunks) in the project. This typically
- requires adding more clones of git repositories inside the system
- branch directory.
-4. Build, test, and fix, repeating as necessary. This requires using
- git directly (not via morph) in the git repositories inside the
- system branch directory.
-5. Merge the changes to relevant target branches. Depending on what the
- change was, it may be necessary ot merge into many branches, e.g.,
- for each stable release branch.
-
-Walkthrough
------------
-
-Let's walk through what happens, making things more concrete. This is
-still fairly high level, and implementation details will come later.
-
- morph init ~/baserock
-
-This creates the `~/baserock` directory if it does not exist, and then
-initializes it as a "morph workspace" directory, by creating a `.morph`
-subdirectory. `.morph` will contain the Morph cache directory, and
-other shared state between the various branches. As part of the cache,
-any git repositories that Morph clones get put into the cache first,
-and cloned into the system branch directories from there (probably
-using hard-linking for speed), so that if there's a need for another
-clone of the repository, it does not need to be cloned from a server
-a second time.
-
- cd ~/baserock
- morph branch liw/foo
- morph branch liw/foo baserock/stable-1.0
- morph branch liw/foo --branch-off-system=/home/liw/system.img
-
-Create a new system branch, and the corresponding system branch
-directory. The three versions shown differ in the starting point
-of the branch: the first one uses the `master` branch in `morphs`,
-the second one uses the named branch instead, and the third one
-gets the SHA-1s from a system image file.
-
-Also, clone the `morphs` git repository inside the system branch
-directory.
-
- cd ~/baserock/liw/foo/morphs
- edit base-system.morph devel-system.morph
- git commit -a
-
-Modify the specified morphologies (or the stratum morphologies they
-refer to) to nail down the references to chunk repositories to use SHA-1s
-instead of branch names or whatever. The changes need to be committed
-to git manually, so that the user has a chance to give a good commit
-message.
-
-Petrification is useful to prevent the set of changes including changes
-by other team members. When a chunk is edited it will be made to refer
-to that ref instead of the SHA-1 that it is petrified to.
-
-Petrification can be done by resolving the chunk references against
-the current state of the git repositories, or it can be done by getting
-the SHA-1s directly from a system image, or a data file.
-
- cd ~/baserock/liw/foo
- morph edit linux
-
-Tell Morph that you want to edit a particular component (chunk).
-This will clone the repository into the system branch directory,
-at the point in history indicated by the morphologies in the
-local version of `morphs`.
-
- cd ~/baserock/liw/foo
- morph git -- log -p master..HEAD
-
-This allows running a git command in each git repository in a
-system branch directory. Morph may offer short forms ("morph status")
-as well, for things that are needed very commonly.
-
- cd ~/baserock/baserock/mainline
- morph merge liw/foo
-
-This merges the changes made in the `liw/foo` branch into the
-`baserock/mainline` branch. The petrification changes are automatically
-undone, since they're not going to be wanted in the merge.
-
- cd ~/baserock
- morph mass-merge liw/foo baserock/stable*
-
-Do the merge from `liw/foo` to every branch matching `baserock/stable*`
-(as expanded by the shell). This is a wrapper around the simpler
-`morph merge` command to make it easier to push a change into many
-branches (e.g., a security fix to all stable branches).
-
-
-Implementation: `morph init`
---------------
-
-Usage:
-
- morph init [DIR]
-
-DIR defaults to the current working directory. If DIR is given,
-but does not exist, it is created.
-
-* Create `DIR/.morph`.
-
-
-Implementation: `morph branch`
---------------
-
-Usage:
-
- morph branch BRANCH [COMMIT]
-
-This needs to be run in the morph workspace directory (the one initialized
-with `morph init`).
-
-* If `./BRANCH` as a directory exists, abort.
-* Create `./BRANCH` directory.
-* Clone the `morphs` repository to `BRANCH/morphs`.
-* Create a new branch called `BRANCH` in morphs, based either the tip of
- `master` or from `COMMIT` if given. Store the SHA-1 of the branch origin
- in some way so we get at it later.
-
-
-Implementation: `morph checkout`
---------------
-
-Usage:
-
- morph checkout BRANCH
-
-This needs to be run in the morph workspace directory. It works like
-`morph branch`, except it does not create the new branch and requires
-it to exist instead.
-
-* If `./BRANCH` as a directory exists, abort.
-* Create `./BRANCH` directory.
-* Clone the `morphs` repository to `BRANCH/morphs`.
-* Run `git checkout BRANCH` in the `morphs` repository.
-
-
-Implementation: `morph edit`
---------------
-
-Usage:
-
- morph edit REPO MORPH...
-
-where `REPO` is a chunk repository (absolute URL or one relative to one of
-the `git-base-url` values). The command must be run in the `morphs`
-directory of the system branch.
-
-* `git clone REPOURL` where the URL is constructed with `git-base-url`
- if necessary.
-* `git branch BRANCH REF` where `BRANCH` is the branch name given to
- `morph branch` and `REF` is the reference to the chunk we want to edit,
- as specified in morphologies.
-* Modify the affected morphologies to refer to the repository using
- the `BRANCH` name, and commit those changes.
-
-If the specified morphology is not a stratum morphology (that is, it is
-a system one), we check all the stratum morphologies mentioned and find
-the one that refers to the specified repository.
-
-Multiple morphologies can be specified. They must have the same original
-reference to the repository. However, they will all be modified.
-
-
-Implementation: `morph git`
---------------
-
-Usage:
-
- morph git -- log -p master..HEAD
-
-This is to be run in the morph workspace. It runs git with the arguments on
-the command line in each local git repository in the workspace. (The `--` is
-only necessary if the git arguments are to contain options.)
-
-
-Implementation: `morph merge`
---------------
-
-Usage:
-
- morph merge BRANCH
-
-This needs to be run inside a system branch directory's `morphs`
-repository, and `BRANCH` must be another system branch checked out
-in the morph workspace.
-
-* In each git repository modified by the `BRANCH` system branch,
- run `git merge --no-commit BRANCH`, then undo any changes to
- stratum morphologies made by `morph edit`, and finally commit
- the changes.
-
-
-Implementation: `morph mass-merge`
---------------
-
-Usage:
-
- morph mass-merge BRANCH [TARGET]...
-
-To be run in the morph workspace directory.
-
-This just runs `morph merge BRANCH` in each `TARGET` system branch.
-
-
-Implementation: `morph cherry-pick`
---------------
-
-Usage:
-
- morph cherry-pick BRANCH [COMMIT]...
- morph cherry-pick BRANCH --since-branch-point
-
-To be run in the system branch directory.
-
-In the first form:
-
-* For each git repository modified by the `BRANCH` system branch,
- run `git cherry-pick COMMIT` for each `COMMIT`.
-
-In the second form:
-
-* For each git repository modified by the `BRANCH` system branch,
- run `git cherry-pick` giving it a list of all commits made after
- the system branch was created.
-
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
deleted file mode 100644
index 6513e2eb..00000000
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ /dev/null
@@ -1,482 +0,0 @@
-# Copyright (C) 2012-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 cliapp
-import contextlib
-import glob
-import logging
-import os
-import shutil
-
-import morphlib
-
-
-class BranchAndMergePlugin(cliapp.Plugin):
-
- '''Add subcommands for handling workspaces and system branches.'''
-
- def enable(self):
- self.app.add_subcommand('init', self.init, arg_synopsis='[DIR]')
- self.app.add_subcommand('workspace', self.workspace, arg_synopsis='')
- self.app.add_subcommand(
- 'checkout', self.checkout, arg_synopsis='REPO BRANCH')
- self.app.add_subcommand(
- 'branch', self.branch, arg_synopsis='REPO NEW [OLD]')
- self.app.add_subcommand(
- 'show-system-branch', self.show_system_branch, arg_synopsis='')
- self.app.add_subcommand(
- 'show-branch-root', self.show_branch_root, arg_synopsis='')
- self.app.add_subcommand('status', self.status,
- arg_synopsis='')
- self.app.add_subcommand('branch-from-image', self.branch_from_image,
- arg_synopsis='BRANCH')
- group_branch = 'Branching Options'
- self.app.settings.string(['metadata-dir'],
- 'Set metadata location for branch-from-image'
- ' (default: /baserock)',
- metavar='DIR',
- default='/baserock',
- group=group_branch)
-
- def disable(self):
- pass
-
- def init(self, args):
- '''Initialize a workspace directory.
-
- Command line argument:
-
- * `DIR` is the directory to use as a workspace, and defaults to
- the current directory.
-
- This creates a workspace, either in the current working directory,
- or if `DIR` is given, in that directory. If the directory doesn't
- exist, it is created. If it does exist, it must be empty.
-
- You need to run `morph init` to initialise a workspace, or none
- of the other system branching tools will work: they all assume
- an existing workspace. Note that a workspace only exists on your
- machine, not on the git server.
-
- Example:
-
- morph init /src/workspace
- cd /src/workspace
-
- '''
-
- if not args:
- args = ['.']
- elif len(args) > 1:
- raise morphlib.Error('init must get at most one argument')
-
- ws = morphlib.workspace.create(args[0])
- self.app.status(msg='Initialized morph workspace', chatty=True)
-
- def workspace(self, args):
- '''Show the toplevel directory of the current workspace.'''
-
- ws = morphlib.workspace.open('.')
- self.app.output.write('%s\n' % ws.root)
-
- # TODO: Move this somewhere nicer
- @contextlib.contextmanager
- def _initializing_system_branch(self, ws, root_url, system_branch,
- cached_repo, base_ref):
- '''A context manager for system branches under construction.
-
- The purpose of this context manager is to factor out the branch
- cleanup code for if an exception occurs while a branch is being
- constructed.
-
- This could be handled by a higher order function which takes
- a function to initialize the branch as a parameter, but with
- statements look nicer and are more obviously about resource
- cleanup.
-
- '''
- root_dir = ws.get_default_system_branch_directory_name(system_branch)
- try:
- sb = morphlib.sysbranchdir.create(
- root_dir, root_url, system_branch)
- gd = sb.clone_cached_repo(cached_repo, base_ref)
-
- yield (sb, gd)
-
- gd.update_submodules(self.app)
- gd.update_remotes()
-
- except morphlib.sysbranchdir.SystemBranchDirectoryAlreadyExists as e:
- logging.error('Caught exception: %s' % str(e))
- raise
- except BaseException as e:
- # Oops. Clean up.
- logging.error('Caught exception: %s' % str(e))
- logging.info('Removing half-finished branch %s' % system_branch)
- self._remove_branch_dir_safe(ws.root, root_dir)
- raise
-
- def checkout(self, args):
- '''Check out an existing system branch.
-
- Command line arguments:
-
- * `REPO` is the URL to the repository to the root repository of
- a system branch.
- * `BRANCH` is the name of the system branch.
-
- This will check out an existing system branch to an existing
- workspace. You must create the workspace first. This only checks
- out the root repository, not the repositories for individual
- components. You need to use `morph edit` to check out those.
-
- Example:
-
- cd /src/workspace
- morph checkout baserock:baserock/morphs master
-
- '''
-
- if len(args) != 2:
- raise cliapp.AppException('morph checkout needs a repo and the '
- 'name of a branch as parameters')
-
- root_url = args[0]
- system_branch = args[1]
- base_ref = system_branch
-
- self._require_git_user_config()
-
- # Open the workspace first thing, so user gets a quick error if
- # we're not inside a workspace.
- ws = morphlib.workspace.open('.')
-
- # Make sure the root repository is in the local git repository
- # cache, and is up to date.
- lrc, rrc = morphlib.util.new_repo_caches(self.app)
- cached_repo = lrc.get_updated_repo(root_url)
-
- # Check the git branch exists.
- cached_repo.resolve_ref_to_commit(system_branch)
-
- with self._initializing_system_branch(
- ws, root_url, system_branch, cached_repo, base_ref) as (sb, gd):
-
- if gd.has_fat():
- gd.fat_init()
- gd.fat_pull()
-
-
- def branch(self, args):
- '''Create a new system branch.
-
- Command line arguments:
-
- * `REPO` is a repository URL.
- * `NEW` is the name of the new system branch.
- * `OLD` is the point from which to branch, and defaults to `master`.
-
- This creates a new system branch. It needs to be run in an
- existing workspace (see `morph workspace`). It creates a new
- git branch in the clone of the repository in the workspace. The
- system branch will not be visible on the git server until you
- push your changes to the repository.
-
- Example:
-
- cd /src/workspace
- morph branch baserock:baserock/morphs jrandom/new-feature
-
- '''
-
- if len(args) not in [2, 3]:
- raise cliapp.AppException(
- 'morph branch needs name of branch as parameter')
-
- root_url = args[0]
- system_branch = args[1]
- base_ref = 'master' if len(args) == 2 else args[2]
- origin_base_ref = 'origin/%s' % base_ref
-
- self._require_git_user_config()
-
- # Open the workspace first thing, so user gets a quick error if
- # we're not inside a workspace.
- ws = morphlib.workspace.open('.')
-
- # Make sure the root repository is in the local git repository
- # cache, and is up to date.
- lrc, rrc = morphlib.util.new_repo_caches(self.app)
- cached_repo = lrc.get_updated_repo(root_url)
-
- # Make sure the system branch doesn't exist yet.
- if cached_repo.ref_exists(system_branch):
- raise cliapp.AppException(
- 'branch %s already exists in repository %s' %
- (system_branch, root_url))
-
- # Make sure the base_ref exists.
- cached_repo.resolve_ref_to_commit(base_ref)
-
- with self._initializing_system_branch(
- ws, root_url, system_branch, cached_repo, base_ref) as (sb, gd):
-
- gd.branch(system_branch, base_ref)
- gd.checkout(system_branch)
- if gd.has_fat():
- gd.fat_init()
- gd.fat_pull()
-
- def _save_dirty_morphologies(self, loader, sb, morphs):
- logging.debug('Saving dirty morphologies: start')
- for morph in morphs:
- if morph.dirty:
- logging.debug(
- 'Saving morphology: %s %s %s' %
- (morph.repo_url, morph.ref, morph.filename))
- loader.unset_defaults(morph)
- loader.save_to_file(
- sb.get_filename(morph.repo_url, morph.filename), morph)
- morph.dirty = False
- logging.debug('Saving dirty morphologies: done')
-
- def show_system_branch(self, args):
- '''Show the name of the current system branch.'''
-
- ws = morphlib.workspace.open('.')
- sb = morphlib.sysbranchdir.open_from_within('.')
- self.app.output.write('%s\n' % sb.system_branch_name)
-
- def show_branch_root(self, args):
- '''Show the name of the repository holding the system morphologies.
-
- This would, for example, write out something like:
-
- /src/ws/master/baserock/baserock/definitions
-
- when the master branch of the `baserock/baserock/definitions`
- repository is checked out.
-
- '''
-
- ws = morphlib.workspace.open('.')
- sb = morphlib.sysbranchdir.open_from_within('.')
- repo_url = sb.get_config('branch.root')
- self.app.output.write('%s\n' % sb.get_git_directory_name(repo_url))
-
- def _remove_branch_dir_safe(self, workspace_root, system_branch_root):
- # This function avoids throwing any exceptions, so it is safe to call
- # inside an 'except' block without altering the backtrace.
-
- def handle_error(function, path, excinfo):
- logging.warning ("Error while trying to clean up %s: %s" %
- (path, excinfo))
-
- shutil.rmtree(system_branch_root, onerror=handle_error)
-
- # Remove parent directories that are empty too, avoiding exceptions
- parent = os.path.dirname(system_branch_root)
- while parent != os.path.abspath(workspace_root):
- if len(os.listdir(parent)) > 0 or os.path.islink(parent):
- break
- os.rmdir(parent)
- parent = os.path.dirname(parent)
-
- def _require_git_user_config(self):
- '''Warn if the git user.name and user.email variables are not set.'''
-
- keys = {
- 'user.name': 'My Name',
- 'user.email': 'me@example.com',
- }
-
- try:
- morphlib.git.check_config_set(self.app.runcmd, keys)
- except morphlib.git.ConfigNotSetException as e:
- self.app.status(
- msg="WARNING: %(message)s",
- message=str(e), error=True)
-
- def _load_all_sysbranch_morphologies(self, sb, loader):
- '''Read in all the morphologies in the root repository.'''
- self.app.status(msg='Loading in all morphologies')
- morphs = morphlib.morphset.MorphologySet()
- for morph in sb.load_all_morphologies():
- morphs.add_morphology(morph)
- return morphs
-
- def status(self, args):
- '''Show information about the current system branch or workspace
-
- This shows the status of every local git repository of the
- current system branch. This is similar to running `git status`
- in each repository separately.
-
- If run in a Morph workspace, but not in a system branch checkout,
- it lists all checked out system branches in the workspace.
-
- '''
-
- if args:
- raise cliapp.AppException('morph status takes no arguments')
-
- ws = morphlib.workspace.open('.')
- try:
- sb = morphlib.sysbranchdir.open_from_within('.')
- except morphlib.sysbranchdir.NotInSystemBranch:
- self._workspace_status(ws)
- else:
- self._branch_status(ws, sb)
-
- def _workspace_status(self, ws):
- '''Show information about the current workspace
-
- This lists all checked out system branches in the workspace.
-
- '''
- self.app.output.write("System branches in current workspace:\n")
- branches = sorted(ws.list_system_branches(),
- key=lambda x: x.root_directory)
- for sb in branches:
- self.app.output.write(" %s\n" % sb.get_config('branch.name'))
-
- def _branch_status(self, ws, sb):
- '''Show information about the current branch
-
- This shows the status of every local git repository of the
- current system branch. This is similar to running `git status`
- in each repository separately.
-
- '''
- branch = sb.get_config('branch.name')
- root = sb.get_config('branch.root')
-
- self.app.output.write("On branch %s, root %s\n" % (branch, root))
-
- has_uncommitted_changes = False
- for gd in sorted(sb.list_git_directories(), key=lambda x: x.dirname):
- try:
- repo = gd.get_config('morph.repository')
- except cliapp.AppException:
- self.app.output.write(
- ' %s: not part of system branch\n' % gd.dirname)
- # TODO: make this less vulnerable to a branch using
- # refs/heads/foo instead of foo
- head = gd.HEAD
- if head != branch:
- self.app.output.write(
- ' %s: unexpected ref checked out %r\n' % (repo, head))
- if any(gd.get_index().get_uncommitted_changes()):
- has_uncommitted_changes = True
- self.app.output.write(' %s: uncommitted changes\n' % repo)
-
- if not has_uncommitted_changes:
- self.app.output.write("\nNo repos have outstanding changes.\n")
-
- def branch_from_image(self, args):
- '''Produce a branch of an existing system image.
-
- Given the metadata specified by --metadata-dir, create a new
- branch then petrify it to the state of the commits at the time
- the system was built.
-
- If --metadata-dir is not specified, it defaults to your currently
- running system.
-
- '''
- if len(args) != 1:
- raise cliapp.AppException(
- "branch-from-image needs exactly 1 argument "
- "of the new system branch's name")
- system_branch = args[0]
- metadata_path = self.app.settings['metadata-dir']
- alias_resolver = morphlib.repoaliasresolver.RepoAliasResolver(
- self.app.settings['repo-alias'])
-
- self._require_git_user_config()
-
- ws = morphlib.workspace.open('.')
-
- system, metadata = self._load_system_metadata(metadata_path)
- resolved_refs = dict(self._resolve_refs_from_metadata(alias_resolver,
- metadata))
- self.app.status(msg='Resolved refs: %r' % resolved_refs)
- base_ref = system['sha1']
- # The previous version would fall back to deducing this from the repo
- # url and the repo alias resolver, but this does not always work, and
- # new systems always have repo-alias in the metadata
- root_url = system['repo-alias']
-
- lrc, rrc = morphlib.util.new_repo_caches(self.app)
- cached_repo = lrc.get_updated_repo(root_url)
-
-
- with self._initializing_system_branch(
- ws, root_url, system_branch, cached_repo, base_ref) as (sb, gd):
-
- # TODO: It's nasty to clone to a sha1 then create a branch
- # of that sha1 then check it out, a nicer API may be the
- # initial clone not checking out a branch at all, then
- # the user creates and checks out their own branches
- gd.branch(system_branch, base_ref)
- gd.checkout(system_branch)
-
- loader = sb.get_morphology_loader()
- morphs = self._load_all_sysbranch_morphologies(sb, loader)
-
- morphs.repoint_refs(sb.root_repository_url,
- sb.system_branch_name)
-
- morphs.petrify_chunks(resolved_refs)
-
- self._save_dirty_morphologies(loader, sb, morphs.morphologies)
-
- @staticmethod
- def _load_system_metadata(path):
- '''Load all metadata in `path` corresponding to a single System.
- '''
-
- smd = morphlib.systemmetadatadir.SystemMetadataDir(path)
- metadata = smd.values()
- systems = [md for md in metadata
- if 'kind' in md and md['kind'] == 'system']
-
- if not systems:
- raise cliapp.AppException(
- 'Metadata directory does not contain any systems.')
- if len(systems) > 1:
- raise cliapp.AppException(
- 'Metadata directory contains multiple systems.')
- system_metadatum = systems[0]
-
- metadata_cache_id_lookup = dict((md['cache-key'], md)
- for md in metadata
- if 'cache-key' in md)
-
- return system_metadatum, metadata_cache_id_lookup
-
- @staticmethod
- def _resolve_refs_from_metadata(alias_resolver, metadata):
- '''Pre-resolve a set of refs from existing metadata.
-
- Given the metadata, generate a mapping of all the (repo, ref)
- pairs defined in the metadata and the commit id they resolved to.
-
- '''
- for md in metadata.itervalues():
- repourls = set((md['repo-alias'], md['repo']))
- repourls.update(alias_resolver.aliases_from_url(md['repo']))
- for repourl in repourls:
- yield ((repourl, md['original_ref']), md['sha1'])