aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAníbal Limón <anibal.limon@linux.intel.com>2015-06-25 13:21:15 -0500
committerRichard Purdie <richard.purdie@linuxfoundation.org>2015-06-26 14:08:03 +0100
commited52d1040ee8be0bfa080d5679c583b1012bb575 (patch)
treec078cdf17ee6f24efc0d3da86b155c460cdbc900
parentc171909352b5ed92166857b0bbcd901ae0f74996 (diff)
downloadopenembedded-core-contrib-ed52d1040ee8be0bfa080d5679c583b1012bb575.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] 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.py156
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())