blob: 6840bb6026253cc202ed572d3e32886deaa36f3c [file] [log] [blame]
# Copyright 2020 Gentoo Authors
# Distributed under the terms of the GNU General Public License v2
import io
from portage import (
_encodings,
_unicode_encode,
os,
)
from portage.dep.soname.parse import parse_soname_deps
from portage.util._dyn_libs.NeededEntry import NeededEntry
def _get_all_provides(vardb):
"""
Get all of the sonames provided by all of the installed packages.
This does not bother to acquire a lock, since its pretty safe to
assume that any packages merged or unmerged while this function
is running must be irrelevant.
@param vardb: an installed package database
@type vardb: vardbapi
@rtype: frozenset
@return: a frozenset od SonameAtom instances provided by all
installed packages
"""
all_provides = []
for cpv in vardb.cpv_all():
try:
provides, = vardb.aux_get(cpv, ['PROVIDES'])
except KeyError:
# Since we don't hold a lock, assume this is due to a
# concurrent unmerge, and PROVIDES from the unmerged package
# are most likely negligible due to topologically sorted
# merge order. Also, note that it's possible for aux_get
# to succeed and return empty PROVIDES metadata if the file
# disappears (due to unmerge) before it can be read.
pass
else:
if provides:
all_provides.extend(parse_soname_deps(provides))
return frozenset(all_provides)
def _get_unresolved_soname_deps(metadata_dir, all_provides):
"""
Get files with unresolved soname dependencies.
@param metadata_dir: directory containing package metadata files
named REQUIRES and NEEDED.ELF.2
@type metadata_dir: str
@param all_provides: a frozenset on SonameAtom instances provided by
all installed packages
@type all_provides: frozenset
@rtype: list
@return: list of tuple(filename, tuple(unresolved sonames))
"""
try:
with io.open(_unicode_encode(os.path.join(metadata_dir, 'REQUIRES'),
encoding=_encodings['fs'], errors='strict'),
mode='rt', encoding=_encodings['repo.content'], errors='strict') as f:
requires = frozenset(parse_soname_deps(f.read()))
except EnvironmentError:
return []
unresolved_by_category = {}
for atom in requires:
if atom not in all_provides:
unresolved_by_category.setdefault(atom.multilib_category, set()).add(atom.soname)
needed_filename = os.path.join(metadata_dir, "NEEDED.ELF.2")
with io.open(_unicode_encode(needed_filename, encoding=_encodings['fs'], errors='strict'),
mode='rt', encoding=_encodings['repo.content'], errors='strict') as f:
needed = f.readlines()
unresolved_by_file = []
for l in needed:
l = l.rstrip("\n")
if not l:
continue
entry = NeededEntry.parse(needed_filename, l)
missing = unresolved_by_category.get(entry.multilib_category)
if not missing:
continue
# NOTE: This can contain some false positives in the case of
# missing DT_RPATH settings, since it's possible that a subset
# package files have the desired DT_RPATH settings. However,
# since reported sonames are unresolved for at least some file(s),
# false positives or this sort should not be not too annoying.
missing = [soname for soname in entry.needed if soname in missing]
if missing:
unresolved_by_file.append((entry.filename, tuple(missing)))
return unresolved_by_file