summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLaurentiu Palcu <laurentiu.palcu@intel.com>2013-12-18 17:24:08 +0200
committerRichard Purdie <richard.purdie@linuxfoundation.org>2014-02-11 11:53:38 +0000
commit8cfe5555a2977ab503cfc843520884d45c1e9338 (patch)
tree0903737a027e059a7a9185b618fdba606995bc27
parent7b840972e54d286df74c748f62653fcfd8aeeae8 (diff)
downloadpoky-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>
-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 @@
1from oe.utils import execute_pre_post_process
2import os
3import subprocess
4import multiprocessing
5
6
7def 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
22class 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
230def create_image(d):
231 Image(d).create()
232
233if __name__ == "__main__":
234 """
235 Image creation can be called independent from bitbake environment.
236 """
237 """
238 TBD
239 """