From ffd90f21c796d3e16e41d3e3aaab74ada8019a5b Mon Sep 17 00:00:00 2001 From: Fabio Erculiani Date: Fri, 5 Mar 2010 14:56:18 +0100 Subject: [PATCH] [entropy.spm] PortagePlugin: several fixes to kernel dependencies and metadata extraction handling 1. Portage doesn't know anything about files installed in /lib/modules so, when mixing Portage and Entropy and syncing the two repositories it can happen to build wrong kernel dependencies. So, use modinfo to get kernel module version magic and use that as tag. Moreover, make sure that kernel dependency metadata is added only when really available. 2. This patch should also make metadata extraction "live-system" independent. Since package is always extracted (to collect extra metadata required nowadays), use the extract path in every metadata collection function. Also check against fake package files provided (ones with no content inside). --- .../interfaces/portage_plugin/__init__.py | 112 +++++++++++------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/libraries/entropy/spm/plugins/interfaces/portage_plugin/__init__.py b/libraries/entropy/spm/plugins/interfaces/portage_plugin/__init__.py index 396f96d8a..6ac4eb56b 100644 --- a/libraries/entropy/spm/plugins/interfaces/portage_plugin/__init__.py +++ b/libraries/entropy/spm/plugins/interfaces/portage_plugin/__init__.py @@ -15,6 +15,8 @@ import sys import shutil import tempfile import subprocess +import tarfile + from entropy.const import etpConst, etpUi, const_get_stringtype, \ const_convert_to_unicode, const_convert_to_rawstring, const_setup_perms from entropy.exceptions import FileNotFound, SPMError, InvalidDependString, \ @@ -715,30 +717,61 @@ class PortagePlugin(SpmPlugin): ) ) - def _add_kernel_dependency_to_pkg(self, pkg_data): + def _add_kernel_dependency_to_pkg(self, pkg_data, pkg_dir_prefix): + # NOTE: i hate hardcoded shit, but our SPM doesn't support + # kernel dependencies. kmod_pfx = "/lib/modules" + kmox_sfx = ".ko" + modinfo_path = "/sbin/modinfo" content = [x for x in pkg_data['content'] if x.startswith(kmod_pfx)] - content = [x for x in content if x != kmod_pfx] + content = [x for x in content if x.endswith(kmox_sfx)] # filter out hidden files - content = [x for x in content if not \ - os.path.basename(x).startswith(".")] if not content: return - content.sort() + + def read_kern_vermagic(ko_path): + + tmp_fd, tmp_file = tempfile.mkstemp() + os.close(tmp_fd) + + tmp_fw = open(tmp_file, "w") + rc = subprocess.call((modinfo_path, "-F", "vermagic", + ko_path), stdout = tmp_fw, stderr = tmp_fw) + tmp_fw.flush() + tmp_fw.close() + tmp_r = open(tmp_file, "r") + modinfo_output = tmp_r.read().strip() + tmp_r.close() + os.remove(tmp_file) + + if rc != 0: + import warnings + warnings.warn( + "Cannot properly guess kernel module vermagic, error" + \ + modinfo_output) + return + + return modinfo_output.split()[0] for item in content: - owners = self.search_paths_owners([item]) - if not owners: + # read vermagic + item_pkg_path = os.path.join(pkg_dir_prefix, item[1:]) + kern_vermagic = read_kern_vermagic(item_pkg_path) + if kern_vermagic is None: continue - k_base = os.path.basename(item) # MUST match SLOT (for triggers here, to be able to handle # multiple packages correctly and set back slot). - pkg_data['versiontag'] = k_base + pkg_data['versiontag'] = kern_vermagic + # overwrite slot, yeah + pkg_data['slot'] = kern_vermagic + # now try to guess package providing that vermagic + possible_kernel_owned_path = os.path.join(kmod_pfx, kern_vermagic) + owners = self.search_paths_owners([possible_kernel_owned_path]) owner_data = None for k_atom, k_slot in owners: k_cat, k_name, k_ver, k_rev = entropy.tools.catpkgsplit(k_atom) @@ -746,16 +779,14 @@ class PortagePlugin(SpmPlugin): owner_data = (k_cat, k_name, k_ver, k_rev,) break - # no kernel found if owner_data is None: - continue + # heh, user has broken deps, who cares! + return + # yippie, kernel dep installed also for SPM. k_cat, k_name, k_ver, k_rev = owner_data if k_rev != "r0": k_ver += "-%s" % (k_rev,) - - # overwrite slot, yeah - pkg_data['slot'] = k_base kern_dep_key = "=%s~-1" % (k_atom,) return kern_dep_key @@ -792,8 +823,12 @@ class PortagePlugin(SpmPlugin): # extract stuff xpaktools.extract_xpak(package_file, meta_dir) - entropy.tools.uncompress_tarball(package_file, - extract_path = pkg_dir, catch_empty = True) + empty_content = False + try: + entropy.tools.uncompress_tarball(package_file, + extract_path = pkg_dir, catch_empty = False) + except tarfile.ReadError: + empty_content = True # package injection status always false by default # developer can change metadatum after this function @@ -859,10 +894,23 @@ class PortagePlugin(SpmPlugin): content_file = os.path.join(meta_dir, PortagePlugin.xpak_entries['contents']) + # even if pkg_dir is tweaked after this, it's fine anyway for + # packages emerge with -B, because for those, we also get the + # full package_file (not a fake one). data['content'] = self._extract_pkg_metadata_content(content_file, - package_file) - data['disksize'] = entropy.tools.sum_file_sizes(data['content']) + package_file, pkg_dir) + # There are packages providing no files, even if given package_file + # is complete (meaning, it contains real file. Not a fake one, like + # it can happen with "equo rescue spmsync", to make things quicker). + # So, to differentiate between "complete package file with no content" + # and "fake package file, with arbitrary content", we check + # data['content']. If empty_content is True but data['content'] is + # contains something, then we have a fake package_file. + if data['content'] and empty_content: + # fake package_file, need to tweak pkg_dir to systemroot + pkg_dir = etpConst['systemroot'] + os.path.sep + data['disksize'] = entropy.tools.sum_file_sizes(data['content']) data['provided_libs'] = self._extract_pkg_metadata_provided_libs( pkg_dir, data['content']) @@ -871,7 +919,7 @@ class PortagePlugin(SpmPlugin): kern_dep_key = None if data['category'] != PortagePlugin.KERNEL_CATEGORY: - kern_dep_key = self._add_kernel_dependency_to_pkg(data) + kern_dep_key = self._add_kernel_dependency_to_pkg(data, pkg_dir) file_ext = PortagePlugin.EBUILD_EXT ebuilds_in_path = [x for x in os.listdir(meta_dir) if \ @@ -3808,7 +3856,7 @@ class PortagePlugin(SpmPlugin): } return data - def _extract_pkg_metadata_content(self, content_file, package_path): + def _extract_pkg_metadata_content(self, content_file, package_path, pkg_dir): pkg_content = {} obj_t = const_convert_to_unicode("obj") @@ -3853,33 +3901,17 @@ class PortagePlugin(SpmPlugin): # CONTENTS is not generated when a package is emerged with # portage and the option -B - # we have to unpack the tbz2 and generate content dict - mytempdir = os.path.join(etpConst['packagestmpdir'], - os.path.basename(package_path) + ".inject") - if os.path.isdir(mytempdir): - shutil.rmtree(mytempdir) - if not os.path.isdir(mytempdir): - os.makedirs(mytempdir) - - entropy.tools.uncompress_tarball(package_path, - extract_path = mytempdir, catch_empty = True) - tmpdir_len = len(mytempdir) - for currentdir, subdirs, files in os.walk(mytempdir): + # we have to use the unpacked package file and generate content dict + tmpdir_len = len(pkg_dir) + for currentdir, subdirs, files in os.walk(pkg_dir): pkg_content[currentdir[tmpdir_len:]] = dir_t for item in files: - item = currentdir + "/" + item + item = currentdir + os.path.sep + item if os.path.islink(item): pkg_content[item[tmpdir_len:]] = sym_t else: pkg_content[item[tmpdir_len:]] = obj_t - # now remove - shutil.rmtree(mytempdir, True) - try: - os.rmdir(mytempdir) - except (OSError,): - pass - return pkg_content def _extract_pkg_metadata_needed(self, needed_file):