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 | |
| 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>
| -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()) |
