summaryrefslogtreecommitdiff
path: root/morphlib
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2014-06-17 16:36:07 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2014-07-10 13:50:00 +0000
commit3dc83847b8f17793bdab5e978d13d394b48987b0 (patch)
treea67c54b99b7e822ab7f49df3c9df2199435f21ff /morphlib
parentae007688d8f1f57b138dafffdfc3683aa7c7730f (diff)
downloadmorph-3dc83847b8f17793bdab5e978d13d394b48987b0.tar.gz
Use exact filenames to refer to morphology files
Rather than repeatedly stripping and appending an optional .morph extension morphology names, instead always use the file path of the morphology relative to the definitions repository. This is an inversion of the previous logic, which would strip the .morph extension and use the "name" internally. The exception to this rule of always using the filename, is that `morph edit CHUNK` uses the name of the morphology as-defined in the stratum. This is based off Adam Coldrick's inital patch, but this version will allow the old style of providing the "name" by converting it into a path if it does not have either a / or a . in it. An unfortunate consequence of this change is that the show-dependencies command's output changed, so the test needed updating.
Diffstat (limited to 'morphlib')
-rw-r--r--morphlib/app.py28
-rw-r--r--morphlib/artifactresolver.py6
-rw-r--r--morphlib/buildcommand.py2
-rw-r--r--morphlib/morphset.py16
-rw-r--r--morphlib/morphset_tests.py6
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py5
-rw-r--r--morphlib/plugins/build_plugin.py15
-rw-r--r--morphlib/plugins/cross-bootstrap_plugin.py2
-rw-r--r--morphlib/plugins/deploy_plugin.py10
-rw-r--r--morphlib/plugins/list_artifacts_plugin.py23
-rw-r--r--morphlib/source.py2
-rw-r--r--morphlib/util.py23
-rw-r--r--morphlib/util_tests.py29
13 files changed, 89 insertions, 78 deletions
diff --git a/morphlib/app.py b/morphlib/app.py
index 07e6348f..0557beef 100644
--- a/morphlib/app.py
+++ b/morphlib/app.py
@@ -282,7 +282,8 @@ class Morph(cliapp.Application):
while args:
assert len(args) >= 2, args
- yield args[0], args[1], args[2] + ".morph"
+ yield (args[0], args[1],
+ morphlib.util.sanitise_morphology_path(args[2]))
args = args[3:]
def create_source_pool(self, lrc, rrc, triplet):
@@ -376,18 +377,23 @@ class Morph(cliapp.Application):
raise cliapp.AppException(
"Cannot build a morphology of type 'cluster'.")
elif morphology['kind'] == 'system':
- queue.extend((s.get('repo') or reponame,
- s.get('ref') or ref,
- '%s.morph' % s['morph'])
- for s in morphology['strata'])
+ queue.extend(
+ (s.get('repo') or reponame,
+ s.get('ref') or ref,
+ morphlib.util.sanitise_morphology_path(s['morph']))
+ for s in morphology['strata'])
elif morphology['kind'] == 'stratum':
if morphology['build-depends']:
- queue.extend((s.get('repo') or reponame,
- s.get('ref') or ref,
- '%s.morph' % s['morph'])
- for s in morphology['build-depends'])
- queue.extend((c['repo'], c['ref'], '%s.morph' % c['morph'])
- for c in morphology['chunks'])
+ queue.extend(
+ (s.get('repo') or reponame,
+ s.get('ref') or ref,
+ morphlib.util.sanitise_morphology_path(s['morph']))
+ for s in morphology['build-depends'])
+ queue.extend(
+ (c['repo'],
+ c['ref'],
+ morphlib.util.sanitise_morphology_path(c['morph']))
+ for c in morphology['chunks'])
def cache_repo_and_submodules(self, cache, url, ref, done):
subs_to_process = set()
diff --git a/morphlib/artifactresolver.py b/morphlib/artifactresolver.py
index 00976eb7..c18042a3 100644
--- a/morphlib/artifactresolver.py
+++ b/morphlib/artifactresolver.py
@@ -142,7 +142,7 @@ class ArtifactResolver(object):
stratum_source = self._source_pool.lookup(
info.get('repo') or source.repo_name,
info.get('ref') or source.original_ref,
- '%s.morph' % info['morph'])
+ morphlib.util.sanitise_morphology_path(info['morph']))
stratum_name = stratum_source.morphology['name']
matches, overlaps, unmatched = source.split_rules.partition(
@@ -167,7 +167,7 @@ class ArtifactResolver(object):
other_source = self._source_pool.lookup(
stratum_info.get('repo') or source.repo_name,
stratum_info.get('ref') or source.original_ref,
- '%s.morph' % stratum_info['morph'])
+ morphlib.util.sanitise_morphology_path(stratum_info['morph']))
# Make every stratum artifact this stratum source produces
# depend on every stratum artifact the other stratum source
@@ -194,7 +194,7 @@ class ArtifactResolver(object):
chunk_source = self._source_pool.lookup(
info['repo'],
info['ref'],
- '%s.morph' % info['morph'])
+ morphlib.util.sanitise_morphology_path(info['morph']))
chunk_name = chunk_source.morphology['name']
diff --git a/morphlib/buildcommand.py b/morphlib/buildcommand.py
index f68046e3..45c6ef00 100644
--- a/morphlib/buildcommand.py
+++ b/morphlib/buildcommand.py
@@ -231,7 +231,7 @@ class BuildCommand(object):
for spec in specs:
repo_name = spec.get('repo') or src.repo_name
ref = spec.get('ref') or src.original_ref
- filename = '%s.morph' % spec['morph']
+ filename = morphlib.util.sanitise_morphology_path(spec['morph'])
logging.debug(
'Validating cross ref to %s:%s:%s' %
(repo_name, ref, filename))
diff --git a/morphlib/morphset.py b/morphlib/morphset.py
index 9f349db7..590ac51e 100644
--- a/morphlib/morphset.py
+++ b/morphlib/morphset.py
@@ -66,7 +66,7 @@ class MorphologySet(object):
def _find_spec(self, specs, wanted_name):
for spec in specs:
- name = spec.get('morph', spec.get('name'))
+ name = spec.get('name', spec.get('morph'))
if name == wanted_name:
return spec.get('repo'), spec.get('ref'), name
return None, None, None
@@ -127,8 +127,8 @@ class MorphologySet(object):
specs = m[kind]
for spec in specs:
if cb_filter(m, kind, spec):
- orig_spec = (spec.get('repo'), spec.get('ref'),
- spec['morph'])
+ fn = morphlib.util.sanitise_morphology_path(spec['morph'])
+ orig_spec = (spec.get('repo'), spec.get('ref'), fn)
dirtied = cb_process(m, kind, spec)
if dirtied:
m.dirty = True
@@ -142,17 +142,18 @@ class MorphologySet(object):
process_spec_list(m, 'chunks')
for m in self.morphologies:
- tup = (m.repo_url, m.ref, m.filename[:-len('.morph')])
+ tup = (m.repo_url, m.ref, m.filename)
if tup in altered_references:
spec = altered_references[tup]
if m.ref != spec.get('ref'):
m.ref = spec.get('ref')
m.dirty = True
- assert (m.filename == spec['morph'] + '.morph'
+ file = morphlib.util.sanitise_morphology_path(spec['morph'])
+ assert (m.filename == file
or m.repo_url == spec.get('repo')), \
'Moving morphologies is not supported.'
- def change_ref(self, repo_url, orig_ref, morph_filename, new_ref):
+ def change_ref(self, repo_url, orig_ref, morph_name, new_ref):
'''Change a triplet's ref to a new one in all morphologies in a ref.
Change orig_ref to new_ref in any morphology that references the
@@ -161,9 +162,10 @@ class MorphologySet(object):
'''
def wanted_spec(m, kind, spec):
+ spec_name = spec.get('name', spec['morph'])
return (spec.get('repo') == repo_url and
spec.get('ref') == orig_ref and
- spec['morph'] + '.morph' == morph_filename)
+ spec_name == morph_name)
def process_spec(m, kind, spec):
spec['unpetrify-ref'] = spec.get('ref')
diff --git a/morphlib/morphset_tests.py b/morphlib/morphset_tests.py
index 03983419..8679c64a 100644
--- a/morphlib/morphset_tests.py
+++ b/morphlib/morphset_tests.py
@@ -98,7 +98,7 @@ class MorphologySetTests(unittest.TestCase):
self.morphs.change_ref(
self.stratum.repo_url,
self.stratum.ref,
- self.stratum.filename,
+ self.stratum['name'],
'new-ref')
self.assertEqual(self.stratum.ref, 'new-ref')
self.assertEqual(
@@ -134,7 +134,7 @@ class MorphologySetTests(unittest.TestCase):
self.morphs.change_ref(
self.stratum.repo_url,
self.stratum.ref,
- self.stratum.filename,
+ self.stratum['name'],
'new-ref')
self.assertEqual(
other_stratum['build-depends'][0],
@@ -151,7 +151,7 @@ class MorphologySetTests(unittest.TestCase):
self.morphs.change_ref(
'test:foo-chunk',
'master',
- 'foo-chunk.morph',
+ 'foo-chunk',
'new-ref')
self.assertEqual(
self.stratum['chunks'],
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 75e2bfe8..a66098b8 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -325,12 +325,13 @@ class BranchAndMergePlugin(cliapp.Plugin):
# Change the refs to the chunk.
if chunk_ref != sb.system_branch_name:
morphs.change_ref(
- chunk_url, chunk_ref, chunk_morph + '.morph',
+ chunk_url, chunk_ref,
+ chunk_morph,
sb.system_branch_name)
return chunk_dirname
- chunk_name = morphlib.util.strip_morph_extension(args[0])
+ chunk_name = args[0]
dirs = set()
found = 0
diff --git a/morphlib/plugins/build_plugin.py b/morphlib/plugins/build_plugin.py
index fb7efa5b..1a4fb573 100644
--- a/morphlib/plugins/build_plugin.py
+++ b/morphlib/plugins/build_plugin.py
@@ -76,7 +76,7 @@ class BuildPlugin(cliapp.Plugin):
Example:
- morph distbuild devel-system-x86_64-generic
+ morph distbuild devel-system-x86_64-generic.morph
'''
@@ -103,8 +103,8 @@ class BuildPlugin(cliapp.Plugin):
Example:
- morph build-morphology baserock:baserock/morphs \
- master devel-system-x86_64-generic
+ morph build-morphology baserock:baserock/definitions \
+ master devel-system-x86_64-generic.morph
'''
@@ -141,7 +141,7 @@ class BuildPlugin(cliapp.Plugin):
Example:
- morph build devel-system-x86_64-generic
+ morph build devel-system-x86_64-generic.morph
'''
@@ -156,7 +156,7 @@ class BuildPlugin(cliapp.Plugin):
self.app.settings['cachedir'],
self.app.settings['cachedir-min-space'])
- system_name = morphlib.util.strip_morph_extension(args[0])
+ system_filename = morphlib.util.sanitise_morphology_path(args[0])
ws = morphlib.workspace.open('.')
sb = morphlib.sysbranchdir.open_from_within('.')
@@ -181,7 +181,8 @@ class BuildPlugin(cliapp.Plugin):
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=sb.system_branch_name)
+ system=system_filename,
+ branch=sb.system_branch_name)
bb = morphlib.buildbranch.BuildBranch(sb, build_ref_prefix,
push_temporary=push)
@@ -210,4 +211,4 @@ class BuildPlugin(cliapp.Plugin):
build_command.build([bb.root_repo_url,
bb.root_ref,
- system_name])
+ system_filename])
diff --git a/morphlib/plugins/cross-bootstrap_plugin.py b/morphlib/plugins/cross-bootstrap_plugin.py
index bfd0d047..cd8e355e 100644
--- a/morphlib/plugins/cross-bootstrap_plugin.py
+++ b/morphlib/plugins/cross-bootstrap_plugin.py
@@ -260,7 +260,7 @@ class CrossBootstrapPlugin(cliapp.Plugin):
self.app.settings, arch)
build_command = morphlib.buildcommand.BuildCommand(self.app, build_env)
- morph_name = system_name + '.morph'
+ morph_name = morphlib.util.sanitise_morphology_path(system_name)
builds_artifacts = [system_name + '-bootstrap-rootfs']
srcpool = build_command.create_source_pool(root_repo, ref, morph_name)
diff --git a/morphlib/plugins/deploy_plugin.py b/morphlib/plugins/deploy_plugin.py
index 7c009071..9384c422 100644
--- a/morphlib/plugins/deploy_plugin.py
+++ b/morphlib/plugins/deploy_plugin.py
@@ -99,7 +99,7 @@ class DeployPlugin(cliapp.Plugin):
name: cluster-foo
kind: cluster
systems:
- - morph: devel-system-x86_64-generic
+ - morph: devel-system-x86_64-generic.morph
deploy:
cluster-foo-x86_64-1:
type: kvm
@@ -278,7 +278,7 @@ class DeployPlugin(cliapp.Plugin):
'/', 0)
self.app.settings['no-git-update'] = True
- cluster_name = morphlib.util.strip_morph_extension(args[0])
+ cluster_filename = morphlib.util.sanitise_morphology_path(args[0])
ws = morphlib.workspace.open('.')
sb = morphlib.sysbranchdir.open_from_within('.')
@@ -294,7 +294,6 @@ class DeployPlugin(cliapp.Plugin):
build_ref_prefix = self.app.settings['build-ref-prefix']
root_repo_dir = morphlib.gitdir.GitDirectory(
sb.get_git_directory_name(sb.root_repository_url))
- cluster_filename = cluster_name + '.morph'
cluster_text = root_repo_dir.read_file(cluster_filename)
cluster_morphology = loader.load_from_string(cluster_text,
filename=cluster_filename)
@@ -387,9 +386,8 @@ class DeployPlugin(cliapp.Plugin):
self.app.status_prefix = system_status_prefix
try:
# Find the artifact to build
- morph = system['morph']
- srcpool = build_command.create_source_pool(build_repo, ref,
- morph + '.morph')
+ morph = morphlib.util.sanitise_morphology_path(system['morph'])
+ srcpool = build_command.create_source_pool(build_repo, ref, morph)
artifact = build_command.resolve_artifacts(srcpool)
diff --git a/morphlib/plugins/list_artifacts_plugin.py b/morphlib/plugins/list_artifacts_plugin.py
index 5e64f708..ad6bc772 100644
--- a/morphlib/plugins/list_artifacts_plugin.py
+++ b/morphlib/plugins/list_artifacts_plugin.py
@@ -55,21 +55,22 @@ class ListArtifactsPlugin(cliapp.Plugin):
'(see help)')
repo, ref = args[0], args[1]
- system_names = map(morphlib.util.strip_morph_extension, args[2:])
+ system_filenames = map(morphlib.util.sanitise_morphology_path,
+ args[2:])
self.lrc, self.rrc = morphlib.util.new_repo_caches(self.app)
self.resolver = morphlib.artifactresolver.ArtifactResolver()
artifact_files = set()
- for system_name in system_names:
+ for system_filename in system_filenames:
system_artifact_files = self.list_artifacts_for_system(
- repo, ref, system_name)
+ repo, ref, system_filename)
artifact_files.update(system_artifact_files)
for artifact_file in sorted(artifact_files):
print artifact_file
- def list_artifacts_for_system(self, repo, ref, system_name):
+ def list_artifacts_for_system(self, repo, ref, system_filename):
'''List all artifact files in the build graph of a single system.'''
# Sadly, we must use a fresh source pool and a fresh list of artifacts
@@ -82,24 +83,24 @@ class ListArtifactsPlugin(cliapp.Plugin):
# different architectures right now.
self.app.status(
- msg='Creating source pool for %s' % system_name, chatty=True)
+ msg='Creating source pool for %s' % system_filename, chatty=True)
source_pool = self.app.create_source_pool(
- self.lrc, self.rrc, (repo, ref, system_name + '.morph'))
+ self.lrc, self.rrc, (repo, ref, system_filename))
self.app.status(
- msg='Resolving artifacts for %s' % system_name, chatty=True)
+ msg='Resolving artifacts for %s' % system_filename, chatty=True)
artifacts = self.resolver.resolve_artifacts(source_pool)
- def find_artifact_by_name(artifacts_list, name):
+ def find_artifact_by_name(artifacts_list, filename):
for a in artifacts_list:
- if a.source.filename == name + '.morph':
+ if a.source.filename == name:
return a
raise ValueError
- system_artifact = find_artifact_by_name(artifacts, system_name)
+ system_artifact = find_artifact_by_name(artifacts, system_filename)
self.app.status(
- msg='Computing cache keys for %s' % system_name, chatty=True)
+ msg='Computing cache keys for %s' % system_filename, chatty=True)
build_env = morphlib.buildenvironment.BuildEnvironment(
self.app.settings, system_artifact.source.morphology['arch'])
ckc = morphlib.cachekeycomputer.CacheKeyComputer(build_env)
diff --git a/morphlib/source.py b/morphlib/source.py
index 75a2e4de..2dbabad1 100644
--- a/morphlib/source.py
+++ b/morphlib/source.py
@@ -55,4 +55,4 @@ class Source(object):
def __str__(self): # pragma: no cover
return '%s|%s|%s' % (self.repo_name,
self.original_ref,
- self.filename[:-len('.morph')])
+ self.filename)
diff --git a/morphlib/util.py b/morphlib/util.py
index 024de495..0c551296 100644
--- a/morphlib/util.py
+++ b/morphlib/util.py
@@ -61,13 +61,22 @@ def indent(string, spaces=4):
return '\n'.join(lines)
-def strip_morph_extension(morph_name):
- if morph_name.startswith('.'):
- raise morphlib.Error(
- 'Invalid morphology name: %s' % morph_name)
- elif morph_name.endswith('.morph'):
- return morph_name[:-len('.morph')]
- return morph_name
+def sanitise_morphology_path(morph_name):
+ '''Turn morph_name into a file path to a morphology.
+
+ We support both a file path being provided, and just the morphology
+ name for backwards compatibility.
+
+ '''
+ # If it has a / it must be a path, so return it unmolested
+ if '/' in morph_name:
+ return morph_name
+ # Must be an old format, which is always name + .morph
+ elif not morph_name.endswith('.morph'):
+ return morph_name + '.morph'
+ # morphology already ends with .morph
+ else:
+ return morph_name
def make_concurrency(cores=None):
diff --git a/morphlib/util_tests.py b/morphlib/util_tests.py
index 5a8ae797..715892b6 100644
--- a/morphlib/util_tests.py
+++ b/morphlib/util_tests.py
@@ -1,4 +1,4 @@
-# Copyright (C) 2011-2013 Codethink Limited
+# Copyright (C) 2011-2014 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
@@ -38,26 +38,19 @@ class IndentTests(unittest.TestCase):
' foo\n bar')
-class StripMorphExtensionTests(unittest.TestCase):
+class SanitiseMorphologyPathTests(unittest.TestCase):
- def test_raises_error_when_string_starts_with_period(self):
- with self.assertRaises(morphlib.Error):
- morphlib.util.strip_morph_extension('.morph')
-
- def test_strips_morph_extension_from_string(self):
- self.assertEqual(morphlib.util.strip_morph_extension('a.morph'), 'a')
-
- def test_returns_morph_when_not_given_as_extension(self):
- self.assertEqual(morphlib.util.strip_morph_extension('morph'), 'morph')
-
- def test_strips_extension_only_once_from_string(self):
- self.assertEqual(morphlib.util.strip_morph_extension('a.morph.morph'),
+ def test_appends_morph_to_string(self):
+ self.assertEqual(morphlib.util.sanitise_morphology_path('a'),
'a.morph')
- def test_returns_input_without_modification_if_no_extension(self):
- self.assertEqual(
- morphlib.util.strip_morph_extension('completely not a path'),
- 'completely not a path')
+ def test_returns_morph_when_given_a_filename(self):
+ self.assertEqual(morphlib.util.sanitise_morphology_path('a.morph'),
+ 'a.morph')
+
+ def test_returns_morph_when_given_a_path(self):
+ self.assertEqual('stratum/a.morph',
+ morphlib.util.sanitise_morphology_path('stratum/a.morph'))
class MakeConcurrencyTests(unittest.TestCase):