summaryrefslogtreecommitdiff
path: root/morphlib
diff options
context:
space:
mode:
authorSam Thursfield <sam.thursfield@codethink.co.uk>2012-09-10 11:09:51 +0100
committerSam Thursfield <sam.thursfield@codethink.co.uk>2012-09-10 20:04:06 +0100
commita12cbe6e106c9f62e08a89a3c012a3f3d4a48e9d (patch)
tree0315b2f2b1835886030922671c5712f3c6ddd866 /morphlib
parent02f4c93a143b7121c5bd84ec2e20c665149db4c8 (diff)
downloadmorph-a12cbe6e106c9f62e08a89a3c012a3f3d4a48e9d.tar.gz
Preserve sort order of morphologies, so they can be edited by Morph
Diffstat (limited to 'morphlib')
-rw-r--r--morphlib/morph2.py62
-rw-r--r--morphlib/morph2_tests.py76
-rw-r--r--morphlib/plugins/branch_and_merge_plugin.py23
3 files changed, 128 insertions, 33 deletions
diff --git a/morphlib/morph2.py b/morphlib/morph2.py
index d99e4a9e..0eca6fed 100644
--- a/morphlib/morph2.py
+++ b/morphlib/morph2.py
@@ -14,7 +14,10 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+import collections
+import copy
import json
+import re
class Morphology(object):
@@ -50,8 +53,15 @@ class Morphology(object):
]
}
+ @staticmethod
+ def _order_keys(pairs):
+ result = collections.OrderedDict()
+ for k,v in pairs:
+ result[k] = v
+ return result
+
def __init__(self, text):
- self._dict = json.loads(text)
+ self._dict = json.loads(text, object_pairs_hook=self._order_keys)
self._set_defaults()
self._validate_children()
@@ -105,19 +115,8 @@ class Morphology(object):
if 'disk-size' in self:
size = self['disk-size']
- if isinstance(size, basestring):
- size = size.lower()
- if size.endswith('g'):
- size = int(size[:-1]) * 1024 ** 3
- elif size.endswith('m'): # pragma: no cover
- size = int(size[:-1]) * 1024 ** 2
- elif size.endswith('k'): # pragma: no cover
- size = int(size[:-1]) * 1024
- else: # pragma: no cover
- size = int(size)
- else: # pragma: no cover
- size = int(size)
- self._dict['disk-size'] = size
+ self._dict['_disk-size'] = size
+ self._dict['disk-size'] = self._parse_size(size)
for name, value in self.static_defaults[self['kind']]:
if name not in self._dict:
@@ -134,3 +133,38 @@ class Morphology(object):
source['morph'] = source['name']
if 'build-depends' not in source:
source['build-depends'] = None
+
+ def _parse_size(self, size):
+ if isinstance(size, basestring):
+ size = size.lower()
+ if size.endswith('g'):
+ return int(size[:-1]) * 1024 ** 3
+ elif size.endswith('m'): # pragma: no cover
+ return int(size[:-1]) * 1024 ** 2
+ elif size.endswith('k'): # pragma: no cover
+ return int(size[:-1]) * 1024
+ return int(size)
+
+ def write_to_file(self, f):
+ # Recreate dict without the empty default values, with a few kind
+ # specific hacks to try and edit standard morphologies as
+ # non-destructively as possible
+ as_dict = collections.OrderedDict()
+ for key in self.keys():
+ if self['kind'] == 'stratum' and key == 'chunks':
+ value = copy.copy(self[key])
+ for chunk in value:
+ if chunk["morph"] == chunk["name"]:
+ del chunk["morph"]
+ if self['kind'] == 'system' and key == 'disk-size':
+ # Use human-readable value (assumes we never programmatically
+ # change this value within morph)
+ value = self['_disk-size']
+ else:
+ value = self[key]
+ if value and key[0] != '_':
+ as_dict[key] = value
+ text = json.dumps(as_dict, indent=4)
+ text = re.sub(" \n", "\n", text)
+ f.write(text)
+ f.write('\n')
diff --git a/morphlib/morph2_tests.py b/morphlib/morph2_tests.py
index 60917537..142b5949 100644
--- a/morphlib/morph2_tests.py
+++ b/morphlib/morph2_tests.py
@@ -14,6 +14,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+import StringIO
import unittest
from morphlib.morph2 import Morphology
@@ -197,3 +198,78 @@ class MorphologyTests(unittest.TestCase):
self.assertRaises(ValueError,
Morphology,
text)
+
+ def test_writing_preserves_field_order(self):
+ text = '''{
+ "kind": "system",
+ "disk-size": 1073741824,
+ "description": "Some text",
+ "arch": "x86_64",
+ "system-kind": "syslinux-disk",
+ "strata": [
+ {
+ "morph": "foundation",
+ "repo": "morphs",
+ "ref": "ref"
+ },
+ {
+ "morph": "devel",
+ "repo": "morphs",
+ "ref": "ref"
+ }
+ ]
+}'''
+ morphology = Morphology(text)
+ output = StringIO.StringIO()
+ morphology.write_to_file(output)
+
+ text_lines = text.splitlines()
+ output_lines = output.getvalue().splitlines()
+
+ # Verify that input and output are equal.
+ self.assertEqual(text_lines, output_lines)
+
+ def test_writing_stratum_morphology_preserves_chunk_order(self):
+ text = '''{
+ "kind": "stratum",
+ "chunks": [
+ {
+ "name": "foo",
+ "repo": "morphs",
+ "ref": "ref",
+ "build-depends": []
+ },
+ {
+ "name": "bar",
+ "repo": "morphs",
+ "ref": "ref",
+ "build-depends": []
+ }
+ ]
+}'''
+ morphology = Morphology(text)
+ output = StringIO.StringIO()
+ morphology.write_to_file(output)
+
+ text_lines = text.splitlines()
+ output_lines = output.getvalue().splitlines()
+
+ # Verify that input and output are equal.
+ self.assertEqual(text_lines, output_lines)
+
+ def test_writing_preserves_disk_size(self):
+ text = '''{
+ "kind": "system",
+ "disk-size": "1g",
+ "arch": "x86_64",
+ "system-kind": "syslinux-disk"
+}'''
+ morphology = Morphology(text)
+ output = StringIO.StringIO()
+ morphology.write_to_file(output)
+
+ text_lines = text.splitlines()
+ output_lines = output.getvalue().splitlines()
+
+ # Verify that in- and output are the same.
+ self.assertEqual(text_lines, output_lines)
diff --git a/morphlib/plugins/branch_and_merge_plugin.py b/morphlib/plugins/branch_and_merge_plugin.py
index 5e5ce0c1..d6485c2b 100644
--- a/morphlib/plugins/branch_and_merge_plugin.py
+++ b/morphlib/plugins/branch_and_merge_plugin.py
@@ -234,14 +234,9 @@ class BranchAndMergePlugin(cliapp.Plugin):
filename = name
else:
filename = os.path.join(repo_dir, name)
- as_dict = {}
- for key in morphology.keys():
- value = morphology[key]
- if value:
- as_dict[key] = value
+ filename = os.path.join(repo_dir, '%s' % name)
with morphlib.savefile.SaveFile(filename, 'w') as f:
- json.dump(as_dict, fp=f, indent=4, sort_keys=True)
- f.write('\n')
+ morphology.write_to_file(f)
@staticmethod
def get_edit_info(morphology_name, morphology, name, collection='strata'):
@@ -258,17 +253,6 @@ class BranchAndMergePlugin(cliapp.Plugin):
(name, morphology_name))
@staticmethod
- def write_morphology(filename, morphology):
- as_dict = {}
- for key in morphology.keys():
- value = morphology[key]
- if value:
- as_dict[key] = value
- with morphlib.savefile.SaveFile(filename, 'w') as f:
- json.dump(as_dict, fp=f, indent=4, sort_keys=True)
- f.write('\n')
-
- @staticmethod
def convert_uri_to_path(uri):
parts = urlparse.urlparse(uri)
@@ -357,7 +341,8 @@ class BranchAndMergePlugin(cliapp.Plugin):
repo = cache.get_repo(reponame)
source['ref'], tree = repo.resolve_ref(ref)
- self.write_morphology(filename, morph)
+ with morphlib.savefile.SaveFile(filename, 'w') as f:
+ morph.write_to_file(f)
def init(self, args):
'''Initialize a workspace directory.'''