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