summaryrefslogtreecommitdiff
path: root/morphlib
diff options
context:
space:
mode:
authorRichard Maw <richard.maw@codethink.co.uk>2014-02-12 16:27:32 +0000
committerRichard Maw <richard.maw@codethink.co.uk>2014-02-13 15:39:37 +0000
commitfbf70e2e5595d0cc7edaf7240a732cc5d2632c34 (patch)
tree26b563899cecad7f1898c672f6cbf9856993a52b /morphlib
parent070bcbd497583955e9069ced7aa2473bce2bc3b5 (diff)
downloadmorph-fbf70e2e5595d0cc7edaf7240a732cc5d2632c34.tar.gz
Warn and default to null if repo or ref are given
This now means that the system morphology is not altered when chunks are altered, so some tests had to change. Since this uses the python warnings API, these warnings can be ignored by running python -W ignore:"stratum morphology" \ -W ignore:"system morphology" \ "$(which morph)" ...` or turned into errors with python -W error:"stratum morphology" \ -W error:"system morphology" \ "$(which morph)" ...`
Diffstat (limited to 'morphlib')
-rw-r--r--morphlib/morphloader.py57
-rw-r--r--morphlib/morphloader_tests.py80
-rw-r--r--morphlib/morphologyfactory.py10
3 files changed, 142 insertions, 5 deletions
diff --git a/morphlib/morphloader.py b/morphlib/morphloader.py
index 32b5b40b..e4367fa1 100644
--- a/morphlib/morphloader.py
+++ b/morphlib/morphloader.py
@@ -18,11 +18,27 @@
import collections
import logging
+import warnings
import yaml
import morphlib
+class MorphologyObsoleteFieldWarning(UserWarning):
+
+ def __init__(self, morphology, spec, field):
+ self.kind = morphology['kind']
+ self.morphology_name = morphology.get('name', '<unknown>')
+ self.stratum_name = spec.get('alias', spec['morph'])
+ self.field = field
+
+ def __str__(self):
+ format_string = ('%(kind)s morphology %(morphology_name)s refers to '
+ 'stratum %(stratum_name)s with the %(field)s field. '
+ 'Defaulting to null.')
+ return format_string % self.__dict__
+
+
class MorphologySyntaxError(morphlib.Error):
def __init__(self, morphology):
@@ -366,6 +382,9 @@ class MorphologyLoader(object):
raise DuplicateStratumError(morph['name'], name)
names.add(name)
+ # Validate stratum spec fields
+ self._validate_stratum_specs_fields(morph, 'strata')
+
# We allow the ARMv7 little-endian architecture to be specified
# as armv7 and armv7l. Normalise.
if morph['arch'] == 'armv7':
@@ -409,6 +428,9 @@ class MorphologyLoader(object):
raise NoStratumBuildDependenciesError(
morph['name'], morph.filename)
+ # Validate build-dependencies if specified
+ self._validate_stratum_specs_fields(morph, 'build-depends')
+
# Require build-dependencies for each chunk.
for spec in morph['chunks']:
if 'build-depends' not in spec:
@@ -496,6 +518,18 @@ class MorphologyLoader(object):
type(pattern), morphology_name)
errors.append(e)
+ @classmethod
+ def _warn_obsolete_field(cls, morphology, spec, field):
+ warnings.warn(MorphologyObsoleteFieldWarning(morphology, spec, field),
+ stacklevel=2)
+
+ @classmethod
+ def _validate_stratum_specs_fields(cls, morphology, specs_field):
+ for spec in morphology.get(specs_field, None) or []:
+ for obsolete_field in ('repo', 'ref'):
+ if obsolete_field in spec:
+ cls._warn_obsolete_field(morphology, spec, obsolete_field)
+
def _require_field(self, field, morphology):
if field not in morphology:
raise MissingFieldError(field, morphology.filename)
@@ -542,9 +576,23 @@ class MorphologyLoader(object):
if key in morphology and morphology[key] == defaults[key]:
del morphology[key]
- if kind in ('stratum', 'cluster'):
+ if kind in ('system', 'stratum', 'cluster'):
getattr(self, '_unset_%s_defaults' % kind)(morphology)
+ @classmethod
+ def _set_stratum_specs_defaults(cls, morphology, specs_field):
+ for spec in morphology.get(specs_field, None) or []:
+ for obsolete_field in ('repo', 'ref'):
+ if obsolete_field in spec:
+ del spec[obsolete_field]
+
+ @classmethod
+ def _unset_stratum_specs_defaults(cls, morphology, specs_field):
+ for spec in morphology.get(specs_field, []):
+ for obsolete_field in ('repo', 'ref'):
+ if obsolete_field in spec:
+ del spec[obsolete_field]
+
def _set_cluster_defaults(self, morph):
for system in morph.get('systems', []):
if 'deploy-defaults' not in system:
@@ -560,7 +608,10 @@ class MorphologyLoader(object):
del system['deploy']
def _set_system_defaults(self, morph):
- pass
+ self._set_stratum_specs_defaults(morph, 'strata')
+
+ def _unset_system_defaults(self, morph):
+ self._unset_stratum_specs_defaults(morph, 'strata')
def _set_stratum_defaults(self, morph):
for spec in morph['chunks']:
@@ -568,6 +619,7 @@ class MorphologyLoader(object):
spec['repo'] = spec['name']
if 'morph' not in spec:
spec['morph'] = spec['name']
+ self._set_stratum_specs_defaults(morph, 'build-depends')
def _unset_stratum_defaults(self, morph):
for spec in morph['chunks']:
@@ -575,6 +627,7 @@ class MorphologyLoader(object):
del spec['repo']
if 'morph' in spec and spec['morph'] == spec['name']:
del spec['morph']
+ self._unset_stratum_specs_defaults(morph, 'strata')
def _set_chunk_defaults(self, morph):
if morph['max-jobs'] is not None:
diff --git a/morphlib/morphloader_tests.py b/morphlib/morphloader_tests.py
index bd3e77e3..b8738804 100644
--- a/morphlib/morphloader_tests.py
+++ b/morphlib/morphloader_tests.py
@@ -16,12 +16,15 @@
# =*= License: GPL-2 =*=
+import contextlib
import os
import shutil
import tempfile
import unittest
+import warnings
import morphlib
+from morphlib.morphloader import MorphologyObsoleteFieldWarning
class MorphologyLoaderTests(unittest.TestCase):
@@ -648,10 +651,13 @@ name: foo
name='foo',
arch='testarch',
strata=[
- {'morph': 'bar'},
+ {
+ 'morph': 'bar',
+ 'repo': 'obsolete',
+ 'ref': 'obsolete',
+ },
])
self.loader.set_defaults(m)
- self.loader.validate(m)
self.assertEqual(
{
'kind': 'system',
@@ -675,7 +681,11 @@ name: foo
'name': 'foo',
'arch': 'testarch',
'strata': [
- {'morph': 'bar'},
+ {
+ 'morph': 'bar',
+ 'repo': None,
+ 'ref': None,
+ },
],
'configuration-extensions': [],
})
@@ -788,3 +798,67 @@ name: foo
self.assertEqual(m['name'], 'foo')
self.assertEqual(m['kind'], 'cluster')
self.assertEqual(m['systems'][0]['morph'], 'bar')
+
+ @contextlib.contextmanager
+ def catch_warnings(*warning_classes):
+ with warnings.catch_warnings(record=True) as caught_warnings:
+ warnings.resetwarnings()
+ for warning_class in warning_classes:
+ warnings.simplefilter("always", warning_class)
+ yield caught_warnings
+
+ def test_warns_when_systems_refer_to_strata_with_repo_or_ref(self):
+ for obsolete_field in ('repo', 'ref'):
+ m = morphlib.morph3.Morphology(
+ name="foo",
+ kind="system",
+ arch="testarch",
+ strata=[
+ {
+ 'morph': 'bar',
+ obsolete_field: 'obsolete',
+ }])
+
+ with self.catch_warnings(MorphologyObsoleteFieldWarning) \
+ as caught_warnings:
+
+ self.loader.validate(m)
+ self.assertEqual(len(caught_warnings), 1)
+ warning = caught_warnings[0].message
+ self.assertEqual(warning.kind, 'system')
+ self.assertEqual(warning.morphology_name, 'foo')
+ self.assertEqual(warning.stratum_name, 'bar')
+ self.assertEqual(warning.field, obsolete_field)
+
+ def test_warns_when_strata_refer_to_build_depends_with_repo_or_ref(self):
+ for obsolete_field in ('repo', 'ref'):
+ m = morphlib.morph3.Morphology(
+ {
+ 'name': 'foo',
+ 'kind': 'stratum',
+ 'build-depends': [
+ {
+ 'morph': 'bar',
+ obsolete_field: 'obsolete'
+ },
+ ],
+ 'chunks': [
+ {
+ 'morph': 'chunk',
+ 'name': 'chunk',
+ 'build-mode': 'test',
+ 'build-depends': [],
+ },
+ ],
+ })
+
+ with self.catch_warnings(MorphologyObsoleteFieldWarning) \
+ as caught_warnings:
+
+ self.loader.validate(m)
+ self.assertEqual(len(caught_warnings), 1)
+ warning = caught_warnings[0].message
+ self.assertEqual(warning.kind, 'stratum')
+ self.assertEqual(warning.morphology_name, 'foo')
+ self.assertEqual(warning.stratum_name, 'bar')
+ self.assertEqual(warning.field, obsolete_field)
diff --git a/morphlib/morphologyfactory.py b/morphlib/morphologyfactory.py
index 3462dd36..8a0b047a 100644
--- a/morphlib/morphologyfactory.py
+++ b/morphlib/morphologyfactory.py
@@ -145,6 +145,11 @@ class MorphologyFactory(object):
morphology.needs_artifact_metadata_cached = False
+ morphlib.morphloader.MorphologyLoader._validate_stratum_specs_fields(
+ morphology, 'strata')
+ morphlib.morphloader.MorphologyLoader._set_stratum_specs_defaults(
+ morphology, 'strata')
+
def _check_and_tweak_stratum(self, morphology, reponame, sha1, filename):
'''Check and tweak a stratum morphology.'''
@@ -164,6 +169,11 @@ class MorphologyFactory(object):
morphology.builds_artifacts = [morphology['name']]
morphology.needs_artifact_metadata_cached = True
+ morphlib.morphloader.MorphologyLoader._validate_stratum_specs_fields(
+ morphology, 'build-depends')
+ morphlib.morphloader.MorphologyLoader._set_stratum_specs_defaults(
+ morphology, 'build-depends')
+
def _check_and_tweak_chunk(self, morphology, reponame, sha1, filename):
'''Check and tweak a chunk morphology.'''