diff options
author | Aníbal Limón <anibal.limon@linux.intel.com> | 2015-06-25 13:21:15 -0500 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2015-06-27 22:42:52 +0100 |
commit | b2c9e7347acdfd0efe1c3dabb853d609233b61b6 (patch) | |
tree | 7bdf2e39ed38c50925c663abe25d58209877ef38 /meta | |
parent | f8661aaeba4d4b1fb328106c36493a5019b59110 (diff) | |
download | poky-b2c9e7347acdfd0efe1c3dabb853d609233b61b6.tar.gz |
oe/rootfs.py: DpkgRootfs/OpkgRootfs add support for dependency handling in postinsts scripts.
The old code don't take into account package dependencies causing
undefined execution order in postinsts scripts, in order to fix:
Add DpkgOpkgRootfs class for store common operations in DpkgRootfs
and OpkgRootfs.
Add _get_delayed_postinsts_common method that process Depends from
status file in dpkg/opkg and resolve dependency order causing an
execption if found circular dependencies.
[YOCTO #5318]
(From OE-Core rev: ed52d1040ee8be0bfa080d5679c583b1012bb575)
Signed-off-by: Aníbal Limón <anibal.limon@linux.intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Diffstat (limited to 'meta')
-rw-r--r-- | meta/lib/oe/rootfs.py | 156 |
1 files changed, 101 insertions, 55 deletions
diff --git a/meta/lib/oe/rootfs.py b/meta/lib/oe/rootfs.py index 48e5754b27..327c8eae86 100644 --- a/meta/lib/oe/rootfs.py +++ b/meta/lib/oe/rootfs.py | |||
@@ -495,8 +495,98 @@ class RpmRootfs(Rootfs): | |||
495 | if os.path.isdir(self.pm.install_dir_path) and not os.listdir(self.pm.install_dir_path): | 495 | if os.path.isdir(self.pm.install_dir_path) and not os.listdir(self.pm.install_dir_path): |
496 | bb.utils.remove(self.pm.install_dir_path, True) | 496 | bb.utils.remove(self.pm.install_dir_path, True) |
497 | 497 | ||
498 | class DpkgOpkgRootfs(Rootfs): | ||
499 | def __init__(self, d): | ||
500 | super(DpkgOpkgRootfs, self).__init__(d) | ||
501 | |||
502 | def _get_pkgs_postinsts(self, status_file): | ||
503 | def _get_pkg_depends_list(pkg_depends): | ||
504 | pkg_depends_list = [] | ||
505 | # filter version requirements like libc (>= 1.1) | ||
506 | for dep in pkg_depends.split(', '): | ||
507 | m_dep = re.match("^(.*) \(.*\)$", dep) | ||
508 | if m_dep: | ||
509 | dep = m_dep.group(1) | ||
510 | pkg_depends_list.append(dep) | ||
511 | |||
512 | return pkg_depends_list | ||
513 | |||
514 | pkgs = {} | ||
515 | pkg_name = "" | ||
516 | pkg_status_match = False | ||
517 | pkg_depends = "" | ||
518 | |||
519 | with open(status_file) as status: | ||
520 | data = status.read() | ||
521 | status.close() | ||
522 | for line in data.split('\n'): | ||
523 | m_pkg = re.match("^Package: (.*)", line) | ||
524 | m_status = re.match("^Status:.*unpacked", line) | ||
525 | m_depends = re.match("^Depends: (.*)", line) | ||
526 | |||
527 | if m_pkg is not None: | ||
528 | if pkg_name and pkg_status_match: | ||
529 | pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends) | ||
530 | |||
531 | pkg_name = m_pkg.group(1) | ||
532 | pkg_status_match = False | ||
533 | pkg_depends = "" | ||
534 | elif m_status is not None: | ||
535 | pkg_status_match = True | ||
536 | elif m_depends is not None: | ||
537 | pkg_depends = m_depends.group(1) | ||
538 | |||
539 | # remove package dependencies not in postinsts | ||
540 | pkg_names = pkgs.keys() | ||
541 | for pkg_name in pkg_names: | ||
542 | deps = pkgs[pkg_name][:] | ||
543 | |||
544 | for d in deps: | ||
545 | if d not in pkg_names: | ||
546 | pkgs[pkg_name].remove(d) | ||
547 | |||
548 | return pkgs | ||
549 | |||
550 | def _get_delayed_postinsts_common(self, status_file): | ||
551 | def _dep_resolve(graph, node, resolved, seen): | ||
552 | seen.append(node) | ||
553 | |||
554 | for edge in graph[node]: | ||
555 | if edge not in resolved: | ||
556 | if edge in seen: | ||
557 | raise RuntimeError("Packages %s and %s have " \ | ||
558 | "a circular dependency in postinsts scripts." \ | ||
559 | % (node, edge)) | ||
560 | _dep_resolve(graph, edge, resolved, seen) | ||
561 | |||
562 | resolved.append(node) | ||
563 | |||
564 | pkg_list = [] | ||
498 | 565 | ||
499 | class DpkgRootfs(Rootfs): | 566 | pkgs = self._get_pkgs_postinsts(status_file) |
567 | if pkgs: | ||
568 | root = "__packagegroup_postinst__" | ||
569 | pkgs[root] = pkgs.keys() | ||
570 | _dep_resolve(pkgs, root, pkg_list, []) | ||
571 | pkg_list.remove(root) | ||
572 | |||
573 | if len(pkg_list) == 0: | ||
574 | return None | ||
575 | |||
576 | return pkg_list | ||
577 | |||
578 | def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir): | ||
579 | num = 0 | ||
580 | for p in self._get_delayed_postinsts(): | ||
581 | bb.utils.mkdirhier(dst_postinst_dir) | ||
582 | |||
583 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
584 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
585 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
586 | |||
587 | num += 1 | ||
588 | |||
589 | class DpkgRootfs(DpkgOpkgRootfs): | ||
500 | def __init__(self, d, manifest_dir): | 590 | def __init__(self, d, manifest_dir): |
501 | super(DpkgRootfs, self).__init__(d) | 591 | super(DpkgRootfs, self).__init__(d) |
502 | self.log_check_regex = '^E:' | 592 | self.log_check_regex = '^E:' |
@@ -540,34 +630,13 @@ class DpkgRootfs(Rootfs): | |||
540 | return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMAND'] | 630 | return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMAND'] |
541 | 631 | ||
542 | def _get_delayed_postinsts(self): | 632 | def _get_delayed_postinsts(self): |
543 | pkg_list = [] | 633 | status_file = self.image_rootfs + "/var/lib/dpkg/status" |
544 | with open(self.image_rootfs + "/var/lib/dpkg/status") as status: | 634 | return self._get_delayed_postinsts_common(status_file) |
545 | for line in status: | ||
546 | m_pkg = re.match("^Package: (.*)", line) | ||
547 | m_status = re.match("^Status:.*unpacked", line) | ||
548 | if m_pkg is not None: | ||
549 | pkg_name = m_pkg.group(1) | ||
550 | elif m_status is not None: | ||
551 | pkg_list.append(pkg_name) | ||
552 | |||
553 | if len(pkg_list) == 0: | ||
554 | return None | ||
555 | |||
556 | return pkg_list | ||
557 | 635 | ||
558 | def _save_postinsts(self): | 636 | def _save_postinsts(self): |
559 | num = 0 | 637 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") |
560 | for p in self._get_delayed_postinsts(): | 638 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") |
561 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") | 639 | return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) |
562 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") | ||
563 | |||
564 | bb.utils.mkdirhier(dst_postinst_dir) | ||
565 | |||
566 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
567 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
568 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
569 | |||
570 | num += 1 | ||
571 | 640 | ||
572 | def _handle_intercept_failure(self, registered_pkgs): | 641 | def _handle_intercept_failure(self, registered_pkgs): |
573 | self.pm.mark_packages("unpacked", registered_pkgs.split()) | 642 | self.pm.mark_packages("unpacked", registered_pkgs.split()) |
@@ -580,7 +649,7 @@ class DpkgRootfs(Rootfs): | |||
580 | pass | 649 | pass |
581 | 650 | ||
582 | 651 | ||
583 | class OpkgRootfs(Rootfs): | 652 | class OpkgRootfs(DpkgOpkgRootfs): |
584 | def __init__(self, d, manifest_dir): | 653 | def __init__(self, d, manifest_dir): |
585 | super(OpkgRootfs, self).__init__(d) | 654 | super(OpkgRootfs, self).__init__(d) |
586 | self.log_check_regex = '(exit 1|Collected errors)' | 655 | self.log_check_regex = '(exit 1|Collected errors)' |
@@ -810,38 +879,15 @@ class OpkgRootfs(Rootfs): | |||
810 | 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'] | 879 | 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'] |
811 | 880 | ||
812 | def _get_delayed_postinsts(self): | 881 | def _get_delayed_postinsts(self): |
813 | pkg_list = [] | ||
814 | status_file = os.path.join(self.image_rootfs, | 882 | status_file = os.path.join(self.image_rootfs, |
815 | self.d.getVar('OPKGLIBDIR', True).strip('/'), | 883 | self.d.getVar('OPKGLIBDIR', True).strip('/'), |
816 | "opkg", "status") | 884 | "opkg", "status") |
817 | 885 | return self._get_delayed_postinsts_common(status_file) | |
818 | with open(status_file) as status: | ||
819 | for line in status: | ||
820 | m_pkg = re.match("^Package: (.*)", line) | ||
821 | m_status = re.match("^Status:.*unpacked", line) | ||
822 | if m_pkg is not None: | ||
823 | pkg_name = m_pkg.group(1) | ||
824 | elif m_status is not None: | ||
825 | pkg_list.append(pkg_name) | ||
826 | |||
827 | if len(pkg_list) == 0: | ||
828 | return None | ||
829 | |||
830 | return pkg_list | ||
831 | 886 | ||
832 | def _save_postinsts(self): | 887 | def _save_postinsts(self): |
833 | num = 0 | 888 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts") |
834 | for p in self._get_delayed_postinsts(): | 889 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info") |
835 | dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts") | 890 | return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) |
836 | src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info") | ||
837 | |||
838 | bb.utils.mkdirhier(dst_postinst_dir) | ||
839 | |||
840 | if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): | ||
841 | shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), | ||
842 | os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) | ||
843 | |||
844 | num += 1 | ||
845 | 891 | ||
846 | def _handle_intercept_failure(self, registered_pkgs): | 892 | def _handle_intercept_failure(self, registered_pkgs): |
847 | self.pm.mark_packages("unpacked", registered_pkgs.split()) | 893 | self.pm.mark_packages("unpacked", registered_pkgs.split()) |