summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py311
-rwxr-xr-xtests.as-root/building-a-system-branch-works-anywhere.script75
-rw-r--r--tests.as-root/building-a-system-branch-works-anywhere.stdout10
-rwxr-xr-xtests.as-root/setup37
-rw-r--r--tests.branching/edit-updates-stratum.stdout6
-rwxr-xr-xtests.branching/setup1
6 files changed, 409 insertions, 31 deletions
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 07f1a154..4f8e940b 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -19,8 +19,11 @@ import copy
import os
import json
import glob
+import socket
import tempfile
+import time
import urlparse
+import uuid
import morphlib
@@ -49,6 +52,8 @@ class BranchAndMergePlugin(cliapp.Plugin):
arg_synopsis='BRANCH REPO...')
self.app.add_subcommand('edit', self.edit,
arg_synopsis='SYSTEM STRATUM [CHUNK]')
+ self.app.add_subcommand('build', self.build,
+ arg_synopsis='SYSTEM')
def disable(self):
pass
@@ -92,7 +97,7 @@ class BranchAndMergePlugin(cliapp.Plugin):
dirname = os.getcwd()
while dirname != workspace and dirname != '/':
if os.path.isdir(os.path.join(dirname, '.morph-system-branch')):
- branch_name = self.get_branch_config(dirname, 'branch-name')
+ branch_name = self.get_branch_config(dirname, 'branch.name')
return branch_name, dirname
dirname = os.path.dirname(dirname)
@@ -103,27 +108,25 @@ class BranchAndMergePlugin(cliapp.Plugin):
for dirname in self.walk_special_directories(
os.getcwd(), special_subdir='.morph-system-branch',
max_subdirs=1):
- branch_name = self.get_branch_config(dirname, 'branch-name')
+ branch_name = self.get_branch_config(dirname, 'branch.name')
return branch_name, dirname
raise cliapp.AppException("Can't find the system branch directory")
- @staticmethod
- def write_branch_root(branch_dir, repo):
- filename = os.path.join(branch_dir, '.morph-system-branch',
- 'branch-root')
- with open(filename, 'w') as f:
- f.write('%s\n' % repo)
-
def set_branch_config(self, branch_dir, option, value):
filename = os.path.join(branch_dir, '.morph-system-branch', 'config')
- self.app.runcmd(['git', 'config', '-f', filename,
- 'branch.%s' % option, '%s' % value])
+ self.app.runcmd(['git', 'config', '-f', filename, option, value])
def get_branch_config(self, branch_dir, option):
filename = os.path.join(branch_dir, '.morph-system-branch', 'config')
- value = self.app.runcmd(['git', 'config', '-f', filename,
- 'branch.%s' % option])
+ value = self.app.runcmd(['git', 'config', '-f', filename, option])
+ return value.strip()
+
+ def set_repo_config(self, repo_dir, option, value):
+ self.app.runcmd(['git', 'config', option, value], cwd=repo_dir)
+
+ def get_repo_config(self, repo_dir, option):
+ value = self.app.runcmd(['git', 'config', option], cwd=repo_dir)
return value.strip()
def clone_to_directory(self, dirname, reponame, ref):
@@ -154,16 +157,19 @@ class BranchAndMergePlugin(cliapp.Plugin):
# Remember the repo name we cloned from in order to be able
# to identify the repo again later using the same name, even
# if the user happens to rename the directory.
- self.app.runcmd(['git', 'config', 'morph.repository', reponame],
- cwd=dirname)
+ self.set_repo_config(dirname, 'morph.repository', reponame)
+
+ # Create a UUID for the clone. We will use this for naming
+ # temporary refs, e.g. for building.
+ self.set_repo_config(dirname, 'morph.uuid', uuid.uuid4().hex)
# Set the origin to point at the original repository.
morphlib.git.set_remote(self.app.runcmd, dirname, 'origin', repo.url)
# Add push url rewrite rule to .git/config.
- self.app.runcmd(['git', 'config',
- 'url.%s.pushInsteadOf' % resolver.push_url(reponame),
- resolver.pull_url(reponame)], cwd=dirname)
+ self.set_repo_config(
+ dirname, 'url.%s.pushInsteadOf' % resolver.push_url(reponame),
+ resolver.pull_url(reponame))
self.app.runcmd(['git', 'remote', 'update'], cwd=dirname)
@@ -187,7 +193,12 @@ class BranchAndMergePlugin(cliapp.Plugin):
@staticmethod
def save_morphology(repo_dir, name, morphology):
- filename = os.path.join(repo_dir, '%s.morph' % name)
+ if not name.endswith('.morph'):
+ name = '%s.morph' % name
+ if os.path.isabs(name):
+ filename = name
+ else:
+ filename = os.path.join(repo_dir, name)
as_dict = {}
for key in morphology.keys():
value = morphology[key]
@@ -267,16 +278,15 @@ class BranchAndMergePlugin(cliapp.Plugin):
def find_repository(self, branch_dir, repo):
for dirname in self.walk_special_directories(branch_dir,
special_subdir='.git'):
- original_repo = self.app.runcmd(
- ['git', 'config', 'morph.repository'], cwd=dirname)
- if repo == original_repo.strip():
+ original_repo = self.get_repo_config(dirname, 'morph.repository')
+ if repo == original_repo:
return dirname
return None
def find_system_branch(self, workspace, branch_name):
for dirname in self.walk_special_directories(
workspace, special_subdir='.morph-system-branch'):
- branch = self.get_branch_config(dirname, 'branch-name')
+ branch = self.get_branch_config(dirname, 'branch.name')
if branch_name == branch:
return dirname
return None
@@ -364,8 +374,12 @@ class BranchAndMergePlugin(cliapp.Plugin):
# Remember the system branch name and the repository we branched
# off from initially.
- self.set_branch_config(branch_dir, 'branch-name', new_branch)
- self.set_branch_config(branch_dir, 'branch-root', repo)
+ self.set_branch_config(branch_dir, 'branch.name', new_branch)
+ self.set_branch_config(branch_dir, 'branch.root', repo)
+
+ # Generate a UUID for the branch. We will use this for naming
+ # temporary refs, e.g. building.
+ self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
# Clone into system branch directory.
repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
@@ -396,8 +410,11 @@ class BranchAndMergePlugin(cliapp.Plugin):
# Remember the system branch name and the repository we
# branched off from.
- self.set_branch_config(branch_dir, 'branch-name', system_branch)
- self.set_branch_config(branch_dir, 'branch-root', repo)
+ self.set_branch_config(branch_dir, 'branch.name', system_branch)
+ self.set_branch_config(branch_dir, 'branch.root', repo)
+
+ # Generate a UUID for the branch.
+ self.set_branch_config(branch_dir, 'branch.uuid', uuid.uuid4().hex)
# Clone into system branch directory.
repo_dir = os.path.join(branch_dir, self.convert_uri_to_path(repo))
@@ -414,7 +431,7 @@ class BranchAndMergePlugin(cliapp.Plugin):
workspace = self.deduce_workspace()
system_branch, branch_dir = self.deduce_system_branch()
- branch_root = self.get_branch_config(branch_dir, 'branch-root')
+ branch_root = self.get_branch_config(branch_dir, 'branch.root')
self.app.output.write('%s\n' % branch_root)
def merge(self, args):
@@ -470,7 +487,7 @@ class BranchAndMergePlugin(cliapp.Plugin):
system_branch, branch_dir = self.deduce_system_branch()
# Find out which repository we branched off from.
- branch_root = self.get_branch_config(branch_dir, 'branch-root')
+ branch_root = self.get_branch_config(branch_dir, 'branch.root')
branch_root_dir = self.find_repository(branch_dir, branch_root)
system_name = args[0]
@@ -537,3 +554,239 @@ class BranchAndMergePlugin(cliapp.Plugin):
self.print_changelog('The following changes were made but have not '
'been comitted')
+
+ def build(self, args):
+ if len(args) != 1:
+ raise cliapp.AppException('morph build expects exactly one '
+ 'parameter: the system to build')
+
+ system_name = args[0]
+
+ # Deduce workspace and system branch and branch root repository.
+ workspace = self.deduce_workspace()
+ branch, branch_dir = self.deduce_system_branch()
+ branch_root = self.get_branch_config(branch_dir, 'branch.root')
+ branch_uuid = self.get_branch_config(branch_dir, 'branch.uuid')
+
+ # Generate a UUID for the build.
+ build_uuid = uuid.uuid4().hex
+
+ self.app.status(msg='Starting build %(uuid)s', uuid=build_uuid)
+
+ self.app.status(msg='Collecting morphologies involved in '
+ 'building %(system)s from %(branch)s',
+ system=system_name, branch=branch)
+
+ # Get repositories of morphologies involved in building this system
+ # from the current system branch.
+ build_repos = self.get_system_build_repos(
+ branch, branch_dir, branch_root, system_name)
+
+ # Generate temporary build ref names for all these repositories.
+ self.generate_build_ref_names(build_repos, branch_uuid)
+
+ # Create the build refs for all these repositories and commit
+ # all uncommitted changes to them, updating all references
+ # to system branch refs to point to the build refs instead.
+ self.update_build_refs(build_repos, branch, build_uuid)
+
+ # Push the temporary build refs.
+ self.push_build_refs(build_repos)
+
+ # Run the build.
+ build_command = morphlib.buildcommand.BuildCommand(self.app)
+ build_command = self.app.hookmgr.call('new-build-command',
+ build_command)
+ build_command.build([branch_root,
+ build_repos[branch_root]['build-ref'],
+ '%s.morph' % system_name])
+
+ # Delete the temporary refs on the server.
+ self.delete_remote_build_refs(build_repos)
+
+ self.app.status(msg='Finished build %(uuid)s', uuid=build_uuid)
+
+ def get_system_build_repos(self, system_branch, branch_dir,
+ branch_root, system_name):
+ build_repos = {}
+
+ def prepare_repo_info(repo, dirname):
+ build_repos[repo] = {
+ 'dirname': dirname,
+ 'systems': [],
+ 'strata': [],
+ 'chunks': []
+ }
+
+ def add_morphology_info(info, category):
+ repo = info['repo']
+ if repo in build_repos:
+ repo_dir = build_repos[repo]['dirname']
+ else:
+ repo_dir = self.find_repository(branch_dir, repo)
+ if repo_dir:
+ if not repo in build_repos:
+ prepare_repo_info(repo, repo_dir)
+ build_repos[repo][category].append(info['morph'])
+ return repo_dir
+
+ # Add repository and morphology of the system.
+ branch_root_dir = self.find_repository(branch_dir, branch_root)
+ prepare_repo_info(branch_root, branch_root_dir)
+ build_repos[branch_root]['systems'].append(system_name)
+
+ # Traverse and add repositories and morphologies involved in
+ # building this system from the system branch.
+ system_morphology = self.load_morphology(branch_root_dir, system_name)
+ for info in system_morphology['strata']:
+ if info['ref'] == system_branch:
+ repo_dir = add_morphology_info(info, 'strata')
+ if repo_dir:
+ stratum_morphology = self.load_morphology(
+ repo_dir, info['morph'])
+ for info in stratum_morphology['chunks']:
+ if info['ref'] == system_branch:
+ add_morphology_info(info, 'chunks')
+
+ return build_repos
+
+ def inject_build_refs(self, morphology, build_repos):
+ # Starting from a system or stratum morphology, update all ref
+ # pointers of strata or chunks involved in a system build (represented
+ # by build_repos) to point to temporary build refs of the repos
+ # involved in the system build.
+ def inject_build_ref(info):
+ if info['repo'] in build_repos and (
+ info['morph'] in build_repos[info['repo']]['strata'] or
+ info['morph'] in build_repos[info['repo']]['chunks']):
+ info['ref'] = build_repos[info['repo']]['build-ref']
+ if morphology['kind'] == 'system':
+ for info in morphology['strata']:
+ inject_build_ref(info)
+ elif morphology['kind'] == 'stratum':
+ for info in morphology['chunks']:
+ inject_build_ref(info)
+
+ def resolve_ref(self, repodir, ref):
+ try:
+ return self.app.runcmd(['git', 'show-ref', ref],
+ cwd=repodir).split()[0]
+ except:
+ return None
+
+ def get_uncommitted_changes(self, repo_dir, env):
+ status = self.app.runcmd(['git', 'status', '--porcelain'],
+ cwd=repo_dir, env=env)
+ changes = []
+ for change in status.strip().splitlines():
+ xy, paths = change.strip().split(' ', 1)
+ if xy != '??':
+ changes.append(paths.split()[0])
+ return changes
+
+ def generate_build_ref_names(self, build_repos, branch_uuid):
+ for repo, info in build_repos.iteritems():
+ repo_dir = info['dirname']
+ repo_uuid = self.get_repo_config(repo_dir, 'morph.uuid')
+ build_ref = os.path.join(self.app.settings['build-ref-prefix'],
+ branch_uuid, repo_uuid)
+ info['build-ref'] = build_ref
+
+ def update_build_refs(self, build_repos, system_branch, build_uuid):
+ # Define the committer.
+ committer_name = 'Morph (on behalf of %s)' % \
+ self.app.runcmd(['git', 'config', 'user.name']).strip()
+ committer_email = '%s@%s' % \
+ (os.environ.get('LOGNAME'), socket.gethostname())
+
+ for repo, info in build_repos.iteritems():
+ repo_dir = info['dirname']
+ build_ref = info['build-ref']
+
+ self.app.status(msg='%(repo)s: Creating build branch', repo=repo)
+
+ # Obtain parent SHA1 for the temporary ref tree to be committed.
+ # This will either be the current commit of the temporary ref or
+ # HEAD in case the temporary ref does not exist yet.
+ parent_sha1 = self.resolve_ref(repo_dir, build_ref)
+ if not parent_sha1:
+ parent_sha1 = self.resolve_ref(repo_dir, system_branch)
+
+ # Prepare an environment with our internal index file.
+ # This index file allows us to commit changes to a tree without
+ # git noticing any change in working tree or its own index.
+ env = dict(os.environ)
+ env['GIT_INDEX_FILE'] = os.path.join(
+ repo_dir, '.git', 'morph-index')
+ env['GIT_COMMITTER_NAME'] = committer_name
+ env['GIT_COMMITTER_EMAIL'] = committer_email
+
+ # Read tree from parent or current HEAD into the morph index.
+ self.app.runcmd(['git', 'read-tree', parent_sha1],
+ cwd=repo_dir, env=env)
+
+ self.app.status(msg='%(repo)s: Adding uncommited changes to '
+ 'build branch', repo=repo)
+
+ # Add all local, uncommitted changes to our internal index.
+ changed_files = self.get_uncommitted_changes(repo_dir, env)
+ self.app.runcmd(['git', 'add'] + changed_files,
+ cwd=repo_dir, env=env)
+
+ self.app.status(msg='%(repo)s: Update morphologies to use '
+ 'build branch instead of "%(branch)s"',
+ repo=repo, branch=system_branch)
+
+ # Update all references to the system branches of strata
+ # and chunks to point to the temporary refs, which is needed
+ # for building.
+ filenames = info['systems'] + info['strata']
+ for filename in filenames:
+ # Inject temporary refs in the right places in each morphology.
+ morphology = self.load_morphology(repo_dir, filename)
+ self.inject_build_refs(morphology, build_repos)
+ handle, tmpfile = tempfile.mkstemp(suffix='.morph')
+ self.save_morphology(repo_dir, tmpfile, morphology)
+
+ morphology_sha1 = self.app.runcmd(
+ ['git', 'hash-object', '-t', 'blob', '-w', tmpfile],
+ cwd=repo_dir, env=env)
+
+ self.app.runcmd(
+ ['git', 'update-index', '--cacheinfo',
+ '100644', morphology_sha1, '%s.morph' % filename],
+ cwd=repo_dir, env=env)
+
+ # Remove the temporary morphology file.
+ os.remove(tmpfile)
+
+ # Create a commit message including the build UUID. This allows us
+ # to collect all commits of a build across repositories and thereby
+ # see the changes made to the entire system between any two builds.
+ message = 'Morph build %s\n\nSystem branch: %s\n' % \
+ (build_uuid, system_branch)
+
+ # Write and commit the tree and update the temporary build ref.
+ tree = self.app.runcmd(
+ ['git', 'write-tree'], cwd=repo_dir, env=env).strip()
+ commit = self.app.runcmd(
+ ['git', 'commit-tree', tree, '-p', parent_sha1,
+ '-m', message], cwd=repo_dir, env=env).strip()
+ self.app.runcmd(
+ ['git', 'update-ref', '-m', message,
+ 'refs/heads/%s' % build_ref, commit],
+ cwd=repo_dir, env=env)
+
+ def push_build_refs(self, build_repos):
+ for repo, info in build_repos.iteritems():
+ self.app.status(msg='%(repo)s: Pushing build branch', repo=repo)
+ self.app.runcmd(['git', 'push', 'origin', '%s:%s' %
+ (info['build-ref'], info['build-ref'])],
+ cwd=info['dirname'])
+
+ def delete_remote_build_refs(self, build_repos):
+ for repo, info in build_repos.iteritems():
+ self.app.status(msg='%(repo)s: Deleting remote build branch',
+ repo=repo)
+ self.app.runcmd(['git', 'push', 'origin',
+ ':%s' % info['build-ref']], cwd=info['dirname'])
diff --git a/tests.as-root/building-a-system-branch-works-anywhere.script b/tests.as-root/building-a-system-branch-works-anywhere.script
new file mode 100755
index 00000000..3bb32f17
--- /dev/null
+++ b/tests.as-root/building-a-system-branch-works-anywhere.script
@@ -0,0 +1,75 @@
+#!/bin/bash
+# Copyright (C) 2012 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, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+# Make sure "morph build" works anywhere in a workspace or system branch
+# and produces the same results every time.
+
+set -eu
+
+# Initialise the workspace.
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" init
+
+# Create a new local system branch.
+"$SRCDIR/scripts/test-morph" branch test:morphs-repo branch1
+
+# Edit linux.
+"$SRCDIR/scripts/test-morph" edit linux-system linux-stratum linux
+
+# Fix the UUIDs being used for the temporary refs. This is needed
+# because the system and stratum morphologies will have references
+# to the temporary build refs and that will affect the artifact
+# cache keys. If we fix the UUIDs, the artifact cache keys will
+# always be the same.
+git config -f "$DATADIR/workspace/branch1/.morph-system-branch/config" \
+ branch.uuid 123456789
+git config -f "$DATADIR/workspace/branch1/test:morphs-repo/.git/config" \
+ morph.uuid 987654321
+git config -f "$DATADIR/workspace/branch1/test:kernel-repo/.git/config" \
+ morph.uuid AABBCCDDE
+
+# Build from the workspace root.
+cd "$DATADIR/workspace"
+"$SRCDIR/scripts/test-morph" build linux-system
+"$SRCDIR/scripts/list-tree" "$DATADIR/cache/artifacts" > "$DATADIR/output1"
+rm -rf "$DATADIR/cache"/*
+
+# Build from the branch.
+cd "$DATADIR/workspace/branch1"
+"$SRCDIR/scripts/test-morph" build linux-system
+"$SRCDIR/scripts/list-tree" "$DATADIR/cache/artifacts" > "$DATADIR/output2"
+rm -rf "$DATADIR/cache/artifacts"/*
+
+# Build form the branch root repository.
+cd "$DATADIR/workspace/branch1/test:morphs-repo"
+"$SRCDIR/scripts/test-morph" build linux-system
+"$SRCDIR/scripts/list-tree" "$DATADIR/cache/artifacts" > "$DATADIR/output3"
+rm -rf "$DATADIR/cache/artifacts"/*
+
+# Build from the linux directory.
+cd "$DATADIR/workspace/branch1/test:kernel-repo"
+"$SRCDIR/scripts/test-morph" build linux-system
+"$SRCDIR/scripts/list-tree" "$DATADIR/cache/artifacts" > "$DATADIR/output4"
+rm -rf "$DATADIR/cache/artifacts"/*
+
+# Verify that we're always building the same and that we're building
+# the right things after all.
+cat "$DATADIR/output1"
+
+# Print diffs of the build results, all of which should be empty.
+diff "$DATADIR/output1" "$DATADIR/output2"
+diff "$DATADIR/output2" "$DATADIR/output3"
+diff "$DATADIR/output3" "$DATADIR/output4"
diff --git a/tests.as-root/building-a-system-branch-works-anywhere.stdout b/tests.as-root/building-a-system-branch-works-anywhere.stdout
new file mode 100644
index 00000000..68c29eae
--- /dev/null
+++ b/tests.as-root/building-a-system-branch-works-anywhere.stdout
@@ -0,0 +1,10 @@
+d .
+f ./4854734df8ff06a9fbaab8536be43a46b54c1e6bcb9545ccb8fc345b5fb17ebd.meta
+f ./4854734df8ff06a9fbaab8536be43a46b54c1e6bcb9545ccb8fc345b5fb17ebd.stratum.linux-stratum
+f ./4854734df8ff06a9fbaab8536be43a46b54c1e6bcb9545ccb8fc345b5fb17ebd.stratum.linux-stratum.meta
+f ./cda58b36cef0fe28c5ffaf080fed5ee85128f109f806c4c599c46b1f064ce028.meta
+f ./cda58b36cef0fe28c5ffaf080fed5ee85128f109f806c4c599c46b1f064ce028.system.linux-system-kernel
+f ./cda58b36cef0fe28c5ffaf080fed5ee85128f109f806c4c599c46b1f064ce028.system.linux-system-rootfs
+f ./e8d3ecb31babcb58516f1298ccc5f63b167186e6527d831af5a788309a648cd6.build-log
+f ./e8d3ecb31babcb58516f1298ccc5f63b167186e6527d831af5a788309a648cd6.chunk.linux
+f ./e8d3ecb31babcb58516f1298ccc5f63b167186e6527d831af5a788309a648cd6.meta
diff --git a/tests.as-root/setup b/tests.as-root/setup
index 2ba0adf9..d4cb6d8a 100755
--- a/tests.as-root/setup
+++ b/tests.as-root/setup
@@ -31,6 +31,9 @@ set -eu
# The $DATADIR should be empty at the beginnig of each test.
find "$DATADIR" -mindepth 1 -delete
+# Create an empty directory to be used as a morph workspace
+mkdir "$DATADIR/workspace"
+
# Create chunk repository.
chunkrepo="$DATADIR/chunk-repo"
@@ -120,6 +123,40 @@ cat <<EOF > hello-system.morph
EOF
git add hello-system.morph
+cat <<EOF > linux-system.morph
+{
+ "name": "linux-system",
+ "kind": "system",
+ "system-kind": "syslinux-disk",
+ "arch": "$(uname -m)",
+ "disk-size": "1G",
+ "strata": [
+ {
+ "morph": "linux-stratum",
+ "repo": "test:morphs-repo",
+ "ref": "master"
+ }
+ ]
+}
+EOF
+git add linux-system.morph
+
+cat <<EOF > linux-stratum.morph
+{
+ "name": "linux-stratum",
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "linux",
+ "repo": "test:kernel-repo",
+ "ref": "master",
+ "build-depends": []
+ }
+ ]
+}
+EOF
+git add linux-stratum.morph
+
git commit --quiet -m "add morphs"
# Make a dummy kernel chunk.
diff --git a/tests.branching/edit-updates-stratum.stdout b/tests.branching/edit-updates-stratum.stdout
index c29f3a9e..a61be053 100644
--- a/tests.branching/edit-updates-stratum.stdout
+++ b/tests.branching/edit-updates-stratum.stdout
@@ -25,15 +25,17 @@ index 006a96c..ad8c08b 100644
+ "name": "hello-stratum"
}
diff --git a/hello-system.morph b/hello-system.morph
-index 8dbcf67..db4f1f2 100644
+index 1a33ed6..d5aae46 100644
--- a/hello-system.morph
+++ b/hello-system.morph
-@@ -1,13 +1,14 @@
+@@ -1,14 +1,15 @@
{
- "name": "hello-system",
- "kind": "system",
- "system-kind": "syslinux-disk",
+- "arch": "x86_64",
- "disk-size": "1G",
++ "arch": "x86_64",
+ "build-system": "manual",
+ "disk-size": 1073741824,
+ "kind": "system",
diff --git a/tests.branching/setup b/tests.branching/setup
index 6cbd18c6..30bfbd24 100755
--- a/tests.branching/setup
+++ b/tests.branching/setup
@@ -64,6 +64,7 @@ cat <<EOF > "$DATADIR/morphs/hello-system.morph"
"name": "hello-system",
"kind": "system",
"system-kind": "syslinux-disk",
+ "arch": "$(uname -m)",
"disk-size": "1G",
"strata": [
{