[oe-commits] Laurentiu Palcu : lib/oe/image.py: add new image creation library

git at git.openembedded.org git at git.openembedded.org
Tue Feb 11 11:56:58 UTC 2014


Module: openembedded-core.git
Branch: master-next
Commit: b75b78ce534fbf0d4de2f7f66af5b721d68b7471
URL:    http://git.openembedded.org/?p=openembedded-core.git&a=commit;h=b75b78ce534fbf0d4de2f7f66af5b721d68b7471

Author: Laurentiu Palcu <laurentiu.palcu at intel.com>
Date:   Wed Dec 18 17:24:08 2013 +0200

lib/oe/image.py: add new image creation library

This will replace the old bash image creation code. This needs the
rootfs to be already generated in order to work.

Usage:
  Image(d).create()
or using the provided wrapper function:
  create_image(d)

Signed-off-by: Laurentiu Palcu <laurentiu.palcu at intel.com>

---

 meta/lib/oe/image.py | 239 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 239 insertions(+)

diff --git a/meta/lib/oe/image.py b/meta/lib/oe/image.py
new file mode 100644
index 0000000..c4fd558
--- /dev/null
+++ b/meta/lib/oe/image.py
@@ -0,0 +1,239 @@
+from oe.utils import execute_pre_post_process
+import os
+import subprocess
+import multiprocessing
+
+
+def generate_image(arg):
+    (type, subimages, create_img_cmd) = arg
+
+    bb.note("Running image creation script for %s: %s ..." %
+            (type, create_img_cmd))
+
+    try:
+        subprocess.check_output(create_img_cmd)
+    except subprocess.CalledProcessError as e:
+        return("Error: The image creation script %s returned %d!" %
+               (e.cmd, e.returncode))
+
+    return None
+
+
+class Image(object):
+    def __init__(self, d):
+        self.d = d
+
+    def _get_rootfs_size(self):
+        """compute the rootfs size"""
+        rootfs_alignment = int(self.d.getVar('IMAGE_ROOTFS_ALIGNMENT', True))
+        overhead_factor = float(self.d.getVar('IMAGE_OVERHEAD_FACTOR', True))
+        rootfs_req_size = int(self.d.getVar('IMAGE_ROOTFS_SIZE', True))
+        rootfs_extra_space = int(self.d.getVar('IMAGE_ROOTFS_EXTRA_SPACE', True))
+
+        output = subprocess.check_output(['du', '-ks',
+                                          self.d.getVar('IMAGE_ROOTFS', True)])
+        size_kb = int(output.split()[0])
+        base_size = size_kb * overhead_factor
+        if base_size < rootfs_req_size:
+            base_size = rootfs_req_size + rootfs_extra_space
+
+        if base_size != int(base_size):
+            base_size = int(base_size + 1)
+
+        base_size += rootfs_alignment - 1
+        base_size -= base_size % rootfs_alignment
+
+        return base_size
+
+    def _create_symlinks(self, subimages):
+        """create symlinks to the newly created image"""
+        deploy_dir = self.d.getVar('DEPLOY_DIR_IMAGE', True)
+        img_name = self.d.getVar('IMAGE_NAME', True)
+        link_name = self.d.getVar('IMAGE_LINK_NAME', True)
+        manifest_name = self.d.getVar('IMAGE_MANIFEST', True)
+
+        os.chdir(deploy_dir)
+
+        if link_name is not None:
+            for type in subimages:
+                if os.path.exists(img_name + ".rootfs." + type):
+                    dst = link_name + "." + type
+                    src = img_name + ".rootfs." + type
+                    bb.note("Creating symlink: %s -> %s" % (dst, src))
+                    os.symlink(src, dst)
+
+            if manifest_name is not None and \
+                    os.path.exists(manifest_name) and \
+                    not os.path.exists(link_name + ".manifest"):
+                os.symlink(os.path.basename(manifest_name),
+                           link_name + ".manifest")
+
+    def _remove_old_symlinks(self):
+        """remove the symlinks to old binaries"""
+
+        if self.d.getVar('IMAGE_LINK_NAME', True):
+            deploy_dir = self.d.getVar('DEPLOY_DIR_IMAGE', True)
+            for img in os.listdir(deploy_dir):
+                if img.find(self.d.getVar('IMAGE_LINK_NAME', True)) == 0:
+                    img = os.path.join(deploy_dir, img)
+                    if os.path.islink(img):
+                        if self.d.getVar('RM_OLD_IMAGE', True) == "1":
+                            os.remove(os.path.realpath(img))
+
+                        os.remove(img)
+
+    def _get_image_types(self):
+        """returns a (types, cimages) tuple"""
+
+        alltypes = self.d.getVar('IMAGE_FSTYPES', True).split()
+        types = []
+        ctypes = self.d.getVar('COMPRESSIONTYPES', True).split()
+        cimages = {}
+
+        # Image type b depends on a having been generated first
+        def addtypedepends(a, b):
+            if a in alltypes:
+                alltypes.remove(a)
+                if b not in alltypes:
+                    alltypes.append(b)
+                alltypes.append(a)
+
+        # The elf image depends on the cpio.gz image already having
+        # been created, so we add that explicit ordering here.
+        addtypedepends("elf", "cpio.gz")
+
+        # jffs2 sumtool'd images need jffs2
+        addtypedepends("sum.jffs2", "jffs2")
+
+        # Filter out all the compressed images from alltypes
+        for type in alltypes:
+            basetype = None
+            for ctype in ctypes:
+                if type.endswith("." + ctype):
+                    basetype = type[:-len("." + ctype)]
+                    if basetype not in types:
+                        types.append(basetype)
+                    if basetype not in cimages:
+                        cimages[basetype] = []
+                    if ctype not in cimages[basetype]:
+                        cimages[basetype].append(ctype)
+                    break
+            if not basetype and type not in types:
+                types.append(type)
+
+        # Live and VMDK images will be processed via inheriting
+        # bbclass and does not get processed here.
+        # vmdk depend on live images also depend on ext3 so ensure its present
+        # Note: we need to ensure ext3 is in alltypes, otherwise, subimages may
+        # not contain ext3 and the .rootfs.ext3 file won't be created.
+        if "vmdk" in types:
+            if "ext3" not in types:
+                types.append("ext3")
+            if "ext3" not in alltypes:
+                alltypes.append("ext3")
+            types.remove("vmdk")
+        if "live" in types or "iso" in types or "hddimg" in types:
+            if "ext3" not in types:
+                types.append("ext3")
+            if "ext3" not in alltypes:
+                alltypes.append("ext3")
+            if "live" in types:
+                types.remove("live")
+            if "iso" in types:
+                types.remove("iso")
+            if "hddimg" in types:
+                types.remove("hddimg")
+
+        return (alltypes, types, cimages)
+
+    def _write_script(self, type, cmds):
+        tempdir = self.d.getVar('T', True)
+        script_name = os.path.join(tempdir, "create_image." + type)
+
+        self.d.setVar('img_creation_func', '\n'.join(cmds))
+        self.d.setVarFlag('img_creation_func', 'func', 1)
+        self.d.setVarFlag('img_creation_func', 'fakeroot', 1)
+
+        with open(script_name, "w+") as script:
+            script.write("%s" % bb.build.shell_trap_code())
+            script.write("export ROOTFS_SIZE=%d\n" % self._get_rootfs_size())
+            bb.data.emit_func('img_creation_func', script, self.d)
+            script.write("img_creation_func\n")
+
+        os.chmod(script_name, 0775)
+
+        return script_name
+
+    def _get_imagecmds(self):
+        old_overrides = self.d.getVar('OVERRIDES', 0)
+
+        alltypes, types, cimages = self._get_image_types()
+
+        image_cmds = []
+        for type in types:
+            cmds = []
+            subimages = []
+
+            localdata = bb.data.createCopy(self.d)
+            localdata.setVar('OVERRIDES', '%s:%s' % (type, old_overrides))
+            bb.data.update_data(localdata)
+            localdata.setVar('type', type)
+
+            cmds.append("\t" + localdata.getVar("IMAGE_CMD", True))
+            cmds.append(localdata.expand("\tcd ${DEPLOY_DIR_IMAGE}"))
+
+            if type in cimages:
+                for ctype in cimages[type]:
+                    cmds.append("\t" + localdata.getVar("COMPRESS_CMD_" + ctype, True))
+                    subimages.append(type + "." + ctype)
+
+            if type not in alltypes:
+                cmds.append(localdata.expand("\trm ${IMAGE_NAME}.rootfs.${type}"))
+            else:
+                subimages.append(type)
+
+            script_name = self._write_script(type, cmds)
+
+            image_cmds.append((type, subimages, script_name))
+
+        return image_cmds
+
+    def create(self):
+        bb.note("###### Generate images #######")
+        pre_process_cmds = self.d.getVar("IMAGE_PREPROCESS_COMMAND", True)
+        post_process_cmds = self.d.getVar("IMAGE_POSTPROCESS_COMMAND", True)
+
+        execute_pre_post_process(self.d, pre_process_cmds)
+
+        self._remove_old_symlinks()
+
+        image_cmds = self._get_imagecmds()
+
+        # create the images in parallel
+        nproc = multiprocessing.cpu_count()
+        pool = bb.utils.multiprocessingpool(nproc)
+        results = list(pool.imap(generate_image, image_cmds))
+        pool.close()
+        pool.join()
+
+        for result in results:
+            if result is not None:
+                bb.fatal(result)
+
+        for image_type, subimages, script in image_cmds:
+            bb.note("Creating symlinks for %s image ..." % image_type)
+            self._create_symlinks(subimages)
+
+        execute_pre_post_process(self.d, post_process_cmds)
+
+
+def create_image(d):
+    Image(d).create()
+
+if __name__ == "__main__":
+    """
+    Image creation can be called independent from bitbake environment.
+    """
+    """
+    TBD
+    """



More information about the Openembedded-commits mailing list