Finished implementation of builddata API
authorEd Bartosh <eduard.bartosh@intel.com>
Wed, 15 May 2013 11:57:50 +0000 (14:57 +0300)
committerEd Bartosh <eduard.bartosh@intel.com>
Wed, 15 May 2013 11:59:11 +0000 (14:59 +0300)
Updated the code and tests to handle this format of build target:
    <buildtarget name="atom">
      <buildconf>
        <location href="3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf"/>
        <checksum type="sh256">3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8</checksum>
      </buildconf>
      <repo arch="i586" type="binary">repos/atom/i586/packages</repo>
      <repo arch="i586" type="binary">repos/atom/i586/debug</repo>
      <repo arch="x86_64" type="binary">repos/atom/x86_64/packages</repo>
      <repo arch="x86_64" type="binary">repos/atom/x86_64/debug</repo>
      <repo type="source">repos/atom/sources</repo>
    </buildtarget>

Change-Id: Ie300bff66699eb402af4b0ca7eaddc37a238c136

common/builddata.py
common/repomaker.py
tests/test_builddata.py

index c6aa613..7707423 100644 (file)
@@ -29,13 +29,7 @@ class BuildDataError(Exception):
     pass
 
 class BuildData(object):
-    """Class for handling build data.
-
-    NOTE! For now it contains only APIs used by pre-release job
-          (see usage example below).
-    NOTE! Feel free to add APIs, used by gbs here
-
-    """
+    """Class for handling build data."""
 
     # fixing of buggy xml.dom.minidom.toprettyxml
     XMLTEXT_RE = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
@@ -62,12 +56,12 @@ class BuildData(object):
         btargets = get_elem(dom, "buildtargets")
 
         for btarget in btargets.getElementsByTagName("buildtarget"):
-            print btarget.childNodes
             bconf = get_elem(btarget, "buildconf")
 
             target = {
                 "name":  btarget.getAttribute("name"),
                 "archs": [],
+                "repos": [],
                 "buildconf": {
                     "location":
                         get_elem(bconf, "location").getAttribute("href"),
@@ -77,10 +71,13 @@ class BuildData(object):
                     }
                 }
             }
-
             # Get archs
-            for barch in btarget.getElementsByTagName("arch"):
-                target["archs"].append(barch.getAttribute("name"))
+            for repo in btarget.getElementsByTagName("repo"):
+                barch = repo.getAttribute("arch")
+                if barch and barch not in target["archs"]:
+                    target["archs"].append(barch)
+                target["repos"].append((repo.getAttribute("type"), barch,
+                                        repo.firstChild.data))
 
             self.targets[target["name"]] = target
 
@@ -102,11 +99,6 @@ class BuildData(object):
             content += '<arch>%s</arch>' % arch
         content += '</archs>'
 
-        # build config
-        #for name in self.targets:
-        #    content += '<buildconf>%s</buildconf>' % \
-        #               self.targets[name]['buildconf']
-
         # build targets
         content += '<buildtargets>'
         for name in self.targets:
@@ -122,10 +114,14 @@ class BuildData(object):
                         buildconf['checksum']['value'])
             content += '</buildconf>'
 
-            # archs
-            content += '<arch default="yes">%s</arch>' % target['archs'][0]
-            for arch in target["archs"][1:]:
-                content += '<arch>%s</arch>' % arch
+            # repos
+            for rtype, rarch, rpath in target["repos"]:
+                if rarch:
+                    content += '<repo type="%s" arch="%s">%s</repo>' % (rtype,
+                                                                        rarch,
+                                                                        rpath)
+                else:
+                    content += '<repo type="%s">%s</repo>' % (rtype, rpath)
 
             content += '</buildtarget>'
         content += '</buildtargets></build>'
index 4cbe8a9..fc6763e 100644 (file)
@@ -57,17 +57,17 @@ def collect(in_dir):
 
 def create_dirs(repo_dir, archs):
     """Create directory structure of the repos."""
-    dirs =  [os.path.join(repo_dir, arch, subdir) for arch in archs \
-                 for subdir in ('packages', 'debug')]
-    dirs.append(os.path.join(repo_dir, "sources"))
-    dirs.append(os.path.join(repo_dir, "repodata"))
-    for dirname in dirs:
+    dirs =  [("binary", arch, os.path.join(repo_dir, arch, subdir)) \
+                 for arch in archs \
+                     for subdir in ('packages', 'debug')]
+    dirs.append(("source", None, os.path.join(repo_dir, "sources")))
+    for _type, _arch, dirname in dirs:
         if not os.path.exists(dirname):
             os.makedirs(dirname)
     return dirs
 
 def gen_target_dirs(repo_dir, archs, ftype, is_debug):
