[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).
This commit is contained in:
Fabio Erculiani
2010-03-05 14:56:18 +01:00
parent e673a821c2
commit ffd90f21c7
@@ -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):