Merge remote branch 'overlays-gentoo-org/master' into prefix
authorFabian Groffen <grobian@gentoo.org>
Fri, 3 Sep 2010 15:30:54 +0000 (17:30 +0200)
committerFabian Groffen <grobian@gentoo.org>
Fri, 3 Sep 2010 15:30:54 +0000 (17:30 +0200)
Conflicts:
bin/ebuild
bin/ebuild-helpers/ecompressdir
bin/ebuild-helpers/prepalldocs
bin/ebuild-helpers/prepallman
bin/ebuild-helpers/prepinfo
bin/ebuild-helpers/prepman
bin/egencache
bin/regenworld
mkrelease.sh
pym/_emerge/AtomArg.py
pym/_emerge/Binpkg.py
pym/_emerge/BinpkgExtractorAsync.py
pym/_emerge/Blocker.py
pym/_emerge/Package.py
pym/_emerge/actions.py
pym/_emerge/depgraph.py
pym/portage/_legacy_globals.py
pym/portage/data.py
pym/portage/dbapi/vartree.py
pym/portage/package/ebuild/config.py
pym/portage/package/ebuild/fetch.py

39 files changed:
1  2 
bin/ebuild
bin/ebuild-helpers/dodoc
bin/ebuild-helpers/ecompressdir
bin/ebuild-helpers/prepalldocs
bin/ebuild-helpers/prepallman
bin/ebuild-helpers/prepinfo
bin/ebuild-helpers/prepman
bin/ebuild-ipc.py
bin/ebuild.sh
bin/egencache
bin/emaint
bin/isolated-functions.sh
bin/misc-functions.sh
bin/portageq
bin/quickpkg
bin/regenworld
bin/repoman
cnf/make.globals
man/emerge.1
pym/_emerge/Binpkg.py
pym/_emerge/EbuildBuild.py
pym/_emerge/Package.py
pym/_emerge/actions.py
pym/_emerge/depgraph.py
pym/_emerge/main.py
pym/portage/__init__.py
pym/portage/_sets/files.py
pym/portage/_sets/profiles.py
pym/portage/const.py
pym/portage/data.py
pym/portage/dbapi/bintree.py
pym/portage/dbapi/vartree.py
pym/portage/dispatch_conf.py
pym/portage/getbinpkg.py
pym/portage/package/ebuild/config.py
pym/portage/package/ebuild/doebuild.py
pym/portage/package/ebuild/fetch.py
pym/portage/util/__init__.py
pym/portage/versions.py

diff --cc bin/ebuild
index a00e5ed7d7bf008cdefeb923ad36265c6b07067f,a419d264b8880e5117350f041a0212a287c58ef7..283c2ff2fa4202d41bb9b9c99fd0ea608482569e
@@@ -1,5 -1,5 +1,5 @@@
 -#!/usr/bin/python -O
 +#!@PORTAGE_PYTHON@ -O
- # Copyright 1999-2006 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
  from __future__ import print_function
Simple merge
index 9bcdd934271151359991ba77688fc7ee3101fb26,acdb1cd7f135053de9a94c690af4da3eeca5c337..3576443bb36b9dbcdb3d3bebc73aeae37063f969
@@@ -13,7 -13,8 +13,8 @@@ case $1 i
        --ignore)
                shift
                for skip in "$@" ; do
-                       [[ -d ${ED}${skip} ]] && touch "${ED}${skip}.ecompress.skip"
 -                      [[ -d ${D}${skip} || -f ${D}${skip} ]] \
++                      [[ -d ${ED}${skip} || -f ${ED}${skip} ]] \
+                               && touch "${D}${skip}.ecompress.skip"
                done
                exit 0
                ;;
index 4dda218b0f908d9be5c66d621aeb1f403543bfdd,3b16f97260397444866249853adaf9392927264f..5c8b8e939bef039075a1e96cc55894c1474e3c6c
@@@ -1,14 -1,20 +1,20 @@@
 -#!/bin/bash
 +#!@PORTAGE_BASH@
- # Copyright 1999-2007 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
 -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
 +source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh
  
+ if ! hasq "${EAPI}" 0 1 2 3; then
+       eqawarn "QA Notice: Deprecated call to 'prepalldocs'"
+       exit 0
+ fi
+ 
  if [[ -n $1 ]] ; then
        vecho "${0##*/}: invalid usage; takes no arguments" 1>&2
  fi
  
- [[ -d ${ED}usr/share/doc ]] || exit 0
+ cd "${D}"
 -[[ -d usr/share/doc ]] || exit 0
++[[ -d ${EPREFIX}usr/share/doc ]] || exit 0
  
  ecompressdir --ignore /usr/share/doc/${PF}/html
  ecompressdir --queue /usr/share/doc
index ea0485bf35bc7166ec4d9368c5228006e7ed6273,4568bac1d4efb70b9c0359334cf4467581b4c5b2..6e95f0d20b516128c3f682e38dd9b3421d0f6f34
@@@ -1,14 -1,17 +1,19 @@@
 -#!/bin/bash
 +#!@PORTAGE_BASH@
- # Copyright 1999-2007 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
 -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
++source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh
+ 
+ # replaced by controllable compression in EAPI 4
+ hasq "${EAPI}" 0 1 2 3 || exit 0
+ 
  ret=0
  
 -find "${D}" -type d -name man > "${T}"/prepallman.filelist
 +[[ -d ${ED} ]] || exit ${ret}
 +
 +find "${ED}" -type d -name man > "${T}"/prepallman.filelist
  while read mandir ; do
 -      mandir=${mandir#${D}}
 +      mandir=${mandir#${ED}}
        prepman "${mandir%/man}"
        ((ret|=$?))
  done < "${T}"/prepallman.filelist
index d372c1bb8f4670b1d155c97ff128b17a805208bf,fa37e5e6438f45fa56b7a911e43f94441eec7e78..2200b89b2bb93bc231f70142f0388acfaab123bf
@@@ -1,16 -1,16 +1,16 @@@
 -#!/bin/bash
 +#!@PORTAGE_BASH@
- # Copyright 1999-2007 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
 -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
 +source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh
  
  if [[ -z $1 ]] ; then
 -      infodir="/usr/share/info"
 +      infodir="${EPREFIX}/usr/share/info"
  else
 -      if [[ -d ${D}$1/share/info ]] ; then
 -              infodir="$1/share/info"
 +      if [[ -d ${ED}$1/share/info ]] ; then
 +              infodir="${EPREFIX}$1/share/info"
        else
 -              infodir="$1/info"
 +              infodir="${EPREFIX}$1/info"
        fi
  fi
  
index 78f91012b6e2241fc6e1a4f8a455d3ae70070646,3466402489e21e5241cd7a50e80a8b76861606b7..231f9aef89faf8a36d2ae37e4393c454b2d08207
@@@ -1,13 -1,13 +1,13 @@@
 -#!/bin/bash
 +#!@PORTAGE_BASH@
- # Copyright 1999-2007 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
 -source "${PORTAGE_BIN_PATH:-/usr/lib/portage/bin}"/isolated-functions.sh
 +source "${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"/isolated-functions.sh
  
  if [[ -z $1 ]] ; then 
 -      mandir="${D}usr/share/man"
 +      mandir="${ED}usr/share/man"
  else
 -      mandir="${D}$1/man"
 +      mandir="${ED}$1/man"
  fi
  
  if [[ ! -d ${mandir} ]] ; then
Simple merge
diff --cc bin/ebuild.sh
index 5938d686b5b0628fc592640dc313642c788d405a,73ea8c807ebf753c338ea5936c7929161e89ddff..8bf22ea5b090a5b43136a2746ecdd9fb5435e728
@@@ -20,15 -20,15 +20,21 @@@ ROOTPATH=${ROOTPATH##:
  ROOTPATH=${ROOTPATH%%:}
  PREROOTPATH=${PREROOTPATH##:}
  PREROOTPATH=${PREROOTPATH%%:}
 -PATH=$PORTAGE_BIN_PATH/ebuild-helpers:$PREROOTPATH${PREROOTPATH:+:}/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin${ROOTPATH:+:}$ROOTPATH
 +#PATH=$PORTAGE_BIN_PATH/ebuild-helpers:$PREROOTPATH${PREROOTPATH:+:}/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin${ROOTPATH:+:}$ROOTPATH
 +# PREFIX: our DEFAULT_PATH is equal to the above when not using an
 +# offset prefix.  With such prefix, the usr/local bits are excluded, and
 +# the prefixed variants of {usr/,}{s,}bin are taken.  The additional
 +# paths given during configure, always come as last thing since they
 +# should never override anything from the prefix itself.
 +PATH="$PORTAGE_BIN_PATH/ebuild-helpers:$PREROOTPATH${PREROOTPATH:+:}${DEFAULT_PATH}${ROOTPATH:+:}$ROOTPATH${EXTRA_PATH:+:}${EXTRA_PATH}"
  export PATH
  
+ # This is just a temporary workaround for portage-9999 users since
+ # earlier portage versions do not detect a version change in this case
+ # (9999 to 9999) and therefore they try execute an incompatible version of
+ # ebuild.sh during the upgrade.
+ export PORTAGE_BZIP2_COMMAND=${PORTAGE_BZIP2_COMMAND:-bzip2} 
+ 
  # These two functions wrap sourcing and calling respectively.  At present they
  # perform a qa check to make sure eclasses and ebuilds and profiles don't mess
  # with shell opts (shopts).  Ebuilds/eclasses changing shopts should reset them 
diff --cc bin/egencache
index 2b89d281109b19c738285aa9f5ddd63bd783ceef,a16ac4f9304a62d4370f601adb881639d49f7adb..3dc65f09a93be93138a7010cbd3d56b472d3d537
@@@ -1,5 -1,5 +1,5 @@@
 -#!/usr/bin/python
 +#!@PORTAGE_PYTHON@
- # Copyright 2009 Gentoo Foundation
+ # Copyright 2009-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
  from __future__ import print_function
diff --cc bin/emaint
Simple merge
Simple merge
index bb936e88f3cfae3bb97a823d4468993e8e454f8f,1edacadca90afecf3f2712fd2382ebf8c22ae1a3..a175c0f174ec6c328e6e3e567de6c9b3a359c210
mode 100644,100755..100644
@@@ -1461,10 -855,10 +1565,10 @@@ dyn_package() 
                PORTAGE_BINPKG_TMPFILE="${PKGDIR}/${CATEGORY}/${PF}.tbz2"
        mkdir -p "${PORTAGE_BINPKG_TMPFILE%/*}" || die "mkdir failed"
        tar $tar_options -cf - $PORTAGE_BINPKG_TAR_OPTS -C "${D}" . | \
-               bzip2 -cf > "$PORTAGE_BINPKG_TMPFILE"
+               $PORTAGE_BZIP2_COMMAND -c > "$PORTAGE_BINPKG_TMPFILE"
        assert "failed to pack binary package: '$PORTAGE_BINPKG_TMPFILE'"
        PYTHONPATH=${PORTAGE_PYM_PATH}${PYTHONPATH:+:}${PYTHONPATH} \
 -              "${PORTAGE_PYTHON:-/usr/bin/python}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \
 +              "${PORTAGE_PYTHON:-@PORTAGE_PYTHON@}" "$PORTAGE_BIN_PATH"/xpak-helper.py recompose \
                "$PORTAGE_BINPKG_TMPFILE" "$PORTAGE_BUILDDIR/build-info"
        if [ $? -ne 0 ]; then
                rm -f "${PORTAGE_BINPKG_TMPFILE}"
diff --cc bin/portageq
Simple merge
diff --cc bin/quickpkg
Simple merge
diff --cc bin/regenworld
index 03815858a216079caae484c0b1bbba1f35ec1af4,292eac1ac73f08f26422c686d0d8a3fa2da5ccb1..ee185131f37b0abfb4662cd33a0ebe276353912d
@@@ -1,23 -1,23 +1,22 @@@
 -#!/usr/bin/python
 +#!@PORTAGE_PYTHON@
- # Copyright 1999-2006 Gentoo Foundation
+ # Copyright 1999-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
- # NOTE: this file does not respect ROOT
- 
  from __future__ import print_function
  
  import sys
 -try:
 -      import portage
 -except ImportError:
 -      from os import path as osp
 -      sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
 -      import portage
 -
 +# for an explanation on this logic, see pym/_emerge/__init__.py 
 +from os import environ as ose
 +from os import path as osp
 +if ose.__contains__("PORTAGE_PYTHONPATH"): 
 +      sys.path.insert(0, ose["PORTAGE_PYTHONPATH"]) 
 +else: 
 +      sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.    realpath(__file__))), "pym")) 
 +import portage 
  from portage import os
