summaryrefslogtreecommitdiffstats
path: root/meta/lib/oe/rootfs.py
diff options
context:
space:
mode:
Diffstat (limited to 'meta/lib/oe/rootfs.py')
-rw-r--r--meta/lib/oe/rootfs.py757
1 files changed, 757 insertions, 0 deletions
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py
new file mode 100644
index 0000000000..dddbef4d64
--- /dev/null
+++ b/meta/lib/oe/rootfs.py
@@ -0,0 +1,757 @@
1from abc import ABCMeta, abstractmethod
2from oe.utils import execute_pre_post_process
3from oe.utils import contains as base_contains
4from oe.package_manager import *
5from oe.manifest import *
6import oe.path
7import filecmp
8import shutil
9import os
10import subprocess
11import re
12
13
14class Rootfs(object):
15 """
16 This is an abstract class. Do not instantiate this directly.
17 """
18 __metaclass__ = ABCMeta
19
20 def __init__(self, d):
21 self.d = d
22 self.pm = None
23 self.image_rootfs = self.d.getVar('IMAGE_ROOTFS', True)
24 self.deploy_dir_image = self.d.getVar('DEPLOY_DIR_IMAGE', True)
25
26 self.install_order = Manifest.INSTALL_ORDER
27
28 @abstractmethod
29 def _create(self):
30 pass
31
32 @abstractmethod
33 def _get_delayed_postinsts(self):
34 pass
35
36 @abstractmethod
37 def _save_postinsts(self):
38 pass
39
40 @abstractmethod
41 def _log_check(self):
42 pass
43
44 def _insert_feed_uris(self):
45 if base_contains("IMAGE_FEATURES", "package-management",
46 True, False, self.d):
47 self.pm.insert_feeds_uris()
48
49 @abstractmethod
50 def _handle_intercept_failure(self, failed_script):
51 pass
52
53 """
54 The _cleanup() method should be used to clean-up stuff that we don't really
55 want to end up on target. For example, in the case of RPM, the DB locks.
56 The method is called, once, at the end of create() method.
57 """
58 @abstractmethod
59 def _cleanup(self):
60 pass
61
62 def _exec_shell_cmd(self, cmd):
63 fakerootcmd = self.d.getVar('FAKEROOT', True)
64 if fakerootcmd is not None:
65 exec_cmd = [fakerootcmd, cmd]
66 else:
67 exec_cmd = cmd
68
69 try:
70 subprocess.check_output(exec_cmd, stderr=subprocess.STDOUT)
71 except subprocess.CalledProcessError as e:
72 return("Command '%s' returned %d:\n%s" % (e.cmd, e.returncode, e.output))
73
74 return None
75
76 def create(self):
77 bb.note("###### Generate rootfs #######")
78 pre_process_cmds = self.d.getVar("ROOTFS_PREPROCESS_COMMAND", True)
79 post_process_cmds = self.d.getVar("ROOTFS_POSTPROCESS_COMMAND", True)
80
81 intercepts_dir = os.path.join(self.d.getVar('WORKDIR', True),
82 "intercept_scripts")
83
84 bb.utils.remove(intercepts_dir, True)
85
86 bb.utils.mkdirhier(self.image_rootfs)
87
88 bb.utils.mkdirhier(self.deploy_dir_image)
89
90 shutil.copytree(self.d.expand("${COREBASE}/scripts/postinst-intercepts"),
91 intercepts_dir)
92
93 shutil.copy(self.d.expand("${COREBASE}/meta/files/deploydir_readme.txt"),
94 self.deploy_dir_image +
95 "/README_-_DO_NOT_DELETE_FILES_IN_THIS_DIRECTORY.txt")
96
97 execute_pre_post_process(self.d, pre_process_cmds)
98
99 # call the package manager dependent create method
100 self._create()
101
102 sysconfdir = self.image_rootfs + self.d.getVar('sysconfdir', True)
103 bb.utils.mkdirhier(sysconfdir)
104 with open(sysconfdir + "/version", "w+") as ver:
105 ver.write(self.d.getVar('BUILDNAME', True) + "\n")
106
107 self._run_intercepts()
108
109 execute_pre_post_process(self.d, post_process_cmds)
110
111 if base_contains("IMAGE_FEATURES", "read-only-rootfs",
112 True, False, self.d):
113 delayed_postinsts = self._get_delayed_postinsts()
114 if delayed_postinsts is not None:
115 bb.fatal("The following packages could not be configured"
116 "offline and rootfs is read-only: %s" %
117 delayed_postinsts)
118
119 if self.d.getVar('USE_DEVFS', True) != "1":
120 self._create_devfs()
121
122 self._uninstall_uneeded()
123
124 self._insert_feed_uris()
125
126 self._run_ldconfig()
127
128 self._generate_kernel_module_deps()
129
130 self._cleanup()
131
132 def _uninstall_uneeded(self):
133 if base_contains("IMAGE_FEATURES", "package-management",
134 True, False, self.d):
135 return
136
137 delayed_postinsts = self._get_delayed_postinsts()
138 if delayed_postinsts is None:
139 installed_pkgs_dir = self.d.expand('${WORKDIR}/installed_pkgs.txt')
140 pkgs_to_remove = list()
141 with open(installed_pkgs_dir, "r+") as installed_pkgs:
142 pkgs_installed = installed_pkgs.read().split('\n')
143 for pkg_installed in pkgs_installed[:]:
144 pkg = pkg_installed.split()[0]
145 if pkg in ["update-rc.d",
146 "base-passwd",
147 self.d.getVar("ROOTFS_BOOTSTRAP_INSTALL", True)
148 ]:
149 pkgs_to_remove.append(pkg)
150 pkgs_installed.remove(pkg_installed)
151
152 if len(pkgs_to_remove) > 0:
153 self.pm.remove(pkgs_to_remove, False)
154 # Update installed_pkgs.txt
155 open(installed_pkgs_dir, "w+").write('\n'.join(pkgs_installed))
156
157 if os.path.exists(self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/init.d/run-postinsts")):
158 self._exec_shell_cmd(["update-rc.d", "-f", "-r",
159 self.d.getVar('IMAGE_ROOTFS', True),
160 "run-postinsts", "remove"])
161 else:
162 self._save_postinsts()
163
164 self.pm.remove_packaging_data()
165
166 def _run_intercepts(self):
167 intercepts_dir = os.path.join(self.d.getVar('WORKDIR', True),
168 "intercept_scripts")
169
170 bb.note("Running intercept scripts:")
171 os.environ['D'] = self.image_rootfs
172 for script in os.listdir(intercepts_dir):
173 script_full = os.path.join(intercepts_dir, script)
174
175 if script == "postinst_intercept" or not os.access(script_full, os.X_OK):
176 continue
177
178 bb.note("> Executing %s intercept ..." % script)
179
180 try:
181 subprocess.check_output(script_full)
182 except subprocess.CalledProcessError as e:
183 bb.warn("The postinstall intercept hook '%s' failed (exit code: %d)! See log for details!" %
184 (script, e.returncode))
185
186 with open(script_full) as intercept:
187 registered_pkgs = None
188 for line in intercept.read().split("\n"):
189 m = re.match("^##PKGS:(.*)", line)
190 if m is not None:
191 registered_pkgs = m.group(1).strip()
192 break
193
194 if registered_pkgs is not None:
195 bb.warn("The postinstalls for the following packages "
196 "will be postponed for first boot: %s" %
197 registered_pkgs)
198
199 # call the backend dependent handler
200 self._handle_intercept_failure(registered_pkgs)
201
202 def _run_ldconfig(self):
203 if self.d.getVar('LDCONFIGDEPEND', True):
204 bb.note("Executing: ldconfig -r" + self.image_rootfs + "-c new -v")
205 self._exec_shell_cmd(['ldconfig', '-r', self.image_rootfs, '-c',
206 'new', '-v'])
207
208 def _generate_kernel_module_deps(self):
209 kernel_abi_ver_file = os.path.join(self.d.getVar('STAGING_KERNEL_DIR', True),
210 'kernel-abiversion')
211 if os.path.exists(kernel_abi_ver_file):
212 kernel_ver = open(kernel_abi_ver_file).read().strip(' \n')
213 modules_dir = os.path.join(self.image_rootfs, 'lib', 'modules', kernel_ver)
214
215 bb.utils.mkdirhier(modules_dir)
216
217 self._exec_shell_cmd(['depmodwrapper', '-a', '-b', self.image_rootfs,
218 kernel_ver])
219
220 """
221 Create devfs:
222 * IMAGE_DEVICE_TABLE is the old name to an absolute path to a device table file
223 * IMAGE_DEVICE_TABLES is a new name for a file, or list of files, seached
224 for in the BBPATH
225 If neither are specified then the default name of files/device_table-minimal.txt
226 is searched for in the BBPATH (same as the old version.)
227 """
228 def _create_devfs(self):
229 devtable_list = []
230 devtable = self.d.getVar('IMAGE_DEVICE_TABLE', True)
231 if devtable is not None:
232 devtable_list.append(devtable)
233 else:
234 devtables = self.d.getVar('IMAGE_DEVICE_TABLES', True)
235 if devtables is None:
236 devtables = 'files/device_table-minimal.txt'
237 for devtable in devtables.split():
238 devtable_list.append("%s" % bb.utils.which(self.d.getVar('BBPATH', True), devtable))
239
240 for devtable in devtable_list:
241 self._exec_shell_cmd(["makedevs", "-r",
242 self.image_rootfs, "-D", devtable])
243
244
245class RpmRootfs(Rootfs):
246 def __init__(self, d, manifest_dir):
247 super(RpmRootfs, self).__init__(d)
248
249 self.manifest = RpmManifest(d, manifest_dir)
250
251 self.pm = RpmPM(d,
252 d.getVar('IMAGE_ROOTFS', True),
253 self.d.getVar('TARGET_VENDOR', True)
254 )
255
256 self.inc_rpm_image_gen = self.d.getVar('INC_RPM_IMAGE_GEN', True)
257 if self.inc_rpm_image_gen != "1":
258 bb.utils.remove(self.image_rootfs, True)
259 else:
260 self.pm.recovery_packaging_data()
261 bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
262
263 self.pm.create_configs()
264
265 '''
266 While rpm incremental image generation is enabled, it will remove the
267 unneeded pkgs by comparing the new install solution manifest and the
268 old installed manifest.
269 '''
270 def _create_incremental(self, pkgs_initial_install):
271 if self.inc_rpm_image_gen == "1":
272
273 pkgs_to_install = list()
274 for pkg_type in pkgs_initial_install:
275 pkgs_to_install += pkgs_initial_install[pkg_type]
276
277 installed_manifest = self.pm.load_old_install_solution()
278 solution_manifest = self.pm.dump_install_solution(pkgs_to_install)
279
280 pkg_to_remove = list()
281 for pkg in installed_manifest:
282 if pkg not in solution_manifest:
283 pkg_to_remove.append(pkg)
284
285 self.pm.update()
286
287 bb.note('incremental update -- upgrade packages in place ')
288 self.pm.upgrade()
289 if pkg_to_remove != []:
290 bb.note('incremental removed: %s' % ' '.join(pkg_to_remove))
291 self.pm.remove(pkg_to_remove)
292
293 def _create(self):
294 pkgs_to_install = self.manifest.parse_initial_manifest()
295
296 # update PM index files
297 self.pm.write_index()
298
299 self.pm.dump_all_available_pkgs()
300
301 if self.inc_rpm_image_gen == "1":
302 self._create_incremental(pkgs_to_install)
303
304 self.pm.update()
305
306 pkgs = []
307 pkgs_attempt = []
308 for pkg_type in pkgs_to_install:
309 if pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY:
310 pkgs_attempt += pkgs_to_install[pkg_type]
311 else:
312 pkgs += pkgs_to_install[pkg_type]
313
314 self.pm.install(pkgs)
315
316 self.pm.install(pkgs_attempt, True)
317
318 self.pm.install_complementary()
319
320 self._log_check()
321
322 if self.inc_rpm_image_gen == "1":
323 self.pm.backup_packaging_data()
324
325 self.pm.rpm_setup_smart_target_config()
326
327 def _get_delayed_postinsts(self):
328 postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/rpm-postinsts")
329 if os.path.isdir(postinst_dir):
330 files = os.listdir(postinst_dir)
331 for f in files:
332 bb.note('Delayed package scriptlet: %s' % f)
333 return files
334
335 return None
336
337 def _save_postinsts(self):
338 # this is just a stub. For RPM, the failed postinstalls are
339 # already saved in /etc/rpm-postinsts
340 pass
341
342 def _log_check(self):
343 r = re.compile('(unpacking of archive failed|Cannot find package|exit 1|ERR|Fail)')
344 log_path = self.d.expand("${T}/log.do_rootfs")
345 with open(log_path, 'r') as log:
346 found_error = 0
347 message = "\n"
348 for line in log.read().split('\n'):
349 if 'log_check' in line:
350 continue
351
352 m = r.search(line)
353 if m:
354 found_error = 1
355 bb.warn('log_check: There were error messages in the logfile')
356 bb.warn('log_check: Matched keyword: [%s]\n\n' % m.group())
357
358 if found_error >= 1 and found_error <= 5:
359 message += line + '\n'
360 found_error += 1
361
362 if found_error == 6:
363 bb.fatal(message)
364
365 def _handle_intercept_failure(self, registered_pkgs):
366 rpm_postinsts_dir = self.image_rootfs + self.d.expand('${sysconfdir}/rpm-postinsts/')
367 bb.utils.mkdirhier(rpm_postinsts_dir)
368
369 # Save the package postinstalls in /etc/rpm-postinsts
370 for pkg in registered_pkgs.split():
371 self.pm.save_rpmpostinst(pkg)
372
373 def _cleanup(self):
374 # during the execution of postprocess commands, rpm is called several
375 # times to get the files installed, dependencies, etc. This creates the
376 # __db.00* (Berkeley DB files that hold locks, rpm specific environment
377 # settings, etc.), that should not get into the final rootfs
378 self.pm.unlock_rpm_db()
379
380
381class DpkgRootfs(Rootfs):
382 def __init__(self, d, manifest_dir):
383 super(DpkgRootfs, self).__init__(d)
384
385 bb.utils.remove(self.image_rootfs, True)
386 bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
387 self.manifest = DpkgManifest(d, manifest_dir)
388 self.pm = DpkgPM(d, d.getVar('IMAGE_ROOTFS', True),
389 d.getVar('PACKAGE_ARCHS', True),
390 d.getVar('DPKG_ARCH', True))
391
392
393 def _create(self):
394 pkgs_to_install = self.manifest.parse_initial_manifest()
395
396 alt_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/alternatives")
397 bb.utils.mkdirhier(alt_dir)
398
399 # update PM index files
400 self.pm.write_index()
401
402 self.pm.update()
403
404 for pkg_type in self.install_order:
405 if pkg_type in pkgs_to_install:
406 self.pm.install(pkgs_to_install[pkg_type],
407 [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
408
409 self.pm.install_complementary()
410
411 self.pm.fix_broken_dependencies()
412
413 self.pm.mark_packages("installed")
414
415 self.pm.run_pre_post_installs()
416
417 def _get_delayed_postinsts(self):
418 pkg_list = []
419 with open(self.image_rootfs + "/var/lib/dpkg/status") as status:
420 for line in status:
421 m_pkg = re.match("^Package: (.*)", line)
422 m_status = re.match("^Status:.*unpacked", line)
423 if m_pkg is not None:
424 pkg_name = m_pkg.group(1)
425 elif m_status is not None:
426 pkg_list.append(pkg_name)
427
428 if len(pkg_list) == 0:
429 return None
430
431 return pkg_list
432
433 def _save_postinsts(self):
434 num = 0
435 for p in self._get_delayed_postinsts():
436 dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts")
437 src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info")
438
439 bb.utils.mkdirhier(dst_postinst_dir)
440
441 if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")):
442 shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"),
443 os.path.join(dst_postinst_dir, "%03d-%s" % (num, p)))
444
445 num += 1
446
447 def _handle_intercept_failure(self, registered_pkgs):
448 self.pm.mark_packages("unpacked", registered_pkgs.split())
449
450 def _log_check(self):
451 pass
452
453 def _cleanup(self):
454 pass
455
456
457class OpkgRootfs(Rootfs):
458 def __init__(self, d, manifest_dir):
459 super(OpkgRootfs, self).__init__(d)
460
461 self.manifest = OpkgManifest(d, manifest_dir)
462 self.opkg_conf = self.d.getVar("IPKGCONF_TARGET", True)
463 self.pkg_archs = self.d.getVar("ALL_MULTILIB_PACKAGE_ARCHS", True)
464
465 self.inc_opkg_image_gen = self.d.getVar('INC_IPK_IMAGE_GEN', True) or ""
466 if self._remove_old_rootfs():
467 bb.utils.remove(self.image_rootfs, True)
468 self.pm = OpkgPM(d,
469 self.image_rootfs,
470 self.opkg_conf,
471 self.pkg_archs)
472 else:
473 self.pm = OpkgPM(d,
474 self.image_rootfs,
475 self.opkg_conf,
476 self.pkg_archs)
477 self.pm.recover_packaging_data()
478
479 bb.utils.remove(self.d.getVar('MULTILIB_TEMP_ROOTFS', True), True)
480
481 def _prelink_file(self, root_dir, filename):
482 bb.note('prelink %s in %s' % (filename, root_dir))
483 prelink_cfg = oe.path.join(root_dir,
484 self.d.expand('${sysconfdir}/prelink.conf'))
485 if not os.path.exists(prelink_cfg):
486 shutil.copy(self.d.expand('${STAGING_DIR_NATIVE}${sysconfdir_native}/prelink.conf'),
487 prelink_cfg)
488
489 cmd_prelink = self.d.expand('${STAGING_DIR_NATIVE}${sbindir_native}/prelink')
490 self._exec_shell_cmd([cmd_prelink,
491 '--root',
492 root_dir,
493 '-amR',
494 '-N',
495 '-c',
496 self.d.expand('${sysconfdir}/prelink.conf')])
497
498 '''
499 Compare two files with the same key twice to see if they are equal.
500 If they are not equal, it means they are duplicated and come from
501 different packages.
502 1st: Comapre them directly;
503 2nd: While incremental image creation is enabled, one of the
504 files could be probaly prelinked in the previous image
505 creation and the file has been changed, so we need to
506 prelink the other one and compare them.
507 '''
508 def _file_equal(self, key, f1, f2):
509
510 # Both of them are not prelinked
511 if filecmp.cmp(f1, f2):
512 return True
513
514 if self.image_rootfs not in f1:
515 self._prelink_file(f1.replace(key, ''), f1)
516
517 if self.image_rootfs not in f2:
518 self._prelink_file(f2.replace(key, ''), f2)
519
520 # Both of them are prelinked
521 if filecmp.cmp(f1, f2):
522 return True
523
524 # Not equal
525 return False
526
527 """
528 This function was reused from the old implementation.
529 See commit: "image.bbclass: Added variables for multilib support." by
530 Lianhao Lu.
531 """
532 def _multilib_sanity_test(self, dirs):
533
534 allow_replace = self.d.getVar("MULTILIBRE_ALLOW_REP", True)
535 if allow_replace is None:
536 allow_replace = ""
537
538 allow_rep = re.compile(re.sub("\|$", "", allow_replace))
539 error_prompt = "Multilib check error:"
540
541 files = {}
542 for dir in dirs:
543 for root, subfolders, subfiles in os.walk(dir):
544 for file in subfiles:
545 item = os.path.join(root, file)
546 key = str(os.path.join("/", os.path.relpath(item, dir)))
547
548 valid = True
549 if key in files:
550 #check whether the file is allow to replace
551 if allow_rep.match(key):
552 valid = True
553 else:
554 if os.path.exists(files[key]) and \
555 os.path.exists(item) and \
556 not self._file_equal(key, files[key], item):
557 valid = False
558 bb.fatal("%s duplicate files %s %s is not the same\n" %
559 (error_prompt, item, files[key]))
560
561 #pass the check, add to list
562 if valid:
563 files[key] = item
564
565 def _multilib_test_install(self, pkgs):
566 ml_temp = self.d.getVar("MULTILIB_TEMP_ROOTFS", True)
567 bb.utils.mkdirhier(ml_temp)
568
569 dirs = [self.image_rootfs]
570
571 for variant in self.d.getVar("MULTILIB_VARIANTS", True).split():
572 ml_target_rootfs = os.path.join(ml_temp, variant)
573
574 bb.utils.remove(ml_target_rootfs, True)
575
576 ml_opkg_conf = os.path.join(ml_temp,
577 variant + "-" + os.path.basename(self.opkg_conf))
578
579 ml_pm = OpkgPM(self.d, ml_target_rootfs, ml_opkg_conf, self.pkg_archs)
580
581 ml_pm.update()
582 ml_pm.install(pkgs)
583
584 dirs.append(ml_target_rootfs)
585
586 self._multilib_sanity_test(dirs)
587
588 '''
589 While ipk incremental image generation is enabled, it will remove the
590 unneeded pkgs by comparing the old full manifest in previous existing
591 image and the new full manifest in the current image.
592 '''
593 def _remove_extra_packages(self, pkgs_initial_install):
594 if self.inc_opkg_image_gen == "1":
595 # Parse full manifest in previous existing image creation session
596 old_full_manifest = self.manifest.parse_full_manifest()
597
598 # Create full manifest for the current image session, the old one
599 # will be replaced by the new one.
600 self.manifest.create_full(self.pm)
601
602 # Parse full manifest in current image creation session
603 new_full_manifest = self.manifest.parse_full_manifest()
604
605 pkg_to_remove = list()
606 for pkg in old_full_manifest:
607 if pkg not in new_full_manifest:
608 pkg_to_remove.append(pkg)
609
610 if pkg_to_remove != []:
611 bb.note('decremental removed: %s' % ' '.join(pkg_to_remove))
612 self.pm.remove(pkg_to_remove)
613
614 '''
615 Compare with previous existing image creation, if some conditions
616 triggered, the previous old image should be removed.
617 The conditions include any of 'PACKAGE_EXCLUDE, NO_RECOMMENDATIONS
618 and BAD_RECOMMENDATIONS' has been changed.
619 '''
620 def _remove_old_rootfs(self):
621 if self.inc_opkg_image_gen != "1":
622 return True
623
624 vars_list_file = self.d.expand('${T}/vars_list')
625
626 old_vars_list = ""
627 if os.path.exists(vars_list_file):
628 old_vars_list = open(vars_list_file, 'r+').read()
629
630 new_vars_list = '%s:%s:%s\n' % \
631 ((self.d.getVar('BAD_RECOMMENDATIONS', True) or '').strip(),
632 (self.d.getVar('NO_RECOMMENDATIONS', True) or '').strip(),
633 (self.d.getVar('PACKAGE_EXCLUDE', True) or '').strip())
634 open(vars_list_file, 'w+').write(new_vars_list)
635
636 if old_vars_list != new_vars_list:
637 return True
638
639 return False
640
641 def _create(self):
642 pkgs_to_install = self.manifest.parse_initial_manifest()
643 opkg_pre_process_cmds = self.d.getVar('OPKG_PREPROCESS_COMMANDS', True)
644 opkg_post_process_cmds = self.d.getVar('OPKG_POSTPROCESS_COMMANDS', True)
645 rootfs_post_install_cmds = self.d.getVar('ROOTFS_POSTINSTALL_COMMAND', True)
646
647 # update PM index files, unless users provide their own feeds
648 if (self.d.getVar('BUILD_IMAGES_FROM_FEEDS', True) or "") != "1":
649 self.pm.write_index()
650
651 execute_pre_post_process(self.d, opkg_pre_process_cmds)
652
653 self.pm.update()
654
655 self.pm.handle_bad_recommendations()
656
657 if self.inc_opkg_image_gen == "1":
658 self._remove_extra_packages(pkgs_to_install)
659
660 for pkg_type in self.install_order:
661 if pkg_type in pkgs_to_install:
662 # For multilib, we perform a sanity test before final install
663 # If sanity test fails, it will automatically do a bb.fatal()
664 # and the installation will stop
665 if pkg_type == Manifest.PKG_TYPE_MULTILIB:
666 self._multilib_test_install(pkgs_to_install[pkg_type])
667
668 self.pm.install(pkgs_to_install[pkg_type],
669 [False, True][pkg_type == Manifest.PKG_TYPE_ATTEMPT_ONLY])
670
671 self.pm.install_complementary()
672
673 execute_pre_post_process(self.d, opkg_post_process_cmds)
674 execute_pre_post_process(self.d, rootfs_post_install_cmds)
675
676 if self.inc_opkg_image_gen == "1":
677 self.pm.backup_packaging_data()
678
679 def _get_delayed_postinsts(self):
680 pkg_list = []
681 status_file = os.path.join(self.image_rootfs,
682 self.d.getVar('OPKGLIBDIR', True).strip('/'),
683 "opkg", "status")
684
685 with open(status_file) as status:
686 for line in status:
687 m_pkg = re.match("^Package: (.*)", line)
688 m_status = re.match("^Status:.*unpacked", line)
689 if m_pkg is not None:
690 pkg_name = m_pkg.group(1)
691 elif m_status is not None:
692 pkg_list.append(pkg_name)
693
694 if len(pkg_list) == 0:
695 return None
696
697 return pkg_list
698
699 def _save_postinsts(self):
700 num = 0
701 for p in self._get_delayed_postinsts():
702 dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts")
703 src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info")
704
705 bb.utils.mkdirhier(dst_postinst_dir)
706
707 if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")):
708 shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"),
709 os.path.join(dst_postinst_dir, "%03d-%s" % (num, p)))
710
711 num += 1
712
713 def _handle_intercept_failure(self, registered_pkgs):
714 self.pm.mark_packages("unpacked", registered_pkgs.split())
715
716 def _log_check(self):
717 pass
718
719 def _cleanup(self):
720 pass
721
722
723def create_rootfs(d, manifest_dir=None):
724 env_bkp = os.environ.copy()
725
726 img_type = d.getVar('IMAGE_PKGTYPE', True)
727 if img_type == "rpm":
728 RpmRootfs(d, manifest_dir).create()
729 elif img_type == "ipk":
730 OpkgRootfs(d, manifest_dir).create()
731 elif img_type == "deb":
732 DpkgRootfs(d, manifest_dir).create()
733
734 os.environ.clear()
735 os.environ.update(env_bkp)
736
737
738def image_list_installed_packages(d, format=None, rootfs_dir=None):
739 if not rootfs_dir:
740 rootfs_dir = d.getVar('IMAGE_ROOTFS', True)
741
742 img_type = d.getVar('IMAGE_PKGTYPE', True)
743 if img_type == "rpm":
744 return RpmPkgsList(d, rootfs_dir).list(format)
745 elif img_type == "ipk":
746 return OpkgPkgsList(d, rootfs_dir, d.getVar("IPKGCONF_TARGET", True)).list(format)
747 elif img_type == "deb":
748 return DpkgPkgsList(d, rootfs_dir).list(format)
749
750if __name__ == "__main__":
751 """
752 We should be able to run this as a standalone script, from outside bitbake
753 environment.
754 """
755 """
756 TBD
757 """