From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) by finch.gentoo.org (Postfix) with ESMTP id A0756138CA3 for ; Wed, 4 Mar 2015 21:38:01 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id F2EE0E0855; Wed, 4 Mar 2015 21:37:55 +0000 (UTC) Received: from smtp.gentoo.org (smtp.gentoo.org [140.211.166.183]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id E7C60E089E for ; Wed, 4 Mar 2015 21:37:54 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id 7346A3406D8 for ; Wed, 4 Mar 2015 21:37:53 +0000 (UTC) Received: from localhost.localdomain (localhost [127.0.0.1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 1BD9F130C5 for ; Wed, 4 Mar 2015 21:37:52 +0000 (UTC) From: "Zac Medico" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Zac Medico" Message-ID: <1425504727.7921e61065502fd0bb08d9dfef6a4493657961bf.zmedico@gentoo> Subject: [gentoo-commits] proj/portage:master commit in: pym/portage/dbapi/ X-VCS-Repository: proj/portage X-VCS-Files: pym/portage/dbapi/virtual.py X-VCS-Directories: pym/portage/dbapi/ X-VCS-Committer: zmedico X-VCS-Committer-Name: Zac Medico X-VCS-Revision: 7921e61065502fd0bb08d9dfef6a4493657961bf X-VCS-Branch: master Date: Wed, 4 Mar 2015 21:37:52 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Archives-Salt: 706b2f32-3a21-400d-b041-3d559d637ebe X-Archives-Hash: e6ad4b15c60c8c29b6b9aca605e8c608 commit: 7921e61065502fd0bb08d9dfef6a4493657961bf Author: Zac Medico gentoo org> AuthorDate: Tue Feb 17 23:04:07 2015 +0000 Commit: Zac Medico gentoo org> CommitDate: Wed Mar 4 21:32:07 2015 +0000 URL: http://sources.gentoo.org/gitweb/?p=proj/portage.git;a=commit;h=7921e610 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). pym/portage/dbapi/virtual.py | 113 +++++++++++++++++++++++++++++++++---------- 1 file changed, 87 insertions(+), 26 deletions(-) diff --git a/pym/portage/dbapi/virtual.py b/pym/portage/dbapi/virtual.py index ba9745c..3b7d10e 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