summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--morphlib/plugins/artifact_inspection_plugin.py46
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py281
-rw-r--r--morphlib/plugins/build_plugin.py23
-rw-r--r--morphlib/plugins/copy-artifacts_plugin.py43
-rw-r--r--morphlib/plugins/deploy_plugin.py159
-rw-r--r--morphlib/plugins/expand_repo_plugin.py24
-rw-r--r--morphlib/plugins/graphing_plugin.py30
-rw-r--r--morphlib/plugins/show_dependencies_plugin.py13
-rw-r--r--morphlib/plugins/trovectl_plugin.py23
-rw-r--r--morphlib/plugins/update_gits_plugin.py17
10 files changed, 618 insertions, 41 deletions
diff --git a/morphlib/plugins/artifact_inspection_plugin.py b/morphlib/plugins/artifact_inspection_plugin.py
index f3417058..0d850319 100644
--- a/morphlib/plugins/artifact_inspection_plugin.py
+++ b/morphlib/plugins/artifact_inspection_plugin.py
@@ -257,13 +257,26 @@ class ArtifactInspectionPlugin(cliapp.Plugin):
arg_synopsis='ARTIFACT CMD')
self.app.add_subcommand('generate-manifest',
self.generate_manifest,
- arg_synopsis='ROOTFS_ARTIFACT')
+ arg_synopsis='SYSTEM-ARTIFACT')
def disable(self):
pass
def run_in_artifact(self, args):
- '''Run a command inside an extracted/mounted chunk or system.'''
+ '''Run a command inside an extracted/mounted chunk or system.
+
+ Command line arguments:
+
+ * `ARTIFACT` is a filename for the artifact.
+ * `CMD` is the command to run.
+
+ run-in-artifact unpacks an artifact, and runs a command in
+ the temporary directory it was unpacked to.
+
+ The command must be given to Morph as a single argument, so
+ use shell quoting appropriately.
+
+ '''
if len(args) < 2:
raise cliapp.AppException(
@@ -279,7 +292,34 @@ class ArtifactInspectionPlugin(cliapp.Plugin):
call_in_artifact_directory(self.app, artifact, run_command_in_dir)
def generate_manifest(self, args):
- '''Generate a content manifest for a system image.'''
+ '''Generate a content manifest for a system image.
+
+ Command line arguments:
+
+ * `SYSTEM-ARTIFACT` is a filename to the system artifact
+ (root filesystem) for the built system.
+
+ This command generates a manifest for a built system image.
+ The manifest includes the constituent artifacts,
+ a guess at the component version, the exact commit for
+ the component (commit SHA1, repository URL, git symbolic
+ ref), and the morphology filename.
+
+
+ The manifest includes each constituent artifact, with several
+ columns of data:
+
+ * 7-char cache key with the artifact kind (system, stratum, chunk),
+ artifact name, and version (if guessable) added
+ * the git repository
+ * the symbolic reference
+ * a 7-char commit id
+
+ Example:
+
+ morph generate-manifest /src/cache/artifacts/foo-rootfs
+
+ '''
if len(args) != 1:
raise cliapp.AppException('morph generate-manifest expects '
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 230367fb..f25e73e6 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -68,7 +68,8 @@ class BranchAndMergePlugin(cliapp.Plugin):
arg_synopsis='SYSTEM STRATUM [CHUNK]')
self.app.add_subcommand('petrify', self.petrify)
self.app.add_subcommand('unpetrify', self.unpetrify)
- self.app.add_subcommand('tag', self.tag)
+ self.app.add_subcommand(
+ 'tag', self.tag, arg_synopsis='TAG-NAME -- [GIT-COMMIT-ARG...]')
self.app.add_subcommand('build', self.build,
arg_synopsis='SYSTEM')
self.app.add_subcommand('status', self.status)
@@ -547,7 +548,28 @@ class BranchAndMergePlugin(cliapp.Plugin):
return system_key, metadata_cache_id_lookup
def init(self, args):
- '''Initialize a workspace directory.'''
+ '''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 = ['.']
@@ -610,7 +632,26 @@ class BranchAndMergePlugin(cliapp.Plugin):
@warns_git_identity
def branch(self, args):
- '''Create a new system branch.'''
+ '''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 '
@@ -631,7 +672,25 @@ class BranchAndMergePlugin(cliapp.Plugin):
@warns_git_identity
def checkout(self, args):
- '''Check out an existing system branch.'''
+ '''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 '
@@ -703,7 +762,65 @@ class BranchAndMergePlugin(cliapp.Plugin):
@warns_git_identity
def edit(self, args):
- '''Edit a component in a system branch.'''
+ '''Edit or checkout a component in a system branch.
+
+ Command line arguments:
+
+ * `SYSTEM` is the name of a system morphology in the root repository
+ of the current system branch.
+ * `STRATUM` is the name of a stratum inside the system.
+ * `CHUNK` is the name of a chunk inside the stratum.
+
+ This marks the specified stratum or chunk (if given) as being
+ changed within the system branch, by creating the git branches in
+ the affected repositories, and changing the relevant morphologies
+ to point at those branches. It also creates a local clone of
+ the git repository of the stratum or chunk.
+
+ For example:
+
+ morph edit devel-system-x86-64-generic devel
+
+ The above command will mark the `devel` stratum as being
+ modified in the current system branch. In this case, the stratum's
+ morphology is in the same git repository as the system morphology,
+ so there is no need to create a new git branch. However, the
+ system morphology is modified to point at the stratum morphology
+ in the same git branch, rather than the original branch.
+
+ In other words, where the system morphology used to say this:
+
+ morph: devel
+ repo: baserock:baserock/morphs
+ ref: master
+
+ The updated system morphology will now say this instead:
+
+ morph: devel
+ repo: baserock:baserock/morphs
+ ref: jrandom/new-feature
+
+ (Assuming the system branch is called `jrandom/new-feature`.)
+
+ Another example:
+
+ morph edit devel-system-x86_64-generic devel gcc
+
+ The above command will mark the `gcc` chunk as being edited in
+ the current system branch. Morph will clone the `gcc` repository
+ locally, into the current workspace, and create a new (local)
+ branch named after the system branch. It will also change the
+ stratum morphology to refer to the new git branch, instead of
+ whatever branch it was referring to originally.
+
+ If the `gcc` repository already had a git branch named after
+ the system branch, that is reused. Similarly, if the stratum
+ morphology was already pointing that that branch, it doesn't
+ need to be changed again. In that case, the only action Morph
+ does is to clone the chunk repository locally, and if that was
+ also done already, Morph does nothing.
+
+ '''
if len(args) not in (2, 3):
raise cliapp.AppException(
@@ -910,10 +1027,42 @@ class BranchAndMergePlugin(cliapp.Plugin):
update_working_tree=True)
def petrify(self, args):
- '''Convert all chunk refs in a system branch to be fixed SHA1s
+ '''Convert all chunk refs in a system branch to be fixed SHA1s.
+
+ This modifies all git commit references in system and stratum
+ morphologies, in the current system branch, to be fixed SHA
+ commit identifiers, rather than symbolic branch or tag names.
+ This is useful for making sure none of the components in a system
+ branch change accidentally.
+
+ Consider the following scenario:
+
+ * The `master` system branch refers to `gcc` using the
+ `baserock/morph` ref. This is appropriate, since the main line
+ of development should use the latest curated code.
+
+ * You create a system branch to prepare for a release, called
+ `TROVE_ID/release/2.0`. The reference to `gcc` is still
+ `baserock/morph`.
+
+ * You test everything, and make a release. You deploy the release
+ images onto devices, which get shipped to your customers.
+
+ * A new version GCC is committed to the `baserock/morph` branch.
+
+ * Your release branch suddenly uses a new compiler, which may
+ or may not work for your particular system at that release.
+
+ To avoid this, you need to _petrify_ all git references
+ so that they do not change accidentally. If you've tested
+ your release with the GCC release that is stored in commit
+ `94c50665324a7aeb32f3096393ec54b2e63bfb28`, then you should
+ continue to use that version of GCC, regardless of what might
+ happen in the master system branch. If, and only if, you decide
+ that a new compiler would be good for your release should you
+ include it in your release branch. This way, only the things
+ that you change intentionally change in your release branch.
- This isolates the branch from changes made by other developers in the
- chunk repositories.
'''
# Stratum refs are not petrified, because they must all be edited to
@@ -934,7 +1083,11 @@ class BranchAndMergePlugin(cliapp.Plugin):
branch, os.environ, None, True)
def unpetrify(self, args):
- '''Reverse the process of petrification'''
+ '''Reverse the process of petrification.
+
+ This undoes the changes `morph petrify` did.
+
+ '''
# This function makes no attempt to 'unedit' strata that were branched
# solely so they could be petrified.
@@ -977,6 +1130,26 @@ class BranchAndMergePlugin(cliapp.Plugin):
@warns_git_identity
def tag(self, args):
+ '''Create an annotated Git tag of a petrified system branch.
+
+ Command line arguments:
+
+ * `TAG-NAME` is the name of the Git tag to be created.
+ * `--` separates the Git arguments and options from the ones
+ Morph parses for itself.
+ * `GIT-COMMIT-ARG` is a `git commit` option or argument,
+ e.g., '-m' or '-F'. These should provide the commit message.
+
+ This command creates an annotated Git tag that points at a commit
+ where all system and stratum morphologies have been petrified.
+ The working tree won't be petrified, only the commit.
+
+ Example:
+
+ morph tag release-12.765 -- -m "Release 12.765"
+
+ '''
+
if len(args) < 1:
raise cliapp.AppException('morph tag expects a tag name')
@@ -1344,8 +1517,20 @@ class BranchAndMergePlugin(cliapp.Plugin):
def merge(self, args):
'''Pull and merge changes from a system branch into the current one.
- The remote branch is pulled from the current workspace into the target
- repositories (so any local commits are included).
+ Command line arguments:
+
+ * `BRANCH` is the name of the system branch to merge _from_.
+
+ This merges another system branch into the current one. Morph
+ will do a `git merge` for each component that has been edited,
+ and undo any changes to `ref` fields in system and stratum
+ morphologies that `morph edit` has made.
+
+ You need to be in the _target_ system branch when merging. If
+ you have two system branches, `TROVE_ID/release/1.2` and
+ `TROVE_ID/bugfixes/12765`, and want to merge the bug fix branch
+ into the release branch, you need to first checkout the release
+ system branch, and then merge the bugfix branch into that.
'''
@@ -1478,7 +1663,31 @@ class BranchAndMergePlugin(cliapp.Plugin):
raise
def build(self, args):
- '''Build a system from the current system branch'''
+ '''Build a system image in the current system branch
+
+ Command line arguments:
+
+ * `SYSTEM` is the name of the system to build.
+
+ This builds a system image, and any of its components that
+ need building. The system name is the basename of the system
+ morphology, in the root repository of the current system branch,
+ without the `.morph` suffix in the filename.
+
+ The location of the resulting system image artifact is printed
+ at the end of the build output.
+
+ You do not need to commit your changes before building, Morph
+ does that for you, in a temporary branch for each build. However,
+ note that Morph does not untracked files to the temporary branch,
+ only uncommitted changes to files git already knows about. You
+ need to `git add` and commit each new file yourself.
+
+ Example:
+
+ morph build devel-system-x86_64-generic
+
+ '''
if len(args) != 1:
raise cliapp.AppException('morph build expects exactly one '
@@ -1726,7 +1935,17 @@ class BranchAndMergePlugin(cliapp.Plugin):
':%s' % info['build-ref']], cwd=info['dirname'])
def status(self, args):
- '''Show information about the current system branch or workspace'''
+ '''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, but the output is nicer.
+
+ If run in a Morph workspace, but not in a system branch checkout,
+ it lists all checked out system branches in the workspace.
+
+ '''
+
if len(args) != 0:
raise cliapp.AppException('morph status takes no arguments')
@@ -1770,11 +1989,30 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.app.output.write("\nNo repos have outstanding changes.\n")
def foreach(self, args):
- '''Run a command in each repository checked out in a system branch
+ '''Run a command in each repository checked out in a system branch.
Use -- before specifying the command to separate its arguments from
Morph's own arguments.
+ Command line arguments:
+
+ * `--` indicates the end of option processing for Morph.
+ * `COMMAND` is a command to run.
+ * `ARG` is a command line argument or option to be passed onto
+ `COMMAND`.
+
+ This runs the given `COMMAND` in each git repository belonging
+ to the current system branch that exists locally in the current
+ workspace. This can be a handy way to do the same thing in all
+ the local git repositories.
+
+ For example:
+
+ morph foreach -- git push
+
+ The above command would push any committed changes in each
+ repository to the git server.
+
'''
# For simplicity, this simply iterates repositories in the directory
@@ -1807,18 +2045,27 @@ class BranchAndMergePlugin(cliapp.Plugin):
'Command failed at repo %s: %s' % (repo, ' '.join(args)))
def workspace(self, args):
- '''Find the toplevel directory of the current workspace'''
+ '''Show the toplevel directory of the current workspace.'''
self.app.output.write('%s\n' % self.deduce_workspace())
def show_system_branch(self, args):
- '''Print name of current system branch'''
+ '''Show the name of the current system branch.'''
branch, dirname = self.deduce_system_branch()
self.app.output.write('%s\n' % branch)
def show_branch_root(self, args):
- '''Print name of the repository holding the system morphologies'''
+ '''Show the name of the repository holding the system morphologies.
+
+ This would, for example, write out something like:
+
+ /src/ws/master/baserock:baserock/morphs
+
+ when the master branch of the `baserock:baserock/morphs`
+ repository is checked out.
+
+ '''
workspace = self.deduce_workspace()
system_branch, branch_dir = self.deduce_system_branch()
diff --git a/morphlib/plugins/build_plugin.py b/morphlib/plugins/build_plugin.py
index 128187cf..e9555888 100644
--- a/morphlib/plugins/build_plugin.py
+++ b/morphlib/plugins/build_plugin.py
@@ -29,10 +29,27 @@ class BuildPlugin(cliapp.Plugin):
pass
def build_morphology(self, args):
- '''Build a system, outside of a system branch
+ '''Build a system, outside of a system branch.
- Command line arguments are the repository, git ref,
- and morphology filename.
+ Command line arguments:
+
+ * `REPO` is a git repository URL.
+ * `REF` is a branch or other commit reference in that repository.
+ * `FILENAME` is a morphology filename at that ref.
+
+ You probably want `morph build` instead. However, in some
+ cases it is more convenient to not have to create a Morph
+ workspace and check out the relevant system branch, and only
+ just run the build. For those times, this command exists.
+
+ This subcommand does not automatically commit changes to a
+ temporary branch, so you can only build from properly committed
+ sources that have been pushed to the git server.
+
+ Example:
+
+ morph build-morphology baserock:baserock/morphs \
+ master devel-system-x86_64-generic
'''
diff --git a/morphlib/plugins/copy-artifacts_plugin.py b/morphlib/plugins/copy-artifacts_plugin.py
index ab51e522..577d0ef2 100644
--- a/morphlib/plugins/copy-artifacts_plugin.py
+++ b/morphlib/plugins/copy-artifacts_plugin.py
@@ -37,16 +37,29 @@ class CopyArtifactsPlugin(cliapp.Plugin):
def enable(self):
self.app.add_subcommand(
'list-artifacts', self.list_artifacts,
- arg_synopsis='SYSTEM')
+ arg_synopsis='SYSTEM-ARTIFACT')
self.app.add_subcommand(
'copy-artifacts', self.copy_artifacts,
- arg_synopsis='SYSTEM DESTINATION')
+ arg_synopsis='SYSTEM-ARTIFACT DESTINATION')
def disable(self):
pass
def list_artifacts(self, args):
- '''List every artifact that makes up a system'''
+ '''List every artifact that makes up a system artifact.
+
+ Command line arguments:
+
+ * `SYSTEM-ARTIFACT` is the filename for a build artifact for
+ a system (ending in `-rootfs`).
+
+ list-artifacts reads the system artifact and writes out a list
+ of the filenames, in the local artifact cache, of all the
+ component artifacts included in the system. It does not include
+ build-dependencies of the system, unless they're included in
+ the system.
+
+ '''
if len(args) != 1:
raise cliapp.AppException(
@@ -59,7 +72,29 @@ class CopyArtifactsPlugin(cliapp.Plugin):
self.app.output.write(artifact + "\n")
def copy_artifacts(self, args):
- '''Copy every artifact that makes up a system to an rsync path'''
+ '''Copy every artifact that makes up a system to an rsync path.
+
+ Command line arguments:
+
+ * `SYSTEM-ARTIFACT` is the filename for a build artifact for
+ a system (ending in `-rootfs`).
+ * `DESTINATION` is a URL for where the artifacts are to be
+ copied to, in a form suitable for the rsync program.
+
+ This command is useful for copying artifacts from a local
+ system to a Morph artifact cache server, so they can be
+ shared by other people. It can also be used to archive
+ artifacts used for a release. Note, however, that it does
+ not include artifacts that are build-dependencies of the
+ strata included in the system, but not actually in cluded
+ in the system.
+
+ Example:
+
+ morph copy-artifacts /src/cache/artifacts/*.system.* \
+ cache.example.com:/srv/cache/
+
+ '''
if len(args) != 2:
raise cliapp.AppException(
diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py
index a0ead149..f9560b91 100644
--- a/morphlib/plugins/deploy_plugin.py
+++ b/morphlib/plugins/deploy_plugin.py
@@ -49,16 +49,161 @@ class DeployPlugin(cliapp.Plugin):
def deploy(self, args):
'''Deploy a built system image.
-
- Command requires a minimum of three arguments:
- morph deploy TYPE SYSTEM LOCATION
+ Command line arguments:
+
+ * `TYPE` is the type of deployment: to a raw disk image,
+ VirtualBox, or something else. See below.
+
+ * `SYSTEM` is the name of the system morphology to deploy.
+
+ * `LOCATION` is where the deployed system should end up at. The
+ syntax depends on the deployment type. See below.
+
+ * `KEY=VALUE` is a configuration parameter to pass onto the
+ configuration extension. See below.
+
+ Morph can deploy a system image. The deployment mechanism is
+ quite flexible, and can be extended by the user. "Deployment"
+ here is quite a general concept: it covers anything where a system
+ image is taken, configured, and then put somewhere where it can
+ be run.
+
+ `TYPE` specifies the exact way in which the deployment happens.
+ Morph provides four deployment types:
+
+ * `rawdisk` where Morph builds a raw disk image at `LOCATION`,
+ and sets up the image with a bootloader and configuration
+ so that it can be booted. Disk size is set with `DISK_SIZE`
+ (see below).
+
+ * `virtualbox-ssh` where Morph creates a VirtualBox disk image,
+ and creates a new virtual machine on a remote host, accessed
+ over ssh. Disk and RAM size are set with `DISK_SIZE` and
+ `RAM_SIZE` (see below).
+
+ * `kvm`, which is similar to `virtualbox-ssh`, but uses libvirt
+ and KVM instead of VirtualBox. Disk and RAM size are set with
+ `DISK_SIZE` and `RAM_SIZE` (see below).
+
+ * `nfsboot` where Morph creates a system to be booted over
+ a network
+
+ The following `KEY=VALUE` parameters are supported for all
+ deployment types:
+
+ * `DISK_SIZE=X` to set the size of the disk image. `X`
+ should use a suffix of `K`, `M`, or `G` (in upper or lower
+ case) to indicate kilo-, mega-, or gigabytes. For example,
+ `DISK_SIZE=100G` would create a 100 gigabyte disk image. **This
+ parameter is mandatory**.
+
+ * `RAM_SIZE=X` to set the size of virtual RAM for the virtual
+ machine. `X` is interpreted in the same was as `DISK_SIZE`,
+ and defaults to `1G`.
+
+ The `kvm` and `virtualbox-ssh` deployment types support an
+ additional parameter:
+
+ * `AUTOSTART=<VALUE>` - allowed values are `yes` and `no`
+ (default)
+
+ The syntax of the `LOCATION` depends on the deployment types. The
+ deployment types provided by Morph use the following syntaxes:
+
+ * `rawdisk`: pathname to the disk image to be created; for
+ example, `/home/alice/testsystem.img`
+
+ * `virtualbox-ssh` and `kvm`: a custom URL scheme that
+ provides the target host machine (the one that runs
+ VirtualBox or `kvm`), the name of the new virtual machine,
+ and the location on the target host of the virtual disk
+ file. The target host is accessed over ssh. For example,
+ `vbox+ssh://alice@192.168.122.1/testsys/home/alice/testsys.vdi`
+ or `kvm+ssh://alice@192.168.122.1/testsys/home/alice/testys.img`
+ where
+
+ * `alice@192.168.122.1` is the target as given to ssh,
+ **from within the development host** (which may be
+ different from the target host's normal address);
+
+ * `testsys` is the new VM's name;
+
+ * `/home/alice/testsys.vdi` and `/home/alice/testys.img` are
+ the pathnames of the disk image files on the target host.
+
+ For the `nfsboot` write extension,
+
+ * LOCATION is the address of the nfsboot server. (Note this
+ is just the _address_ of the trove, _not_ `user@...`, since
+ `root@` will automatically be prepended to the server address.)
+
+ * the following KEY=VALUE PAIRS are mandatory
+
+ * NFSBOOT_CONFIGURE=yes (or any non-empty value). This
+ enables the `nfsboot` configuration extension (see
+ below) which MUST be used when using the `nfsboot`
+ write extension.
+
+ * HOSTNAME=<STRING> a unique identifier for that system's
+ `nfs` root when it's deployed on the nfsboot server - the
+ extension creates a directory with that name for the `nfs`
+ root, and stores kernels by that name for the tftp server.
- where
+ * the following KEY=VALUE PAIRS are optional
- * TYPE is type of deployment
- * SYSTEM is name of the system morphology to deploy
- * LOCATION is the destination of the deployed system
+ * VERSION_LABEL=<STRING> - set the name of the system
+ version being deployed, when upgrading. Defaults to
+ "factory".
+
+ An example command line using `morph deploy with the nfsboot`
+ type is
+
+ morph deploy nfsboot devel-system-x86_64-generic \
+ customer-trove \
+ NFSBOOT_CONFIGURE=yes \
+ HOSTNAME=test-deployment-1 \
+ VERSION_LABEL=inital-test
+
+ Each deployment type is implemented by a **write extension**. The
+ ones provided by Morph are listed above, but users may also
+ create their own by adding them in the same git repository
+ and branch as the system morphology. A write extension is a
+ script that does whatever is needed for the deployment. A write
+ extension is passed two command line parameters: the name of an
+ unpacked directory tree that contains the system files (after
+ configuration, see below), and the `LOCATION` argument. Any
+ additional `KEY=VALUE` arguments given to `morph deploy` are
+ set as environment variables when the write extension runs.
+
+ Regardless of the type of deployment, the image may be
+ configured for a specific deployment by using **configuration
+ extensions**. The extensions are listed in the system morphology
+ file:
+
+ ...
+ configuration-extensions:
+ - set-hostname
+
+ The above specifies that the extension `set-hostname` is to
+ be run. Morph will run all the configuration extensions listed
+ in the system morphology, and no others. (This way, configuration
+ is more easily tracked in git.)
+
+ Configuration extensions are scripts that get the unpacked
+ directory tree of the system as their parameter, and do whatever
+ is needed to configure the tree.
+
+ Morph provides the following configuration extension built in:
+
+ * `set-hostname` sets the hostname of the system to the value
+ of the `HOSTNAME` variable.
+ * `nfsboot` configures the system for nfsbooting. This MUST
+ be used when deploying with the `nfsboot` write extension.
+
+ Any `KEY=VALUE` parameters given to `morph deploy` are set as
+ environment variables when either the configuration or the write
+ extension runs.
'''
diff --git a/morphlib/plugins/expand_repo_plugin.py b/morphlib/plugins/expand_repo_plugin.py
index 16087c6b..4c8ab126 100644
--- a/morphlib/plugins/expand_repo_plugin.py
+++ b/morphlib/plugins/expand_repo_plugin.py
@@ -22,15 +22,33 @@ import morphlib
class ExpandRepoPlugin(cliapp.Plugin):
'''Expand an aliased repo URL to be unaliases.'''
-
+
def enable(self):
self.app.add_subcommand(
'expand-repo', self.expand_repo, arg_synopsis='[REPOURL...]')
-
+
def disable(self):
pass
-
+
def expand_repo(self, args):
+ '''Expand repo aliases in URLs.
+
+ Command line arguments:
+
+ * `REPOURL` is a URL that may or may not be using repository
+ aliases.
+
+ See the `--repo-alias` option for more about repository aliases.
+
+ Example:
+
+ $ morph expand-repo baserock:baserock/morphs
+ Original: baserock:baserock/morphs
+ pull: git://trove.baserock.org/baserock/baserock/morphs
+ push: ssh://git@git.baserock.org/baserock/baserock/morphs
+
+ '''
+
aliases = self.app.settings['repo-alias']
resolver = morphlib.repoaliasresolver.RepoAliasResolver(aliases)
for repourl in args:
diff --git a/morphlib/plugins/graphing_plugin.py b/morphlib/plugins/graphing_plugin.py
index 8c4ea2ef..75514eec 100644
--- a/morphlib/plugins/graphing_plugin.py
+++ b/morphlib/plugins/graphing_plugin.py
@@ -31,7 +31,35 @@ class GraphingPlugin(cliapp.Plugin):
pass
def graph_build_depends(self, args):
- '''Create a visualisation of build dependencies in a stratum'''
+ '''Create a visualisation of build dependencies in a system.
+
+ Command line arguments:
+
+ * `REPO` is a repository URL.
+ * `REF` is a git reference (usually branch name).
+ * `MORPHOLOGY` is a system morphology.
+
+ This produces a GraphViz DOT file representing all the build
+ dependencies within a system, based on information in the
+ morphologies. The GraphViz `dot` program can then be used to
+ create a graphical representation of the dependencies. This
+ can be helpful for inspecting whether there are any problems in
+ the dependencies.
+
+ Example:
+
+ morph graph-build-depends baserock:baserock/morphs master \
+ devel-system-x86_64-generic > foo.dot
+ dot -Tpng foo.dot > foo.png
+
+ The above would create a picture with the build dependencies of
+ everything in the development system for 64-bit Intel systems.
+
+ GraphViz is not, currently, part of Baserock, so you need to run
+ `dot` on another system.
+
+ '''
+
for repo_name, ref, filename in self.app.itertriplets(args):
self.app.status(msg='Creating build order for '
'%(repo_name)s %(ref)s %(filename)s',
diff --git a/morphlib/plugins/show_dependencies_plugin.py b/morphlib/plugins/show_dependencies_plugin.py
index e4e40311..856a9361 100644
--- a/morphlib/plugins/show_dependencies_plugin.py
+++ b/morphlib/plugins/show_dependencies_plugin.py
@@ -31,7 +31,18 @@ class ShowDependenciesPlugin(cliapp.Plugin):
pass
def show_dependencies(self, args):
- '''Dumps the dependency tree of all input morphologies'''
+ '''Dumps the dependency tree of all input morphologies.
+
+ Command line arguments:
+
+ * `REPO` is a git repository URL.
+ * `REF` is a branch or other commit reference in that repository.
+ * `FILENAME` is a morphology filename at that ref.
+
+ This command analyses a system morphology and produces a listing
+ of build dependencies of the constituent components.
+
+ '''
if not os.path.exists(self.app.settings['cachedir']):
os.mkdir(self.app.settings['cachedir'])
diff --git a/morphlib/plugins/trovectl_plugin.py b/morphlib/plugins/trovectl_plugin.py
index fe96cc49..7db2cbb5 100644
--- a/morphlib/plugins/trovectl_plugin.py
+++ b/morphlib/plugins/trovectl_plugin.py
@@ -20,12 +20,33 @@ import morphlib
class TrovectlPlugin(cliapp.Plugin):
def enable(self):
- self.app.add_subcommand('trovectl', self.trovectl)
+ self.app.add_subcommand(
+ 'trovectl', self.trovectl, arg_synopsis='GITANO-COMMAND [ARG...]')
def disable(self):
pass
def trovectl(self, args, **kwargs):
+ '''Invoke Gitano commands on the Trove host.
+
+ Command line arguments:
+
+ * `GITANO-COMMAND` is the Gitano command to invoke on the Trove.
+ * `ARG` is a Gitano command argument.
+
+ This invokes Gitano commands on the Trove host configured
+ in the Morph configuration (see `--trove-host`).
+
+ Trove is the Codethink code hosting appliance. Gitano is the
+ git server management component of that.
+
+ Example:
+
+ morph trovectl whoami
+ morph trovectl help
+
+ '''
+
trove = 'git@' + self.app.settings['trove-host']
self.app.runcmd(['ssh', trove] + args,
stdout=None, stderr=None)
diff --git a/morphlib/plugins/update_gits_plugin.py b/morphlib/plugins/update_gits_plugin.py
index 083439f5..e3d7a81b 100644
--- a/morphlib/plugins/update_gits_plugin.py
+++ b/morphlib/plugins/update_gits_plugin.py
@@ -31,7 +31,22 @@ class UpdateGitsPlugin(cliapp.Plugin):
pass
def update_gits(self, args):
- '''Manually update cached git repositories for the given morphology'''
+ '''Manually update cached git repositories for the given morphology
+
+ Command line arguments:
+
+ * `REPO` is a git repository URL.
+ * `REF` is a git commit ref (sha1, branch, tag).
+ * `MORPHOLOGY` is a morphology filename.
+
+ This updates the local cached copy of a git repository, and any
+ git repositories of components in the morphology (for system
+ and stratum morphologies).
+
+ You do not normally need to do this. Morph updates the cached
+ repositories automatically anyway.
+
+ '''
app = self.app
if not os.path.exists(app.settings['cachedir']):