-    """"Prepare list of target dirs depending on type of package."""
+    """Prepare list of target dirs depending on type of package."""
     if ftype ==  "src":
         return [os.path.join(repo_dir, "sources")]
     else:
@@ -151,7 +151,7 @@ class RepoMaker(object):
                 for filename in ("group.xml", "patterns.xml"):
                     os.system("rpm2cpio %s | cpio -i --to-stdout "\
                               "./usr/share/package-groups/%s > %s" % \
-                              (fpath, filename, os.path.join(repo_dir,
+                              (fpath, filename, os.path.join(repo_dir, ftype,
                                                              "repodata",
                                                              filename)))
             # extract .ks file
@@ -161,29 +161,29 @@ class RepoMaker(object):
 
         # Save build configuration file if provided
         if buildconf:
-            confpath = os.path.join(repo_dir, "repodata",
-                                    "%s-build.conf" % name)
+            confpath = os.path.join(repo_dir, "%s-build.conf" % name)
             with open(confpath, 'w') as conf:
                 conf.write(buildconf)
-            # Generate or update build.xml
-            self.update_builddata(name, buildconf)
+
+        # Generate or update build.xml
+        self.update_builddata(name, dirs, buildconf)
 
         # TODO: Generate images.xml from previously saved data (see above)
 
         # Run createrepo
-        for repo in dirs:
+        for _rtype, _rarch, rpath in dirs:
             # run createrepo
-            os.system('createrepo --quiet %s' % repo)
+            os.system('createrepo --quiet %s' % rpath)
 
         # sign if gpg_key is provided
         if gpg_key and os.path.exists(signer) and os.access(signer, os.X_OK):
-            for repo in dirs:
-                repomd_path = os.path.join(repo_dir, repo, "repodata",
+            for _rtype, _rarch, rpath in dirs:
+                repomd_path = os.path.join(rpath, "repodata",
                                            "repomd.xml")
                 os.system('%s -d % s' % (signer, repomd_path))
 
 
-    def update_builddata(self, name, buildconf=None):
+    def update_builddata(self, name, dirs, buildconf=None):
         """
         Update or create build.xml
 
@@ -194,18 +194,22 @@ class RepoMaker(object):
         Raises: RepoMakerError
 
         """
-        try:
-            bdata = BuildData(self.build_id)
-            target = {"name":  name, "archs": list(self.repos[name]['archs'])}
-            if buildconf:
-                target["buildconf"] = {
-                    "location": os.path.join("repos", name),
-                    "checksum": {
-                       "type": "sh256",
-                       "value": sha256(buildconf).hexdigest()
-                    }
+        repos = self.repos[name]
+        target = {"name":  name, "archs": list(repos['archs'])}
+        if buildconf:
+            target["buildconf"] = {
+                "location": os.path.join("repos", name),
+                "checksum": {
+                   "type": "sh256",
+                   "value": sha256(buildconf).hexdigest()
                 }
+            }
+        target["repos"] = [(rtype, rarch,
+                            os.path.join('repos', rpath.split('repos/')[1])) \
+                                for rtype, rarch, rpath in dirs]
 
+        try:
+            bdata = BuildData(self.build_id)
             # Create or update build.xml
             outf = os.path.join(self.outdir, 'build.xml')
             if os.path.exists(outf):
index d4ecdf4..ffac2fd 100644 (file)
@@ -25,46 +25,40 @@ from collections import OrderedDict
 from common.builddata import BuildData, BuildDataError
 
 
-TEST_XML = """<?xml version="1.0"?>
+TEST_XML = """<?xml version="1.0" ?>
 <build version="1.0">
-  <archs>
-    <arch>i586</arch>
-    <arch>armv7l</arch>
-  </archs>
+  <id>test.id</id>
   <repos>
-    <repo>exynos</repo>
     <repo>atom</repo>
+    <repo>exynos</repo>
   </repos>
+  <archs>
+    <arch>x86_64</arch>
+    <arch>armv7l</arch>
+    <arch>i586</arch>
+  </archs>
   <buildtargets>
     <buildtarget name="atom">
       <buildconf>
         <location href="3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf"/>
         <checksum type="sh256">3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8</checksum>
       </buildconf>
-      <arch default="yes" name="i586">
-        <repo type="binary">repos/atom/i586/packages</repo>
-        <repo type="debug">repos/atom/i586/debug</repo>
-        <repo type="source">repos/atom/i586/sources</repo>
-      </arch>
-      <arch name="x86_64">
-        <repo type="binary">repos/atom/x86_64/packages</repo>
-        <repo type="debug">repos/atom/x86_64/debug</repo>
-        <repo type="source">repos/atom/x86_64/sources</repo>
-      </arch>
+      <repo arch="i586" type="binary">repos/atom/i586/packages</repo>
+      <repo arch="i586" type="binary">repos/atom/i586/debug</repo>
+      <repo arch="x86_64" type="binary">repos/atom/x86_64/packages</repo>
+      <repo arch="x86_64" type="binary">repos/atom/x86_64/debug</repo>
+      <repo type="source">repos/atom/sources</repo>
     </buildtarget>
     <buildtarget name="exynos">
       <buildconf>
         <location href="3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf"/>
         <checksum type="sh256">3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8</checksum>
       </buildconf>
-      <arch default="yes" name="armv7l">
-        <repo type="binary">repos/exynos/armv7l/packages</repo>
-        <repo type="debug">repos/exynos/armv7l/debug</repo>
-        <repo type="source">repos/exynos/armv7l/sources</repo>
-      </arch>
+      <repo arch="armv7l" type="binary">repos/exynos/armv7l/packages</repo>
+      <repo arch="armv7l" type="binary">repos/exynos/armv7l/debug</repo>
+      <repo type="source">repos/exynos/sources</repo>
     </buildtarget>
   </buildtargets>
-  <id>tizen-2.1_20130326.13</id>
 </build>
 """
 
@@ -75,17 +69,30 @@ class BuildDataTest(unittest.TestCase):
         bdata = BuildData(build_id='test.id')
         bdata.load(TEST_XML)
         self.assertEqual(bdata.targets, OrderedDict(
-            [(u'atom', {'buildconf':
-               {'checksum': {'type': u'sh256',
-                             'value': u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8'},
-                'location':  u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf'},
+            [(u'atom',
+              {"repos":
+               [(u'binary', u'i586', u'repos/atom/i586/packages'),
+                (u'binary', u'i586', u'repos/atom/i586/debug'),
+                (u'binary', u'x86_64', u'repos/atom/x86_64/packages'),
+                (u'binary', u'x86_64', u'repos/atom/x86_64/debug'),
+                (u'source', '', u'repos/atom/sources')],
+               'buildconf':
+                 {'checksum': {'type': u'sh256',
+                  'value': u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8'},
+                  'location':  u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf'},
                'name': u'atom', 'archs': [u'i586', u'x86_64']}),
-             (u'exynos', {'buildconf':
+             (u'exynos',
+              {"repos":
+               [(u'binary', u'armv7l', u'repos/exynos/armv7l/packages'),
+                (u'binary', u'armv7l', u'repos/exynos/armv7l/debug'),
+                (u'source', '', u'repos/exynos/sources')],
+               'buildconf':
                {'checksum': {'type': u'sh256',
                              'value': u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8'},
                 'location': u'3bd64bd5fa862d99dbc363ccb1557d137b5685bc3bfe9a86bcbf50767da5e2e8-build.conf'},
                'name': u'exynos', 'archs': [u'armv7l']})]))
 
+
     def test_load_error(self):
         """Test rasing BuildDataError."""
         bdata = BuildData(1)
@@ -103,7 +110,11 @@ class BuildDataTest(unittest.TestCase):
                           "value": "45c5fb8bd2b9065bd7eb961cf3663b8c"
                        },
                       "location": 'build.conf'
-                   }
+                   },
+                  "repos": [
+                      ("binary", "arm7vl", "repos/exynos/armv71/packages"),
+                      ("binary", "arm7vl", "repos/exynos/armv71/debug"),
+                      ("source", None, "repos/exynos/sources")]
                  }
 
         bdata.add_target(target)
@@ -114,8 +125,8 @@ class BuildDataTest(unittest.TestCase):
         """Test xml output."""
         bdata = BuildData(build_id='test.id')
         bdata.load(TEST_XML)
-        self.assertEqual(len(bdata.to_xml()), 964)
-        self.assertEqual(len(bdata.to_xml(hreadable=False)), 809)
+        self.assertEqual(bdata.to_xml(), TEST_XML)
+        self.assertEqual(len(bdata.to_xml(hreadable=False)), 1207)
 
 
     def test_save(self):
@@ -123,5 +134,5 @@ class BuildDataTest(unittest.TestCase):
         bdata.load(TEST_XML)
         fname = 'test_save.tmp'
         bdata.save(fname)
-        self.assertEqual(len(open(fname).read()), 964)
+        self.assertEqual(open(fname).read(), TEST_XML)
         os.unlink(fname)