Fix the binarytree._read_metadata method to return empty strings for undefined metadata values, in order to fulfill a contract with the _pkg_str class. This prevents an AttributeError triggered by old binary packages which have undefined repository metadata, as reported in bug 603826.
X-Gentoo-bug: 603826 X-Gentoo-bug-url: https://bugs.gentoo.org/603826 --- pym/portage/dbapi/bintree.py | 31 +++++++++++++++++++++++++------ pym/portage/versions.py | 8 +++++++- 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/pym/portage/dbapi/bintree.py b/pym/portage/dbapi/bintree.py index f483059..3341889 100644 --- a/pym/portage/dbapi/bintree.py +++ b/pym/portage/dbapi/bintree.py @@ -1,4 +1,4 @@ -# Copyright 1998-2014 Gentoo Foundation +# Copyright 1998-2016 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import unicode_literals @@ -1041,12 +1041,12 @@ class binarytree(object): noiselevel=-1) return metadata = self._read_metadata(full_path, s) - slot = metadata.get("SLOT") + invalid_depend = False try: self._eval_use_flags(cpv, metadata) except portage.exception.InvalidDependString: - slot = None - if slot is None: + invalid_depend = True + if invalid_depend or not metadata.get("SLOT"): writemsg(_("!!! Invalid binary package: '%s'\n") % full_path, noiselevel=-1) return @@ -1126,6 +1126,21 @@ class binarytree(object): return cpv def _read_metadata(self, filename, st, keys=None): + """ + Read metadata from a binary package. The returned metadata + dictionary will contain empty strings for any values that + are undefined (this is important because the _pkg_str class + distinguishes between missing and undefined values). + + @param filename: File path of the binary package + @type filename: string + @param st: stat result for the binary package + @type st: os.stat_result + @param keys: optional list of specific metadata keys to retrieve + @type keys: iterable + @rtype: dict + @return: package metadata + """ if keys is None: keys = self.dbapi._aux_cache_keys metadata = self.dbapi._aux_cache_slot_dict() @@ -1139,10 +1154,14 @@ class binarytree(object): metadata[k] = _unicode(st.st_size) else: v = binary_metadata.get(_unicode_encode(k)) - if v is not None: + if v is None: + if k == "EAPI": + metadata[k] = "0" + else: + metadata[k] = "" + else: v = _unicode_decode(v) metadata[k] = " ".join(v.split()) - metadata.setdefault("EAPI", "0") return metadata def _inject_file(self, pkgindex, cpv, filename): diff --git a/pym/portage/versions.py b/pym/portage/versions.py index a028d93..adfb1c3 100644 --- a/pym/portage/versions.py +++ b/pym/portage/versions.py @@ -1,5 +1,5 @@ # versions.py -- core Portage functionality -# Copyright 1998-2014 Gentoo Foundation +# Copyright 1998-2016 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 from __future__ import unicode_literals @@ -359,6 +359,12 @@ class _pkg_str(_unicode): Instances are typically created in dbapi.cp_list() or the Atom contructor, and propagate from there. Generally, code that pickles these objects will manually convert them to a plain unicode object first. + + Instances of this class will have missing attributes for metadata that + has not been passed into the constructor. The missing attributes are + used to distinguish missing metadata values from undefined metadata values. + For example, the repo attribute will be missing if the 'repository' key + is missing from the metadata dictionary. """ def __new__(cls, cpv, metadata=None, settings=None, eapi=None, -- 2.7.4