summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2013-11-22 18:28:12 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2013-11-29 16:11:31 +0000
commitf5c1a50c9f35450801846a0309aa571e9893946a (patch)
tree2a5ed1e3c5145ac89893eadbb539ffaefe54899a
parent6e30db8033160fedbf864db08e98fd18b92a0d08 (diff)
downloadmorph-f5c1a50c9f35450801846a0309aa571e9893946a.tar.gz
morphloader: Require systems have at least one stratum
It doesn't currently make sense to build a system which contains no strata. We may later add other fields, such as initramfs to contribute to the system's artifact, but until then it's another bug to trip over. This uses collections.Sequence for checking the type of the systems entry in the morphology as a style choice, though it allows more flexibility if the types in the parsed morphology change.
-rw-r--r--morphlib/morphloader.py46
-rw-r--r--morphlib/morphloader_tests.py128
-rw-r--r--yarns/implementations.yarn25
-rw-r--r--yarns/regression.yarn4
4 files changed, 155 insertions, 48 deletions
diff --git a/morphlib/morphloader.py b/morphlib/morphloader.py
index 9ac248da..fdc3b62f 100644
--- a/morphlib/morphloader.py
+++ b/morphlib/morphloader.py
@@ -16,6 +16,7 @@
# =*= License: GPL-2 =*=
+import collections
import logging
import yaml
@@ -102,6 +103,16 @@ class DuplicateChunkError(morphlib.Error):
'in stratum %(stratum_name)s' % locals())
+class SystemStrataNotListError(morphlib.Error):
+
+ def __init__(self, system_name, strata_type):
+ self.system_name = system_name
+ self.strata_type = strata_type
+ typename = strata_type.__name__
+ morphlib.Error.__init__(
+ self, 'System %(system_name)s has the wrong type for its strata: '\
+ '%(typename)s, expected list' % locals())
+
class DuplicateStratumError(morphlib.Error):
def __init__(self, system_name, stratum_name):
@@ -112,6 +123,23 @@ class DuplicateStratumError(morphlib.Error):
'in system %(system_name)s' % locals())
+class SystemStratumSpecsNotMappingError(morphlib.Error):
+
+ def __init__(self, system_name, strata):
+ self.system_name = system_name
+ self.strata = strata
+ morphlib.Error.__init__(
+ self, 'System %(system_name)s has stratum specs '\
+ 'that are not mappings.' % locals())
+
+
+class EmptySystemError(morphlib.Error):
+
+ def __init__(self, system_name):
+ morphlib.Error.__init__(
+ self, 'System %(system_name)s has no strata.' % locals())
+
+
class MorphologyLoader(object):
'''Load morphologies from disk, or save them back to disk.'''
@@ -126,6 +154,7 @@ class MorphologyLoader(object):
'system': [
'name',
'arch',
+ 'strata',
],
'cluster': [
'name',
@@ -166,7 +195,6 @@ class MorphologyLoader(object):
'build-depends': [],
},
'system': {
- 'strata': [],
'description': '',
'arch': None,
'configuration-extensions': [],
@@ -270,9 +298,23 @@ class MorphologyLoader(object):
assert kind == 'cluster'
def _validate_system(self, morph):
+ # A system must contain at least one stratum
+ strata = morph['strata']
+ if (not isinstance(strata, collections.Iterable)
+ or isinstance(strata, collections.Mapping)):
+
+ raise SystemStrataNotListError(morph['name'],
+ type(strata))
+
+ if not strata:
+ raise EmptySystemError(morph['name'])
+
+ if not all(isinstance(o, collections.Mapping) for o in strata):
+ raise SystemStratumSpecsNotMappingError(morph['name'], strata)
+
# All stratum names should be unique within a system.
names = set()
- for spec in morph['strata']:
+ for spec in strata:
name = spec.get('alias', spec['morph'])
if name in names:
raise DuplicateStratumError(morph['name'], name)
diff --git a/morphlib/morphloader_tests.py b/morphlib/morphloader_tests.py
index b6ebff6a..8b87467a 100644
--- a/morphlib/morphloader_tests.py
+++ b/morphlib/morphloader_tests.py
@@ -99,6 +99,9 @@ build-system: dummy
'kind': 'system',
'name': 'foo',
'arch': 'x86_64',
+ 'strata': [
+ {'morph': 'bar'},
+ ],
'system-kind': 'foo',
})
self.assertRaises(
@@ -109,6 +112,9 @@ build-system: dummy
'kind': 'system',
'name': 'foo',
'arch': 'x86_64',
+ 'strata': [
+ {'morph': 'bar'},
+ ],
'disk-size': 'over 9000',
})
self.assertRaises(
@@ -122,12 +128,14 @@ build-system: dummy
morphlib.morphloader.MissingFieldError, self.loader.validate, m)
def test_fails_to_validate_system_with_invalid_field(self):
- m = morphlib.morph3.Morphology({
- 'kind': 'system',
- 'name': 'name',
- 'arch': 'x86_64',
- 'invalid': 'field',
- })
+ m = morphlib.morph3.Morphology(
+ kind="system",
+ name="foo",
+ arch="blah",
+ strata=[
+ {'morph': 'bar'},
+ ],
+ invalid='field')
self.assertRaises(
morphlib.morphloader.InvalidFieldError, self.loader.validate, m)
@@ -183,24 +191,24 @@ build-system: dummy
def test_validate_requires_a_valid_architecture(self):
m = morphlib.morph3.Morphology(
- {
- "kind": "system",
- "name": "foo",
- "arch": "blah",
- "strata": [],
- })
+ kind="system",
+ name="foo",
+ arch="blah",
+ strata=[
+ {'morph': 'bar'},
+ ])
self.assertRaises(
morphlib.morphloader.UnknownArchitectureError,
self.loader.validate, m)
def test_validate_normalises_architecture_armv7_to_armv7l(self):
m = morphlib.morph3.Morphology(
- {
- "kind": "system",
- "name": "foo",
- "arch": "armv7",
- "strata": [],
- })
+ kind="system",
+ name="foo",
+ arch="armv7",
+ strata=[
+ {'morph': 'bar'},
+ ])
self.loader.validate(m)
self.assertEqual(m['arch'], 'armv7l')
@@ -276,6 +284,50 @@ build-system: dummy
morphlib.morphloader.EmptyStratumError,
self.loader.validate, m)
+ def test_validate_requires_strata_in_system(self):
+ m = morphlib.morph3.Morphology(
+ name='system',
+ kind='system',
+ arch='testarch')
+ self.assertRaises(
+ morphlib.morphloader.MissingFieldError,
+ self.loader.validate, m)
+
+ def test_validate_requires_list_of_strata_in_system(self):
+ for v in (None, {}):
+ m = morphlib.morph3.Morphology(
+ name='system',
+ kind='system',
+ arch='testarch',
+ strata=v)
+ with self.assertRaises(
+ morphlib.morphloader.SystemStrataNotListError) as cm:
+
+ self.loader.validate(m)
+ self.assertEqual(cm.exception.strata_type, type(v))
+
+ def test_validate_requires_non_empty_strata_in_system(self):
+ m = morphlib.morph3.Morphology(
+ name='system',
+ kind='system',
+ arch='testarch',
+ strata=[])
+ self.assertRaises(
+ morphlib.morphloader.EmptySystemError,
+ self.loader.validate, m)
+
+ def test_validate_requires_stratum_specs_in_system(self):
+ m = morphlib.morph3.Morphology(
+ name='system',
+ kind='system',
+ arch='testarch',
+ strata=["foo"])
+ with self.assertRaises(
+ morphlib.morphloader.SystemStratumSpecsNotMappingError) as cm:
+
+ self.loader.validate(m)
+ self.assertEqual(cm.exception.strata, ["foo"])
+
def test_loads_yaml_from_string(self):
string = '''\
name: foo
@@ -463,11 +515,13 @@ name: foo
test_dict)
def test_sets_defaults_for_system(self):
- m = morphlib.morph3.Morphology({
- 'kind': 'system',
- 'name': 'foo',
- 'arch': 'x86_64',
- })
+ m = morphlib.morph3.Morphology(
+ kind='system',
+ name='foo',
+ arch='testarch',
+ strata=[
+ {'morph': 'bar'},
+ ])
self.loader.set_defaults(m)
self.loader.validate(m)
self.assertEqual(
@@ -476,25 +530,35 @@ name: foo
'kind': 'system',
'name': 'foo',
'description': '',
- 'arch': 'x86_64',
- 'strata': [],
+ 'arch': 'testarch',
+ 'strata': [
+ {'morph': 'bar'},
+ ],
'configuration-extensions': [],
})
def test_unsets_defaults_for_system(self):
- m = morphlib.morph3.Morphology({
- 'kind': 'system',
- 'name': 'foo',
- 'arch': 'x86_64',
- 'strata': [],
- })
+ m = morphlib.morph3.Morphology(
+ {
+ 'description': '',
+ 'kind': 'system',
+ 'name': 'foo',
+ 'arch': 'testarch',
+ 'strata': [
+ {'morph': 'bar'},
+ ],
+ 'configuration-extensions': [],
+ })
self.loader.unset_defaults(m)
self.assertEqual(
dict(m),
{
'kind': 'system',
'name': 'foo',
- 'arch': 'x86_64',
+ 'arch': 'testarch',
+ 'strata': [
+ {'morph': 'bar'},
+ ],
})
def test_sets_defaults_for_cluster(self):
diff --git a/yarns/implementations.yarn b/yarns/implementations.yarn
index 6491b38e..98955f48 100644
--- a/yarns/implementations.yarn
+++ b/yarns/implementations.yarn
@@ -75,13 +75,6 @@ another to hold a chunk.
morph: test-stratum
EOF
- cat << EOF > "$DATADIR/gits/morphs/simple-system.morph"
- name: simple-system
- kind: system
- arch: $arch
- strata: []
- EOF
-
cat << EOF > "$DATADIR/gits/morphs/test-stratum.morph"
name: test-stratum
kind: stratum
@@ -134,7 +127,11 @@ another to hold a chunk.
description: A system called $MATCH_1 for architectures $MATCH_2
kind: system
name: $MATCH_1
- strata: []
+ strata:
+ - name: test-stratum
+ repo: test:morphs
+ ref: master
+ morph: test-stratum
EOF
run_in "$DATADIR/gits/morphs" git add "$MATCH_1.morph"
run_in "$DATADIR/gits/morphs" git commit -m "Added $MATCH_1 morphology."
@@ -275,7 +272,11 @@ Editing morphologies with `morph edit`.
description: A system called $MATCH_1 for architectures $MATCH_2
kind: system
name: $MATCH_1
- strata: []
+ strata:
+ - name: test-stratum
+ repo: test:morphs
+ ref: master
+ morph: test-stratum
EOF
Reporting status of checked out repositories:
@@ -425,7 +426,7 @@ Generating a manifest.
> "$DATADIR/baserock/hello_world.meta"
{
"artifact-name": "hello_world",
- "cache-key":
+ "cache-key":
"ab8d00a80298a842446ce23507cea6b4d0e34c7ddfa05c67f460318b04d21308",
"kind": "chunk",
"morphology": "hello_world.morph",
@@ -440,7 +441,7 @@ Generating a manifest.
IMPLEMENTS WHEN morph generates a manifest
run_morph generate-manifest "$DATADIR/artifact.tar" > "$DATADIR/manifest"
-
+
IMPLEMENTS THEN the manifest is generated
# Generated manifest should contain the name of the repository
@@ -554,4 +555,4 @@ Implementations for building systems
IMPLEMENTS THEN morph build the system (\S+) of the (branch|tag) (\S+) of the repo (\S+)
cd "$DATADIR/workspace/$MATCH_3/$MATCH_4"
- run_morph build "$MATCH_1"
+ run_morph build "$MATCH_1"
diff --git a/yarns/regression.yarn b/yarns/regression.yarn
index a17d2f87..582ebb08 100644
--- a/yarns/regression.yarn
+++ b/yarns/regression.yarn
@@ -10,13 +10,13 @@ Testing if we can build after checking out from a tag.
GIVEN a workspace
AND a git server
WHEN the user checks out the system tag called test-tag
- THEN morph build the system simple-system of the tag test-tag of the repo test:morphs
+ THEN morph build the system test-system of the tag test-tag of the repo test:morphs
Running `morph branch` when the branch directory exists doesn't
remove the existing directory.
- SCENARIO re-running 'morph branch' fails, original branch untouched
+ SCENARIO re-running 'morph branch' fails, original branch untouched
GIVEN a workspace
AND a git server
WHEN the user creates a system branch called foo