summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--meta/lib/oe/image.py239
1 files changed, 239 insertions, 0 deletions
diff --git a/meta/lib/oe/image.py b/meta/lib/oe/image.py
new file mode 100644
index 0000000000..c4fd558484
--- /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
+ """