summaryrefslogtreecommitdiff
path: root/morphlib
diff options
context:
space:
mode:
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.'''