- import portage.exception
- import re, portage.const
 -from portage._sets.files import StaticFileSet, WorldSelectedSet
 -
+ import re
+ import tempfile
+ import textwrap
  
  __candidatematcher__ = re.compile("^[0-9]+: \\*\\*\\* emerge ")
  __noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot|--fetchonly| unmerge( |$)")
diff --cc bin/repoman
Simple merge
Simple merge
diff --cc man/emerge.1
Simple merge
index 5632fa8d7813e7f3b6cc8cb9d9a6f36220b99fcf,ac9a68a0f62ff1ec35e685c57f49246271379cc2..5f190df593af8c5084eb7d9ca18c3b4416f8089a
@@@ -299,15 -273,9 +299,16 @@@ class Binpkg(CompositeTask)
                        self.wait()
                        return
  
 +              # if the prefix differs, we copy it to the image after
 +              # extraction using chpathtool
 +              if (self._buildprefix != EPREFIX):
 +                      pkgloc = self._work_dir
 +              else:
 +                      pkgloc = self._image_dir
 +
                extractor = BinpkgExtractorAsync(background=self.background,
 -                      image_dir=self._image_dir,
+                       env=self.settings.environ(),
 +                      image_dir=pkgloc,
                        pkg=self.pkg, pkg_path=self._pkg_path,
                        logfile=self.settings.get("PORTAGE_LOG_FILE"),
                        scheduler=self.scheduler)
Simple merge
index 35b7879e0b00da96df715459b6edffc278eb0e8d,0a4f2ab7aaae183f7675ca8bdee9ff652d9f868a..e8ac2ff2c2c7618022491463dc4b2df9ab567a5c
@@@ -6,11 -5,11 +5,12 @@@ import sy
  from itertools import chain
  import portage
  from portage.cache.mappings import slot_dict_class
- from portage.dep import isvalidatom, use_reduce, \
+ from portage.dep import Atom, check_required_use, use_reduce, \
        paren_enclose, _slot_re
  from portage.eapi import eapi_has_iuse_defaults, eapi_has_required_use
- from portage.const import EPREFIX
+ from portage.exception import InvalidDependString
  from _emerge.Task import Task
++from portage.const import EPREFIX
  
  if sys.hexversion >= 0x3000000:
        basestring = str
@@@ -32,8 -31,11 +32,11 @@@ class Package(Task)
                "INHERITED", "IUSE", "KEYWORDS",
                "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND",
                "repository", "PROPERTIES", "RESTRICT", "SLOT", "USE",
 -              "_mtime_", "DEFINED_PHASES", "REQUIRED_USE"]
 +              "_mtime_", "DEFINED_PHASES", "REQUIRED_USE", "EPREFIX"]
  
