aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Medico <zmedico@gentoo.org>2015-02-17 15:04:07 -0800
committerZac Medico <zmedico@gentoo.org>2015-03-04 13:32:07 -0800
commit7921e61065502fd0bb08d9dfef6a4493657961bf (patch)
tree6a34e334567687003e3cef77313599ce87fba80a
parentbinpkg-multi-instance 1 of 7 (diff)
downloadportage-7921e61065502fd0bb08d9dfef6a4493657961bf.tar.gz
portage-7921e61065502fd0bb08d9dfef6a4493657961bf.tar.bz2
portage-7921e61065502fd0bb08d9dfef6a4493657961bf.zip
binpkg-multi-instance 2 of 7
Add multi-instance support to fakedbapi, which allows multiple instances with the same cpv to be stored simultaneously, as long as they are distinguishable using the new _pkg_str build_id, build_time, file_size, and mtime attributes. This will be used to add multi-instance support to the bindbapi class (which inherits from fakedbapi).
-rw-r--r--pym/portage/dbapi/virtual.py113
1 files changed, 87 insertions, 26 deletions
diff --git a/pym/portage/dbapi/virtual.py b/pym/portage/dbapi/virtual.py
index ba9745c2a..3b7d10e85 100644
--- a/pym/portage/dbapi/virtual.py
+++ b/pym/portage/dbapi/virtual.py
@@ -11,12 +11,17 @@ class fakedbapi(dbapi):
"""A fake dbapi that allows consumers to inject/remove packages to/from it
portage.settings is required to maintain the dbAPI.
"""
- def __init__(self, settings=None, exclusive_slots=True):
+ def __init__(self, settings=None, exclusive_slots=True,
+ multi_instance=False):
"""
@param exclusive_slots: When True, injecting a package with SLOT
metadata causes an existing package in the same slot to be
automatically removed (default is True).
@type exclusive_slots: Boolean
+ @param multi_instance: When True, multiple instances with the
+ same cpv may be stored simultaneously, as long as they are
+ distinguishable (default is False).
+ @type multi_instance: Boolean
"""
self._exclusive_slots = exclusive_slots
self.cpvdict = {}
@@ -25,6 +30,56 @@ class fakedbapi(dbapi):
from portage import settings
self.settings = settings
self._match_cache = {}
+ self._set_multi_instance(multi_instance)
+
+ def _set_multi_instance(self, multi_instance):
+ """
+ Enable or disable multi_instance mode. This should before any
+ packages are injected, so that all packages are indexed with
+ the same implementation of self._instance_key.
+ """
+ if self.cpvdict:
+ raise AssertionError("_set_multi_instance called after "
+ "packages have already been added")
+ self._multi_instance = multi_instance
+ if multi_instance:
+ self._instance_key = self._instance_key_multi_instance
+ else:
+ self._instance_key = self._instance_key_cpv
+
+ def _instance_key_cpv(self, cpv, support_string=False):
+ return cpv
+
+ def _instance_key_multi_instance(self, cpv, support_string=False):
+ try:
+ return (cpv, cpv.build_id, cpv.file_size, cpv.build_time,
+ cpv.mtime)
+ except AttributeError:
+ if not support_string:
+ raise
+
+ # Fallback for interfaces such as aux_get where API consumers
+ # may pass in a plain string.
+ latest = None
+ for pkg in self.cp_list(cpv_getkey(cpv)):
+ if pkg == cpv and (
+ latest is None or
+ latest.build_time < pkg.build_time):
+ latest = pkg
+
+ if latest is not None:
+ return (latest, latest.build_id, latest.file_size,
+ latest.build_time, latest.mtime)
+
+ raise KeyError(cpv)
+
+ def clear(self):
+ """
+ Remove all packages.
+ """
+ self._clear_cache()
+ self.cpvdict.clear()
+ self.cpdict.clear()
def _clear_cache(self):
if self._categories is not None:
@@ -43,7 +98,8 @@ class fakedbapi(dbapi):
return result[:]
def cpv_exists(self, mycpv, myrepo=None):
- return mycpv in self.cpvdict
+ return self._instance_key(mycpv,
+ support_string=True) in self.cpvdict
def cp_list(self, mycp, use_cache=1, myrepo=None):
# NOTE: Cache can be safely shared with the match cache, since the
@@ -63,7 +119,10 @@ class fakedbapi(dbapi):
return list(self.cpdict)
def cpv_all(self):
- return list(self.cpvdict)
+ if self._multi_instance:
+ return [x[0] for x in self.cpvdict]
+ else:
+ return list(self.cpvdict)
def cpv_inject(self, mycpv, metadata=None):
"""Adds a cpv to the list of available packages. See the
@@ -99,13 +158,14 @@ class fakedbapi(dbapi):
except AttributeError:
pass
- self.cpvdict[mycpv] = metadata
+ instance_key = self._instance_key(mycpv)
+ self.cpvdict[instance_key] = metadata
if not self._exclusive_slots:
myslot = None
if myslot and mycp in self.cpdict:
# If necessary, remove another package in the same SLOT.
for cpv in self.cpdict[mycp]:
- if mycpv != cpv:
+ if instance_key != self._instance_key(cpv):
try:
other_slot = cpv.slot
except AttributeError:
@@ -115,40 +175,41 @@ class fakedbapi(dbapi):
self.cpv_remove(cpv)
break
- cp_list = self.cpdict.get(mycp)
- if cp_list is None:
- cp_list = []
- self.cpdict[mycp] = cp_list
- try:
- cp_list.remove(mycpv)
- except ValueError:
- pass
+ cp_list = self.cpdict.get(mycp, [])
+ cp_list = [x for x in cp_list
+ if self._instance_key(x) != instance_key]
cp_list.append(mycpv)
+ self.cpdict[mycp] = cp_list
def cpv_remove(self,mycpv):
"""Removes a cpv from the list of available packages."""
self._clear_cache()
mycp = cpv_getkey(mycpv)
- if mycpv in self.cpvdict:
- del self.cpvdict[mycpv]
- if mycp not in self.cpdict:
- return
- while mycpv in self.cpdict[mycp]:
- del self.cpdict[mycp][self.cpdict[mycp].index(mycpv)]
- if not len(self.cpdict[mycp]):
- del self.cpdict[mycp]
+ instance_key = self._instance_key(mycpv)
+ self.cpvdict.pop(instance_key, None)
+ cp_list = self.cpdict.get(mycp)
+ if cp_list is not None:
+ cp_list = [x for x in cp_list
+ if self._instance_key(x) != instance_key]
+ if cp_list:
+ self.cpdict[mycp] = cp_list
+ else:
+ del self.cpdict[mycp]
def aux_get(self, mycpv, wants, myrepo=None):
- if not self.cpv_exists(mycpv):
+ metadata = self.cpvdict.get(
+ self._instance_key(mycpv, support_string=True))
+ if metadata is None:
raise KeyError(mycpv)
- metadata = self.cpvdict[mycpv]
- if not metadata:
- return ["" for x in wants]
return [metadata.get(x, "") for x in wants]
def aux_update(self, cpv, values):
self._clear_cache()
- self.cpvdict[cpv].update(values)
+ metadata = self.cpvdict.get(
+ self._instance_key(cpv, support_string=True))
+ if metadata is None:
+ raise KeyError(cpv)
+ metadata.update(values)
class testdbapi(object):
"""A dbapi instance with completely fake functions to get by hitting disk