diff options
| author | Laurentiu Palcu <laurentiu.palcu@intel.com> | 2013-12-18 17:24:08 +0200 |
|---|---|---|
| committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2014-02-11 11:53:38 +0000 |
| commit | 8cfe5555a2977ab503cfc843520884d45c1e9338 (patch) | |
| tree | 0903737a027e059a7a9185b618fdba606995bc27 /meta | |
| parent | 7b840972e54d286df74c748f62653fcfd8aeeae8 (diff) | |
| download | poky-8cfe5555a2977ab503cfc843520884d45c1e9338.tar.gz | |
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)
(From OE-Core rev: b75b78ce534fbf0d4de2f7f66af5b721d68b7471)
Signed-off-by: Laurentiu Palcu <laurentiu.palcu@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
| -rw-r--r-- | meta/lib/oe/image.py | 239 |
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 @@ | |||
| 1 | from oe.utils import execute_pre_post_process | ||
| 2 | import os | ||
| 3 | import subprocess | ||
| 4 | import multiprocessing | ||
| 5 | |||
| 6 | |||
| 7 | def generate_image(arg): | ||
| 8 | (type, subimages, create_img_cmd) = arg | ||
| 9 | |||
| 10 | bb.note("Running image creation script for %s: %s ..." % | ||
| 11 | (type, create_img_cmd)) | ||
| 12 | |||
| 13 | try: | ||
| 14 | subprocess.check_output(create_img_cmd) | ||
| 15 | except subprocess.CalledProcessError as e: | ||
| 16 | return("Error: The image creation script %s returned %d!" % | ||
| 17 | (e.cmd, e.returncode)) | ||
| 18 | |||
| 19 | return None | ||
| 20 | |||
| 21 | |||
| 22 | class Image(object): | ||
| 23 | def __init__(self, d): | ||
| 24 | self.d = d | ||
| 25 | |||
| 26 | def _get_rootfs_size(self): | ||
| 27 | """compute the rootfs size""" | ||
| 28 | rootfs_alignment = int(self.d.getVar('IMAGE_ROOTFS_ALIGNMENT', True)) | ||
| 29 | overhead_factor = float(self.d.getVar('IMAGE_OVERHEAD_FACTOR', True)) | ||
| 30 | rootfs_req_size = int(self.d.getVar('IMAGE_ROOTFS_SIZE', True)) | ||
| 31 | rootfs_extra_space = int(self.d.getVar('IMAGE_ROOTFS_EXTRA_SPACE', True)) | ||
| 32 | |||
| 33 | output = subprocess.check_output(['du', '-ks', | ||
| 34 | self.d.getVar('IMAGE_ROOTFS', True)]) | ||
| 35 | size_kb = int(output.split()[0]) | ||
| 36 | base_size = size_kb * overhead_factor | ||
| 37 | if base_size < rootfs_req_size: | ||
| 38 | base_size = rootfs_req_size + rootfs_extra_space | ||
| 39 | |||
| 40 | if base_size != int(base_size): | ||
| 41 | base_size = int(base_size + 1) | ||
| 42 | |||
| 43 | base_size += rootfs_alignment - 1 | ||
| 44 | base_size -= base_size % rootfs_alignment | ||
| 45 | |||
| 46 | return base_size | ||
| 47 | |||
| 48 | def _create_symlinks(self, subimages): | ||
| 49 | """create symlinks to the newly created image""" | ||
| 50 | deploy_dir = self.d.getVar('DEPLOY_DIR_IMAGE', True) | ||
| 51 | img_name = self.d.getVar('IMAGE_NAME', True) | ||
| 52 | link_name = self.d.getVar('IMAGE_LINK_NAME', True) | ||
| 53 | manifest_name = self.d.getVar('IMAGE_MANIFEST', True) | ||
| 54 | |||
| 55 | os.chdir(deploy_dir) | ||
| 56 | |||
| 57 | if link_name is not None: | ||
| 58 | for type in subimages: | ||
| 59 | if os.path.exists(img_name + ".rootfs." + type): | ||
| 60 | dst = link_name + "." + type | ||
| 61 | src = img_name + ".rootfs." + type | ||
| 62 | bb.note("Creating symlink: %s -> %s" % (dst, src)) | ||
| 63 | os.symlink(src, dst) | ||
| 64 | |||
| 65 | if manifest_name is not None and \ | ||
| 66 | os.path.exists(manifest_name) and \ | ||
| 67 | not os.path.exists(link_name + ".manifest"): | ||
| 68 | os.symlink(os.path.basename(manifest_name), | ||
| 69 | link_name + ".manifest") | ||
| 70 | |||
| 71 | def _remove_old_symlinks(self): | ||
| 72 | """remove the symlinks to old binaries""" | ||
| 73 | |||
| 74 | if self.d.getVar('IMAGE_LINK_NAME', True): | ||
| 75 | deploy_dir = self.d.getVar('DEPLOY_DIR_IMAGE', True) | ||
| 76 | for img in os.listdir(deploy_dir): | ||
| 77 | if img.find(self.d.getVar('IMAGE_LINK_NAME', True)) == 0: | ||
| 78 | img = os.path.join(deploy_dir, img) | ||
| 79 | if os.path.islink(img): | ||
| 80 | if self.d.getVar('RM_OLD_IMAGE', True) == "1": | ||
| 81 | os.remove(os.path.realpath(img)) | ||
| 82 | |||
| 83 | os.remove(img) | ||
| 84 | |||
| 85 | def _get_image_types(self): | ||
| 86 | """returns a (types, cimages) tuple""" | ||
| 87 | |||
| 88 | alltypes = self.d.getVar('IMAGE_FSTYPES', True).split() | ||
| 89 | types = [] | ||
| 90 | ctypes = self.d.getVar('COMPRESSIONTYPES', True).split() | ||
| 91 | cimages = {} | ||
| 92 | |||
| 93 | # Image type b depends on a having been generated first | ||
| 94 | def addtypedepends(a, b): | ||
| 95 | if a in alltypes: | ||
| 96 | alltypes.remove(a) | ||
| 97 | if b not in alltypes: | ||
| 98 | alltypes.append(b) | ||
| 99 | alltypes.append(a) | ||
| 100 | |||
| 101 | # The elf image depends on the cpio.gz image already having | ||
| 102 | # been created, so we add that explicit ordering here. | ||
| 103 | addtypedepends("elf", "cpio.gz") | ||
| 104 | |||
| 105 | # jffs2 sumtool'd images need jffs2 | ||
| 106 | addtypedepends("sum.jffs2", "jffs2") | ||
| 107 | |||
| 108 | # Filter out all the compressed images from alltypes | ||
| 109 | for type in alltypes: | ||
| 110 | basetype = None | ||
| 111 | for ctype in ctypes: | ||
| 112 | if type.endswith("." + ctype): | ||
| 113 | basetype = type[:-len("." + ctype)] | ||
| 114 | if basetype not in types: | ||
| 115 | types.append(basetype) | ||
| 116 | if basetype not in cimages: | ||
| 117 | cimages[basetype] = [] | ||
| 118 | if ctype not in cimages[basetype]: | ||
| 119 | cimages[basetype].append(ctype) | ||
| 120 | break | ||
| 121 | if not basetype and type not in types: | ||
| 122 | types.append(type) | ||
| 123 | |||
| 124 | # Live and VMDK images will be processed via inheriting | ||
| 125 | # bbclass and does not get processed here. | ||
| 126 | # vmdk depend on live images also depend on ext3 so ensure its present | ||
| 127 | # Note: we need to ensure ext3 is in alltypes, otherwise, subimages may | ||
| 128 | # not contain ext3 and the .rootfs.ext3 file won't be created. | ||
| 129 | if "vmdk" in types: | ||
| 130 | if "ext3" not in types: | ||
| 131 | types.append("ext3") | ||
| 132 | if "ext3" not in alltypes: | ||
| 133 | alltypes.append("ext3") | ||
| 134 | types.remove("vmdk") | ||
| 135 | if "live" in types or "iso" in types or "hddimg" in types: | ||
| 136 | if "ext3" not in types: | ||
| 137 | types.append("ext3") | ||
| 138 | if "ext3" not in alltypes: | ||
| 139 | alltypes.append("ext3") | ||
| 140 | if "live" in types: | ||
| 141 | types.remove("live") | ||
| 142 | if "iso" in types: | ||
| 143 | types.remove("iso") | ||
| 144 | if "hddimg" in types: | ||
| 145 | types.remove("hddimg") | ||
| 146 | |||
| 147 | return (alltypes, types, cimages) | ||
| 148 | |||
| 149 | def _write_script(self, type, cmds): | ||
| 150 | tempdir = self.d.getVar('T', True) | ||
| 151 | script_name = os.path.join(tempdir, "create_image." + type) | ||
| 152 | |||
| 153 | self.d.setVar('img_creation_func', '\n'.join(cmds)) | ||
| 154 | self.d.setVarFlag('img_creation_func', 'func', 1) | ||
| 155 | self.d.setVarFlag('img_creation_func', 'fakeroot', 1) | ||
| 156 | |||
| 157 | with open(script_name, "w+") as script: | ||
| 158 | script.write("%s" % bb.build.shell_trap_code()) | ||
| 159 | script.write("export ROOTFS_SIZE=%d\n" % self._get_rootfs_size()) | ||
| 160 | bb.data.emit_func('img_creation_func', script, self.d) | ||
| 161 | script.write("img_creation_func\n") | ||
| 162 | |||
| 163 | os.chmod(script_name, 0775) | ||
| 164 | |||
| 165 | return script_name | ||
| 166 | |||
| 167 | def _get_imagecmds(self): | ||
| 168 | old_overrides = self.d.getVar('OVERRIDES', 0) | ||
| 169 | |||
| 170 | alltypes, types, cimages = self._get_image_types() | ||
| 171 | |||
| 172 | image_cmds = [] | ||
| 173 | for type in types: | ||
| 174 | cmds = [] | ||
| 175 | subimages = [] | ||
| 176 | |||
| 177 | localdata = bb.data.createCopy(self.d) | ||
| 178 | localdata.setVar('OVERRIDES', '%s:%s' % (type, old_overrides)) | ||
| 179 | bb.data.update_data(localdata) | ||
| 180 | localdata.setVar('type', type) | ||
| 181 | |||
| 182 | cmds.append("\t" + localdata.getVar("IMAGE_CMD", True)) | ||
| 183 | cmds.append(localdata.expand("\tcd ${DEPLOY_DIR_IMAGE}")) | ||
| 184 | |||
| 185 | if type in cimages: | ||
| 186 | for ctype in cimages[type]: | ||
| 187 | cmds.append("\t" + localdata.getVar("COMPRESS_CMD_" + ctype, True)) | ||
| 188 | subimages.append(type + "." + ctype) | ||
| 189 | |||
| 190 | if type not in alltypes: | ||
| 191 | cmds.append(localdata.expand("\trm ${IMAGE_NAME}.rootfs.${type}")) | ||
| 192 | else: | ||
| 193 | subimages.append(type) | ||
| 194 | |||
| 195 | script_name = self._write_script(type, cmds) | ||
| 196 | |||
| 197 | image_cmds.append((type, subimages, script_name)) | ||
| 198 | |||
| 199 | return image_cmds | ||
| 200 | |||
| 201 | def create(self): | ||
| 202 | bb.note("###### Generate images #######") | ||
| 203 | pre_process_cmds = self.d.getVar("IMAGE_PREPROCESS_COMMAND", True) | ||
| 204 | post_process_cmds = self.d.getVar("IMAGE_POSTPROCESS_COMMAND", True) | ||
| 205 | |||
| 206 | execute_pre_post_process(self.d, pre_process_cmds) | ||
| 207 | |||
| 208 | self._remove_old_symlinks() | ||
| 209 | |||
| 210 | image_cmds = self._get_imagecmds() | ||
| 211 | |||
| 212 | # create the images in parallel | ||
| 213 | nproc = multiprocessing.cpu_count() | ||
| 214 | pool = bb.utils.multiprocessingpool(nproc) | ||
| 215 | results = list(pool.imap(generate_image, image_cmds)) | ||
| 216 | pool.close() | ||
| 217 | pool.join() | ||
| 218 | |||
| 219 | for result in results: | ||
| 220 | if result is not None: | ||
| 221 | bb.fatal(result) | ||
| 222 | |||
| 223 | for image_type, subimages, script in image_cmds: | ||
| 224 | bb.note("Creating symlinks for %s image ..." % image_type) | ||
| 225 | self._create_symlinks(subimages) | ||
| 226 | |||
| 227 | execute_pre_post_process(self.d, post_process_cmds) | ||
| 228 | |||
| 229 | |||
| 230 | def create_image(d): | ||
| 231 | Image(d).create() | ||
| 232 | |||
| 233 | if __name__ == "__main__": | ||
| 234 | """ | ||
| 235 | Image creation can be called independent from bitbake environment. | ||
| 236 | """ | ||
| 237 | """ | ||
| 238 | TBD | ||
| 239 | """ | ||
