Implemented ImageData API
authorEd Bartosh <eduard.bartosh@intel.com>
Mon, 20 May 2013 17:48:35 +0000 (20:48 +0300)
committerGerrit Code Review <gerrit2@otctools.jf.intel.com>
Mon, 27 May 2013 02:50:52 +0000 (19:50 -0700)
This API is responcible for generating and parsing images.xml

Change-Id: Id0e36d6371f173b7cdaf862bc120db886d42e830
Signed-off-by: Ed Bartosh <eduard.bartosh@intel.com>
common/imagedata.py [new file with mode: 0644]
tests/test_imagedata.py [new file with mode: 0644]

diff --git a/common/imagedata.py b/common/imagedata.py
new file mode 100644 (file)
index 0000000..f13d754
--- /dev/null
@@ -0,0 +1,88 @@
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""
+This module takes care of handling/generating/parsing of build.xml
+"""
+
+import re
+
+from collections import OrderedDict
+from xml.dom import minidom
+
+class ImageDataError(Exception):
+    """Custom ImgData exception."""
+    pass
+
+class ImageData(object):
+    """Class for handling image data."""
+
+    # fixing of buggy xml.dom.minidom.toprettyxml
+    XMLTEXT_RE = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
+
+    def __init__(self):
+        self.images = OrderedDict()
+
+    def add_image(self, image):
+        """Add (or update) target to the list of targets."""
+        self.images[image["name"]] = image
+
+    def load(self, xml):
+        """Load image data from xml."""
+
+        def get_elem(node, name):
+            """Helper: get first element by tag name."""
+            try:
+                return node.getElementsByTagName(name)[0]
+            except IndexError:
+                raise ImageDataError("Error: <%s><%s> not found" % \
+                                     (node.nodeName, name))
+        dom = minidom.parseString(xml)
+        images = get_elem(dom, "images")
+
+        for image in images.getElementsByTagName("image"):
+            img = {}
+            for field in ('name', 'description', 'path', 'arch',
+                          'ks', 'buildtarget'):
+                img[field] = str(get_elem(image, field).firstChild.data)
+
+            self.images[img['name']] = img
+
+    def to_xml(self, hreadable=True):
+        """Format image data as xml."""
+        content = '<?xml version="1.0" ?><images>'
+
+        for image in self.images.itervalues():
+            content += '<image>'
+            for field, value in image.iteritems():
+                content += '<%s>%s</%s>' % (field, value, field)
+            content += '</image>'
+        content += '</images>'
+
+        # make it human readable
+        if hreadable:
+            dom = minidom.parseString(content)
+            content = self.XMLTEXT_RE.sub('>\g<1></',
+                                          dom.toprettyxml(indent='  '))
+
+        return content
+
+    def save(self, fname, hreadable=True):
+        """Save image data to xml file."""
+        # Write content down
+        with open(fname, 'w') as out:
+            out.write(self.to_xml(hreadable))
diff --git a/tests/test_imagedata.py b/tests/test_imagedata.py
new file mode 100644 (file)
index 0000000..b52b90f
--- /dev/null
@@ -0,0 +1,102 @@
+#!/usr/bin/python -tt
+# vim: ai ts=4 sts=4 et sw=4
+#
+# Copyright (c) 2012 Intel, Inc.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the Free
+# Software Foundation; version 2 of the License
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+# or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc., 59
+# Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+"""Unit tests for class ImageData"""
+
+import os
+import unittest
+
+from common.imagedata import ImageData, ImageDataError
+
+
+TEST_XML = '''<?xml version="1.0" ?>
+<images>
+  <image>
+    <name>XX-00</name>
+    <description>Image for device XX-00</description>
+    <path>images/XX-00/</path>
+    <ks>images/XX-00/xx-00.ks</ks>
+    <buildtarget>arm</buildtarget>
+    <arch>armv7l</arch>
+  </image>
+  <image>
+    <name>YY-01</name>
+    <description>Image for device YY-01</description>
+    <path>images/YY-01/</path>
+    <ks>images/YY-01/yy-01.ks</ks>
+    <buildtarget>standard</buildtarget>
+    <arch>ia32</arch>
+  </image>
+</images>
+'''
+
+class ImageDataTest(unittest.TestCase):
+    '''Tests for BuildData functionality.'''
+
+    def test_load(self):
+        """Test loading image data from xml."""
+        idata = ImageData()
+        idata.load(TEST_XML)
+        self.assertEqual(idata.images,
+                         {'XX-00': {'name': 'XX-00',
+                                    'description': 'Image for device XX-00',
+                                    'path': 'images/XX-00/',
+                                    'ks': 'images/XX-00/xx-00.ks',
+                                    'buildtarget': 'arm',
+                                    'arch': 'armv7l',
+                                    },
+                          'YY-01': {'name': 'YY-01',
+                                    'description': 'Image for device YY-01',
+                                    'path': 'images/YY-01/',
+                                    'ks': 'images/YY-01/yy-01.ks',
+                                    'buildtarget': 'standard',
+                                    'arch': 'ia32'}})
+
+    def test_load_error(self):
+        """Test rasing ImageDataError."""
+        idata = ImageData()
+        self.assertRaises(ImageDataError, idata.load, '<test/>')
+
+
+    def test_add_image(self):
+        """Test adding new image."""
+        idata = ImageData()
+        image = {'name': 'test_image', 'description': 'test image',
+                 'path': 'images/test/', 'ks': 'images/test/test.ks',
+                 'buildtarget': 'standard', 'arch': 'ia64'}
+        idata.add_image(image)
+        self.assertTrue(image["name"] in idata.images)
+
+
+    def test_to_xml(self):
+        """Test xml output."""
+        idata = ImageData()
+        idata.load(TEST_XML)
+        self.assertEqual(len(idata.to_xml()), 491)
+        self.assertEqual(len(idata.to_xml(hreadable=False)), 416)
+
+    def test_save(self):
+        """Test saving image data."""
+        saved = ImageData()
+        saved.load(TEST_XML)
+        fname = 'test_save.tmp'
+        saved.save(fname)
+        loaded = ImageData()
+        loaded.load(open(fname).read())
+        self.assertEqual(saved.images, loaded.images)
+        os.unlink(fname)