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/lib/oe/image.py | |
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/lib/oe/image.py')
-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 | """ | ||