+       _dep_keys = ('DEPEND', 'PDEPEND', 'RDEPEND',)
+       _use_conditional_misc_keys = ('LICENSE', 'PROPERTIES', 'RESTRICT')
+ 
        def __init__(self, **kwargs):
                Task.__init__(self, **kwargs)
                self.root = self.root_config.root
                        if 'EAPI.unsupported' in masks:
                                return False
  
 -                      if 'invalid' in masks:
 +                      if self.built and not self.installed and ( \
 +                              'EPREFIX.missing' in masks or \
-                               'EPREFIX.tooshort' in masks):
++                              'EPREFIX.tooshort' in masks) or \
++                              'invalid' in masks:
                                return False
  
                        if not self.installed and ( \
index bb6d7d55f03e1b5754c9418a4841af212deb5d4e,d84e434d6b520dbc6b95cc9fab8548ff77c2cc97..6fe7480c5d2738493b1125d7114fab9665a2f5bd
@@@ -25,9 -25,10 +25,10 @@@ from itertools import chai
  import portage
  from portage import os
  from portage import digraph
- from portage import _unicode_decode, _unicode_encode
+ from portage import _unicode_decode
  from portage.cache.cache_errors import CacheError
 -from portage.const import GLOBAL_CONFIG_PATH, NEWS_LIB_PATH
 +from portage.const import GLOBAL_CONFIG_PATH, NEWS_LIB_PATH, EPREFIX
+ from portage.const import _ENABLE_DYN_LINK_MAP
  from portage.dbapi.dep_expand import dep_expand
  from portage.output import blue, bold, colorize, create_color_func, darkgreen, \
        red, yellow
index 7e2b0d1a1c901d2171a76d4cb76011b89b0c4941,a51bd7facf984727908e1170d1f96e4fb3f4763f..e46659d00337ad4be9f4c1f1ae54f9e154b3053c
@@@ -6119,12 -6150,12 +6150,18 @@@ def _get_masking_status(pkg, pkgsetting
                                        msg = "violated use flag constraints: '%s'" % required_use
                                        mreasons.append(_MaskReason("REQUIRED_USE", "REQUIRED_USE violated"))
  
 +      if pkg.built and not pkg.installed:
 +              if not "EPREFIX" in pkg.metadata or not pkg.metadata["EPREFIX"]:
 +                      mreasons.append("missing EPREFIX")
 +              elif len(pkg.metadata["EPREFIX"].strip()) < len(pkgsettings["EPREFIX"]):
 +                      mreasons.append("EPREFIX: '%s' too small" % pkg.metadata["EPREFIX"])
 +
+       if pkg.invalid:
+               for msg_type, msgs in pkg.invalid.items():
+                       for msg in msgs:
+                               mreasons.append(
+                                       _MaskReason("invalid", "invalid: %s" % (msg,)))
+ 
        if not pkg.metadata["SLOT"]:
                mreasons.append(
                        _MaskReason("invalid", "SLOT: undefined"))
Simple merge
Simple merge
Simple merge
index 87ac0ac96d79322652ee975c786f2ed071617a74,e47f08db3c4f0d67996b69bde60cfc2f9751bb5c..d2e29aa2d814c83edd874dd932ef3779e1bb2fc2
@@@ -5,10 -5,9 +5,10 @@@ import loggin
  
  from portage import os
  from portage.util import grabfile_package, stack_lists
- from portage.sets.base import PackageSet
- from portage.sets import get_boolean
+ from portage._sets.base import PackageSet
+ from portage._sets import get_boolean
  from portage.util import writemsg_level
 +from portage.const import EPREFIX
  
  __all__ = ["PackagesSystemSet"]
  
Simple merge
index 006ee13420f52e519a943e32725050588ee0abcb,c38fa17bc6b9ee97e3df2f29043d970544290964..b1018edd0879a6c36ab2b5d954a544fb8b2ab24d
@@@ -1,9 -1,8 +1,9 @@@
  # data.py -- Calculated/Discovered Data Values
- # Copyright 1998-2009 Gentoo Foundation
+ # Copyright 1998-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
- import os, sys, pwd, grp, platform
+ import os, pwd, grp, platform
 +from portage.const import PORTAGE_GROUPNAME, PORTAGE_USERNAME, rootuid, EPREFIX
  
  import portage
  portage.proxy.lazyimport.lazyimport(globals(),
index 22565d1f1d2e6c6f64dff7d97c444b59871d9b8b,8cb59255de6d4f65ecf3ed84a612b21e2bd76879..874c4247e360a8e6ae9fdb575bd30579a79073e6
@@@ -18,10 -18,9 +18,10 @@@ portage.proxy.lazyimport.lazyimport(glo
  
  from portage.cache.mappings import slot_dict_class
  from portage.dbapi.virtual import fakedbapi
- from portage.dep import use_reduce, paren_enclose
+ from portage.dep import Atom, use_reduce, paren_enclose
  from portage.exception import InvalidPackageName, \
        PermissionDenied, PortageException
 +from portage.const import EAPI
  from portage.localization import _
  
  from portage import _movefile
index c693476d4387811f98dd812b1a38f4eacfb2f5f9,25956f198252160ffa67fdf320d2dbcefa661d72..854aba91667f98d7130fd8e3cd04baad388b7a9c
@@@ -1,8 -1,7 +1,8 @@@
  # Copyright 1998-2010 Gentoo Foundation
  # Distributed under the terms of the GNU General Public License v2
  
- __all__ = ["PreservedLibsRegistry", "LinkageMap",
+ __all__ = [
 +      "LinkageMapMachO", "LinkageMapPeCoff", "LinkageMapXCoff"
        "vardbapi", "vartree", "dblink"] + \
        ["write_contents", "tar_contents"]
  
@@@ -31,7 -32,8 +33,8 @@@ portage.proxy.lazyimport.lazyimport(glo
  )
  
  from portage.const import CACHE_PATH, CONFIG_MEMORY_FILE, \
 -      PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH
 +      PORTAGE_PACKAGE_ATOM, PRIVATE_PATH, VDB_PATH, EPREFIX, EPREFIX_LSTRIP, BASH_BINARY
+ from portage.const import _ENABLE_DYN_LINK_MAP, _ENABLE_PRESERVE_LIBS
  from portage.dbapi import dbapi
  from portage.exception import CommandNotFound, \
        InvalidData, InvalidPackageName, \
@@@ -73,1713 -74,6 +75,987 @@@ if sys.hexversion >= 0x3000000
        basestring = str
        long = int
  
- class PreservedLibsRegistry(object):
-       """ This class handles the tracking of preserved library objects """
-       def __init__(self, root, filename, autocommit=True):
-               """ 
-                       @param root: root used to check existence of paths in pruneNonExisting
-                   @type root: String
-                       @param filename: absolute path for saving the preserved libs records
-                   @type filename: String
-                       @param autocommit: determines if the file is written after every update
-                       @type autocommit: Boolean
-               """
-               self._root = root
-               self._filename = filename
-               self._autocommit = autocommit
-               self.load()
-               self.pruneNonExisting()
- 
-       def load(self):
-               """ Reload the registry data from file """
-               self._data = None
-               try:
-                       self._data = pickle.load(
-                               open(_unicode_encode(self._filename,
-                                       encoding=_encodings['fs'], errors='strict'), 'rb'))
-               except (ValueError, pickle.UnpicklingError) as e:
-                       writemsg_level(_("!!! Error loading '%s': %s\n") % \
-                               (self._filename, e), level=logging.ERROR, noiselevel=-1)
-               except (EOFError, IOError) as e:
-                       if isinstance(e, EOFError) or e.errno == errno.ENOENT:
-                               pass
-                       elif e.errno == PermissionDenied.errno:
-                               raise PermissionDenied(self._filename)
-                       else:
-                               raise
-               if self._data is None:
-                       self._data = {}
-               self._data_orig = self._data.copy()
-       def store(self):
-               """ Store the registry data to file. No need to call this if autocommit
-                   was enabled.
-               """
-               if os.environ.get("SANDBOX_ON") == "1" or \
-                       self._data == self._data_orig:
-                       return
-               try:
-                       f = atomic_ofstream(self._filename, 'wb')
-                       pickle.dump(self._data, f, protocol=2)
-                       f.close()
-               except EnvironmentError as e:
-                       if e.errno != PermissionDenied.errno:
-                               writemsg("!!! %s %s\n" % (e, self._filename), noiselevel=-1)
-               else:
-                       self._data_orig = self._data.copy()
- 
-       def register(self, cpv, slot, counter, paths):
-               """ Register new objects in the registry. If there is a record with the
-                       same packagename (internally derived from cpv) and slot it is 
-                       overwritten with the new data.
-                       @param cpv: package instance that owns the objects
-                       @type cpv: CPV (as String)
-                       @param slot: the value of SLOT of the given package instance
-                       @type slot: String
-                       @param counter: vdb counter value for the package instace
-                       @type counter: Integer
-                       @param paths: absolute paths of objects that got preserved during an update
-                       @type paths: List
-               """
-               cp = "/".join(catpkgsplit(cpv)[:2])
-               cps = cp+":"+slot
-               if len(paths) == 0 and cps in self._data \
-                               and self._data[cps][0] == cpv and int(self._data[cps][1]) == int(counter):
-                       del self._data[cps]
-               elif len(paths) > 0:
-                       self._data[cps] = (cpv, counter, paths)
-               if self._autocommit:
-                       self.store()
-       
-       def unregister(self, cpv, slot, counter):
-               """ Remove a previous registration of preserved objects for the given package.
-                       @param cpv: package instance whose records should be removed
-                       @type cpv: CPV (as String)
-                       @param slot: the value of SLOT of the given package instance
-                       @type slot: String
-               """
-               self.register(cpv, slot, counter, [])
-       
-       def pruneNonExisting(self):
-               """ Remove all records for objects that no longer exist on the filesystem. """
- 
-               os = _os_merge
- 
-               for cps in list(self._data):
-                       cpv, counter, paths = self._data[cps]
-                       paths = [f for f in paths \
-                               if os.path.exists(os.path.join(self._root, f.lstrip(os.sep)))]
-                       if len(paths) > 0:
-                               self._data[cps] = (cpv, counter, paths)
-                       else:
-                               del self._data[cps]
-               if self._autocommit:
-                       self.store()
-       
-       def hasEntries(self):
-               """ Check if this registry contains any records. """
-               return len(self._data) > 0
-       
-       def getPreservedLibs(self):
-               """ Return a mapping of packages->preserved objects.
-                       @returns mapping of package instances to preserved objects
-                       @rtype Dict cpv->list-of-paths
-               """
-               rValue = {}
-               for cps in self._data:
-                       rValue[self._data[cps][0]] = self._data[cps][2]
-               return rValue
- 
- class LinkageMap(object):
- 
-       """Models dynamic linker dependencies."""
- 
-       _needed_aux_key = "NEEDED.ELF.2"
-       _soname_map_class = slot_dict_class(
-               ("consumers", "providers"), prefix="")
- 
-       def __init__(self, vardbapi):
-               self._dbapi = vardbapi
-               self._root = self._dbapi._eroot
-               self._libs = {}
-               self._obj_properties = {}
-               self._obj_key_cache = {}
-               self._defpath = set()
-               self._path_key_cache = {}
- 
-       def _clear_cache(self):
-               self._libs.clear()
-               self._obj_properties.clear()
-               self._obj_key_cache.clear()
-               self._defpath.clear()
-               self._path_key_cache.clear()
- 
-       def _path_key(self, path):
-               key = self._path_key_cache.get(path)
-               if key is None:
-                       key = self._ObjectKey(path, self._root)
-                       self._path_key_cache[path] = key
-               return key
- 
-       def _obj_key(self, path):
-               key = self._obj_key_cache.get(path)
-               if key is None:
-                       key = self._ObjectKey(path, self._root)
-                       self._obj_key_cache[path] = key
-               return key
- 
-       class _ObjectKey(object):
- 
-               """Helper class used as _obj_properties keys for objects."""
- 
-               __slots__ = ("__weakref__", "_key")
- 
-               def __init__(self, obj, root):
-                       """
-                       This takes a path to an object.
- 
-                       @param object: path to a file
-                       @type object: string (example: '/usr/bin/bar')
- 
-                       """
-                       self._key = self._generate_object_key(obj, root)
- 
-               def __hash__(self):
-                       return hash(self._key)
- 
-               def __eq__(self, other):
-                       return self._key == other._key
- 
-               def _generate_object_key(self, obj, root):
-                       """
-                       Generate object key for a given object.
- 
-                       @param object: path to a file
-                       @type object: string (example: '/usr/bin/bar')
-                       @rtype: 2-tuple of types (long, int) if object exists. string if
-                               object does not exist.
-                       @return:
-                               1. 2-tuple of object's inode and device from a stat call, if object
-                                       exists.
-                               2. realpath of object if object does not exist.
- 
-                       """
- 
-                       os = _os_merge
- 
-                       try:
-                               _unicode_encode(obj,
-                                       encoding=_encodings['merge'], errors='strict')
-                       except UnicodeEncodeError:
-                               # The package appears to have been merged with a 
-                               # different value of sys.getfilesystemencoding(),
-                               # so fall back to utf_8 if appropriate.
-                               try:
-                                       _unicode_encode(obj,
-                                               encoding=_encodings['fs'], errors='strict')
-                               except UnicodeEncodeError:
-                                       pass
-                               else:
-                                       os = portage.os
- 
-                       abs_path = os.path.join(root, obj.lstrip(os.sep))
-                       try:
-                               object_stat = os.stat(abs_path)
-                       except OSError:
-                               # Use the realpath as the key if the file does not exists on the
-                               # filesystem.
-                               return os.path.realpath(abs_path)
-                       # Return a tuple of the device and inode.
-                       return (object_stat.st_dev, object_stat.st_ino)
- 
-               def file_exists(self):
-                       """
-                       Determine if the file for this key exists on the filesystem.
- 
-                       @rtype: Boolean
-                       @return:
-                               1. True if the file exists.
-                               2. False if the file does not exist or is a broken symlink.
- 
-                       """
-                       return isinstance(self._key, tuple)
- 
-       class _LibGraphNode(_ObjectKey):
-               __slots__ = ("alt_paths",)
- 
-               def __init__(self, obj, root):
-                       LinkageMap._ObjectKey.__init__(self, obj, root)
-                       self.alt_paths = set()
- 
-               def __str__(self):
-                       return str(sorted(self.alt_paths))
- 
-       def rebuild(self, exclude_pkgs=None, include_file=None):
-               """
-               Raises CommandNotFound if there are preserved libs
-               and the scanelf binary is not available.
-               """
- 
-               os = _os_merge
-               root = self._root
-               root_len = len(root) - 1
-               self._clear_cache()
-               self._defpath.update(getlibpaths(self._root))
-               libs = self._libs
-               obj_key_cache = self._obj_key_cache
-               obj_properties = self._obj_properties
- 
-               lines = []
- 
-               # Data from include_file is processed first so that it
-               # overrides any data from previously installed files.
-               if include_file is not None:
-                       lines += grabfile(include_file)
- 
-               aux_keys = [self._needed_aux_key]
-               for cpv in self._dbapi.cpv_all():
-                       if exclude_pkgs is not None and cpv in exclude_pkgs:
-                               continue
-                       lines += self._dbapi.aux_get(cpv, aux_keys)[0].split('\n')
-               # Cache NEEDED.* files avoid doing excessive IO for every rebuild.
-               self._dbapi.flush_cache()
- 
-               # have to call scanelf for preserved libs here as they aren't 
-               # registered in NEEDED.ELF.2 files
-               plibs = set()
-               if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
-                       args = [EPREFIX+"/usr/bin/scanelf", "-qF", "%a;%F;%S;%r;%n"]
-                       for items in self._dbapi.plib_registry.getPreservedLibs().values():
-                               plibs.update(items)
-                               args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
-                                       for x in items)
-                       try:
-                               proc = subprocess.Popen(args, stdout=subprocess.PIPE)
-                       except EnvironmentError as e:
-                               if e.errno != errno.ENOENT:
-                                       raise
-                               raise CommandNotFound(args[0])
-                       else:
-                               for l in proc.stdout:
-                                       try:
-                                               l = _unicode_decode(l,
-                                                       encoding=_encodings['content'], errors='strict')
-                                       except UnicodeDecodeError:
-                                               l = _unicode_decode(l,
-                                                       encoding=_encodings['content'], errors='replace')
-                                               writemsg_level(_("\nError decoding characters " \
-                                                       "returned from scanelf: %s\n\n") % (l,),
-                                                       level=logging.ERROR, noiselevel=-1)
-                                       l = l[3:].rstrip("\n")
-                                       if not l:
-                                               continue
-                                       fields = l.split(";")
-                                       if len(fields) < 5:
-                                               writemsg_level(_("\nWrong number of fields " \
-                                                       "returned from scanelf: %s\n\n") % (l,),
-                                                       level=logging.ERROR, noiselevel=-1)
-                                               continue
-                                       fields[1] = fields[1][root_len:]
-                                       plibs.discard(fields[1])
-                                       lines.append(";".join(fields))
-                               proc.wait()
- 
-               if plibs:
-                       # Preserved libraries that did not appear in the scanelf output.
-                       # This is known to happen with statically linked libraries.
-                       # Generate dummy lines for these, so we can assume that every
-                       # preserved library has an entry in self._obj_properties. This
-                       # is important in order to prevent findConsumers from raising
-                       # an unwanted KeyError.
-                       for x in plibs:
-                               lines.append(";".join(['', x, '', '', '']))
- 
-               for l in lines:
-                       l = l.rstrip("\n")
-                       if not l:
-                               continue
-                       fields = l.split(";")
-                       if len(fields) < 5:
-                               writemsg_level(_("\nWrong number of fields " \
-                                       "in %s: %s\n\n") % (self._needed_aux_key, l),
-                                       level=logging.ERROR, noiselevel=-1)
-                               continue
-                       arch = fields[0]
-                       obj = fields[1]
-                       soname = fields[2]
-                       path = set([normalize_path(x) \
-                               for x in filter(None, fields[3].replace(
-                               "${ORIGIN}", os.path.dirname(obj)).replace(
-                               "$ORIGIN", os.path.dirname(obj)).split(":"))])
-                       needed = [x for x in fields[4].split(",") if x]
- 
-                       obj_key = self._obj_key(obj)
-                       indexed = True
-                       myprops = obj_properties.get(obj_key)
-                       if myprops is None:
-                               indexed = False
-                               myprops = (arch, needed, path, soname, set())
-                               obj_properties[obj_key] = myprops
-                       # All object paths are added into the obj_properties tuple.
-                       myprops[4].add(obj)
- 
-                       # Don't index the same file more that once since only one
-                       # set of data can be correct and therefore mixing data
-                       # may corrupt the index (include_file overrides previously
-                       # installed).
-                       if indexed:
-                               continue
- 
-                       arch_map = libs.get(arch)
-                       if arch_map is None:
-                               arch_map = {}
-                               libs[arch] = arch_map
-                       if soname:
-                               soname_map = arch_map.get(soname)
-                               if soname_map is None:
-                                       soname_map = self._soname_map_class(
-                                               providers=set(), consumers=set())
-                                       arch_map[soname] = soname_map
-                               soname_map.providers.add(obj_key)
-                       for needed_soname in needed:
-                               soname_map = arch_map.get(needed_soname)
-                               if soname_map is None:
-                                       soname_map = self._soname_map_class(
-                                               providers=set(), consumers=set())
-                                       arch_map[needed_soname] = soname_map
-                               soname_map.consumers.add(obj_key)
- 
-       def listBrokenBinaries(self, debug=False):
-               """
-               Find binaries and their needed sonames, which have no providers.
- 
-               @param debug: Boolean to enable debug output
-               @type debug: Boolean
-               @rtype: dict (example: {'/usr/bin/foo': set(['libbar.so'])})
-               @return: The return value is an object -> set-of-sonames mapping, where
-                       object is a broken binary and the set consists of sonames needed by
-                       object that have no corresponding libraries to fulfill the dependency.
- 
-               """
- 
-               os = _os_merge
- 
-               class _LibraryCache(object):
- 
-                       """
-                       Caches properties associated with paths.
- 
-                       The purpose of this class is to prevent multiple instances of
-                       _ObjectKey for the same paths.
- 
-                       """
- 
-                       def __init__(cache_self):
-                               cache_self.cache = {}
- 
-                       def get(cache_self, obj):
-                               """
-                               Caches and returns properties associated with an object.
- 
-                               @param obj: absolute path (can be symlink)
-                               @type obj: string (example: '/usr/lib/libfoo.so')
-                               @rtype: 4-tuple with types
-                                       (string or None, string or None, 2-tuple, Boolean)
-                               @return: 4-tuple with the following components:
-                                       1. arch as a string or None if it does not exist,
-                                       2. soname as a string or None if it does not exist,
-                                       3. obj_key as 2-tuple,
-                                       4. Boolean representing whether the object exists.
-                                       (example: ('libfoo.so.1', (123L, 456L), True))
- 
-                               """
-                               if obj in cache_self.cache:
-                                       return cache_self.cache[obj]
-                               else:
-                                       obj_key = self._obj_key(obj)
-                                       # Check that the library exists on the filesystem.
-                                       if obj_key.file_exists():
-                                               # Get the arch and soname from LinkageMap._obj_properties if
-                                               # it exists. Otherwise, None.
-                                               arch, _needed, _path, soname, _objs = \
-                                                               self._obj_properties.get(obj_key, (None,)*5)
-                                               return cache_self.cache.setdefault(obj, \
-                                                               (arch, soname, obj_key, True))
-                                       else:
-                                               return cache_self.cache.setdefault(obj, \
-                                                               (None, None, obj_key, False))
- 
-               rValue = {}
-               cache = _LibraryCache()
-               providers = self.listProviders()
- 
-               # Iterate over all obj_keys and their providers.
-               for obj_key, sonames in providers.items():
-                       arch, _needed, path, _soname, objs = self._obj_properties[obj_key]
-                       path = path.union(self._defpath)
-                       # Iterate over each needed soname and the set of library paths that
-                       # fulfill the soname to determine if the dependency is broken.
-                       for soname, libraries in sonames.items():
-                               # validLibraries is used to store libraries, which satisfy soname,
-                               # so if no valid libraries are found, the soname is not satisfied
-                               # for obj_key.  If unsatisfied, objects associated with obj_key
-                               # must be emerged.
-                               validLibraries = set()
-                               # It could be the case that the library to satisfy the soname is
-                               # not in the obj's runpath, but a symlink to the library is (eg
-                               # libnvidia-tls.so.1 in nvidia-drivers).  Also, since LinkageMap
-                               # does not catalog symlinks, broken or missing symlinks may go
-                               # unnoticed.  As a result of these cases, check that a file with
-                               # the same name as the soname exists in obj's runpath.
-                               # XXX If we catalog symlinks in LinkageMap, this could be improved.
-                               for directory in path:
-                                       cachedArch, cachedSoname, cachedKey, cachedExists = \
-                                                       cache.get(os.path.join(directory, soname))
-                                       # Check that this library provides the needed soname.  Doing
-                                       # this, however, will cause consumers of libraries missing
-                                       # sonames to be unnecessarily emerged. (eg libmix.so)
-                                       if cachedSoname == soname and cachedArch == arch:
-                                               validLibraries.add(cachedKey)
-                                               if debug and cachedKey not in \
-                                                               set(map(self._obj_key_cache.get, libraries)):
-                                                       # XXX This is most often due to soname symlinks not in
-                                                       # a library's directory.  We could catalog symlinks in
-                                                       # LinkageMap to avoid checking for this edge case here.
-                                                       writemsg(
-                                                               _("Found provider outside of findProviders:") + \
-                                                               (" %s -> %s %s\n" % (os.path.join(directory, soname),
-                                                               self._obj_properties[cachedKey][4], libraries)),
-                                                               noiselevel=-1)
-                                               # A valid library has been found, so there is no need to
-                                               # continue.
-                                               break
-                                       if debug and cachedArch == arch and \
-                                                       cachedKey in self._obj_properties:
-                                               writemsg((_("Broken symlink or missing/bad soname: " + \
-                                                       "%(dir_soname)s -> %(cachedKey)s " + \
-                                                       "with soname %(cachedSoname)s but expecting %(soname)s") % \
-                                                       {"dir_soname":os.path.join(directory, soname),
-                                                       "cachedKey": self._obj_properties[cachedKey],
-                                                       "cachedSoname": cachedSoname, "soname":soname}) + "\n",
-                                                       noiselevel=-1)
-                               # This conditional checks if there are no libraries to satisfy the
-                               # soname (empty set).
-                               if not validLibraries:
-                                       for obj in objs:
-                                               rValue.setdefault(obj, set()).add(soname)
-                                       # If no valid libraries have been found by this point, then
-                                       # there are no files named with the soname within obj's runpath,
-                                       # but if there are libraries (from the providers mapping), it is
-                                       # likely that soname symlinks or the actual libraries are
-                                       # missing or broken.  Thus those libraries are added to rValue
-                                       # in order to emerge corrupt library packages.
-                                       for lib in libraries:
-                                               rValue.setdefault(lib, set()).add(soname)
-                                               if debug:
-                                                       if not os.path.isfile(lib):
-                                                               writemsg(_("Missing library:") + " %s\n" % (lib,),
-                                                                       noiselevel=-1)
-                                                       else:
-                                                               writemsg(_("Possibly missing symlink:") + \
-                                                                       "%s\n" % (os.path.join(os.path.dirname(lib), soname)),
-                                                                       noiselevel=-1)
-               return rValue
- 
-       def listProviders(self):
-               """
-               Find the providers for all object keys in LinkageMap.
- 
-               @rtype: dict (example:
-                       {(123L, 456L): {'libbar.so': set(['/lib/libbar.so.1.5'])}})
-               @return: The return value is an object key -> providers mapping, where
-                       providers is a mapping of soname -> set-of-library-paths returned
-                       from the findProviders method.
- 
-               """
-               rValue = {}
-               if not self._libs:
-                       self.rebuild()
-               # Iterate over all object keys within LinkageMap.
-               for obj_key in self._obj_properties:
-                       rValue.setdefault(obj_key, self.findProviders(obj_key))
-               return rValue
- 
-       def isMasterLink(self, obj):
-               """
-               Determine whether an object is a master link.
- 
-               @param obj: absolute path to an object
-               @type obj: string (example: '/usr/bin/foo')
-               @rtype: Boolean
-               @return:
-                       1. True if obj is a master link
-                       2. False if obj is not a master link
- 
-               """
-               os = _os_merge
-               basename = os.path.basename(obj)
-               obj_key = self._obj_key(obj)
-               if obj_key not in self._obj_properties:
-                       raise KeyError("%s (%s) not in object list" % (obj_key, obj))
-               soname = self._obj_properties[obj_key][3]
-               return (len(basename) < len(soname))
- 
-       def listLibraryObjects(self):
-               """
-               Return a list of library objects.
- 
-               Known limitation: library objects lacking an soname are not included.
- 
-               @rtype: list of strings
-               @return: list of paths to all providers
- 
-               """
-               rValue = []
-               if not self._libs:
-                       self.rebuild()
-               for arch_map in self._libs.values():
-                       for soname_map in arch_map.values():
-                               for obj_key in soname_map.providers:
-                                       rValue.extend(self._obj_properties[obj_key][4])
-               return rValue
- 
-       def getSoname(self, obj):
-               """
-               Return the soname associated with an object.
- 
-               @param obj: absolute path to an object
-               @type obj: string (example: '/usr/bin/bar')
-               @rtype: string
-               @return: soname as a string
- 
-               """
-               if not self._libs:
-                       self.rebuild()
-               if isinstance(obj, self._ObjectKey):
-                       obj_key = obj
-                       if obj_key not in self._obj_properties:
-                               raise KeyError("%s not in object list" % obj_key)
-                       return self._obj_properties[obj_key][3]
-               if obj not in self._obj_key_cache:
-                       raise KeyError("%s not in object list" % obj)
-               return self._obj_properties[self._obj_key_cache[obj]][3]
- 
-       def findProviders(self, obj):
-               """
-               Find providers for an object or object key.
- 
-               This method may be called with a key from _obj_properties.
- 
-               In some cases, not all valid libraries are returned.  This may occur when
-               an soname symlink referencing a library is in an object's runpath while
-               the actual library is not.  We should consider cataloging symlinks within
-               LinkageMap as this would avoid those cases and would be a better model of
-               library dependencies (since the dynamic linker actually searches for
-               files named with the soname in the runpaths).
- 
-               @param obj: absolute path to an object or a key from _obj_properties
-               @type obj: string (example: '/usr/bin/bar') or _ObjectKey
-               @rtype: dict (example: {'libbar.so': set(['/lib/libbar.so.1.5'])})
-               @return: The return value is a soname -> set-of-library-paths, where
-               set-of-library-paths satisfy soname.
- 
-               """
- 
-               os = _os_merge
- 
-               rValue = {}
- 
-               if not self._libs:
-                       self.rebuild()
- 
-               # Determine the obj_key from the arguments.
-               if isinstance(obj, self._ObjectKey):
-                       obj_key = obj
-                       if obj_key not in self._obj_properties:
-                               raise KeyError("%s not in object list" % obj_key)
-               else:
-                       obj_key = self._obj_key(obj)
-                       if obj_key not in self._obj_properties:
-                               raise KeyError("%s (%s) not in object list" % (obj_key, obj))
- 
-               arch, needed, path, _soname, _objs = self._obj_properties[obj_key]
-               path_keys = set(self._path_key(x) for x in path.union(self._defpath))
-               for soname in needed:
-                       rValue[soname] = set()
-                       if arch not in self._libs or soname not in self._libs[arch]:
-                               continue
-                       # For each potential provider of the soname, add it to rValue if it
-                       # resides in the obj's runpath.
-                       for provider_key in self._libs[arch][soname].providers:
-                               providers = self._obj_properties[provider_key][4]
-                               for provider in providers:
-                                       if self._path_key(os.path.dirname(provider)) in path_keys:
-                                               rValue[soname].add(provider)
-               return rValue
- 
-       def findConsumers(self, obj):
-               """
-               Find consumers of an object or object key.
- 
-               This method may be called with a key from _obj_properties.  If this
-               method is going to be called with an object key, to avoid not catching
-               shadowed libraries, do not pass new _ObjectKey instances to this method.
-               Instead pass the obj as a string.
- 
-               In some cases, not all consumers are returned.  This may occur when
-               an soname symlink referencing a library is in an object's runpath while
-               the actual library is not. For example, this problem is noticeable for
-               binutils since it's libraries are added to the path via symlinks that
-               are gemerated in the /usr/$CHOST/lib/ directory by binutils-config.
-               Failure to recognize consumers of these symlinks makes preserve-libs
-               fail to preserve binutils libs that are needed by these unrecognized
-               consumers.
- 
-               Note that library consumption via dlopen (common for kde plugins) is
-               currently undetected. However, it is possible to use the
-               corresponding libtool archive (*.la) files to detect such consumers
-               (revdep-rebuild is able to detect them).
- 
-               @param obj: absolute path to an object or a key from _obj_properties
-               @type obj: string (example: '/usr/bin/bar') or _ObjectKey
-               @rtype: set of strings (example: set(['/bin/foo', '/usr/bin/bar']))
-               @return: The return value is a soname -> set-of-library-paths, where
-               set-of-library-paths satisfy soname.
- 
-               """
- 
-               os = _os_merge
- 
-               rValue = set()
- 
-               if not self._libs:
-                       self.rebuild()
- 
-               # Determine the obj_key and the set of objects matching the arguments.
-               if isinstance(obj, self._ObjectKey):
-                       obj_key = obj
-                       if obj_key not in self._obj_properties:
-                               raise KeyError("%s not in object list" % obj_key)
-                       objs = self._obj_properties[obj_key][4]
-               else:
-                       objs = set([obj])
-                       obj_key = self._obj_key(obj)
-                       if obj_key not in self._obj_properties:
-                               raise KeyError("%s (%s) not in object list" % (obj_key, obj))
- 
-               # If there is another version of this lib with the
-               # same soname and the master link points to that
-               # other version, this lib will be shadowed and won't
-               # have any consumers.
-               if not isinstance(obj, self._ObjectKey):
-                       soname = self._obj_properties[obj_key][3]
-                       master_link = os.path.join(self._root,
-                               os.path.dirname(obj).lstrip(os.path.sep), soname)
-                       try:
-                               master_st = os.stat(master_link)
-                               obj_st = os.stat(obj)
-                       except OSError:
-                               pass
-                       else:
-                               if (obj_st.st_dev, obj_st.st_ino) != \
-                                       (master_st.st_dev, master_st.st_ino):
-                                       return set()
- 
-               # Determine the directory(ies) from the set of objects.
-               objs_dir_keys = set(self._path_key(os.path.dirname(x)) for x in objs)
-               defpath_keys = set(self._path_key(x) for x in self._defpath)
- 
-               arch, _needed, _path, soname, _objs = self._obj_properties[obj_key]
-               if arch in self._libs and soname in self._libs[arch]:
-                       # For each potential consumer, add it to rValue if an object from the
-                       # arguments resides in the consumer's runpath.
-                       for consumer_key in self._libs[arch][soname].consumers:
-                               _arch, _needed, path, _soname, consumer_objs = \
-                                               self._obj_properties[consumer_key]
-                               path_keys = defpath_keys.union(self._path_key(x) for x in path)
-                               if objs_dir_keys.intersection(path_keys):
-                                       rValue.update(consumer_objs)
-               return rValue
 +
 +class LinkageMapMachO(object):
 +
 +      """Models dynamic linker dependencies."""
 +
 +      _needed_aux_key = "NEEDED.MACHO.3"
 +      _installname_map_class = slot_dict_class(
 +              ("consumers", "providers"), prefix="")
 +
 +      def __init__(self, vardbapi):
 +              self._dbapi = vardbapi
 +              self._root = self._dbapi.root
 +              self._libs = {}
 +              self._obj_properties = {}
 +              self._obj_key_cache = {}
 +              self._path_key_cache = {}
 +
 +      def _clear_cache(self):
 +              self._libs.clear()
 +              self._obj_properties.clear()
 +              self._obj_key_cache.clear()
 +              self._path_key_cache.clear()
 +
 +      def _path_key(self, path):
 +              key = self._path_key_cache.get(path)
 +              if key is None:
 +                      key = self._ObjectKey(path, self._root)
 +                      self._path_key_cache[path] = key
 +              return key
 +
 +      def _obj_key(self, path):
 +              key = self._obj_key_cache.get(path)
 +              if key is None:
 +                      key = self._ObjectKey(path, self._root)
 +                      self._obj_key_cache[path] = key
 +              return key
 +
 +      class _ObjectKey(object):
 +
 +              """Helper class used as _obj_properties keys for objects."""
 +
 +              __slots__ = ("__weakref__", "_key")
 +
 +              def __init__(self, obj, root):
 +                      """
 +                      This takes a path to an object.
 +
 +                      @param object: path to a file
 +                      @type object: string (example: '/usr/bin/bar')
 +
 +                      """
 +                      self._key = self._generate_object_key(obj, root)
 +
 +              def __hash__(self):
 +                      return hash(self._key)
 +
 +              def __eq__(self, other):
 +                      return self._key == other._key
 +
 +              def _generate_object_key(self, obj, root):
 +                      """
 +                      Generate object key for a given object.
 +
 +                      @param object: path to a file
 +                      @type object: string (example: '/usr/bin/bar')
 +                      @rtype: 2-tuple of types (long, int) if object exists. string if
 +                              object does not exist.
 +                      @return:
 +                              1. 2-tuple of object's inode and device from a stat call, if object
 +                                      exists.
 +                              2. realpath of object if object does not exist.
 +
 +                      """
 +
 +                      os = _os_merge
 +
 +                      try:
 +                              _unicode_encode(obj,
 +                                      encoding=_encodings['merge'], errors='strict')
 +                      except UnicodeEncodeError:
 +                              # The package appears to have been merged with a 
 +                              # different value of sys.getfilesystemencoding(),
 +                              # so fall back to utf_8 if appropriate.
 +                              try:
 +                                      _unicode_encode(obj,
 +                                              encoding=_encodings['fs'], errors='strict')
 +                              except UnicodeEncodeError:
 +                                      pass
 +                              else:
 +                                      os = portage.os
 +
 +                      abs_path = os.path.join(root, obj.lstrip(os.path.sep))
 +                      try:
 +                              object_stat = os.stat(abs_path)
 +                      except OSError:
 +                              # Use the realpath as the key if the file does not exists on the
 +                              # filesystem.
 +                              return os.path.realpath(abs_path)
 +                      # Return a tuple of the device and inode.
 +                      return (object_stat.st_dev, object_stat.st_ino)
 +
 +              def file_exists(self):
 +                      """
 +                      Determine if the file for this key exists on the filesystem.
 +
 +                      @rtype: Boolean
 +                      @return:
 +                              1. True if the file exists.
 +                              2. False if the file does not exist or is a broken symlink.
 +
 +                      """
 +                      return isinstance(self._key, tuple)
 +
 +      class _LibGraphNode(_ObjectKey):
 +              __slots__ = ("alt_paths",)
 +
 +              def __init__(self, obj, root):
 +                      LinkageMapMachO._ObjectKey.__init__(self, obj, root)
 +                      self.alt_paths = set()
 +
 +              def __str__(self):
 +                      return str(sorted(self.alt_paths))
 +
 +      def rebuild(self, exclude_pkgs=None, include_file=None):
 +              """
 +              Raises CommandNotFound if there are preserved libs
 +              and the scanmacho binary is not available.
 +              """
 +              root = self._root
 +              root_len = len(root) - 1
 +              self._clear_cache()
 +              libs = self._libs
 +              obj_key_cache = self._obj_key_cache
 +              obj_properties = self._obj_properties
 +
 +              lines = []
 +
 +              # Data from include_file is processed first so that it
 +              # overrides any data from previously installed files.
 +              if include_file is not None:
 +                      lines += grabfile(include_file)
 +
 +              aux_keys = [self._needed_aux_key]
 +              for cpv in self._dbapi.cpv_all():
 +                      if exclude_pkgs is not None and cpv in exclude_pkgs:
 +                              continue
 +                      lines += self._dbapi.aux_get(cpv, aux_keys)[0].split('\n')
 +              # Cache NEEDED.* files avoid doing excessive IO for every rebuild.
 +              self._dbapi.flush_cache()
 +
 +              # have to call scanmacho for preserved libs here as they aren't 
 +              # registered in NEEDED.MACHO.3 files
 +              plibs = set()
 +              if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
 +                      args = [EPREFIX+"/usr/bin/scanmacho", "-qF", "%a;%F;%S;%n"]
 +                      for items in self._dbapi.plib_registry.getPreservedLibs().values():
 +                              plibs.update(items)
 +                              args.extend(os.path.join(root, x.lstrip("." + os.sep)) \
 +                                              for x in items)
 +                      try:
 +                              proc = subprocess.Popen(args, stdout=subprocess.PIPE)
 +                      except EnvironmentError, e:
 +                              if e.errno != errno.ENOENT:
 +                                      raise
 +                              raise CommandNotFound(args[0])
 +                      else:
 +                              for l in proc.stdout:
 +                                      if not isinstance(l, unicode):
 +                                              l = unicode(l, encoding='utf_8', errors='replace')
 +                                      l = l.rstrip("\n")
 +                                      if not l:
 +                                              continue
 +                                      fields = l.split(";")
 +                                      if len(fields) < 4:
 +                                              writemsg_level("\nWrong number of fields " + \
 +                                                      "returned from scanmacho: %s\n\n" % (l,),
 +                                                      level=logging.ERROR, noiselevel=-1)
 +                                              continue
 +                                      fields[1] = fields[1][root_len:]
 +                                      plibs.discard(fields[1])
 +                                      lines.append(";".join(fields))
 +                              proc.wait()
 +
 +              if plibs:
 +                      # Preserved libraries that did not appear in the scanmacho
 +                      # output.  This is known to happen with statically linked
 +                      # libraries.  Generate dummy lines for these, so we can
 +                      # assume that every preserved library has an entry in
 +                      # self._obj_properties.  This is important in order to
 +                      # prevent findConsumers from raising an unwanted KeyError.
 +                      for x in plibs:
 +                              lines.append(";".join(['', x, '', '']))
 +
 +              for l in lines:
 +                      l = l.rstrip("\n")
 +                      if not l:
 +                              continue
 +                      fields = l.split(";")
 +                      if len(fields) < 4:
 +                              writemsg_level("\nWrong number of fields " + \
 +                                      "in %s: %s\n\n" % (self._needed_aux_key, l),
 +                                      level=logging.ERROR, noiselevel=-1)
 +                              continue
 +                      arch = fields[0]
 +                      obj = fields[1]
 +                      install_name = os.path.normpath(fields[2])
 +                      needed = filter(None, fields[3].split(","))
 +
 +                      obj_key = self._obj_key(obj)
 +                      indexed = True
 +                      myprops = obj_properties.get(obj_key)
 +                      if myprops is None:
 +                              indexed = False
 +                              myprops = (arch, needed, install_name, set())
 +                              obj_properties[obj_key] = myprops
 +                      # All object paths are added into the obj_properties tuple.
 +                      myprops[3].add(obj)
 +
 +                      # Don't index the same file more that once since only one
 +                      # set of data can be correct and therefore mixing data
 +                      # may corrupt the index (include_file overrides previously
 +                      # installed).
 +                      if indexed:
 +                              continue
 +
 +                      arch_map = libs.get(arch)
 +                      if arch_map is None:
 +                              arch_map = {}
 +                              libs[arch] = arch_map
 +                      if install_name:
 +                              installname_map = arch_map.get(install_name)
 +                              if installname_map is None:
 +                                      installname_map = self._installname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[install_name] = installname_map
 +                              installname_map.providers.add(obj_key)
 +                      for needed_installname in needed:
 +                              installname_map = arch_map.get(needed_installname)
 +                              if installname_map is None:
 +                                      installname_map = self._installname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[needed_installname] = installname_map
 +                              installname_map.consumers.add(obj_key)
 +              
 +      def listBrokenBinaries(self, debug=False):
 +              """
 +              Find binaries and their needed install_names, which have no providers.
 +
 +              @param debug: Boolean to enable debug output
 +              @type debug: Boolean
 +              @rtype: dict (example: {'/usr/bin/foo': set(['/usr/lib/libbar.dylib'])})
 +              @return: The return value is an object -> set-of-install_names
 +                      mapping, where object is a broken binary and the set
 +                      consists of install_names needed by object that have no
 +                      corresponding libraries to fulfill the dependency.
 +
 +              """
 +              class _LibraryCache(object):
 +
 +                      """
 +                      Caches properties associated with paths.
 +
 +                      The purpose of this class is to prevent multiple instances of
 +                      _ObjectKey for the same paths.
 +
 +                      """
 +
 +                      def __init__(cache_self):
 +                              cache_self.cache = {}
 +
 +                      def get(cache_self, obj):
 +                              """
 +                              Caches and returns properties associated with an object.
 +
 +                              @param obj: absolute path (can be symlink)
 +                              @type obj: string (example: '/usr/lib/libfoo.dylib')
 +                              @rtype: 4-tuple with types
 +                                      (string or None, string or None, 2-tuple, Boolean)
 +                              @return: 4-tuple with the following components:
 +                                      1. arch as a string or None if it does not exist,
 +                                      2. soname as a string or None if it does not exist,
 +                                      3. obj_key as 2-tuple,
 +                                      4. Boolean representing whether the object exists.
 +                                      (example: ('libfoo.1.dylib', (123L, 456L), True))
 +
 +                              """
 +                              if obj in cache_self.cache:
 +                                      return cache_self.cache[obj]
 +                              else:
 +                                      obj_key = self._obj_key(obj)
 +                                      # Check that the library exists on the filesystem.
 +                                      if obj_key.file_exists():
 +                                              # Get the install_name from LinkageMapMachO._obj_properties if
 +                                              # it exists. Otherwise, None.
 +                                              arch, _, install_name, _ = \
 +                                                              self._obj_properties.get(obj_key, (None,)*4)
 +                                              return cache_self.cache.setdefault(obj, \
 +                                                              (arch, install_name, obj_key, True))
 +                                      else:
 +                                              return cache_self.cache.setdefault(obj, \
 +                                                              (None, None, obj_key, False))
 +
 +              rValue = {}
 +              cache = _LibraryCache()
 +              providers = self.listProviders()
 +
 +              # Iterate over all obj_keys and their providers.
 +              for obj_key, install_names in providers.items():
 +                      arch, _, _, objs = self._obj_properties[obj_key]
 +                      # Iterate over each needed install_name and the set of
 +                      # library paths that fulfill the install_name to determine
 +                      # if the dependency is broken.
 +                      for install_name, libraries in install_names.items():
 +                              # validLibraries is used to store libraries, which
 +                              # satisfy install_name, so if no valid libraries are
 +                              # found, the install_name is not satisfied for obj_key.
 +                              # If unsatisfied, objects associated with obj_key must
 +                              # be emerged.
 +                              validLibrary = set() # for compat with LinkageMap
 +                              cachedArch, cachedInstallname, cachedKey, cachedExists = \
 +                                              cache.get(install_name)
 +                              # Check that the this library provides the needed soname.  Doing
 +                              # this, however, will cause consumers of libraries missing
 +                              # sonames to be unnecessarily emerged. (eg libmix.so)
 +                              if cachedInstallname == install_name and cachedArch == arch:
 +                                      validLibrary.add(cachedKey)
 +                                      if debug and cachedKey not in \
 +                                                      set(map(self._obj_key_cache.get, libraries)):
 +                                              # XXX This is most often due to soname symlinks not in
 +                                              # a library's directory.  We could catalog symlinks in
 +                                              # LinkageMap to avoid checking for this edge case here.
 +                                              print(_("Found provider outside of findProviders:"), \
 +                                                              install_name, "->", cachedRealpath)
 +                              if debug and cachedArch == arch and \
 +                                              cachedKey in self._obj_properties:
 +                                      print(_("Broken symlink or missing/bad install_name:"), \
 +                                                      install_name, '->', cachedRealpath, \
 +                                                      "with install_name", cachedInstallname, "but expecting", install_name)
 +                              # This conditional checks if there are no libraries to
 +                              # satisfy the install_name (empty set).
 +                              if not validLibrary:
 +                                      for obj in objs:
 +                                              rValue.setdefault(obj, set()).add(install_name)
 +                                      # If no valid libraries have been found by this
 +                                      # point, then the install_name does not exist in the
 +                                      # filesystem, but if there are libraries (from the
 +                                      # providers mapping), it is likely that soname
 +                                      # symlinks or the actual libraries are missing or
 +                                      # broken.  Thus those libraries are added to rValue
 +                                      # in order to emerge corrupt library packages.
 +                                      for lib in libraries:
 +                                              rValue.setdefault(lib, set()).add(install_name)
 +                                              if debug:
 +                                                      if not os.path.isfile(lib):
 +                                                              print(_("Missing library:"), lib)
 +                                                      else:
 +                                                              print(_("Possibly missing symlink:"), \
 +                                                                              install_name)
 +              return rValue
 +
 +      def listProviders(self):
 +              """
 +              Find the providers for all object keys in LinkageMap.
 +
 +              @rtype: dict (example:
 +                      {(123L, 456L): {'libbar.dylib': set(['/lib/libbar.1.5.dylib'])}})
 +              @return: The return value is an object -> providers mapping, where
 +                      providers is a mapping of install_name ->
 +                      set-of-library-paths returned from the findProviders method.
 +
 +              """
 +              rValue = {}
 +              if not self._libs:
 +                      self.rebuild()
 +              # Iterate over all binaries within LinkageMapMachO.
 +              for obj_key in self._obj_properties:
 +                      rValue.setdefault(obj_key, self.findProviders(obj_key))
 +              return rValue
 +
 +      def isMasterLink(self, obj):
 +              """
 +              Determine whether an object is a master link.
 +
 +              @param obj: absolute path to an object
 +              @type obj: string (example: '/usr/bin/foo')
 +              @rtype: Boolean
 +              @return:
 +                      1. True if obj is a master link
 +                      2. False if obj is not a master link
 +
 +              """
 +              basename = os.path.basename(obj)
 +              obj_key = self._obj_key(obj)
 +              if obj_key not in self._obj_properties:
 +                      raise KeyError("%s (%s) not in object list" % (obj_key, obj))
 +              install_name = self._obj_properties[obj_key][2]
 +              return (len(basename) < len(os.path.basename(install_name)))
 +
 +      def listLibraryObjects(self):
 +              """
 +              Return a list of library objects.
 +
 +              Known limitation: library objects lacking an soname are not included.
 +
 +              @rtype: list of strings
 +              @return: list of paths to all providers
 +
 +              """
 +              rValue = []
 +              if not self._libs:
 +                      self.rebuild()
 +              for arch_map in self._libs.itervalues():
 +                      for soname_map in arch_map.itervalues():
 +                              for obj_key in soname_map.providers:
 +                                      rValue.extend(self._obj_properties[obj_key][3])
 +              return rValue
 +      
 +      def getSoname(self, obj):
 +              """
 +              Return the soname associated with an object.
 +
 +              @param obj: absolute path to an object
 +              @type obj: string (example: '/usr/bin/bar')
 +              @rtype: string
 +              @return: soname as a string
 +
 +              """
 +              if not self._libs:
 +                      self.rebuild()
 +              if isinstance(obj, self._ObjectKey):
 +                      obj_key = obj
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s not in object list" % obj_key)
 +                      return self._obj_properties[obj_key][2]
 +              if obj not in self._obj_key_cache:
 +                      raise KeyError("%s not in object list" % obj)
 +              return self._obj_properties[self._obj_key_cache[obj]][2]
 +
 +      def findProviders(self, obj):
 +              """
 +              Find providers for an object or object key.
 +
 +              This method may be called with a key from _obj_properties.
 +
 +              In some cases, not all valid libraries are returned.  This may occur when
 +              an soname symlink referencing a library is in an object's runpath while
 +              the actual library is not.  We should consider cataloging symlinks within
 +              LinkageMap as this would avoid those cases and would be a better model of
 +              library dependencies (since the dynamic linker actually searches for
 +              files named with the soname in the runpaths).
 +
 +              @param obj: absolute path to an object or a key from _obj_properties
 +              @type obj: string (example: '/usr/bin/bar') or _ObjectKey
 +              @rtype: dict (example: {'libbar.dylib': set(['/lib/libbar.1.5.dylib'])})
 +              @return: The return value is a install_name -> set-of-library-paths, where
 +              set-of-library-paths satisfy install_name.
 +
 +              """
 +              rValue = {}
 +
 +              if not self._libs:
 +                      self.rebuild()
 +
 +              # Determine the obj_key from the arguments.
 +              if isinstance(obj, self._ObjectKey):
 +                      obj_key = obj
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s not in object list" % obj_key)
 +              else:
 +                      obj_key = self._obj_key(obj)
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s (%s) not in object list" % (obj_key, obj))
 +
 +              arch, needed, install_name, _ = self._obj_properties[obj_key]
 +              for install_name in needed:
 +                      rValue[install_name] = set()
 +                      if arch not in self._libs or install_name not in self._libs[arch]:
 +                              continue
 +                      # For each potential provider of the install_name, add it to
 +                      # rValue if it exists.  (Should be one)
 +                      for provider_key in self._libs[arch][install_name].providers:
 +                              providers = self._obj_properties[provider_key][3]
 +                              for provider in providers:
 +                                      if os.path.exists(provider):
 +                                              rValue[install_name].add(provider)
 +              return rValue
 +
 +      def findConsumers(self, obj):
 +              """
 +              Find consumers of an object or object key.
 +
 +              This method may be called with a key from _obj_properties.  If this
 +              method is going to be called with an object key, to avoid not catching
 +              shadowed libraries, do not pass new _ObjectKey instances to this method.
 +              Instead pass the obj as a string.
 +
 +              In some cases, not all consumers are returned.  This may occur when
 +              an soname symlink referencing a library is in an object's runpath while
 +              the actual library is not. For example, this problem is noticeable for
 +              binutils since it's libraries are added to the path via symlinks that
 +              are gemerated in the /usr/$CHOST/lib/ directory by binutils-config.
 +              Failure to recognize consumers of these symlinks makes preserve-libs
 +              fail to preserve binutils libs that are needed by these unrecognized
 +              consumers.
 +
 +              @param obj: absolute path to an object or a key from _obj_properties
 +              @type obj: string (example: '/usr/bin/bar') or _ObjectKey
 +              @rtype: set of strings (example: set(['/bin/foo', '/usr/bin/bar']))
 +              @return: The return value is a install_name -> set-of-library-paths, where
 +              set-of-library-paths satisfy install_name.
 +
 +              """
 +              rValue = set()
 +
 +              if not self._libs:
 +                      self.rebuild()
 +
 +              # Determine the obj_key and the set of objects matching the arguments.
 +              if isinstance(obj, self._ObjectKey):
 +                      obj_key = obj
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s not in object list" % obj_key)
 +                      objs = self._obj_properties[obj_key][3]
 +              else:
 +                      objs = set([obj])
 +                      obj_key = self._obj_key(obj)
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s (%s) not in object list" % (obj_key, obj))
 +
 +              # If there is another version of this lib with the
 +              # same soname and the master link points to that
 +              # other version, this lib will be shadowed and won't
 +              # have any consumers.
 +              if not isinstance(obj, self._ObjectKey):
 +                      install_name = self._obj_properties[obj_key][2]
 +                      master_link = os.path.join(self._root,
 +                                      install_name.lstrip(os.path.sep))
 +                      try:
 +                              master_st = os.stat(master_link)
 +                              obj_st = os.stat(obj)
 +                      except OSError:
 +                              pass
 +                      else:
 +                              if (obj_st.st_dev, obj_st.st_ino) != \
 +                                      (master_st.st_dev, master_st.st_ino):
 +                                      return set()
 +
 +              arch, _, install_name, _ = self._obj_properties[obj_key]
 +              if arch in self._libs and install_name in self._libs[arch]:
 +                      # For each potential consumer, add it to rValue if an object from the
 +                      # arguments resides in the consumer's runpath.
 +                      for consumer_key in self._libs[arch][install_name].consumers:
 +                              _, _, _, consumer_objs = \
 +                                              self._obj_properties[consumer_key]
 +                              rValue.update(consumer_objs)
 +              return rValue
 +
 +class LinkageMapPeCoff(LinkageMap):
 +
 +      """Models dynamic linker dependencies."""
 +
 +      # NEEDED.PECOFF.1 has effectively the _same_ format as NEEDED.ELF.2,
 +      # but we keep up the relation "scanelf" -> "NEEDED.ELF", "readpecoff" ->
 +      # "NEEDED.PECOFF", "scanmacho" -> "NEEDED.MACHO", etc. others will follow.
 +      _needed_aux_key = "NEEDED.PECOFF.1"
 +
 +      class _ObjectKey(LinkageMap._ObjectKey):
 +
 +              """Helper class used as _obj_properties keys for objects."""
 +
 +              def _generate_object_key(self, obj, root):
 +                      """
 +                      Generate object key for a given object. This is different from the
 +                      Linux implementation, since some systems (e.g. interix) don't have
 +                      "inodes", thus the inode field is always zero, or a random value,
 +                      making it inappropriate for identifying a file... :)
 +
 +                      @param object: path to a file
 +                      @type object: string (example: '/usr/bin/bar')
 +                      @rtype: 2-tuple of types (bool, string)
 +                      @return:
 +                              2-tuple of boolean indicating existance, and absolut path
 +                      """
 +                      abs_path = os.path.join(root, obj.lstrip(os.sep))
 +                      try:
 +                              object_stat = os.stat(abs_path)
 +                      except OSError:
 +                              return (False, os.path.realpath(abs_path))
 +                      # On Interix, the inode field may always be zero, since the
 +                      # filesystem (NTFS) has no inodes ...
 +                      return (True, os.path.realpath(abs_path))
 +
 +              def file_exists(self):
 +                      """
 +                      Determine if the file for this key exists on the filesystem.
 +
 +                      @rtype: Boolean
 +                      @return:
 +                              1. True if the file exists.
 +                              2. False if the file does not exist or is a broken symlink.
 +
 +                      """
 +                      return self._key[0]
 +
 +      class _LibGraphNode(_ObjectKey):
 +              __slots__ = ("alt_paths",)
 +
 +              def __init__(self, obj, root):
 +                      LinkageMapPeCoff._ObjectKey.__init__(self, obj, root)
 +                      self.alt_paths = set()
 +
 +              def __str__(self):
 +                      return str(sorted(self.alt_paths))
 +
 +      def rebuild(self, exclude_pkgs=None, include_file=None):
 +              """
 +              Raises CommandNotFound if there are preserved libs
 +              and the readpecoff binary is not available.
 +              """
 +              root = self._root
 +              root_len = len(root) - 1
 +              self._clear_cache()
 +              self._defpath.update(getlibpaths(self._root))
 +              libs = self._libs
 +              obj_key_cache = self._obj_key_cache
 +              obj_properties = self._obj_properties
 +
 +              lines = []
 +
 +              # Data from include_file is processed first so that it
 +              # overrides any data from previously installed files.
 +              if include_file is not None:
 +                      lines += grabfile(include_file)
 +
 +              aux_keys = [self._needed_aux_key]
 +              for cpv in self._dbapi.cpv_all():
 +                      if exclude_pkgs is not None and cpv in exclude_pkgs:
 +                              continue
 +                      lines += self._dbapi.aux_get(cpv, aux_keys)[0].split('\n')
 +              # Cache NEEDED.* files avoid doing excessive IO for every rebuild.
 +              self._dbapi.flush_cache()
 +
 +              # have to call readpecoff for preserved libs here as they aren't 
 +              # registered in NEEDED.PECOFF.1 files
 +              if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
 +                      args = ["readpecoff", self._dbapi.settings.get('CHOST')]
 +                      for items in self._dbapi.plib_registry.getPreservedLibs().values():
 +                              args.extend(os.path.join(root, x.lstrip("." + os.path.sep)) \
 +                                      for x in items)
 +                      try:
 +                              proc = subprocess.Popen(args, stdout=subprocess.PIPE)
 +                      except EnvironmentError, e:
 +                              if e.errno != errno.ENOENT:
 +                                      raise
 +                              raise CommandNotFound(args[0])
 +                      else:
 +                              for l in proc.stdout:
 +                                      if not isinstance(l, unicode):
 +                                              l = unicode(l, encoding='utf_8', errors='replace')
 +                                      l = l.lstrip().rstrip()
 +                                      if not l:
 +                                              continue
 +                                      lines.append(l)
 +                              proc.wait()
 +
 +              for l in lines:
 +                      l = l.rstrip("\n")
 +                      if not l:
 +                              continue
 +                      fields = l.split(";")
 +                      if len(fields) < 5:
 +                              writemsg_level(_("\nWrong number of fields " \
 +                                      "in %s: %s\n\n") % (self._needed_aux_key, l),
 +                                      level=logging.ERROR, noiselevel=-1)
 +                              continue
 +                      arch = fields[0]
 +                      obj = fields[1]
 +                      soname = fields[2]
 +                      path = set([normalize_path(x) \
 +                              for x in filter(None, fields[3].replace(
 +                              "${ORIGIN}", os.path.dirname(obj)).replace(
 +                              "$ORIGIN", os.path.dirname(obj)).split(":"))])
 +                      needed = filter(None, fields[4].split(","))
 +
 +                      obj_key = self._obj_key(obj)
 +                      indexed = True
 +                      myprops = obj_properties.get(obj_key)
 +                      if myprops is None:
 +                              indexed = False
 +                              myprops = (arch, needed, path, soname, set())
 +                              obj_properties[obj_key] = myprops
 +                      # All object paths are added into the obj_properties tuple.
 +                      myprops[4].add(obj)
 +
 +                      # Don't index the same file more that once since only one
 +                      # set of data can be correct and therefore mixing data
 +                      # may corrupt the index (include_file overrides previously
 +                      # installed).
 +                      if indexed:
 +                              continue
 +
 +                      arch_map = libs.get(arch)
 +                      if arch_map is None:
 +                              arch_map = {}
 +                              libs[arch] = arch_map
 +                      if soname:
 +                              soname_map = arch_map.get(soname)
 +                              if soname_map is None:
 +                                      soname_map = self._soname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[soname] = soname_map
 +                              soname_map.providers.add(obj_key)
 +                      for needed_soname in needed:
 +                              soname_map = arch_map.get(needed_soname)
 +                              if soname_map is None:
 +                                      soname_map = self._soname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[needed_soname] = soname_map
 +                              soname_map.consumers.add(obj_key)
 +
 +class LinkageMapXCoff(LinkageMap):
 +
 +      """Models dynamic linker dependencies."""
 +
 +      _needed_aux_key = "NEEDED.XCOFF.1"
 +
 +      class _ObjectKey(LinkageMap._ObjectKey):
 +
 +              def __init__(self, obj, root):
 +                      LinkageMap._ObjectKey.__init__(self, obj, root)
 +
 +              def _generate_object_key(self, obj, root):
 +                      """
 +                      Generate object key for a given object.
 +
 +                      @param object: path to a file
 +                      @type object: string (example: '/usr/bin/bar')
 +                      @rtype: 2-tuple of types (long, int) if object exists. string if
 +                              object does not exist.
 +                      @return:
 +                              1. 2-tuple of object's inode and device from a stat call, if object
 +                                      exists.
 +                              2. realpath of object if object does not exist.
 +
 +                      """
 +
 +                      os = _os_merge
 +
 +                      try:
 +                              _unicode_encode(obj,
 +                                      encoding=_encodings['merge'], errors='strict')
 +                      except UnicodeEncodeError:
 +                              # The package appears to have been merged with a 
 +                              # different value of sys.getfilesystemencoding(),
 +                              # so fall back to utf_8 if appropriate.
 +                              try:
 +                                      _unicode_encode(obj,
 +                                              encoding=_encodings['fs'], errors='strict')
 +                              except UnicodeEncodeError:
 +                                      pass
 +                              else:
 +                                      os = portage.os
 +
 +                      abs_path = os.path.join(root, obj.lstrip(os.sep))
 +                      try:
 +                              object_stat = os.stat(abs_path)
 +                      except OSError:
 +                              # Use the realpath as the key if the file does not exists on the
 +                              # filesystem.
 +                              return os.path.realpath(abs_path)
 +                      # Return a tuple of the device and inode, as well as the basename,
 +                      # because of hardlinks the device and inode might be identical.
 +                      return (object_stat.st_dev, object_stat.st_ino, os.path.basename(abs_path.rstrip(os.sep)))
 +
 +              def file_exists(self):
 +                      """
 +                      Determine if the file for this key exists on the filesystem.
 +
 +                      @rtype: Boolean
 +                      @return:
 +                              1. True if the file exists.
 +                              2. False if the file does not exist or is a broken symlink.
 +
 +                      """
 +                      return isinstance(self._key, tuple)
 +
 +      class _LibGraphNode(_ObjectKey):
 +              __slots__ = ("alt_paths",)
 +
 +              def __init__(self, obj, root):
 +                      LinkageMapXCoff._ObjectKey.__init__(self, obj, root)
 +                      self.alt_paths = set()
 +
 +              def __str__(self):
 +                      return str(sorted(self.alt_paths))
 +
 +      def rebuild(self, exclude_pkgs=None, include_file=None):
 +              """
 +              Raises CommandNotFound if there are preserved libs
 +              and the scanelf binary is not available.
 +              """
 +
 +              os = _os_merge
 +              root = self._root
 +              root_len = len(root) - 1
 +              self._clear_cache()
 +              self._defpath.update(getlibpaths(self._root))
 +              libs = self._libs
 +              obj_key_cache = self._obj_key_cache
 +              obj_properties = self._obj_properties
 +
 +              lines = []
 +
 +              # Data from include_file is processed first so that it
 +              # overrides any data from previously installed files.
 +              if include_file is not None:
 +                      lines += grabfile(include_file)
 +
 +              aux_keys = [self._needed_aux_key]
 +              for cpv in self._dbapi.cpv_all():
 +                      if exclude_pkgs is not None and cpv in exclude_pkgs:
 +                              continue
 +                      lines += self._dbapi.aux_get(cpv, aux_keys)[0].split('\n')
 +              # Cache NEEDED.* files avoid doing excessive IO for every rebuild.
 +              self._dbapi.flush_cache()
 +
 +              # have to call scanelf for preserved libs here as they aren't 
 +              # registered in NEEDED.XCOFF.1 files
 +              plibs = set()
 +              if self._dbapi.plib_registry and self._dbapi.plib_registry.getPreservedLibs():
 +                      for items in self._dbapi.plib_registry.getPreservedLibs().values():
 +                              plibs.update(items)
 +                              for x in items:
 +                                      args = [BASH_BINARY, "-c", ':'
 +                                              + '; member="' + x + '"'
 +                                              + '; archive=${member}'
 +                                              + '; if [[ ${member##*/} == .*"["*"]" ]]'
 +                                              + '; then member=${member%/.*}/${member##*/.}'
 +                                                       + '; archive=${member%[*}'
 +                                              + '; fi'
 +                                              + '; member=${member#${archive}}'
 +                                              + '; [[ -r ${archive} ]] || chmod a+r "${archive}"'
 +                                              + '; eval $(aixdll-query "${archive}${member}" FILE MEMBER FLAGS FORMAT RUNPATH DEPLIBS)'
 +                                              + '; [[ -n ${member} ]] && needed=${FILE##*/} || needed='
 +                                              + '; for deplib in ${DEPLIBS}'
 +                                              + '; do eval deplib=${deplib}'
 +                                                 + '; if [[ ${deplib} != "." && ${deplib} != ".." ]]'
 +                                                 + '; then needed="${needed}${needed:+,}${deplib}"'
 +                                                 + '; fi'
 +                                              + '; done'
 +                                              + '; [[ -n ${MEMBER} ]] && MEMBER="[${MEMBER}]"'
 +                                              + '; [[ " ${FLAGS} " == *" SHROBJ "* ]] && soname=${FILE##*/}${MEMBER} || soname='
 +                                              + '; echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}}${MEMBER};${soname};${RUNPATH};${needed}"'
 +                                              + '; [[ -z ${member} && -n ${MEMBER} ]] && echo "${FORMAT##* }${FORMAT%%-*};${FILE#${ROOT%/}};${FILE##*/};;"'
 +                                      ]
 +                                      try:
 +                                              proc = subprocess.Popen(args, stdout=subprocess.PIPE)
 +                                      except EnvironmentError as e:
 +                                              if e.errno != errno.ENOENT:
 +                                                      raise
 +                                              raise CommandNotFound("aixdll-query via " + argv[0])
 +                                      else:
 +                                              for l in proc.stdout:
 +                                                      try:
 +                                                              l = _unicode_decode(l,
 +                                                                      encoding=_encodings['content'], errors='strict')
 +                                                      except UnicodeDecodeError:
 +                                                              l = _unicode_decode(l,
 +                                                                      encoding=_encodings['content'], errors='replace')
 +                                                              writemsg_level(_("\nError decoding characters " \
 +                                                                      "returned from aixdll-query: %s\n\n") % (l,),
 +                                                                      level=logging.ERROR, noiselevel=-1)
 +                                                      l = l.rstrip("\n")
 +                                                      if not l:
 +                                                              continue
 +                                                      fields = l.split(";")
 +                                                      if len(fields) < 5:
 +                                                              writemsg_level(_("\nWrong number of fields " \
 +                                                                      "returned from aixdll-query: %s\n\n") % (l,),
 +                                                                      level=logging.ERROR, noiselevel=-1)
 +                                                              continue
 +                                                      fields[1] = fields[1][root_len:]
 +                                                      plibs.discard(fields[1])
 +                                                      lines.append(";".join(fields))
 +                                              proc.wait()
 +
 +              if plibs:
 +                      # Preserved libraries that did not appear in the bash
 +                      # aixdll-query code output.  This is known to happen with
 +                      # statically linked libraries.  Generate dummy lines for
 +                      # these, so we can assume that every preserved library has
 +                      # an entry in self._obj_properties.  This is important in
 +                      # order to prevent findConsumers from raising an unwanted
 +                      # KeyError.
 +                      for x in plibs:
 +                              lines.append(";".join(['', x, '', '', '']))
 +
 +              for l in lines:
 +                      l = l.rstrip("\n")
 +                      if not l:
 +                              continue
 +                      fields = l.split(";")
 +                      if len(fields) < 5:
 +                              writemsg_level(_("\nWrong number of fields " \
 +                                      "in %s: %s\n\n") % (self._needed_aux_key, l),
 +                                      level=logging.ERROR, noiselevel=-1)
 +                              continue
 +                      arch = fields[0]
 +
 +                      def as_contentmember(obj):
 +                              if obj.endswith("]"):
 +                                      if obj.find("/") >= 0:
 +                                              return obj[:obj.rfind("/")] + "/." + obj[obj.rfind("/")+1:]
 +                                      return "." + obj
 +                              return obj
 +
 +                      obj = as_contentmember(fields[1])
 +                      soname = as_contentmember(fields[2])
 +                      path = set([normalize_path(x) \
 +                              for x in filter(None, fields[3].replace(
 +                              "${ORIGIN}", os.path.dirname(obj)).replace(
 +                              "$ORIGIN", os.path.dirname(obj)).split(":"))])
 +                      needed = [as_contentmember(x) for x in fields[4].split(",") if x]
 +
 +                      obj_key = self._obj_key(obj)
 +                      indexed = True
 +                      myprops = obj_properties.get(obj_key)
 +                      if myprops is None:
 +                              indexed = False
 +                              myprops = (arch, needed, path, soname, set())
 +                              obj_properties[obj_key] = myprops
 +                      # All object paths are added into the obj_properties tuple.
 +                      myprops[4].add(obj)
 +
 +                      # Don't index the same file more that once since only one
 +                      # set of data can be correct and therefore mixing data
 +                      # may corrupt the index (include_file overrides previously
 +                      # installed).
 +                      if indexed:
 +                              continue
 +
 +                      arch_map = libs.get(arch)
 +                      if arch_map is None:
 +                              arch_map = {}
 +                              libs[arch] = arch_map
 +                      if soname:
 +                              soname_map = arch_map.get(soname)
 +                              if soname_map is None:
 +                                      soname_map = self._soname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[soname] = soname_map
 +                              soname_map.providers.add(obj_key)
 +                      for needed_soname in needed:
 +                              soname_map = arch_map.get(needed_soname)
 +                              if soname_map is None:
 +                                      soname_map = self._soname_map_class(
 +                                              providers=set(), consumers=set())
 +                                      arch_map[needed_soname] = soname_map
 +                              soname_map.consumers.add(obj_key)
 +
 +      def getSoname(self, obj):
 +              """
 +              Return the soname associated with an object.
 +
 +              @param obj: absolute path to an object
 +              @type obj: string (example: '/usr/bin/bar')
 +              @rtype: string
 +              @return: soname as a string
 +
 +              """
 +              if not self._libs:
 +                      self.rebuild()
 +              if isinstance(obj, self._ObjectKey):
 +                      obj_key = obj
 +                      if obj_key not in self._obj_properties:
 +                              raise KeyError("%s not in object list" % obj_key)
 +                      return self._obj_properties[obj_key][3]
 +              if obj not in self._obj_key_cache:
 +                      raise KeyError("%s not in object list" % obj)
 +              return self._obj_properties[self._obj_key_cache[obj]][3]
 +
  class vardbapi(dbapi):
  
        _excluded_dirs = ["CVS", "lost+found"]
                self._counter_path = os.path.join(self._eroot,
                        CACHE_PATH, "counter")
  
-               try:
-                       self.plib_registry = PreservedLibsRegistry(self._eroot,
-                               os.path.join(self._eroot, PRIVATE_PATH, "preserved_libs_registry"))
-               except PermissionDenied:
-                       # apparently this user isn't allowed to access PRIVATE_PATH
-                       self.plib_registry = None
- 
-               chost = self.settings.get('CHOST')
-               if not chost:
-                       chost = 'lunix?' # this happens when profiles are not available
-               if chost.find('darwin') >= 0:
-                       self.linkmap = LinkageMapMachO(self)
-               elif chost.find('interix') >= 0 or chost.find('winnt') >= 0:
-                       self.linkmap = LinkageMapPeCoff(self)
-               elif chost.find('aix') >= 0:
-                       self.linkmap = LinkageMapXCoff(self)
-               else:
-                       self.linkmap = LinkageMap(self)
+               self._plib_registry = None
+               if _ENABLE_PRESERVE_LIBS:
+                       try:
+                               self._plib_registry = PreservedLibsRegistry(self._eroot,
+                                       os.path.join(self._eroot, PRIVATE_PATH,
+                                       "preserved_libs_registry"))
+                       except PermissionDenied:
+                               # apparently this user isn't allowed to access PRIVATE_PATH
+                               pass
+ 
+               self._linkmap = None
+               if _ENABLE_DYN_LINK_MAP:
 -                      self._linkmap = LinkageMap(self)
++                      chost = self.settings.get('CHOST')
++                      if not chost:
++                              chost = 'lunix?' # this happens when profiles are not available
++                      if chost.find('darwin') >= 0:
++                              self.linkmap = LinkageMapMachO(self)
++                      elif chost.find('interix') >= 0 or chost.find('winnt') >= 0:
++                              self.linkmap = LinkageMapPeCoff(self)
++                      elif chost.find('aix') >= 0:
++                              self.linkmap = LinkageMapXCoff(self)
++                      else:
++                              self.linkmap = LinkageMap(self)
                self._owners = self._owners_db(self)
  
        def getpath(self, mykey, filename=None):
Simple merge
Simple merge
index 83f4c1b78d53b44cac9646847c3997daa274f184,443a735eb8101167ce31dc499ca38352a5adea3c..e5eaf921a757d77e43c9c5827a2c55fcffe205cc
@@@ -21,13 -22,13 +22,13 @@@ import portag
  portage.proxy.lazyimport.lazyimport(globals(),
        'portage.data:portage_gid',
  )
- from portage import bsd_chflags, eapi_is_supported, \
+ from portage import bsd_chflags, \
        load_mod, os, selinux, _encodings, _unicode_encode, _unicode_decode
- from portage.const import CACHE_PATH, CUSTOM_PROFILE_PATH, \
-       DEPCACHE_PATH, GLOBAL_CONFIG_PATH, INCREMENTALS, MAKE_CONF_FILE, \
+ from portage.const import CACHE_PATH, \
+       DEPCACHE_PATH, INCREMENTALS, MAKE_CONF_FILE, \
        MODULES_FILE_PATH, PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, \
-       PRIVATE_PATH, PROFILE_PATH, SUPPORTED_FEATURES, USER_CONFIG_PATH, \
+       PRIVATE_PATH, PROFILE_PATH, USER_CONFIG_PATH, \
 -      USER_VIRTUALS_FILE
 +      USER_VIRTUALS_FILE, EPREFIX, EPREFIX_LSTRIP, BPREFIX
  from portage.dbapi import dbapi
  from portage.dbapi.porttree import portdbapi
  from portage.dbapi.vartree import vartree
index cc6b4e98f055407594053490cb72b3872ec9fda2,06cb90801d3acae92db8077c0b7c3f6d852b60d7..3d87e49149cc45561ae4a75f1715b9161795b067
@@@ -28,8 -28,7 +28,8 @@@ from portage import OrderedDict, os, se
        _shell_quote, _unicode_encode
  from portage.checksum import perform_md5, verify_all
  from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, \
-       EBUILD_SH_BINARY, GLOBAL_CONFIG_PATH
+       GLOBAL_CONFIG_PATH
 +from portage.const import rootgid
  from portage.data import portage_gid, portage_uid, secpass, userpriv_groups
  from portage.exception import FileNotFound, OperationNotPermitted, \
        PermissionDenied, PortageException, TryAgain
Simple merge
Simple merge