summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--morphlib/cachekeycomputer.py2
-rw-r--r--morphlib/morphloader.py31
-rw-r--r--morphlib/morphloader_tests.py30
-rw-r--r--morphlib/plugins/distbuild_plugin.py2
-rw-r--r--morphlib/stagingarea.py4
-rw-r--r--morphlib/yamlparse.py2
6 files changed, 65 insertions, 6 deletions
diff --git a/morphlib/cachekeycomputer.py b/morphlib/cachekeycomputer.py
index 73cc75f3..b124b789 100644
--- a/morphlib/cachekeycomputer.py
+++ b/morphlib/cachekeycomputer.py
@@ -122,6 +122,8 @@ class CacheKeyComputer(object):
# products is omitted as they are part of the split-rules
elif kind in ('system', 'stratum'):
morphology = artifact.source.morphology
+ # Exclude fields starting with _orig_. This filtering can be
+ # removed once the morph2 code is gone.
morph_dict = dict((k, morphology[k]) for k in morphology.keys()
if not k.startswith('_orig_'))
diff --git a/morphlib/morphloader.py b/morphlib/morphloader.py
index 45416a19..21e10827 100644
--- a/morphlib/morphloader.py
+++ b/morphlib/morphloader.py
@@ -224,7 +224,7 @@ class DuplicateDeploymentNameError(MorphologyValidationError):
% (cluster_filename, '\n ' + '\n '.join(duplicates)))
-class OrderedDumper(yaml.SafeDumper):
+class MorphologyDumper(yaml.SafeDumper):
keyorder = (
'name',
'kind',
@@ -274,9 +274,36 @@ class OrderedDumper(yaml.SafeDumper):
return dumper.represent_mapping('tag:yaml.org,2002:map',
cls._iter_in_global_order(mapping))
+ @classmethod
+ def _represent_str(cls, dumper, orig_data):
+ fallback_representer = yaml.representer.SafeRepresenter.represent_str
+ try:
+ data = unicode(orig_data, 'ascii')
+ if data.count('\n') == 0:
+ return fallback_representer(dumper, orig_data)
+ except UnicodeDecodeError:
+ try:
+ data = unicode(orig_data, 'utf-8')
+ if data.count('\n') == 0:
+ return fallback_representer(dumper, orig_data)
+ except UnicodeDecodeError:
+ return fallback_representer(dumper, orig_data)
+ return dumper.represent_scalar(u'tag:yaml.org,2002:str',
+ data, style='|')
+
+ @classmethod
+ def _represent_unicode(cls, dumper, data):
+ if data.count('\n') == 0:
+ return yaml.representer.SafeRepresenter.represent_unicode(dumper,
+ data)
+ return dumper.represent_scalar(u'tag:yaml.org,2002:str',
+ data, style='|')
+
def __init__(self, *args, **kwargs):
yaml.SafeDumper.__init__(self, *args, **kwargs)
self.add_representer(dict, self._represent_dict)
+ self.add_representer(str, self._represent_str)
+ self.add_representer(unicode, self._represent_unicode)
class MorphologyLoader(object):
@@ -394,7 +421,7 @@ class MorphologyLoader(object):
def save_to_string(self, morphology):
'''Return normalised textual form of morphology.'''
- return yaml.dump(morphology.data, Dumper=OrderedDumper,
+ return yaml.dump(morphology.data, Dumper=MorphologyDumper,
default_flow_style=False)
def save_to_file(self, filename, morphology):
diff --git a/morphlib/morphloader_tests.py b/morphlib/morphloader_tests.py
index 82663298..f4d2f9b6 100644
--- a/morphlib/morphloader_tests.py
+++ b/morphlib/morphloader_tests.py
@@ -912,3 +912,33 @@ build-system: dummy
# deployment keys field order
self.assertLess(s.find('type'), s.find('location'))
self.assertLess(s.find('location'), s.find('HOSTNAME'))
+
+ def test_multi_line_round_trip(self):
+ s = ('name: foo\n'
+ 'kind: bar\n'
+ 'description: |\n'
+ ' 1 2 3\n'
+ ' 4 5 6\n'
+ ' 7 8 9\n')
+ m = self.loader.parse_morphology_text(s, 'string')
+ self.assertEqual(s, self.loader.save_to_string(m))
+
+ def test_smoketest_multi_line_unicode(self):
+ m = morphlib.morph3.Morphology(
+ name=u'foo',
+ description=u'1 2 3\n4 5 6\n7 8 9\n',
+ )
+ s = self.loader.save_to_string(m)
+
+ def test_smoketest_multi_line_unicode_encoded(self):
+ m = morphlib.morph3.Morphology(
+ name=u'foo \u263A'.encode('utf-8'),
+ description=u'1 \u263A\n2 \u263A\n3 \u263A\n'.encode('utf-8'),
+ )
+ s = self.loader.save_to_string(m)
+
+ def test_smoketest_binary_garbage(self):
+ m = morphlib.morph3.Morphology(
+ description='\x92',
+ )
+ s = self.loader.save_to_string(m)
diff --git a/morphlib/plugins/distbuild_plugin.py b/morphlib/plugins/distbuild_plugin.py
index c60dee6e..50ab7eeb 100644
--- a/morphlib/plugins/distbuild_plugin.py
+++ b/morphlib/plugins/distbuild_plugin.py
@@ -59,7 +59,7 @@ class SerialiseArtifactPlugin(cliapp.Plugin):
raise cliapp.AppException('Must get triplet')
repo_name, ref, morph_name = args
- filename = '%s.morph' % morph_name
+ filename = morphlib.util.sanitise_morphology_path(morph_name)
build_command = morphlib.buildcommand.BuildCommand(self.app)
srcpool = build_command.create_source_pool(repo_name, ref, filename)
artifact = build_command.resolve_artifacts(srcpool)
diff --git a/morphlib/stagingarea.py b/morphlib/stagingarea.py
index 124edabf..0126b4d9 100644
--- a/morphlib/stagingarea.py
+++ b/morphlib/stagingarea.py
@@ -65,8 +65,8 @@ class StagingArea(object):
os.makedirs(dirname)
def _dir_for_source(self, source, suffix):
- dirname = os.path.join(self.dirname,
- '%s.%s' % (source.morphology['name'], suffix))
+ basename = '%s.%s' % (str(source.morphology['name']), suffix)
+ dirname = os.path.join(self.dirname, basename)
self._mkdir(dirname)
return dirname
diff --git a/morphlib/yamlparse.py b/morphlib/yamlparse.py
index 726b4181..6f139304 100644
--- a/morphlib/yamlparse.py
+++ b/morphlib/yamlparse.py
@@ -29,7 +29,7 @@ if morphlib.got_yaml: # pragma: no cover
def dump(*args, **kwargs):
if 'default_flow_style' not in kwargs:
kwargs['default_flow_style'] = False
- return yaml.dump(Dumper=morphlib.morphloader.OrderedDumper,
+ return yaml.dump(Dumper=morphlib.morphloader.MorphologyDumper,
*args, **kwargs)
else: # pragma: no cover