blob: 1650edd4ed2ba12d10895e78491c3a49a0592b88 [file] [log] [blame]
# Copyright 2015 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
import bisect
import collections
import sys
class DbapiProvidesIndex(object):
"""
The DbapiProvidesIndex class is used to wrap existing dbapi
interfaces, index packages by the sonames that they provide, and
implement the dbapi.match method for SonameAtom instances. Since
this class acts as a wrapper, it can be used conditionally, so that
soname indexing overhead is avoided when soname dependency
resolution is disabled.
Since it's possible for soname atom match results to consist of
packages with multiple categories or names, it is essential that
Package.__lt__ behave meaningfully when Package.cp is dissimilar,
so that match results will be correctly ordered by version for each
value of Package.cp.
"""
_copy_attrs = ('aux_get', 'aux_update', 'categories', 'cpv_all',
'cpv_exists', 'cp_all', 'cp_list', 'getfetchsizes',
'settings', '_aux_cache_keys', '_clear_cache',
'_cpv_sort_ascending', '_iuse_implicit_cnstr', '_pkg_str',
'_pkg_str_aux_keys')
def __init__(self, db):
self._db = db
for k in self._copy_attrs:
try:
setattr(self, k, getattr(db, k))
except AttributeError:
pass
self._provides_index = collections.defaultdict(list)
def match(self, atom, use_cache=DeprecationWarning):
if atom.soname:
result = self._match_soname(atom)
else:
result = self._db.match(atom)
return result
def _match_soname(self, atom):
result = self._provides_index.get(atom)
if result is None:
result = []
else:
result = [pkg.cpv for pkg in result]
return result
def _provides_inject(self, pkg):
index = self._provides_index
for atom in pkg.provides:
# Use bisect.insort for ordered match results.
bisect.insort(index[atom], pkg)
class PackageDbapiProvidesIndex(DbapiProvidesIndex):
"""
This class extends DbapiProvidesIndex in order to make it suitable
for wrapping a PackageVirtualDbapi instance.
"""
_copy_attrs = DbapiProvidesIndex._copy_attrs + (
"clear", "get", "_cpv_map")
def clear(self):
self._db.clear()
self._provides_index.clear()
def __bool__(self):
return bool(self._db)
if sys.hexversion < 0x3000000:
__nonzero__ = __bool__
def __iter__(self):
return iter(self._db)
def __contains__(self, item):
return item in self._db
def match_pkgs(self, atom):
return [self._db._cpv_map[cpv] for cpv in self.match(atom)]
def cpv_inject(self, pkg):
self._db.cpv_inject(pkg)
self._provides_inject(pkg)
def cpv_remove(self, pkg):
self._db.cpv_remove(pkg)
index = self._provides_index
for atom in pkg.provides:
items = index[atom]
try:
items.remove(pkg)
except ValueError:
pass
if not items:
del index[atom]