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


Reply via email to