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-26 14:08:03 +0100 |
commit | ed52d1040ee8be0bfa080d5679c583b1012bb575 (patch) | |
tree | c078cdf17ee6f24efc0d3da86b155c460cdbc900 | |
parent | c171909352b5ed92166857b0bbcd901ae0f74996 (diff) | |
download | openembedded-core-ed52d1040ee8be0bfa080d5679c583b1012bb575.tar.gz openembedded-core-ed52d1040ee8be0bfa080d5679c583b1012bb575.tar.bz2 openembedded-core-ed52d1040ee8be0bfa080d5679c583b1012bb575.zip |
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]
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): if os.path.isdir(self.pm.install_dir_path) and not os.listdir(self.pm.install_dir_path): bb.utils.remove(self.pm.install_dir_path, True) +class DpkgOpkgRootfs(Rootfs): + def __init__(self, d): + super(DpkgOpkgRootfs, self).__init__(d) + + def _get_pkgs_postinsts(self, status_file): + def _get_pkg_depends_list(pkg_depends): + pkg_depends_list = [] + # filter version requirements like libc (>= 1.1) + for dep in pkg_depends.split(', '): + m_dep = re.match("^(.*) \(.*\)$", dep) + if m_dep: + dep = m_dep.group(1) + pkg_depends_list.append(dep) + + return pkg_depends_list + + pkgs = {} + pkg_name = "" + pkg_status_match = False + pkg_depends = "" + + with open(status_file) as status: + data = status.read() + status.close() + for line in data.split('\n'): + m_pkg = re.match("^Package: (.*)", line) + m_status = re.match("^Status:.*unpacked", line) + m_depends = re.match("^Depends: (.*)", line) + + if m_pkg is not None: + if pkg_name and pkg_status_match: + pkgs[pkg_name] = _get_pkg_depends_list(pkg_depends) + + pkg_name = m_pkg.group(1) + pkg_status_match = False + pkg_depends = "" + elif m_status is not None: + pkg_status_match = True + elif m_depends is not None: + pkg_depends = m_depends.group(1) + + # remove package dependencies not in postinsts + pkg_names = pkgs.keys() + for pkg_name in pkg_names: + deps = pkgs[pkg_name][:] + + for d in deps: + if d not in pkg_names: + pkgs[pkg_name].remove(d) + + return pkgs + + def _get_delayed_postinsts_common(self, status_file): + def _dep_resolve(graph, node, resolved, seen): + seen.append(node) + + for edge in graph[node]: + if edge not in resolved: + if edge in seen: + raise RuntimeError("Packages %s and %s have " \ + "a circular dependency in postinsts scripts." \ + % (node, edge)) + _dep_resolve(graph, edge, resolved, seen) + + resolved.append(node) + + pkg_list = [] -class DpkgRootfs(Rootfs): + pkgs = self._get_pkgs_postinsts(status_file) + if pkgs: + root = "__packagegroup_postinst__" + pkgs[root] = pkgs.keys() + _dep_resolve(pkgs, root, pkg_list, []) + pkg_list.remove(root) + + if len(pkg_list) == 0: + return None + + return pkg_list + + def _save_postinsts_common(self, dst_postinst_dir, src_postinst_dir): + num = 0 + for p in self._get_delayed_postinsts(): + bb.utils.mkdirhier(dst_postinst_dir) + + if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): + shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), + os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) + + num += 1 + +class DpkgRootfs(DpkgOpkgRootfs): def __init__(self, d, manifest_dir): super(DpkgRootfs, self).__init__(d) self.log_check_regex = '^E:' @@ -540,34 +630,13 @@ class DpkgRootfs(Rootfs): return ['DEPLOY_DIR_DEB', 'DEB_SDK_ARCH', 'APTCONF_TARGET', 'APT_ARGS', 'DPKG_ARCH', 'DEB_PREPROCESS_COMMANDS', 'DEB_POSTPROCESS_COMMAND'] def _get_delayed_postinsts(self): - pkg_list = [] - with open(self.image_rootfs + "/var/lib/dpkg/status") as status: - for line in status: - m_pkg = re.match("^Package: (.*)", line) - m_status = re.match("^Status:.*unpacked", line) - if m_pkg is not None: - pkg_name = m_pkg.group(1) - elif m_status is not None: - pkg_list.append(pkg_name) - - if len(pkg_list) == 0: - return None - - return pkg_list + status_file = self.image_rootfs + "/var/lib/dpkg/status" + return self._get_delayed_postinsts_common(status_file) def _save_postinsts(self): - num = 0 - for p in self._get_delayed_postinsts(): - dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") - src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") - - bb.utils.mkdirhier(dst_postinst_dir) - - if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): - shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), - os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) - - num += 1 + dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/deb-postinsts") + src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}/var/lib/dpkg/info") + return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) def _handle_intercept_failure(self, registered_pkgs): self.pm.mark_packages("unpacked", registered_pkgs.split()) @@ -580,7 +649,7 @@ class DpkgRootfs(Rootfs): pass -class OpkgRootfs(Rootfs): +class OpkgRootfs(DpkgOpkgRootfs): def __init__(self, d, manifest_dir): super(OpkgRootfs, self).__init__(d) self.log_check_regex = '(exit 1|Collected errors)' @@ -810,38 +879,15 @@ class OpkgRootfs(Rootfs): 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'] def _get_delayed_postinsts(self): - pkg_list = [] status_file = os.path.join(self.image_rootfs, self.d.getVar('OPKGLIBDIR', True).strip('/'), "opkg", "status") - - with open(status_file) as status: - for line in status: - m_pkg = re.match("^Package: (.*)", line) - m_status = re.match("^Status:.*unpacked", line) - if m_pkg is not None: - pkg_name = m_pkg.group(1) - elif m_status is not None: - pkg_list.append(pkg_name) - - if len(pkg_list) == 0: - return None - - return pkg_list + return self._get_delayed_postinsts_common(status_file) def _save_postinsts(self): - num = 0 - for p in self._get_delayed_postinsts(): - dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts") - src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info") - - bb.utils.mkdirhier(dst_postinst_dir) - - if os.path.exists(os.path.join(src_postinst_dir, p + ".postinst")): - shutil.copy(os.path.join(src_postinst_dir, p + ".postinst"), - os.path.join(dst_postinst_dir, "%03d-%s" % (num, p))) - - num += 1 + dst_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${sysconfdir}/ipk-postinsts") + src_postinst_dir = self.d.expand("${IMAGE_ROOTFS}${OPKGLIBDIR}/opkg/info") + return self._save_postinsts_common(dst_postinst_dir, src_postinst_dir) def _handle_intercept_failure(self, registered_pkgs): self.pm.mark_packages("unpacked", registered_pkgs.split()) |