Merged from trunk 3641:4674
authorFabian Groffen <grobian@gentoo.org>
Sat, 14 Oct 2006 07:12:03 +0000 (07:12 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 14 Oct 2006 07:12:03 +0000 (07:12 -0000)
vimdiff is nice, but still it's a lot of work with these changes...

svn path=/main/branches/prefix/; revision=4681

22 files changed:
bin/dispatch-conf
bin/dojar [deleted file]
bin/doman
bin/dosed
bin/ebuild
bin/ebuild.sh
bin/emaint
bin/emerge
bin/emerge-webrsync
bin/env-update
bin/etc-update
bin/isolated-functions.sh
bin/md5check.py
bin/misc-functions.sh
bin/pkgmerge [deleted file]
bin/pkgmerge.new [deleted file]
bin/portageq
bin/prepman
bin/prepstrip
bin/quickpkg
bin/regenworld
bin/repoman

index a2370de9419da43343927c8d6421179faa8d1897..6f9c0209b15394aec713613354748b2f0e820ef0 100755 (executable)
 
 from stat import *
 from random import *
-import os, shutil, sys, string, re, commands, atexit
+import atexit, commands, os, re, shutil, stat, string, sys
 sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
 
 import portage, dispatch_conf
 
-FIND_EXTANT_CONFIGS  = "find %s/ -iname '._cfg????_*' | sed -e 's://:/:g'"
+FIND_EXTANT_CONFIGS  = "find '%s' %s -iname '._cfg????_%s'"
 DIFF_CONTENTS        = 'diff -Nu %s %s'
 DIFF_CVS_INTERP      = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "# .Header:.*"'
 DIFF_WSCOMMENTS      = 'diff -Nu %s %s | grep "^[+-][^+-]" | grep -v "^[-+]#" | grep -v "^[-+][:space:]*$"'
@@ -78,10 +78,18 @@ class dispatch:
         #
 
         for path in config_paths.split ():
-            if not os.path.exists (path):
+            path = portage.normalize_path(path)
+            try:
+                mymode = os.lstat(path).st_mode
+            except OSError:
                 continue
+            basename = "*"
+            find_opts = ""
+            if not stat.S_ISDIR(mymode):
+                path, basename = os.path.split(path)
+                find_opts = "-maxdepth 1"
 
-            confs += self.massage (os.popen (FIND_EXTANT_CONFIGS % (path,)).readlines ())
+            confs += self.massage(os.popen(FIND_EXTANT_CONFIGS % (path, find_opts, basename)).readlines())
 
         if self.options['use-rcs'] == 'yes' and ((os.system( "which rcs >/dev/null 2>&1" ) == 256)
                                                  or (os.system( "which ci >/dev/null 2>&1" ) == 256)
diff --git a/bin/dojar b/bin/dojar
deleted file mode 100755 (executable)
index 1a462d6..0000000
--- a/bin/dojar
+++ /dev/null
@@ -1,54 +0,0 @@
-#!@BASH@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/dojar,v 1.8 2004/10/04 13:56:50 vapier Exp $
-# Author Karl Trygve Kalleberg <karltk@gentoo.org>
-
-#
-# Typical usage:
-#  dojar foo.jar bar.jar
-#   - installs foo.jar and bar.jar into /usr/share/${PN}/lib, and adds them 
-#     both to /usr/share/${PN}/classpath.env
-#
-# Detailed usage
-#  dojar <list-of-jars>
-#   - installs <list-of-jars> into /usr/share/${PN}/lib and adds each to
-#     /usr/share/${PN}/classpath.env. 
-# 
-# The classpath.env file is currently merely a convenience for the user as
-# it allows him to:
-# export CLASSPATH=${CLASSPATH}:`cat /usr/share/foo/classpath.env`
-#
-# For many packages that set FOO_HOME, placing the jar files into
-# lib will allow the user to set FOO_HOME=/usr/share/foo and have the
-# scripts work as expected.
-#
-# Possibly a jarinto will be needed in the future.
-#
-
-if [ -z "$JARDESTTREE" ] ; then
-       JARDESTTREE="lib"
-fi
-
-jarroot="${DESTTREE}/share/${PN}/"
-jardest="${DESTTREE}/share/${PN}/${JARDESTTREE}/"
-pf="${D}${jarroot}/package.env"
-
-dodir "${jardest}"
-
-for i in $* ; do
-       bn="$(basename $i)"
-
-       if [ -f "$pf" ] ; then
-               oldcp=`grep "CLASSPATH=" "$pf" | sed "s/CLASSPATH=//"`
-               grep -v "CLASSPATH=" "$pf" > "${pf}.new"
-               echo "CLASSPATH=${oldcp}:${jardest}${bn}" >> "${pf}.new"
-               mv "${pf}.new" "$pf"
-       else
-               echo "DESCRIPTION=\"${DESCRIPTION}\"" > "$pf"
-               echo "CLASSPATH=${jardest}${bn}" >> "$pf"
-       fi
-
-       cp "$i" "${D}${jardest}/"
-       chmod 0444 "${D}${jardest}/${bn}"
-done
index 410a67fb3bdb34928b73ce4009175da53877600e..dafcb6201b328b53ccdee90f92ff8d3002fb2bab 100755 (executable)
--- a/bin/doman
+++ b/bin/doman
@@ -17,7 +17,7 @@ for x in "$@" ; do
                i18n=${x:6}/
                continue
        fi
-       if [[ ${x} == ".keep" ]] ; then
+       if [[ ${x:0:6} == ".keep_" ]] ; then
                continue
        fi
 
index e606844aef4b5f30ff9758ff880a8fc8f61159c7..637939b2c54f1a03fbc61daa72379463e58b6352 100755 (executable)
--- a/bin/dosed
+++ b/bin/dosed
@@ -7,7 +7,7 @@ mysed="s:${D}::g"
 
 for x in "$@" ; do
        y="${D}${x}"
-       if [ -a "${y}" ] ; then
+       if [ -e "${y}" ] ; then
                if [ -f "${y}" ] ; then
                        mysrc="${T}/${y##*/}"
                        cp "${y}" "${mysrc}"
index f5be32ab4520c7c9aba806216944af2328e24284..5d7f2def836fd1c58687f52749ab0f013c9739b9 100755 (executable)
@@ -12,9 +12,9 @@ if len(sys.argv) <= 2:
        sys.exit(1)
 
 
-(opts, pargs) = getopt.getopt(sys.argv[1:], '', ['debug'])
+opts, pargs = getopt.getopt(sys.argv[1:], '', ['debug', 'force'])
 debug = ("--debug",'') in opts
-
+force = ("--force",'') in opts
 
 if "merge" in pargs:
        print "Disabling noauto in features... merge disables it. (qmerge doesn't)"
@@ -66,7 +66,7 @@ else:
                overlay = "/".join(ebuild_split[:-2])
                os.environ["PORTDIR_OVERLAY"] = os.environ.get("PORTDIR_OVERLAY","") + " " + overlay
                print "Appending %s to PORTDIR_OVERLAY..." % overlay
-
+               portage.close_portdbapi_caches()
                reload(portage)
                portage_ebuild = portage.portdb.findname(cpv)
 
@@ -79,10 +79,33 @@ if len(pargs) > 1 and "config" in pargs:
        print "config must be called on it's own, not combined with any other phase"
        sys.exit(1)
 
+def discard_digests(myebuild, mysettings, mydbapi):
+       """Discard all distfiles digests for the given ebuild.  This is useful when
+       upstream has changed the identity of the distfiles and the user would
+       otherwise have to manually remove the Manifest and files/digest-* files in
+       order to ensure correct results."""
+       pkgdir = os.path.dirname(myebuild)
+       fetchlist_dict = portage.FetchlistDict(pkgdir, mysettings, mydbapi)
+       cat, pkg = pkgdir.split(os.sep)[-2:]
+       cpv = cat + "/" + os.path.basename(myebuild)[:-7]
+       from portage_manifest import Manifest
+       mf = Manifest(pkgdir, mysettings["DISTDIR"],
+               fetchlist_dict=fetchlist_dict)
+       mf.create(requiredDistfiles=None,
+               assumeDistHashesSometimes=True, assumeDistHashesAlways=True)
+       distfiles = fetchlist_dict[cpv]
+       for myfile in distfiles:
+               try:
+                       del mf.fhashdict["DIST"][myfile]
+               except KeyError:
+                       pass
+       mf.write()
 
 for arg in pargs:
        try:
                tmpsettings = portage.config(clone=portage.settings)
+               if arg == "digest" and force:
+                       discard_digests(ebuild, tmpsettings, portage.portdb)
                a = portage.doebuild(ebuild, arg, portage.root, tmpsettings, debug=debug, cleanup=("noauto" not in portage.features), tree=mytree)
        except KeyboardInterrupt:
                print "Interrupted."
index 59aea576844d62d5a57f578776486376f4d55039..408ce7cdc8939940b4f3c3992625ffe0a55b250c 100755 (executable)
@@ -1,9 +1,14 @@
 #!@BASH@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/ebuild.sh,v 1.201.2.42 2005/08/20 17:24:30 jstubbs Exp $
+# $Id$
 
-export SANDBOX_PREDICT="${SANDBOX_PREDICT}:/proc/self/maps:/dev/console:@PORTAGE_BASE@/pym:/dev/random"
+PORTAGE_BIN_PATH="${PORTAGE_BIN_PATH:-@PORTAGE_BASE@/bin}"
+PORTAGE_PYM_PATH="${PORTAGE_PYM_PATH:-@PORTAGE_BASE@/pym}"
+declare -rx PORTAGE_BIN_PATH PORTAGE_PYM_PATH
+
+SANDBOX_PREDICT="${SANDBOX_PREDICT}:/proc/self/maps:/dev/console:/dev/random"
+export SANDBOX_PREDICT="${SANDBOX_PREDICT}:${PORTAGE_PYM_PATH}:${PORTAGE_DEPCACHEDIR}"
 export SANDBOX_WRITE="${SANDBOX_WRITE}:/dev/shm:/dev/stdout:/dev/stderr:${PORTAGE_TMPDIR}"
 export SANDBOX_READ="${SANDBOX_READ}:/dev/shm:/dev/stdin:${PORTAGE_TMPDIR}"
 
@@ -11,17 +16,17 @@ if [ ! -z "${PORTAGE_GPG_DIR}" ]; then
        SANDBOX_PREDICT="${SANDBOX_PREDICT}:${PORTAGE_GPG_DIR}"
 fi
 
+declare -rx EBUILD_PHASE
+
 if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "nofetch" ]; then
        if [ -f "${T}/environment" ]; then
                source "${T}/environment" &>/dev/null
        fi
 fi
 
-if [ -n "$#" ]; then
-       ARGS="${*}"
-fi
+EBUILD_SH_ARGS="$*"
 
-declare -rx EBUILD_PHASE="$*"
+shift $#
 
 # Prevent aliases from causing portage to act inappropriately.
 # Make sure it's before everything so we don't mess aliases that follow.
@@ -40,26 +45,11 @@ alias restore_IFS='if [ "${old_IFS:-unset}" != "unset" ]; then IFS="${old_IFS}";
 
 OCC="$CC"
 OCXX="$CXX"
-source ${EPREFIX}/etc/profile.env &>/dev/null
-if [ -f "${PORTAGE_BASHRC}" ]; then
-       # If $- contains x, then tracing has already enabled elsewhere for some
-       # reason.  We preserve it's state so as not to interfere.
-       if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then
-               source "${PORTAGE_BASHRC}"
-       else
-               set -x
-               source "${PORTAGE_BASHRC}"
-               set +x
-       fi
-fi
-[ ! -z "$OCC" ] && export CC="$OCC"
-[ ! -z "$OCXX" ] && export CXX="$OCXX"
 
 export PATH="${DEFAULT_PATH}:${ROOTPATH}"
 [ ! -z "$PREROOTPATH" ] && export PATH="${PREROOTPATH%%:}:$PATH"
 
-source @PORTAGE_BASE@/bin/isolated-functions.sh &>/dev/null
-
+source "@PORTAGE_BASE@"/bin/isolated-functions.sh &>/dev/null
 
 case "${NOCOLOR:-false}" in
        yes|true)
@@ -111,6 +101,20 @@ for dir in ${PROFILE_PATHS}; do
 done
 restore_IFS
 
+if [ -f "${PORTAGE_BASHRC}" ]; then
+       # If $- contains x, then tracing has already enabled elsewhere for some
+       # reason.  We preserve it's state so as not to interfere.
+       if [ "$PORTAGE_DEBUG" != "1" ] || [ "${-/x/}" != "$-" ]; then
+               source "${PORTAGE_BASHRC}"
+       else
+               set -x
+               source "${PORTAGE_BASHRC}"
+               set +x
+       fi
+fi
+
+[ ! -z "$OCC" ] && export CC="$OCC"
+[ ! -z "$OCXX" ] && export CXX="$OCXX"
 
 esyslog() {
        # Custom version of esyslog() to take care of the "Red Star" bug.
@@ -118,7 +122,6 @@ esyslog() {
        return 0
 }
 
-
 use() {
        useq ${1}
 }
@@ -143,10 +146,10 @@ useq() {
 
        # Make sure we have this USE flag in IUSE
        if ! hasq "${u}" ${IUSE} ${E_IUSE} && ! hasq "${u}" ${PORTAGE_ARCHLIST} selinux; then
-               echo "QA Notice: USE Flag '${u}' not in IUSE for ${CATEGORY}/${PF}" >&2
+               vecho "QA Notice: USE Flag '${u}' not in IUSE for ${CATEGORY}/${PF}" >&2
        fi
 
-       if [[ " ${USE} " == *" ${u} "* ]] ; then
+       if hasq ${u} ${USE} ; then
                return ${found}
        else
                return $((!found))
@@ -159,7 +162,7 @@ has_version() {
        fi
        # return shell-true/shell-false if exists.
        # Takes single depend-type atoms.
-       if @PORTAGE_BASE@/bin/portageq 'has_version' "${ROOT}" "$1"; then
+       if "@PORTAGE_BASE@"/bin/portageq 'has_version' "${ROOT}" "$1"; then
                return 0
        else
                return 1
@@ -170,7 +173,7 @@ portageq() {
        if [ "${EBUILD_PHASE}" == "depend" ]; then
                die "portageq calls are not allowed in the global scope"
        fi
-       @PORTAGE_BASE@/bin/portageq "$@"
+       "@PORTAGE_BASE@"/bin/portageq "$@"
 }
 
 
@@ -185,7 +188,7 @@ best_version() {
        fi
        # returns the best/most-current match.
        # Takes single depend-type atoms.
-       @PORTAGE_BASE@/bin/portageq 'best_version' "${ROOT}" "$1"
+       "@PORTAGE_BASE@"/bin/portageq 'best_version' "${ROOT}" "$1"
 }
 
 with_bindir() {
@@ -454,10 +457,10 @@ export DESTTREE=/usr
 export INSDESTTREE=""
 export EXEDESTTREE=""
 export DOCDESTTREE=""
-export INSOPTIONS="-m 0644"
-export EXEOPTIONS="-m 0755"
-export LIBOPTIONS="-m 0644"
-export DIROPTIONS="-m 0755"
+export INSOPTIONS="-m0644"
+export EXEOPTIONS="-m0755"
+export LIBOPTIONS="-m0644"
+export DIROPTIONS="-m0755"
 export MOPREFIX=${PN}
 
 check_KV() {
@@ -480,10 +483,10 @@ keepdir() {
        local x
        if [ "$1" == "-R" ] || [ "$1" == "-r" ]; then
                shift
-               find "$@" -type d -printf "${D}/%p/.keep\n" | tr "\n" "\0" | $XARGS -0 -n100 touch || die "Failed to recursive create .keep files"
+               find "$@" -type d -printf "${D}/%p/.keep_${CATEGORY}_${PN}-${SLOT}\n" | tr "\n" "\0" | $XARGS -0 -n100 touch || die "Failed to recursive create .keep files"
        else
                for x in "$@"; do
-                       touch "${D}/${x}/.keep" || die "Failed to create .keep in ${D}/${x}"
+                       touch "${D}/${x}/.keep_${CATEGORY}_${PN}-${SLOT}" || die "Failed to create .keep in ${D}/${x}"
                done
        fi
 }
@@ -503,7 +506,7 @@ unpack() {
        [ -z "$*" ] && die "Nothing passed to the 'unpack' command"
 
        for x in "$@"; do
-               echo ">>> Unpacking ${x} to ${PWD}"
+               vecho ">>> Unpacking ${x} to ${PWD}"
                y=${x%.*}
                y=${y##*.}
 
@@ -513,6 +516,8 @@ unpack() {
                else
                        srcdir="${DISTDIR}/"
                fi
+               [[ ${x} == ${DISTDIR}* ]] && \
+                       die "Arguments to unpack() should not begin with \${DISTDIR}."
                [ ! -s "${srcdir}${x}" ] && die "$myfail"
 
                myfail="failure unpacking ${x}"
@@ -537,7 +542,7 @@ unpack() {
                                        gzip -dc "${srcdir}${x}" > ${x%.*} || die "$myfail"
                                fi
                                ;;
-                       bz2)
+                       bz2|bz)
                                if [ "${y}" == "tar" ]; then
                                        bzip2 -dc "${srcdir}${x}" | tar xf - ${tarvars}
                                        assert "$myfail"
@@ -545,8 +550,16 @@ unpack() {
                                        bzip2 -dc "${srcdir}${x}" > ${x%.*} || die "$myfail"
                                fi
                                ;;
+                       7Z|7z)
+                               local my_output
+                               my_output="$(7z x -y "${srcdir}/${x}")"
+                               if [ $? -ne 0 ]; then
+                                       echo "${my_output}" >&2
+                                       die "$myfail"
+                               fi
+                               ;;
                        RAR|rar)
-                               unrar x -idq "${srcdir}/${x}" || die "$myfail"
+                               unrar x -idq -o+ "${srcdir}/${x}" || die "$myfail"
                                ;;
                        LHa|LHA|lha|lzh)
                                lha xqf "${srcdir}/${x}" || die "$myfail"
@@ -555,17 +568,19 @@ unpack() {
                                ar x "${srcdir}/${x}" || die "$myfail"
                                ;;
                        *)
-                               echo "unpack ${x}: file format not recognized. Ignoring."
+                               vecho "unpack ${x}: file format not recognized. Ignoring."
                                ;;
                esac
        done
        chmod -Rf a+rX,u+w,g-w,o-w .
 }
 
-strip_duplicate_slashes () {
-       if [ -n "${1}" ]; then
-               local removed="${1/\/\///}"
-               [ "${removed}" != "${removed/\/\///}" ] && removed=$(strip_duplicate_slashes "${removed}")
+strip_duplicate_slashes() {
+       if [[ -n $1 ]] ; then
+               local removed=$1
+               while [[ ${removed} == *//* ]] ; do
+                       removed=${removed//\/\///}
+               done
                echo ${removed}
        fi
 }
@@ -578,10 +593,10 @@ econf() {
                ECONF_SOURCE="."
        fi
        if [ -x "${ECONF_SOURCE}/configure" ]; then
-               if [ -e ${EPREFIX}/usr/share/gnuconfig/ ]; then
+               if [ -e "${EPREFIX}"/usr/share/gnuconfig/ ]; then
                        for x in $(find "${WORKDIR}" -type f '(' -name config.guess -o -name config.sub ')') ; do
-                               echo " * econf: updating ${x/${WORKDIR}\/} with ${EPREFIX}/usr/share/gnuconfig/${x##*/}"
-                               cp -f ${EPREFIX}/usr/share/gnuconfig/${x##*/} ${x}
+                               vecho " * econf: updating ${x/${WORKDIR}\/} with ${EPREFIX}/usr/share/gnuconfig/${x##*/}"
+                               cp -f "${EPREFIX}"/usr/share/gnuconfig/${x##*/} ${x}
                        done
                fi
 
@@ -617,11 +632,7 @@ econf() {
                        export CONF_PREFIX
                        [ "${CONF_LIBDIR:0:1}" != "/" ] && CONF_LIBDIR="/${CONF_LIBDIR}"
 
-                       CONF_LIBDIR_RESULT="${CONF_PREFIX}${CONF_LIBDIR}"
-                       for x in 1 2 3; do
-                               # The escaping is weird. It will break if you escape the last one.
-                               CONF_LIBDIR_RESULT="${CONF_LIBDIR_RESULT//\/\///}"
-                       done
+                       CONF_LIBDIR_RESULT="$(strip_duplicate_slashes ${CONF_PREFIX}${CONF_LIBDIR})"
 
                        LOCAL_EXTRA_ECONF="--libdir=${CONF_LIBDIR_RESULT} ${LOCAL_EXTRA_ECONF}"
                fi
@@ -651,7 +662,7 @@ econf() {
                        CONFCACHE=
                fi
 
-               echo ${CONFCACHE} ${CONFCACHE_ARG} ${TMP_CONFCACHE_DIR} "${ECONF_SOURCE}/configure" \
+               vecho ${CONFCACHE} ${CONFCACHE_ARG} ${TMP_CONFCACHE_DIR} "${ECONF_SOURCE}/configure" \
                        --prefix=${EPREFIX}/usr \
                        --host=${CHOST} \
                        --mandir=${EPREFIX}/usr/share/man \
@@ -700,22 +711,22 @@ einstall() {
        fi
 
        if [ -f ./[mM]akefile -o -f ./GNUmakefile ] ; then
-               if [ ! -z "${PORTAGE_DEBUG}" ]; then
-                       make -n prefix=${D}/usr \
-                               datadir=${D}/usr/share \
-                               infodir=${D}/usr/share/info \
-                               localstatedir=${D}/var/lib \
-                               mandir=${D}/usr/share/man \
-                               sysconfdir=${D}/etc \
+               if [ "${PORTAGE_DEBUG}" == "1" ]; then
+                       make -n prefix="${D}/usr" \
+                               datadir="${D}/usr/share" \
+                               infodir="${D}/usr/share/info" \
+                               localstatedir="${D}/var/lib" \
+                               mandir="${D}/usr/share/man" \
+                               sysconfdir="${D}/etc" \
                                ${EXTRA_EINSTALL} \
                                "$@" install
                fi
-               make prefix=${D}/usr \
-                       datadir=${D}/usr/share \
-                       infodir=${D}/usr/share/info \
-                       localstatedir=${D}/var/lib \
-                       mandir=${D}/usr/share/man \
-                       sysconfdir=${D}/etc \
+               make prefix="${D}/usr" \
+                       datadir="${D}/usr/share" \
+                       infodir="${D}/usr/share/info" \
+                       localstatedir="${D}/var/lib" \
+                       mandir="${D}/usr/share/man" \
+                       sysconfdir="${D}/etc" \
                        ${EXTRA_EINSTALL} \
                        "$@" install || die "einstall failed"
        else
@@ -732,7 +743,7 @@ pkg_nofetch() {
 
        echo "!!! The following are listed in SRC_URI for ${PN}:"
        local x
-       for x in `echo ${SRC_URI}`; do
+       for x in $(echo ${SRC_URI}); do
                echo "!!!   ${x}"
        done
 }
@@ -751,23 +762,21 @@ src_compile() {
 }
 
 src_test() {
-       addpredict /
        if emake -j1 check -n &> /dev/null; then
-               echo ">>> Test phase [check]: ${CATEGORY}/${PF}"
+               vecho ">>> Test phase [check]: ${CATEGORY}/${PF}"
                if ! emake -j1 check; then
                        hasq test $FEATURES && die "Make check failed. See above for details."
                        hasq test $FEATURES || eerror "Make check failed. See above for details."
                fi
        elif emake -j1 test -n &> /dev/null; then
-               echo ">>> Test phase [test]: ${CATEGORY}/${PF}"
+               vecho ">>> Test phase [test]: ${CATEGORY}/${PF}"
                if ! emake -j1 test; then
                        hasq test $FEATURES && die "Make test failed. See above for details."
                        hasq test $FEATURES || eerror "Make test failed. See above for details."
                fi
        else
-               echo ">>> Test phase [none]: ${CATEGORY}/${PF}"
+               vecho ">>> Test phase [none]: ${CATEGORY}/${PF}"
        fi
-       SANDBOX_PREDICT="${SANDBOX_PREDICT%:/}"
 }
 
 src_install() {
@@ -817,40 +826,40 @@ dyn_unpack() {
                local x
                local checkme
                for x in ${AA}; do
-                       echo ">>> Checking ${x}'s mtime..."
+                       vecho ">>> Checking ${x}'s mtime..."
                        if [ "${PORTAGE_ACTUAL_DISTDIR:-${DISTDIR}}/${x}" -nt "${WORKDIR}" ]; then
-                               echo ">>> ${x} has been updated; recreating WORKDIR..."
+                               vecho ">>> ${x} has been updated; recreating WORKDIR..."
                                newstuff="yes"
                                rm -rf "${WORKDIR}"
                                break
                        fi
                done
                if [ "${EBUILD}" -nt "${WORKDIR}" ]; then
-                       echo ">>> ${EBUILD} has been updated; recreating WORKDIR..."
+                       vecho ">>> ${EBUILD} has been updated; recreating WORKDIR..."
                        newstuff="yes"
                        rm -rf "${WORKDIR}"
                elif [ ! -f "${PORTAGE_BUILDDIR}/.unpacked" ]; then
-                       echo ">>> Not marked as unpacked; recreating WORKDIR..."
+                       vecho ">>> Not marked as unpacked; recreating WORKDIR..."
                        newstuff="yes"
                        rm -rf "${WORKDIR}"
                fi
        fi
        if [ -e "${WORKDIR}" ]; then
                if [ "$newstuff" == "no" ]; then
-                       echo ">>> WORKDIR is up-to-date, keeping..."
+                       vecho ">>> WORKDIR is up-to-date, keeping..."
                        [ "$(type -t post_src_unpack)" == "function" ] && post_src_unpack
                        return 0
                fi
        fi
 
        if [ ! -d "${WORKDIR}" ]; then
-               install -m ${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'"
+               install -m${PORTAGE_WORKDIR_MODE:-0700} -d "${WORKDIR}" || die "Failed to create dir '${WORKDIR}'"
        fi
        cd "${WORKDIR}" || die "Directory change failed: \`cd '${WORKDIR}'\`"
-       echo ">>> Unpacking source..."
+       vecho ">>> Unpacking source..."
        src_unpack
        touch "${PORTAGE_BUILDDIR}/.unpacked" || die "IO Failure -- Failed 'touch .unpacked' in ${PORTAGE_BUILDDIR}"
-       echo ">>> Source unpacked."
+       vecho ">>> Source unpacked."
        cd "${PORTAGE_BUILDDIR}"
 
        [ "$(type -t post_src_unpack)" == "function" ] && post_src_unpack
@@ -864,24 +873,21 @@ dyn_clean() {
                return 1
        fi
 
-       if [ "$USERLAND" == "BSD" ] && type -p chflags &>/dev/null; then
-               chflags -R noschg,nouchg,nosappnd,nouappnd,nosunlnk,nouunlnk \
-                       "${PORTAGE_BUILDDIR}"
-       fi
-
-       if [ "$USERLAND" == "Darwin" ] && type -p chflags &>/dev/null; then
+       if type -p chflags &>/dev/null; then
                chflags -R noschg,nouchg,nosappnd,nouappnd "${PORTAGE_BUILDDIR}"
+               chflags -R nosunlnk,nouunlnk "${PORTAGE_BUILDDIR}" 2>/dev/null
        fi
 
-       rm -rf "${PORTAGE_BUILDDIR}/image"
+       rm -rf "${PORTAGE_BUILDDIR}/image" "${PORTAGE_BUILDDIR}/homedir"
 
        if ! hasq keeptemp $FEATURES; then
                rm -rf "${T}"
        else
-               mv "${T}/environment" "${T}/environment.keeptemp"
+               [ -e "${T}/environment" ] && mv "${T}/environment" "${T}/environment.keeptemp"
        fi
 
        if ! hasq keepwork $FEATURES; then
+               rm -rf "${PORTAGE_BUILDDIR}/.logid"
                rm -rf "${PORTAGE_BUILDDIR}/.unpacked"
                rm -rf "${PORTAGE_BUILDDIR}/.compiled"
                rm -rf "${PORTAGE_BUILDDIR}/.tested"
@@ -944,8 +950,8 @@ docinto() {
                export DOCDESTTREE=""
        else
                export DOCDESTTREE="$1"
-               if [ ! -d "${D}/usr/share/doc/${PF}/${DOCDESTTREE}" ]; then
-                       install -d "${D}/usr/share/doc/${PF}/${DOCDESTTREE}"
+               if [ ! -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}" ]; then
+                       install -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}"
                fi
        fi
 }
@@ -954,7 +960,7 @@ insopts() {
        export INSOPTIONS="$@"
 
        # `install` should never be called with '-s' ...
-       [[ " ${INSOPTIONS} " == *" -s "* ]] && die "Never call insopts() with -s"
+       hasq -s ${INSOPTIONS} && die "Never call insopts() with -s"
 }
 
 diropts() {
@@ -965,14 +971,14 @@ exeopts() {
        export EXEOPTIONS="$@"
 
        # `install` should never be called with '-s' ...
-       [[ " ${EXEOPTIONS} " == *" -s "* ]] && die "Never call exeopts() with -s"
+       hasq -s ${EXEOPTIONS} && die "Never call exeopts() with -s"
 }
 
 libopts() {
        export LIBOPTIONS="$@"
 
        # `install` should never be called with '-s' ...
-       [[ " ${LIBOPTIONS} " == *" -s "* ]] && die "Never call libopts() with -s"
+       hasq -s ${LIBOPTIONS} && die "Never call libopts() with -s"
 }
 
 abort_handler() {
@@ -1033,6 +1039,12 @@ dyn_compile() {
        [ "${DISTCC_DIR-unset}"  == "unset" ] && export DISTCC_DIR="${PORTAGE_TMPDIR}/.distcc"
        [ ! -z "${DISTCC_DIR}" ] && addwrite "${DISTCC_DIR}"
 
+       LIBDIR_VAR="LIBDIR_${ABI}"
+       if [ -z "${PKG_CONFIG_PATH}" -a -n "${ABI}" -a -n "${!LIBDIR_VAR}" ]; then
+               export PKG_CONFIG_PATH="${EPREFIX}/usr/${!LIBDIR_VAR}/pkgconfig"
+       fi
+       unset LIBDIR_VAR
+
        if hasq noauto $FEATURES &>/dev/null && [ ! -f ${PORTAGE_BUILDDIR}/.unpacked ]; then
                echo
                echo "!!! We apparently haven't unpacked... This is probably not what you"
@@ -1056,9 +1068,9 @@ dyn_compile() {
        fi
        cp "${EBUILD}" "build-info/${PF}.ebuild"
 
-       if [ "${PORTAGE_BUILDDIR}/.compiled" -nt "${WORKDIR}" ]; then
-               echo ">>> It appears that ${PN} is already compiled; skipping."
-               echo ">>> (clean to force compilation)"
+       if [[ ${PORTAGE_BUILDDIR}/.compiled -nt ${WORKDIR} ]] ; then
+               vecho ">>> It appears that '${PF}' is already compiled; skipping."
+               vecho ">>> Remove '${PORTAGE_BUILDDIR}/.compiled' to force install."
                trap SIGINT SIGQUIT
                [ "$(type -t post_src_compile)" == "function" ] && post_src_compile
                return
@@ -1073,14 +1085,15 @@ dyn_compile() {
        #some packages use an alternative to $S to build in, cause
        #our libtool to create problematic .la files
        export PWORKDIR="$WORKDIR"
-       echo ">>> Compiling source in ${srcdir} ..."
+       vecho ">>> Compiling source in ${srcdir} ..."
        src_compile
-       echo ">>> Source compiled."
+       vecho ">>> Source compiled."
        #|| abort_compile "fail"
        cd "${PORTAGE_BUILDDIR}"
        touch .compiled
        cd build-info
 
+       set -f
        for f in ASFLAGS CATEGORY CBUILD CC CFLAGS CHOST CTARGET CXX \
                CXXFLAGS DEPEND EXTRA_ECONF EXTRA_EINSTALL EXTRA_MAKE \
                FEATURES INHERITED IUSE LDFLAGS LIBCFLAGS LIBCXXFLAGS \
@@ -1090,14 +1103,13 @@ dyn_compile() {
        done
        echo "${USE}"           > USE
        echo "${EAPI:-0}"       > EAPI
+       set +f
        set                     >  environment
        export -p | sed 's:declare -rx:declare -x:' >> environment
        bzip2 -9 environment
 
        cp "${EBUILD}" "${PF}.ebuild"
-       if [[ " ${FEATURES} " == *" nostrip "* ]] || \
-          [[ " ${RESTRICT} " == *" nostrip "* ]] || \
-          [[ " ${RESTRICT} " == *" strip "* ]]
+       if hasq nostrip ${FEATURES} ${RESTRICT} || hasq strip ${RESTRICT}
        then
                touch DEBUGBUILD
        fi
@@ -1110,7 +1122,7 @@ dyn_compile() {
 dyn_test() {
        [ "$(type -t pre_src_test)" == "function" ] && pre_src_test
        if [ "${PORTAGE_BUILDDIR}/.tested" -nt "${WORKDIR}" ]; then
-               echo ">>> It appears that ${PN} has already been tested; skipping."
+               vecho ">>> It appears that ${PN} has already been tested; skipping."
                [ "$(type -t post_src_test)" == "function" ] && post_src_test
                return
        fi
@@ -1118,13 +1130,15 @@ dyn_test() {
        if [ -d "${S}" ]; then
                cd "${S}"
        fi
-       if hasq test $RESTRICT; then
+       if ! hasq test $FEATURES; then
+               vecho ">>> Test phase [not enabled]: ${CATEGORY}/${PF}"
+       elif hasq test $RESTRICT; then
                ewarn "Skipping make test/check due to ebuild restriction."
-               echo ">>> Test phase [explicitly disabled]: ${CATEGORY}/${PF}"
-       elif ! hasq test $FEATURES; then
-               echo ">>> Test phase [not enabled]: ${CATEGORY}/${PF}"
+               vecho ">>> Test phase [explicitly disabled]: ${CATEGORY}/${PF}"
        else
+               addpredict /
                src_test
+               SANDBOX_PREDICT="${SANDBOX_PREDICT%:/}"
        fi
 
        cd "${PORTAGE_BUILDDIR}"
@@ -1135,6 +1149,13 @@ dyn_test() {
 
 dyn_install() {
        [ -z "$PORTAGE_BUILDDIR" ] && die "${FUNCNAME}: PORTAGE_BUILDDIR is unset"
+       if hasq noauto $FEATURES ; then
+               rm -f "${PORTAGE_BUILDDIR}/.installed"
+       elif [[ ${PORTAGE_BUILDDIR}/.installed -nt ${WORKDIR} ]] ; then
+               vecho ">>> It appears that '${PF}' is already installed; skipping."
+               vecho ">>> Remove '${PORTAGE_BUILDDIR}/.installed' to force install."
+               return 0
+       fi
        trap "abort_install" SIGINT SIGQUIT
        [ "$(type -t pre_src_install)" == "function" ] && pre_src_install
        rm -rf "${PORTAGE_BUILDDIR}/image"
@@ -1142,8 +1163,8 @@ dyn_install() {
        if [ -d "${S}" ]; then
                cd "${S}"
        fi
-       echo
-       echo ">>> Install ${PF} into ${D} category ${CATEGORY}"
+       vecho
+       vecho ">>> Install ${PF} into ${D} category ${CATEGORY}"
        #our custom version of libtool uses $S and $D to fix
        #invalid paths in .la files
        export S D
@@ -1152,8 +1173,8 @@ dyn_install() {
        export PWORKDIR="$WORKDIR"
        src_install
        touch "${PORTAGE_BUILDDIR}/.installed"
-       echo ">>> Completed installing ${PF} into ${D}"
-       echo
+       vecho ">>> Completed installing ${PF} into ${D}"
+       vecho
        cd ${PORTAGE_BUILDDIR}
        [ "$(type -t post_src_install)" == "function" ] && post_src_install
        trap SIGINT SIGQUIT
@@ -1217,9 +1238,7 @@ dyn_help() {
        echo "  c++ flags   : ${CXXFLAGS}"
        echo "  make flags  : ${MAKEOPTS}"
        echo -n "  build mode  : "
-       if [[ " ${FEATURES} " == *" nostrip "* ]] || \
-          [[ " ${RESTRICT} " == *" nostrip "* ]] || \
-          [[ " ${RESTRICT} " == *" strip "* ]]
+       if hasq nostrip ${FEATURES} ${RESTRICT} || hasq strip ${RESTRICT} ;
        then
                echo "debug (large)"
        else
@@ -1303,9 +1322,9 @@ inherit() {
 
                if [ "$EBUILD_PHASE" != "depend" ]; then
                        if ! hasq $ECLASS $INHERITED; then
-                               echo
-                               echo "QA Notice: ECLASS '$ECLASS' inherited illegally in $CATEGORY/$PF" >&2
-                               echo
+                               vecho
+                               vecho "QA Notice: ECLASS '$ECLASS' inherited illegally in $CATEGORY/$PF" >&2
+                               vecho
                        fi
                fi
 
@@ -1321,6 +1340,7 @@ inherit() {
                        done
                fi
                debug-print "inherit: $1 -> $location"
+               [ ! -e "$location" ] && die "${1}.eclass could not be found by inherit()"
 
                #We need to back up the value of DEPEND and RDEPEND to B_DEPEND and B_RDEPEND
                #(if set).. and then restore them after the inherit call.
@@ -1338,8 +1358,7 @@ inherit() {
                #turn on glob expansion
                set +f
 
-               source "$location" || export ERRORMSG="died sourcing $location in inherit()"
-               [ -z "${ERRORMSG}" ] || die "${ERRORMSG}"
+               source "$location" || die "died sourcing $location in inherit()"
 
                #turn off glob expansion
                set -f
@@ -1480,7 +1499,7 @@ remove_path_entry() {
 # === === === === === functions end, main part begins === === === === ===
 # === === === === === === === === === === === === === === === === === ===
 
-if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "setup" ]; then
+if [[ ${EBUILD_SH_ARGS} != "depend" ]] && [[ ${EBUILD_SH_ARGS}  != "clean" ]] && [[ ${EBUILD_SH_ARGS} != "setup" ]]; then
        cd ${PORTAGE_TMPDIR} &> /dev/null
        cd ${BUILD_PREFIX} &> /dev/null
 
@@ -1489,7 +1508,7 @@ if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "setup" ]; then
        fi
 
        if hasq distcc ${FEATURES} &>/dev/null; then
-               if [ -d ${EPREFIX}/usr/lib/distcc/bin ]; then
+               if [ -d "${EPREFIX}"/usr/lib/distcc/bin ]; then
                        #We can enable distributed compile support
                        if [ -z "${PATH/*distcc*/}" ]; then
                                # Remove the other reference.
@@ -1498,8 +1517,12 @@ if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "setup" ]; then
                        export PATH="${EPREFIX}/usr/lib/distcc/bin:${PATH}"
                        [ ! -z "${DISTCC_LOG}" ] && addwrite "$(dirname ${DISTCC_LOG})"
                elif which distcc &>/dev/null; then
-                       export CC="distcc $CC"
-                       export CXX="distcc $CXX"
+                       if ! hasq distcc $CC; then
+                               export CC="distcc $CC"
+                       fi
+                       if ! hasq distcc $CXX; then
+                               export CXX="distcc $CXX"
+                       fi
                fi
        fi
 
@@ -1510,9 +1533,9 @@ if [ "$*" != "depend" ] && [ "$*" != "clean" ] && [ "$*" != "setup" ]; then
                        remove_path_entry "ccache"
                fi
 
-               if [ -d ${EPREFIX}/usr/lib/ccache/bin ]; then
+               if [ -d "${EPREFIX}"/usr/lib/ccache/bin ]; then
                        export PATH="${EPREFIX}/usr/lib/ccache/bin:${PATH}"
-               elif [ -d ${EPREFIX}/usr/bin/ccache ]; then
+               elif [ -d "${EPREFIX}"/usr/bin/ccache ]; then
                        export PATH="${EPREFIX}/usr/bin/ccache:${PATH}"
                fi
 
@@ -1548,34 +1571,34 @@ for x in T P PN PV PVR PR CATEGORY A EBUILD EMERGE_FROM O PPID FILESDIR PORTAGE_
        [[ ${!x-UNSET_VAR} != UNSET_VAR ]] && declare -r ${x}
 done
 # Need to be able to change D in dyn_preinst due to the IMAGE stuff
-[[ $* != "preinst" ]] && declare -r D
+[[ ${EBUILD_SH_ARGS} != "preinst" ]] && declare -r D
 unset x
 
 # Turn of extended glob matching so that g++ doesn't get incorrectly matched.
 shopt -u extglob
 
-QA_INTERCEPTORS="javac java-config python python-config perl grep fgrep sed gcc g++ cc bash awk nawk gawk pkg-config"
+QA_INTERCEPTORS="javac java-config python python-config perl grep egrep fgrep sed gcc g++ cc bash awk nawk gawk pkg-config"
 # level the QA interceptors if we're in depend
-if hasq "depend" "$@"; then
+if hasq "depend" "${EBUILD_SH_ARGS}"; then
        for BIN in ${QA_INTERCEPTORS}; do
-               BIN_PATH=`type -pf ${BIN}`
+               BIN_PATH=$(type -pf ${BIN})
                if [ "$?" != "0" ]; then
                        BODY="echo \"*** missing command: ${BIN}\" >&2; return 127"
                else
                        BODY="${BIN_PATH} \"\$@\"; return \$?"
                fi
                FUNC_SRC="${BIN}() {
-               echo -n \"QA Notice: ${BIN} in global scope: \" >&2
+               vecho -n \"QA Notice: ${BIN} in global scope: \" >&2
                if [ \$ECLASS_DEPTH -gt 0 ]; then
-                       echo \"eclass \${ECLASS}\" >&2
+                       vecho \"eclass \${ECLASS}\" >&2
                else
-                       echo \"\${CATEGORY}/\${PF}\" >&2
+                       vecho \"\${CATEGORY}/\${PF}\" >&2
                fi
                ${BODY}
                }";
                eval "$FUNC_SRC" || echo "error creating QA interceptor ${BIN}" >&2
        done
-       unset src bin_path body
+       unset BIN_PATH BIN BODY FUNC_SRC
 fi
 
 # reset the EBUILD_DEATH_HOOKS so they don't multiple due to stable's re-sourcing of env.
@@ -1587,7 +1610,6 @@ if ! hasq depend $EBUILD_PHASE; then
        RESTRICT="${PORTAGE_RESTRICT}"
        unset PORTAGE_RESTRICT
 fi
-[ -z "${ERRORMSG}" ] || die "${ERRORMSG}"
 
 # Expand KEYWORDS
 # We need to turn off pathname expansion for -* in KEYWORDS and
@@ -1596,9 +1618,7 @@ set -f
 KEYWORDS=$(eval echo ${KEYWORDS//~/\\~})
 set +f
 
-if [[ " ${FEATURES} " == *" nostrip "* ]] || \
-   [[ " ${RESTRICT} " == *" nostrip "* ]] || \
-   [[ " ${RESTRICT} " == *" strip "* ]]
+if hasq nostrip ${FEATURES} ${RESTRICT} || hasq strip ${RESTRICT}
 then
        export DEBUGBUILD=1
 fi
@@ -1609,7 +1629,7 @@ if [ "$S" = "" ]; then
 fi
 
 #wipe the interceptors.  we don't want saved.
-if hasq "depend" "$@"; then
+if hasq "depend" "${EBUILD_SH_ARGS}"; then
        unset -f $QA_INTERCEPTORS
        unset QA_INTERCEPTORS
 fi
@@ -1648,7 +1668,7 @@ fi
 
 set +f
 
-for myarg in $*; do
+for myarg in ${EBUILD_SH_ARGS} ; do
        case $myarg in
        nofetch)
                pkg_nofetch
@@ -1687,7 +1707,7 @@ for myarg in $*; do
                fi
                export SANDBOX_ON="0"
                ;;
-       help|clean|setup|preinst)
+       help|setup|preinst)
                #pkg_setup needs to be out of the sandbox for tmp file creation;
                #for example, awking and piping a file in /tmp requires a temp file to be created
                #in /etc.  If pkg_setup is in the sandbox, both our lilo and apache ebuilds break.
@@ -1708,35 +1728,35 @@ for myarg in $*; do
                #dbkey=${PORTAGE_CACHEDIR}/${CATEGORY}/${PF}
 
                if [ ! -d "${dbkey%/*}" ]; then
-                       install -d -g ${PORTAGE_GID} -m 2775 "${dbkey%/*}"
+                       install -d -g ${PORTAGE_GID} -m2775 "${dbkey%/*}"
                fi
 
                # Make it group writable. 666&~002==664
                umask 002
 
-               #the extra `echo` commands remove newlines
-               echo `echo "$DEPEND"`       > $dbkey
-               echo `echo "$RDEPEND"`     >> $dbkey
-               echo `echo "$SLOT"`        >> $dbkey
-               echo `echo "$SRC_URI"`     >> $dbkey
-               echo `echo "$RESTRICT"`    >> $dbkey
-               echo `echo "$HOMEPAGE"`    >> $dbkey
-               echo `echo "$LICENSE"`     >> $dbkey
-               echo `echo "$DESCRIPTION"` >> $dbkey
-               echo `echo "$KEYWORDS"`    >> $dbkey
-               echo `echo "$INHERITED"`   >> $dbkey
-               echo `echo "$IUSE"`        >> $dbkey
+               #the extra $(echo) commands remove newlines
+               echo $(echo "$DEPEND")       > $dbkey
+               echo $(echo "$RDEPEND")     >> $dbkey
+               echo $(echo "$SLOT")        >> $dbkey
+               echo $(echo "$SRC_URI")     >> $dbkey
+               echo $(echo "$RESTRICT")    >> $dbkey
+               echo $(echo "$HOMEPAGE")    >> $dbkey
+               echo $(echo "$LICENSE")     >> $dbkey
+               echo $(echo "$DESCRIPTION") >> $dbkey
+               echo $(echo "$KEYWORDS")    >> $dbkey
+               echo $(echo "$INHERITED")   >> $dbkey
+               echo $(echo "$IUSE")        >> $dbkey
                echo                       >> $dbkey
-               echo `echo "$PDEPEND"`     >> $dbkey
-               echo `echo "$PROVIDE"`     >> $dbkey
-               echo `echo "${EAPI:-0}"`   >> $dbkey
-               echo `echo "$UNUSED_01"`   >> $dbkey
-               echo `echo "$UNUSED_02"`   >> $dbkey
-               echo `echo "$UNUSED_03"`   >> $dbkey
-               echo `echo "$UNUSED_04"`   >> $dbkey
-               echo `echo "$UNUSED_05"`   >> $dbkey
-               echo `echo "$UNUSED_06"`   >> $dbkey
-               echo `echo "$UNUSED_07"`   >> $dbkey
+               echo $(echo "$PDEPEND")     >> $dbkey
+               echo $(echo "$PROVIDE")     >> $dbkey
+               echo $(echo "${EAPI:-0}")   >> $dbkey
+               echo $(echo "$UNUSED_01")   >> $dbkey
+               echo $(echo "$UNUSED_02")   >> $dbkey
+               echo $(echo "$UNUSED_03")   >> $dbkey
+               echo $(echo "$UNUSED_04")   >> $dbkey
+               echo $(echo "$UNUSED_05")   >> $dbkey
+               echo $(echo "$UNUSED_06")   >> $dbkey
+               echo $(echo "$UNUSED_07")   >> $dbkey
                set +f
                #make sure it is writable by our group:
                exit 0
index 05cc45a0a89eaf06d79d3902c580addc53d89ccc..f29013ae22ef34c85124bd92830639afdc565109 100755 (executable)
@@ -1,11 +1,12 @@
 #!@PYTHON@ -O
+
 import sys
 sys.path.insert(0, "@PORTAGE_BASE@/pym")
-
-import os, portage, portage_const, re
-from copy import copy
 from optparse import OptionParser, OptionValueError
 
+import re
+
+import os, portage, portage_const, portage_exception
 class WorldHandler(object):
 
        def name():
@@ -24,8 +25,6 @@ class WorldHandler(object):
                                self.invalid.append(atom)
                        elif not portage.db["/"]["vartree"].dbapi.match(atom):
                                self.not_installed.append(atom)
-                       elif not portage.db["/"]["porttree"].dbapi.match("match-visible", atom):
-                               self.masked.append(atom)
                        else:
                                self.okay.append(atom)
 
@@ -34,8 +33,6 @@ class WorldHandler(object):
                if self.found:
                        errors += map(lambda x: "'%s' is not a valid atom" % x, self.invalid)
                        errors += map(lambda x: "'%s' is not installed" % x, self.not_installed)
-                       if self.masked:
-                               errors += "Masked ebuilds can be manually unmasked with package.keywords or package.unmask"
                else:
                        errors.append(self.world_file + " could not be opened for reading")
                return errors
@@ -44,7 +41,7 @@ class WorldHandler(object):
                errors = []
                try:
                        portage.write_atomic(self.world_file, "\n".join(self.okay))
-               except OSError:
+               except portage_exception.PortageException:
                        errors.append(self.world_file + " could not be opened for writing")
                return errors
 
@@ -106,16 +103,16 @@ class VdbKeyHandler(object):
                
                return errors
 
-# this sucks, should track this in a different manner.
-#modules = {"world" : WorldHandler,
-#                 "vdbkeys": VdbKeyHandler}
-modules = {"world" : WorldHandler}
+def emaint_main(myargv):
 
-module_names = modules.keys()
-module_names.sort()
-module_names.insert(0, "all")
+       # TODO: Create a system that allows external modules to be added without
+       #       the need for hard coding.
+       modules = {"world" : WorldHandler}
+
+       module_names = modules.keys()
+       module_names.sort()
+       module_names.insert(0, "all")
 
-if __name__ == "__main__":
        def exclusive(option, *args, **kw):
                var = kw.get("var", None)
                if var is None:
@@ -140,7 +137,7 @@ if __name__ == "__main__":
        parser.action = None
 
 
-       (options, args) = parser.parse_args()
+       (options, args) = parser.parse_args(args=myargv)
        if len(args) != 1:
                parser.error("Incorrect number of arguments")
        if args[0] not in module_names:
@@ -176,3 +173,6 @@ if __name__ == "__main__":
                        print "\n"
 
        print "Finished"
+
+if __name__ == "__main__":
+       emaint_main(sys.argv[1:])
index c73fd8d6c2f3e09ec1511a20549c89358f1703bd..3d2dd2c75e0faaee72c2b07e67c815abbe56dd24 100755 (executable)
 #!@PYTHON@ -O
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/emerge,v 1.345.2.38 2005/08/13 17:25:26 ferringb Exp $
-
-import os,sys
-os.environ["PORTAGE_CALLER"]="emerge"
-sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
+# $Id$
 
+import sys
+# This block ensures that ^C interrupts are handled quietly.
 try:
-       import portage
+       import signal
+
+       def exithandler(signum,frame):
+               signal.signal(signal.SIGINT, signal.SIG_IGN)
+               signal.signal(signal.SIGTERM, signal.SIG_IGN)
+               sys.exit(1)
+       
+       signal.signal(signal.SIGINT, exithandler)
+       signal.signal(signal.SIGTERM, exithandler)
+       signal.signal(signal.SIGPIPE, signal.SIG_DFL)
+
 except KeyboardInterrupt:
-       sys.exit(1) # If they control C during imports, just die silently
+       sys.exit(1)
 
-import emergehelp,xpak,string,re,commands,time,shutil,traceback,signal,socket,types
-from stat import *
-from output import *
+import os, stat
+sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
+
+os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
+import portage
+del os.environ["PORTAGE_LEGACY_GLOBALS"]
+from portage import digraph
+
+import emergehelp, xpak, commands, errno, re, socket, string, time, types
+from output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \
+       havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \
+       xtermTitleReset, yellow
+from output import create_color_func
+good = create_color_func("GOOD")
+bad = create_color_func("BAD")
 
 import portage_util
 import portage_locks
 import portage_exception
 import portage_const
+from portage_data import secpass
+
+if not hasattr(__builtins__, "set"):
+       from sets import Set as set
+
+class stdout_spinner(object):
+       scroll_msgs = [
+               "Gentoo Rocks ("+os.uname()[0]+")",
+               "Thank you for using Gentoo. :)",
+               "Are you actually trying to read this?",
+               "How many times have you stared at this?",
+               "We are generating the cache right now",
+               "You are paying too much attention.",
+               "A theory is better than its explanation.",
+               "Phasers locked on target, Captain.",
+               "Thrashing is just virtual crashing.",
+               "To be is to program.",
+               "Real Users hate Real Programmers.",
+               "When all else fails, read the instructions.",
+               "Functionality breeds Contempt.",
+               "The future lies ahead.",
+               "3.1415926535897932384626433832795028841971694",
+               "Sometimes insanity is the only alternative.",
+               "Inaccuracy saves a world of explanation.",
+       ]
+
+       twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
 
-spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")",
-                "Thank you for using Gentoo. :)",
-                "Are you actually trying to read this?",
-                "How many times have you stared at this?",
-                "We are generating the cache right now",
-                "You are paying too much attention.",
-                "A theory is better than its explanation.",
-                "Phasers locked on target, Captain.",
-                "Thrashing is just virtual crashing.",
-                "To be is to program.",
-                "Real Users hate Real Programmers.",
-                "When all else fails, read the instructions.",
-                "Functionality breeds Contempt.",
-                "The future lies ahead.",
-                "3.1415926535897932384626433832795028841971694",
-                "Sometimes insanity is the only alternative.",
-                "Inaccuracy saves a world of explanation.",
-               ]
-
-
-def update_basic_spinner():
-       global spinner, spinpos
-       spinpos = (spinpos+1) % 500
-       if (spinpos % 100) == 0:
-               if spinpos == 0:
-                       sys.stdout.write(". ")
-               else:
-                       sys.stdout.write(".")
-       sys.stdout.flush()
-
-def update_scroll_spinner():
-       global spinner, spinpos
-       if(spinpos >= len(spinner)):
-               sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))]))
-       else:
-               sys.stdout.write(green("\b "+spinner[spinpos]))
-       sys.stdout.flush()
-       spinpos = (spinpos+1) % (2*len(spinner))
-
-def update_twirl_spinner():
-       global spinner, spinpos
-       spinpos = (spinpos+1) % len(spinner)
-       sys.stdout.write("\b\b "+spinner[spinpos])
-       sys.stdout.flush()
+       def __init__(self):
+               self.spinpos = 0
+               self.update = self.update_twirl
+               self.scroll_sequence = self.scroll_msgs[
+                       int(time.time() * 100) % len(self.scroll_msgs)]
+
+       def update_basic(self):
+               self.spinpos = (self.spinpos + 1) % 500
+               if (self.spinpos % 100) == 0:
+                       if self.spinpos == 0:
+                               sys.stdout.write(". ")
+                       else:
+                               sys.stdout.write(".")
+               sys.stdout.flush()
 
-def update_quiet_spinner():
-       return
+       def update_scroll(self):
+               if(self.spinpos >= len(self.scroll_sequence)):
+                       sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[
+                               len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))]))
+               else:
+                       sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos]))
+               sys.stdout.flush()
+               self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence))
 
-spinpos = 0
-spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
-update_spinner = update_twirl_spinner
-if "candy" in portage.settings.features:
-       spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)]
-       update_spinner = update_scroll_spinner
+       def update_twirl(self):
+               self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence)
+               sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos])
+               sys.stdout.flush()
 
-if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]):
-       nocolor()
+       def update_quiet(self):
+               return
 
 
 
@@ -95,7 +116,8 @@ def normpath(mystr):
 def userquery(prompt, responses=None, colours=None):
        """Displays a prompt and a set of responses, then waits for a response
        which is checked against the responses and the first to match is
-       returned.
+       returned.  An empty response will match the first value in responses.  The
+       input buffer is *not* cleared prior to the prompt!
 
        prompt: a String.
        responses: a List of Strings.
@@ -119,6 +141,7 @@ def userquery(prompt, responses=None, colours=None):
                while True:
                        response=raw_input("["+string.join([colours[i](responses[i]) for i in range(len(responses))],"/")+"] ")
                        for key in responses:
+                               # An empty response will match the first value in responses.
                                if response.upper()==key[:len(response)].upper():
                                        return key
                        print "Sorry, response '%s' not understood." % response,
@@ -151,23 +174,7 @@ def sorted_versions(verlist):
                ret.insert(x, ver)
        return ret
 
-if portage.settings.has_key("PORTAGE_NICENESS"):
-       try:
-               os.nice(int(portage.settings["PORTAGE_NICENESS"]))
-       except (OSError,ValueError), e:
-               print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'"
-               print "!!!",e
-
-#Freeze the portdbapi for enhanced performance:
-portage.portdb.freeze()
-
-# Kill noauto as it will break merges otherwise.
-while 'noauto' in portage.features:
-       del portage.features[portage.features.index('noauto')]
 
-#number of ebuilds merged
-merged=0
-params=["selective", "deep", "self", "recurse", "empty"]
 actions=[
 "clean", "config", "depclean",
 "info", "metadata",
@@ -177,7 +184,7 @@ actions=[
 options=[
 "--ask",          "--alphabetical",
 "--buildpkg",     "--buildpkgonly",
-"--changelog",    "--columns", "--cols",
+"--changelog",    "--columns",
 "--debug",        "--deep",
 "--digest",
 "--emptytree",
@@ -191,7 +198,7 @@ options=[
 "--onlydeps",     "--pretend",
 "--quiet",        "--resume",
 "--searchdesc",   "--selective",
-"--skipfirst",    "--skip-first",
+"--skipfirst",
 "--tree",
 "--update",       
 "--usepkg",       "--usepkgonly",
@@ -220,230 +227,18 @@ shortmapping={
 "v":"--verbose",   "V":"--version"
 }
 
-myaction=None
-myopts=[]
-myfiles=[]
-edebug=0
-
-# process short actions
-tmpcmdline=sys.argv[1:]
-if "--ignore-default-opts" not in tmpcmdline:
-       tmpcmdline.extend(portage.settings["EMERGE_DEFAULT_OPTS"].split())
-cmdline=[]
-for x in tmpcmdline:
-       if x[0:1]=="-" and x[1:2]!="-":
-               for y in x[1:]:
-                       if shortmapping.has_key(y):
-                               if shortmapping[y] in cmdline:
-                                       print
-                                       print "*** Warning: Redundant use of",shortmapping[y]
-                               else:
-                                       cmdline.append(shortmapping[y])
-                       else:
-                               print "!!! Error: -"+y+" is an invalid short action or option."
-                               sys.exit(1)
-       else:
-               cmdline.append(x)
-
-# process the options and command arguments
-for x in cmdline:
-       if not x:
-               continue
-       if len(x)>=2 and x[0:2]=="--":
-               if x == "--cols":
-                       x = "--columns"
-               elif x == "--skip-first":
-                       x = "--skipfirst"
-               if x in options:
-                       if x not in myopts:
-                               myopts.append(x)
-               elif x[2:] in actions:
-                       if myaction:
-                               if myaction not in ["system", "world"]:
-                                       myaction="--"+myaction
-                               print
-                               print red("!!!")+green(" Multiple actions requested... Please choose one only.")
-                               print red("!!!")+" '"+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
-                               print
-                               sys.exit(1)
-                       myaction=x[2:]
-               else:
-                       print "!!! Error:",x,"is an invalid option."
-                       sys.exit(1)
-       elif (not myaction) and (x in actions):
-               if x not in ["system", "world"]:
-                       print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x))
-               if myaction:
-                       print
-                       print red("!!!")+green(" Multiple actions requested... Please choose one only.")
-                       print red("!!! '")+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
-                       print
-                       sys.exit(1)
-               myaction=x
-       elif x[-1]=="/":
-               # this little conditional helps tab completion
-               myfiles.append(x[:-1])
-       else:
-               myfiles.append(x)
-
-
-if "moo" in myfiles:
-       print """
-
-  Larry loves Gentoo (""" + os.uname()[0] + """)
-
- _______________________
-< Have you mooed today? >
- -----------------------
-        \   ^__^
-         \  (oo)\_______
-            (__)\       )\/\ 
-                ||----w |
-                ||     ||
-
-"""
-
-if (myaction in ["world", "system"]) and myfiles:
-       print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
-       sys.exit(1)
-
-for x in myfiles:
-       ext = os.path.splitext(x)[1]
-       if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
-               print "emerging by path implies --oneshot... adding --oneshot to options."
-               print red("\n*** emerging by path is broken and may not always work!!!\n")
-               break
-
-if ("--tree" in myopts) and ("--columns" in myopts):
-       print "emerge: can't specify both of \"--tree\" and \"--columns\"."
-       sys.exit(1)
-
-if ("--quiet" in myopts):
-       update_spinner = update_quiet_spinner
-       portage_util.noiselimit = -1
-       portage.settings.unlock()
-       portage.settings["PORTAGE_QUIET"]="1"
-       portage.settings.backup_changes("PORTAGE_QUIET")
-       portage.settings.lock()
-
-# Always create packages if FEATURES=buildpkg
-# Imply --buildpkg if --buildpkgonly
-if ("buildpkg" in portage.features) or ("--buildpkgonly" in myopts):
-       if "--buildpkg" not in myopts:
-               myopts.append("--buildpkg")
-
-# --tree only makes sense with --pretend
-if "--tree" in myopts and not (("--pretend" in myopts) or ("--ask" in myopts)):
-       print ">>> --tree implies --pretend... adding --pretend to options."
-       myopts.append("--pretend")
-
-# Also allow -S to invoke search action (-sS)
-if ("--searchdesc" in myopts):
-       if myaction and myaction != "search":
-               myfiles.append(myaction)
-       if "--search" not in myopts:
-               myopts.append("--search")
-       myaction = "search"
-
-# Always try and fetch binary packages if FEATURES=getbinpkg
-if ("getbinpkg" in portage.features):
-       myopts.append("--getbinpkg")
-
-if "--skipfirst" in myopts and "--resume" not in myopts:
-       myopts.append("--resume")
-
-if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts):
-       myopts.append("--usepkgonly")
-
-if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts):
-       myopts.append("--getbinpkg")
-
-if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts):
-       myopts.append("--usepkg")
-
-# Also allow -K to apply --usepkg/-k
-if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts):
-       myopts.append("--usepkg")
-
-if ("--newuse" in myopts) and not ("--update" in myopts):
-       print ">>> --newuse implies --update... adding --update to options."
-       myopts.append("--update")
-
-# Also allow -l to apply --pretend/-p, but if already in --ask mode
-if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)):
-       print ">>> --changelog implies --pretend... adding --pretend to options."
-       myopts.append("--pretend")
-
-# Allow -p to remove --ask
-if ("--pretend" in myopts) and ("--ask" in myopts):
-       print ">>> --pretend disables --ask... removing --ask from options."
-       myopts.remove("--ask")
-
-# forbid --ask when not in a terminal
-# note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
-if ("--ask" in myopts) and (not sys.stdin.isatty()):
-       portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n")
-       sys.exit(1)
-
-# Set so that configs will be merged regardless of remembered status
-if ("--noconfmem" in myopts):
-       portage.settings.unlock()
-       portage.settings["NOCONFMEM"]="1"
-       portage.settings.backup_changes("NOCONFMEM")
-       portage.settings.lock()
-
-# Set various debug markers... They should be merged somehow.
-if ("--debug" in myopts):
-       portage.settings.unlock()
-       portage.settings["PORTAGE_DEBUG"]="1"
-       portage.settings.backup_changes("PORTAGE_DEBUG")
-       portage.debug=1
-       portage.settings.lock()
-       if "python-trace" in portage.features:
-               import portage_debug
-               portage_debug.set_trace(True)
-
-if ("--resume" in myopts):
-       if "--tree" in myopts:
-               print "* --tree is currently broken with --resume. Disabling..."
-               myopts.remove("--tree")
-
-# Set color output
-if "--nocolor" in myopts or \
-portage.settings["NOCOLOR"] in ("yes","true"):
-       nocolor()
-       if "NOCOLOR" not in portage.settings:
-               portage.settings.unlock()
-               portage.settings["NOCOLOR"] = "true"
-               portage.settings.backup_changes("NOCOLOR")
-               portage.settings.lock()
-
-if not ("--quiet" in myopts):
-       if not sys.stdout.isatty() or ("--nospinner" in myopts):
-               update_spinner = update_basic_spinner
-
-CLEAN_DELAY = 5
-EMERGE_WARNING_DELAY = 10
-if portage.settings["CLEAN_DELAY"]:
-       CLEAN_DELAY = string.atoi("0"+portage.settings["CLEAN_DELAY"])
-if portage.settings["EMERGE_WARNING_DELAY"]:
-       EMERGE_WARNING_DELAY = string.atoi("0"+portage.settings["EMERGE_WARNING_DELAY"])
-
-def emergelog(mystr,short_msg=None):
-       if "notitles" not in portage.features:
+def emergelog(xterm_titles, mystr, short_msg=None):
+       if xterm_titles:
                if short_msg:
                        xtermTitle(short_msg)
                else:
                        xtermTitle(mystr)
        try:
-               #seems odd opening a file each write...
-               elog = portage_const.EPREFIX+"/var/log/emerge.log"
-               if not os.path.exists(elog):
-                       mylogfile=open(elog, "w")
-                       os.chmod(elog, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-                       os.chown(elog, portage.portage_uid, portage.portage_gid)
-               else:
-                       mylogfile=open(elog, "a")
+               file_path = portage_const.EPREFIX+"/var/log/emerge.log"
+               mylogfile = open(file_path, "a")
+               portage_util.apply_secpass_permissions(file_path,
+                       uid=portage.portage_uid, gid=portage.portage_gid,
+                       mode=0660)
 
                l=portage_locks.lockfile(mylogfile)
                # seek because we may have gotten held up by the lock.
@@ -453,27 +248,9 @@ def emergelog(mystr,short_msg=None):
                mylogfile.flush()
                portage_locks.unlockfile(l)
                mylogfile.close()
-       except SystemExit, e:
-               raise # Needed else can't exit
-       except Exception, e:
-               if edebug:
-                       print "emergelog():",e
-               pass
-
-def emergeexit():
-       """This gets out final log message in before we quit."""
-       if "--pretend" not in myopts:
-               emergelog(" *** terminating.")
-       if "notitles" not in portage.features:
-               xtermTitleReset()
-portage.atexit_register(emergeexit)
-
-def emergeexitsig(signum, frame):
-       signal.signal(signal.SIGINT, signal.SIG_IGN)
-       portage.portageexit()
-       portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
-       sys.exit(100+signum)
-signal.signal(signal.SIGINT, emergeexitsig)
+       except (IOError,OSError,portage_exception.PortageException), e:
+               if secpass >= 1:
+                       print >> sys.stderr, "emergelog():",e
 
 def countdown(secs=5, doing="Starting"):
        if secs:
@@ -482,7 +259,7 @@ def countdown(secs=5, doing="Starting"):
                ticks=range(secs)
                ticks.reverse()
                for sec in ticks:
-                       sys.stdout.write(red(str(sec+1)+" "))
+                       sys.stdout.write(colorize("UNMERGE_WARN", str(sec+1)+" "))
                        sys.stdout.flush()
                        time.sleep(1)
                print
@@ -499,87 +276,60 @@ def format_size(mysize):
        return mystr+" kB"
 
 
-def getgccversion():
+def getgccversion(chost):
        """
        rtype: C{str}
        return:  the current in-use gcc version
        """
 
-       gcc_env_dir = os.path.join('/', 'etc', 'env.d', 'gcc')
-       gcc_config_config = os.path.join(gcc_env_dir, 'config')
        gcc_ver_command = 'gcc -dumpversion'
        gcc_ver_prefix = 'gcc-'
 
        gcc_not_found_error = red(
        "!!! No gcc found. You probably need to 'source /etc/profile'\n" +
        "!!! to update the environment of this terminal and possibly\n" +
-       "!!! other terminals also."
+       "!!! other terminals also.\n"
        )
 
-       gcc_distcc_broken_error = green(
-       '!!! Relying on the shell to locate gcc, this may break\n' +
-       '!!! DISTCC, installing gcc-config and setting your current gcc\n' +
-       '!!! profile will fix this'
-       )
-
-       def fallback():
-
-               print >>sys.stderr, gcc_distcc_broken_error
-
-               gccout = commands.getstatusoutput(gcc_ver_command)
-
-               if gccout[0] != 0:
-                       print >>sys.stderr, gcc_not_found_error
-                       gccver = "[unavailable]"
+       mystatus, myoutput = commands.getstatusoutput("eselect compiler show")
+       if mystatus == os.EX_OK and len(myoutput.split("/")) == 2:
+               part1, part2 = myoutput.split("/")
+               if part1.startswith(chost + "-"):
+                       return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
+
+       mystatus, myoutput = commands.getstatusoutput("gcc-config -c")
+       if mystatus == os.EX_OK and len(myoutput.split("-")) > 0:
+               return gcc_ver_prefix + myoutput.split("-")[-1]
+
+       mystatus, myoutput = commands.getstatusoutput(
+               chost + "-" + gcc_ver_command)
+       if mystatus == os.EX_OK:
+               return gcc_ver_prefix + myoutput
+
+       mystatus, myoutput = commands.getstatusoutput(gcc_ver_command)
+       if mystatus == os.EX_OK:
+               return gcc_ver_prefix + myoutput
+
+       portage.writemsg(gcc_not_found_error, noiselevel=-1)
+       return "[unavailable]"
+
+def getportageversion(portdir, target_root, profile, chost, vardb):
+       profilever = "unavailable"
+       if profile:
+               realpath = os.path.realpath(profile)
+               basepath   = os.path.realpath(os.path.join(portdir, "profiles"))
+               if realpath.startswith(basepath):
+                       profilever = realpath[1 + len(basepath):]
                else:
-                       gccver = gcc_ver_prefix + gccout[1]
-
-               return gccver
-
-       if os.path.isfile(gcc_config_config):
-               try:
-                       gccver_str = open(gcc_config_config).read().strip()
-                       gccver = gcc_ver_prefix + string.join(gccver_str.split('-')[4:], '-')
-               except IndexError:
-                       gccver = fallback()
-
-       else:
-               import glob
-               dir_l = glob.glob(os.path.join(gcc_env_dir, '*-*'))
-
-               if len(dir_l) == 1:
                        try:
-                               gccver = gcc_ver_prefix + dir_l[0].split('-')[-1]
-                       except IndexError:
-                               gccver = fallback()
-
-               else:
-                       # There was no "config" file in /etc/env.d/gcc and there was more
-                       # than one profile in /etc/env.d/gcc so we can't actively
-                       # determine what version of gcc we are using so we fall back on the
-                       # old way that breaks distcc
+                               profilever = "!" + os.readlink(profile)
+                       except (OSError):
+                               pass
+               del realpath, basepath
 
-                       gccver = fallback()
-
-       return gccver
-
-def getportageversion():
-       try:
-               import re
-               profilever = os.path.normpath("///"+os.readlink(portage_const.EPREFIX+"/etc/make.profile"))
-               basepath   = os.path.normpath("///"+portage.settings["PORTDIR"]+"/profiles")
-               if re.match(basepath,profilever):
-                       profilever = profilever[len(basepath)+1:]
-               else:
-                       profilever = "!"+profilever
-               del basepath
-       except SystemExit, e:
-               raise # Needed else can't exit
-       except:
-               profilever="unavailable"
        libcver=[]
-       libclist  = portage.vardbapi(portage.root).match("virtual/libc")
-       libclist += portage.vardbapi(portage.root).match("virtual/glibc")
+       libclist  = vardb.match("virtual/libc")
+       libclist += vardb.match("virtual/glibc")
        libclist  = portage_util.unique_array(libclist)
        for x in libclist:
                xs=portage.catpkgsplit(x)
@@ -590,84 +340,41 @@ def getportageversion():
        if libcver==[]:
                libcver="unavailable"
 
-       gccver = getgccversion()
+       gccver = getgccversion(chost)
        unameout=os.uname()[2]+" "+os.uname()[4]
 
        return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")"
 
-def help():
-       # Move all the help stuff out of this file.
-       emergehelp.help(myaction,myopts,havecolor)
-
-if "--version" in myopts:
-       print getportageversion()
-       sys.exit(0)
-elif "--help" in myopts:
-       help()
-       sys.exit(0)
-
-if "--debug" in myopts:
-       print "myaction", myaction
-       print "myopts", myopts
-
-# check if root user is the current user for the actions where emerge needs this
-if portage.secpass < 2:
-       # We've already allowed "--version" and "--help" above.
-       if "--pretend" not in myopts and \
-       myaction not in ("search","info"):
-               if portage.secpass >= 1:
-                       if "--fetchonly" not in myopts and \
-                       "--fetch-all-uri" not in myopts:
-                               print "emerge: root access required."
-                               sys.exit(1)
-               else:
-                       print "emerge: root access required."
-                       sys.exit(1)
-
-if not "--pretend" in myopts:
-       emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
-       myelogstr=""
-       if myopts:
-               myelogstr=string.join(myopts, " ")
-       if myaction:
-               myelogstr+=" "+myaction
-       if myfiles:
-               myelogstr+=" "+string.join(myfiles, " ")
-       emergelog(" *** emerge "+myelogstr)
-
-#configure emerge engine parameters
-#
-# self:      include _this_ package regardless of if it is merged.
-# selective: exclude the package if it is merged
-# recurse:   go into the dependencies
-# empty:     pretend nothing is merged
-myparams=["self","recurse"]
-add=[]
-sub=[]
-if "--update" in myopts or myaction in ("system", "world"):
-       add.extend(["selective","empty"])
-if "--emptytree" in myopts:
-       add.extend(["empty"])
-       sub.extend(["selective"])
-if "--nodeps" in myopts:
-       sub.extend(["recurse"])
-if "--noreplace" in myopts:
-       add.extend(["selective"])
-if "--deep" in myopts:
-       add.extend(["deep"])
-if "--selective" in myopts:
-       add.extend(["selective"])
-if myaction in ["world","system"]:
-       add.extend(["selective"])
-elif myaction in ["depclean"]:
-       add.extend(["empty"])
-       sub.extend(["selective"])
-for x in add:
-       if (x not in myparams) and (x not in sub):
-               myparams.append(x)
-for x in sub:
-       if x in myparams:
-               myparams.remove(x)
+def create_depgraph_params(myopts, myaction):
+       #configure emerge engine parameters
+       #
+       # self:      include _this_ package regardless of if it is merged.
+       # selective: exclude the package if it is merged
+       # recurse:   go into the dependencies
+       # deep:      go into the dependencies of already merged packages
+       # empty:     pretend nothing is merged
+       myparams = ["recurse"]
+       add=[]
+       sub=[]
+       if "--update" in myopts or \
+               "--newuse" in myopts or \
+               "--noreplace" in myopts or \
+               myaction in ("system", "world"):
+               add.extend(["selective"])
+       if "--emptytree" in myopts:
+               add.extend(["empty"])
+               sub.extend(["selective"])
+       if "--nodeps" in myopts:
+               sub.extend(["recurse"])
+       if "--deep" in myopts:
+               add.extend(["deep"])
+       for x in add:
+               if (x not in myparams) and (x not in sub):
+                       myparams.append(x)
+       for x in sub:
+               if x in myparams:
+                       myparams.remove(x)
+       return myparams
 
 # search functionality
 class search:
@@ -681,19 +388,24 @@ class search:
        #
        # public interface
        #
-       def __init__(self):
+       def __init__(self, settings, portdb, vartree, spinner, searchdesc,
+               verbose):
                """Searches the available and installed packages for the supplied search key.
                The list of available and installed packages is created at object instantiation.
                This makes successive searches faster."""
-               self.installcache = portage.db["/"]["vartree"]
+               self.settings = settings
+               self.portdb = portdb
+               self.vartree = vartree
+               self.spinner = spinner
+               self.verbose = verbose
+               self.searchdesc = searchdesc
 
        def execute(self,searchkey):
                """Performs the search for the supplied search key"""
-               global myopts
                match_category = 0
                self.searchkey=searchkey
                self.packagematches = []
-               if "--searchdesc" in myopts:
+               if self.searchdesc:
                        self.searchdesc=1
                        self.matches = {"pkg":[], "desc":[]}
                else:
@@ -701,18 +413,19 @@ class search:
                        self.matches = {"pkg":[]}
                print "Searching...   ",
 
+               regexsearch = False
+               if self.searchkey[0] == '%':
+                       regexsearch = True
+                       self.searchkey = self.searchkey[1:]
                if self.searchkey[0] == '@':
                        match_category = 1
                        self.searchkey = self.searchkey[1:]
-               if self.searchkey=="*":
-                       #hack for people who aren't regular expression gurus
-                       self.searchkey==".*"
-               if re.search("\+\+", self.searchkey):
-                       #hack for people who aren't regular expression gurus
-                       self.searchkey=re.sub("\+\+","\+\+",self.searchkey)
-               self.searchre=re.compile(self.searchkey.lower(),re.I)
-               for package in portage.portdb.cp_all():
-                       update_spinner()
+               if regexsearch:
+                       self.searchre=re.compile(self.searchkey,re.I)
+               else:
+                       self.searchre=re.compile(re.escape(self.searchkey), re.I)
+               for package in self.portdb.cp_all():
+                       self.spinner.update()
 
                        if match_category:
                                match_string  = package[:]
@@ -721,20 +434,22 @@ class search:
 
                        masked=0
                        if self.searchre.search(match_string):
-                               if not portage.portdb.xmatch("match-visible",package):
+                               if not self.portdb.xmatch("match-visible", package):
                                        masked=1
                                self.matches["pkg"].append([package,masked])
                        elif self.searchdesc: # DESCRIPTION searching
-                               full_package = portage.portdb.xmatch("bestmatch-visible",package)
+                               full_package = self.portdb.xmatch("bestmatch-visible", package)
                                if not full_package:
                                        #no match found; we don't want to query description
-                                       full_package=portage.best(portage.portdb.xmatch("match-all",package))
+                                       full_package = portage.best(
+                                               self.portdb.xmatch("match-all", package))
                                        if not full_package:
                                                continue
                                        else:
                                                masked=1
                                try:
-                                       full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0]
+                                       full_desc = self.portdb.aux_get(
+                                               full_package, ["DESCRIPTION"])[0]
                                except KeyError:
                                        print "emerge: search: aux_get() failed, skipping"
                                        continue
@@ -754,18 +469,21 @@ class search:
                        for match,masked in self.matches[mtype]:
                                if mtype=="pkg":
                                        catpack=match
-                                       full_package = portage.portdb.xmatch("bestmatch-visible",match)
+                                       full_package = self.portdb.xmatch(
+                                               "bestmatch-visible", match)
                                        if not full_package:
                                                #no match found; we don't want to query description
                                                masked=1
-                                               full_package=portage.best(portage.portdb.xmatch("match-all",match))
+                                               full_package = portage.best(
+                                                       self.portdb.xmatch("match-all",match))
                                else:
                                        full_package = match
                                        match        = portage.pkgsplit(match)[0]
 
                                if full_package:
                                        try:
-                                               desc, homepage, license = portage.portdb.aux_get(full_package,["DESCRIPTION","HOMEPAGE","LICENSE"])
+                                               desc, homepage, license = self.portdb.aux_get(
+                                                       full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"])
                                        except KeyError:
                                                print "emerge: search: aux_get() failed, skipping"
                                                continue
@@ -778,28 +496,26 @@ class search:
                                        mysum = [0,0]
                                        mycat = match.split("/")[0]
                                        mypkg = match.split("/")[1]
-
-                                       mydigest = portage.db["/"]["porttree"].dbapi.finddigest(mycat+"/"+mypkg + "-" + myversion)
-
+                                       mycpv = match + "-" + myversion
+                                       myebuild = self.portdb.findname(mycpv)
+                                       pkgdir = os.path.dirname(myebuild)
+                                       import portage_manifest
+                                       mf = portage_manifest.Manifest(
+                                               pkgdir, self.settings["DISTDIR"])
+                                       fetchlist = self.portdb.getfetchlist(mycpv,
+                                               mysettings=self.settings, all=True)[1]
                                        try:
-                                               myfile = open(mydigest,"r")
-                                               for line in myfile.readlines():
-                                                       mysum[0] += int(line.split(" ")[3])
-                                               myfile.close()
+                                               mysum[0] = mf.getDistfilesSize(fetchlist)
                                                mystr = str(mysum[0]/1024)
                                                mycount=len(mystr)
                                                while (mycount > 3):
                                                        mycount-=3
                                                        mystr=mystr[:mycount]+","+mystr[mycount:]
                                                mysum[0]=mystr+" kB"
-                                       except SystemExit, e:
-                                               raise # Needed else can't exit
-                                       except Exception, e:
-                                               if edebug:
-                                                       print "!!! Exception:",e
-                                               mysum[0]=" [no/bad digest]"
+                                       except KeyError, e:
+                                               mysum[0] = "Unknown (missing digest for %s)" % str(e)
 
-                                       if "--quiet" not in myopts:
+                                       if self.verbose:
                                                print "     ", darkgreen("Latest version available:"),myversion
                                                print "     ", self.getInstallationStatus(mycat+'/'+mypkg)
                                                print "     ", darkgreen("Size of files:"),mysum[0]
@@ -812,7 +528,7 @@ class search:
        # private interface
        #
        def getInstallationStatus(self,package):
-               installed_package = self.installcache.dep_bestmatch(package)
+               installed_package = self.vartree.dep_bestmatch(package)
                result = ""
                version = self.getVersion(installed_package,search.VERSION_RELEASE)
                if len(version) > 0:
@@ -834,20 +550,21 @@ class search:
 
 
 #build our package digraph
-def getlist(mode):
+def getlist(settings, mode):
        if mode=="system":
-               mylines=portage.settings.packages
+               mylines = settings.packages
        elif mode=="world":
                try:
-                       myfile = open(os.path.join(portage.root, portage.WORLD_FILE), "r")
-                       mylines=myfile.readlines()
+                       file_path = os.path.join(settings["ROOT"], portage.WORLD_FILE)
+                       myfile = open(file_path, "r")
+                       mylines = myfile.readlines()
                        myfile.close()
-               except OSError:
-                       print "!!! Couldn't open "+pfile+"; exiting."
-                       sys.exit(1)
-               except IOError:
-                       #world file doesn't exist
-                       mylines=[]
+               except (OSError, IOError), e:
+                       if e.errno == errno.ENOENT:
+                               portage.writemsg("\n!!! World file does not exist: '%s'\n" % file_path)
+                               mylines=[]
+                       else:
+                               raise
        mynewlines=[]
        for x in mylines:
                myline=string.join(string.split(x))
@@ -863,232 +580,366 @@ def getlist(mode):
 
        # Remove everything that is package.provided from our list
        for atom in mynewlines[:]:
-               for expanded_atom in portage.flatten(portage.dep_virtual([atom], portage.settings)):
+               for expanded_atom in portage.flatten(
+                       portage.dep_virtual([atom], settings)):
                        mykey = portage.dep_getkey(expanded_atom)
-                       if portage.settings.pprovideddict.has_key(mykey) and \
-                               portage.match_from_list(expanded_atom, portage.settings.pprovideddict[mykey]):
+                       if mykey in settings.pprovideddict and \
+                               portage.match_from_list(
+                                       expanded_atom, settings.pprovideddict[mykey]):
                                        mynewlines.remove(atom)
                                        break
 
        return mynewlines
 
+def clean_world(vardb, cpv):
+       """Remove a package from the world file when unmerged."""
+       world_filename = os.path.join(vardb.root, portage.WORLD_FILE)
+       worldlist = portage_util.grabfile(world_filename)
+       mykey = portage.cpv_getkey(cpv)
+       newworldlist = []
+       for x in worldlist:
+               if portage.dep_getkey(x) == mykey:
+                       matches = vardb.match(x, use_cache=0)
+                       if not matches:
+                               #zap our world entry
+                               pass
+                       elif len(matches) == 1 and matches[0] == cpv:
+                               #zap our world entry
+                               pass
+                       else:
+                               #others are around; keep it.
+                               newworldlist.append(x)
+               else:
+                       #this doesn't match the package we're unmerging; keep it.
+                       newworldlist.append(x)
+
+       portage_util.ensure_dirs(os.path.join(vardb.root, portage.PRIVATE_PATH),
+               gid=portage.portage_gid, mode=02770)
+       portage_util.write_atomic(world_filename, "\n".join(newworldlist))
+
 def genericdict(mylist):
        mynewdict={}
        for x in mylist:
                mynewdict[portage.dep_getkey(x)]=x
        return mynewdict
 
-olddbapi=None
 class depgraph:
 
-       def __init__(self,myaction,myopts):
-               global olddbapi
-               self.pkgsettings = portage.config(clone=portage.settings)
-               if not self.pkgsettings["ARCH"]:
-                       portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n"))
-                       portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n"))
-                       sys.exit(9)
-               self.applied_useflags = {}
+       pkg_tree_map = {
+               "ebuild":"porttree",
+               "binary":"bintree",
+               "installed":"vartree"}
+
+       def __init__(self, settings, trees, myopts, myparams, spinner):
+               self.settings = settings
+               self.target_root = settings["ROOT"]
+               self.trees = trees
+               self.myopts = myopts
+               self.myparams = myparams
+               self.edebug = 0
+               if settings.get("PORTAGE_DEBUG", "") == "1":
+                       self.edebug = 1
+               self.spinner = spinner
+               self.pkgsettings = {}
+               self.pkgsettings[self.target_root] = portage.config(clone=settings)
+               if self.target_root != "/":
+                       self.pkgsettings["/"] = \
+                               portage.config(clone=trees["/"]["vartree"].settings)
+               self.useFlags = {}
+               self.useFlags[self.target_root] = {}
+               if self.target_root != "/":
+                       self.useFlags["/"] = {}
 
                self.missingbins=[]
-               self.myaction=myaction
                self.digraph=portage.digraph()
                self.orderedkeys=[]
                self.outdatedpackages=[]
                self.mydbapi={}
-               self.mydbapi["/"] = portage.fakedbapi()
-               if "empty" not in myparams or portage.root != "/":
-                       for pkg in portage.db["/"]["vartree"].getallcpv():
-                               self.mydbapi["/"].cpv_inject(pkg)
-               if portage.root != "/":
-                       self.mydbapi[portage.root] = portage.fakedbapi()
-                       if "empty" not in myparams:
-                               for pkg in portage.db[portage.root]["vartree"].getallcpv():
-                                       self.mydbapi[portage.root].cpv_inject(pkg)
-
-               if "--usepkg" in myopts:
-                       portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts))
-
-       def create(self,mybigkey,myparent=None,addme=1,myuse=None):
-               """creates the actual digraph of packages to merge.  return 1 on success, 0 on failure
-               mybigkey = specification of package to merge; myparent = parent package (one depending on me);
-               addme = should I be added to the tree? (for the --onlydeps mode)"""
+               self.mydbapi["/"] = portage.fakedbapi(settings=settings)
+               vardb = self.trees["/"]["vartree"].dbapi
+               fakedb = self.mydbapi["/"]
+               if "empty" not in self.myparams or self.target_root != "/":
+                       for pkg in vardb.cpv_all():
+                               myslot = vardb.aux_get(pkg, ["SLOT"])[0]
+                               fakedb.cpv_inject(pkg, myslot=myslot)
+               if self.target_root != "/":
+                       self.mydbapi[self.target_root] = \
+                               portage.fakedbapi(settings=settings)
+                       vardb = self.trees[self.target_root]["vartree"].dbapi
+                       fakedb = self.mydbapi[self.target_root]
+                       if "empty" not in self.myparams:
+                               for pkg in vardb.cpv_all():
+                                       myslot = vardb.aux_get(pkg, ["SLOT"])[0]
+                                       fakedb.cpv_inject(pkg, myslot=myslot)
+               if "--usepkg" in self.myopts:
+                       trees["/"]["bintree"].populate(
+                               "--getbinpkg" in self.myopts, "--getbinpkgonly" in self.myopts)
+                       if self.target_root != "/":
+                               trees[self.target_root]["bintree"].populate(
+                                       "--getbinpkg" in self.myopts,
+                                       "--getbinpkgonly" in self.myopts)
+               self.args_keys = []
+               self.global_updates = {}
+
+       def create(self, mybigkey, myparent=None, addme=1, myuse=None,
+               priority=digraph.HARD, rev_dep=False, arg=None):
+               """
+               Fills the digraph with nodes comprised of packages to merge.
+               mybigkey is the package spec of the package to merge.
+               myparent is the package depending on mybigkey ( or None )
+               addme = Should we add this package to the digraph or are we just looking at it's deps?
+                       Think --onlydeps, we need to ignore packages in that case.
                #stuff to add:
                #SLOT-aware emerge
-               #IUSE-aware emerge
+               #IUSE-aware emerge -> USE DEP aware depgraph
                #"no downgrade" emerge
-               #print "mybigkey:",mybigkey
-
-               jbigkey=string.join(mybigkey)
-               if self.digraph.hasnode(jbigkey+" merge") or self.digraph.hasnode(jbigkey+" nomerge"):
-                       #this conditional is needed to prevent infinite recursion on already-processed deps
+               """
+
+               jbigkey = " ".join(mybigkey) + " merge"
+               if self.digraph.hasnode(jbigkey):
+                       if addme and jbigkey != myparent:
+                               # Refuse to make a node depend on itself so that the we don't
+                               # don't create a bogus circular dependency in self.altlist().
+                               if rev_dep and myparent:
+                                       self.digraph.addnode(myparent, jbigkey, priority=priority)
+                               else:
+                                       self.digraph.addnode(jbigkey, myparent, priority=priority)
                        return 1
-
-               update_spinner()
-
+               jbigkey = " ".join(mybigkey) + " nomerge"
+               if self.digraph.hasnode(jbigkey):
+                       """XXX: It's possible that this package has been explicitly
+                       requested as a command line argument.  This can be solved by
+                       checking all args prior to marking packages as nomerge"""
+                       if rev_dep and myparent:
+                               self.digraph.addnode(myparent, jbigkey, priority=priority)
+                       else:
+                               self.digraph.addnode(jbigkey, myparent, priority=priority)
+                       return 1
+               
+               self.spinner.update()
                mytype,myroot,mykey=mybigkey
+               if mytype == "blocks":
+                       if addme and "--buildpkgonly" not in self.myopts and myparent:
+                               mybigkey[1] = myparent.split()[1]
+                               self.digraph.addnode(" ".join(mybigkey), myparent,
+                                       priority=priority)
+                       return 1
+               if not arg:
+                       arg = portage.best_match_to_list(mykey, self.args_keys)
                # select the correct /var database that we'll be checking against
-               vardbapi=portage.db[myroot]["vartree"].dbapi
+               vardbapi = self.trees[myroot]["vartree"].dbapi
+               portdb = self.trees[myroot]["porttree"].dbapi
+               bindb = self.trees[myroot]["bintree"].dbapi
+               pkgsettings = self.pkgsettings[myroot]
 
                # if the package is already on the system, we add a "nomerge"
                # directive, otherwise we add a "merge" directive.
-               if mytype=="blocks":
-                       # we've encountered a "blocks" node.  We will totally ignore this
-                       # node and not add it to our digraph if it doesn't apply to us.
-                       if addme and "--buildpkgonly" not in myopts and myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)):
-                               mybigkey.append(myparent.split()[2])
-                               self.digraph.addnode(string.join(mybigkey),myparent)
-                       return 1
 
-               if myuse == None:
-                       self.pkgsettings.setcpv(mykey)
-                       myuse = self.pkgsettings["USE"].split()
-               self.applied_useflags[mykey] = myuse
+               mydbapi = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi
+
+               if myuse is None:
+                       self.pkgsettings[myroot].setcpv(mykey)
+                       myuse = self.pkgsettings[myroot]["USE"].split()
+               self.useFlags[myroot][mykey] = myuse
 
                merging=1
-               if addme:
+               if mytype == "installed":
+                       merging = 0
+               if addme and mytype != "installed":
                # this is where we add the node to the list of packages to merge
-                       if not myparent:
-                               # command-line specified or part of a world list...
-                               if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)):
-                                       # the package is on the system, so don't merge it.
+                       if "selective" in self.myparams or not arg:
+                               if "empty" not in self.myparams and vardbapi.cpv_exists(mykey):
                                        merging=0
-                       elif ("selective" in myparams) and vardbapi.cpv_exists(mykey):
-                               merging=0
 
-                       if (merging==0 and "--newuse" in myopts and vardbapi.cpv_exists(mykey)):
+                       """ If we aren't merging, perform the --newuse check.
+                           If the package has new iuse flags or different use flags then if
+                           --newuse is specified, we need to merge the package. """
+                       if merging==0 and "--newuse" in self.myopts and \
+                               vardbapi.cpv_exists(mykey):
+                               pkgsettings.setcpv(mykey)
+                               forced_flags = set()
+                               forced_flags.update(pkgsettings.useforce)
+                               forced_flags.update(pkgsettings.puseforce)
+                               forced_flags.update(pkgsettings.usemask)
+                               forced_flags.update(pkgsettings.pusemask)
                                old_use = vardbapi.aux_get(mykey, ["USE"])[0].split()
-                               if mytype == "binary":
-                                       iuses = portage.db["/"]["bintree"].dbapi.aux_get(mykey, ["IUSE"])[0].split()
-                               else:
-                                       iuses = portage.db["/"]["porttree"].dbapi.aux_get(mykey, ["IUSE"])[0].split()
-                               for x in iuses:
-                                       if (old_use.count(x) and not myuse.count(x)) or (not old_use.count(x) and myuse.count(x)):
-                                               merging=1
-                                               break
-               else:
-                       #onlydeps mode; don't merge
-                       merging=2
-               if merging==1:
+                               iuses = set(mydbapi.aux_get(mykey, ["IUSE"])[0].split())
+                               old_iuse = set(vardbapi.aux_get(mykey, ["IUSE"])[0].split())
+                               if iuses.symmetric_difference(
+                                       old_iuse).difference(forced_flags):
+                                       merging = 1
+                               elif old_iuse.intersection(old_use) != \
+                                       iuses.intersection(myuse):
+                                       merging=1
+
+               if addme and merging == 1:
                        mybigkey.append("merge")
                else:
                        mybigkey.append("nomerge")
 
-               # whatever the case, we need to add the node to our digraph so
-               # that children can depend upon it.
-               self.digraph.addnode(string.join(mybigkey),myparent)
-               if ("deep" not in myparams) and (not merging):
+               if merging == 0 and vardbapi.cpv_exists(mykey):
+                       myuse = vardbapi.aux_get(mykey, ["USE"])[0].split()
+                       self.useFlags[myroot][mykey] = myuse
+
+               """ At this point, we have either hit a blocker and returned, found the package in the
+                   depgraph already and returned, or we are here.  Whether we are merging or not; we must
+                   add the package to the depgraph; so we do that here. """
+               if rev_dep and myparent:
+                       self.digraph.addnode(myparent, " ".join(mybigkey),
+                               priority=priority)
+               else:
+                       self.digraph.addnode(" ".join(mybigkey), myparent,
+                               priority=priority)
+               
+               """ This section determines whether we go deeper into dependencies or not.
+                   We want to go deeper on a few occasions:
+                   Installing package A, we need to make sure package A's deps are met.
+                   emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
+                   If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
+               """
+               if "deep" not in self.myparams and not merging and \
+                       not ("--update" in self.myopts and arg and merging):
                        return 1
-               elif "recurse" not in myparams:
+               elif "recurse" not in self.myparams:
                        return 1
 
+               """ Check DEPEND/RDEPEND/PDEPEND/SLOT
+               Pull from bintree if it's binary package, porttree if it's ebuild.
+               Binpkg's can be either remote or local. """
+
                edepend={}
-               if mytype=="binary":
-                       mypkgparts=portage.catpkgsplit(mykey)
-                       tbz2name = string.split(mykey, "/")[1]+".tbz2"
-                       if tbz2name in portage.db[portage.root]["bintree"].invalids:
-                               sys.stderr.write("\nINVALID PACKAGE (is required to continue): "+str(mykey)+"\n")
-                               sys.exit(1)
-                       if portage.db[portage.root]["bintree"].isremote(mykey):
-                               edepend = portage.db[portage.root]["bintree"].remotepkgs[tbz2name]
-                               edepend["DEPEND"] =""
-                               edepend["RDEPEND"]=string.join(string.split(edepend["RDEPEND"])," ")
-                               edepend["PDEPEND"]=string.join(string.split(edepend["PDEPEND"])," ")
-                               edepend["SLOT"]   =string.strip(edepend["SLOT"])
-                               #portage.db[portage.root]["bintree"].gettbz2(mykey)
-                       else: # It's local.
-                               mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey))
-                               edepend["DEPEND"] =""
-                               edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ")
-                               edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ")
-                               edepend["SLOT"]   =mytbz2.getfile("SLOT",mypkgparts[2])
-               elif mytype=="ebuild":
-                       try:
-                               mymeta = ["DEPEND","RDEPEND","PDEPEND"]
-                               myfoo = portage.portdb.aux_get(mykey, mymeta)
-                               for index in range(0,len(mymeta)):
-                                       edepend[mymeta[index]] = myfoo[index]
-                               if "--buildpkgonly" in myopts:
-                                       edepend["RDEPEND"] = ""
-                                       edepend["PDEPEND"] = ""
-                       except (KeyError,IOError):
-                               print "emerge: create(): aux_get() error on",mykey+"; aborting..."
-                               sys.exit(1)
-               mydep={}
+               depkeys = ["DEPEND","RDEPEND","PDEPEND"]
+               depvalues = mydbapi.aux_get(mykey, depkeys)
+               for i in xrange(len(depkeys)):
+                       edepend[depkeys[i]] = depvalues[i]
+
+               if mytype == "ebuild":
+                       if "--buildpkgonly" in self.myopts:
+                               edepend["RDEPEND"] = ""
+                               edepend["PDEPEND"] = ""
+               if self.myopts.get("--with-bdeps", "n") == "n" and \
+                       (mytype == "binary" or mybigkey[3] == "nomerge"):
+                       edepend["DEPEND"] = ""
+
+               """ We have retrieve the dependency information, now we need to recursively
+                   process them.  DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """
+               
                mp=string.join(mybigkey)
 
-               if myroot=="/":
-                       mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"]
-                       if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse):
-                               return 0
-               else:
-                       mydep["/"]=edepend["DEPEND"]
-                       mydep[myroot]=edepend["RDEPEND"]
-                       if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse):
-                               return 0
-                       if not self.select_dep(myroot,mydep[myroot],myparent=mp,myuse=myuse):
+               try:
+                       if not self.select_dep("/", edepend["DEPEND"], myparent=mp,
+                               myuse=myuse, parent_arg=arg):
                                return 0
-
-               if edepend.has_key("PDEPEND") and edepend["PDEPEND"]:
-                       # Post Depend -- Add to the list without a parent, as it depends
-                       # on a package being present AND must be built after that package.
-                       if not self.select_dep(myroot,edepend["PDEPEND"],myuse=myuse):
+                       """RDEPEND is soft by definition.  However, in order to ensure
+                       correct merge order, we make it a hard dependency.  Otherwise, a
+                       build time dependency might not be usable due to it's run time
+                       dependencies not being installed yet.
+                       """
+                       if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp,
+                               myuse=myuse, priority=digraph.MEDIUM, parent_arg=arg):
                                return 0
-
+                       if edepend.has_key("PDEPEND") and edepend["PDEPEND"]:
+                               # Post Depend -- Add to the list without a parent, as it depends
+                               # on a package being present AND must be built after that package.
+                               if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp,
+                                       myuse=myuse, priority=digraph.SOFT, rev_deps=True, parent_arg=arg):
+                                       return 0
+               except ValueError, e:
+                       pkgs = e.args[0]
+                       portage.writemsg("\n\n!!! An atom in the dependencies " + \
+                               "is not fully-qualified. Multiple matches:\n\n", noiselevel=-1)
+                       for cpv in pkgs:
+                               portage.writemsg("    %s\n" % cpv, noiselevel=-1)
+                       portage.writemsg("\n", noiselevel=-1)
+                       if mytype == "binary":
+                               portage.writemsg(
+                                       "!!! This binary package cannot be installed: '%s'\n" % \
+                                       mykey, noiselevel=-1)
+                       elif mytype == "ebuild":
+                               myebuild, mylocation = portdb.findname2(mykey)
+                               portage.writemsg("!!! This ebuild cannot be installed: " + \
+                                       "'%s'\n" % myebuild, noiselevel=-1)
+                       portage.writemsg("!!! Please notify the package maintainer " + \
+                               "that atoms must be fully-qualified.\n", noiselevel=-1)
+                       return 0
                return 1
 
        def select_files(self,myfiles):
                "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list"
                myfavorites=[]
+               myroot = self.target_root
+               portdb = self.trees[myroot]["porttree"].dbapi
+               bindb = self.trees[myroot]["bintree"].dbapi
+               pkgsettings = self.pkgsettings[myroot]
+               arg_atoms = []
                for x in myfiles:
                        ext = os.path.splitext(x)[1]
                        if ext==".tbz2":
                                if not os.path.exists(x):
-                                       if os.path.exists(self.pkgsettings["PKGDIR"]+"/All/"+x):
-                                               x=self.pkgsettings["PKGDIR"]+"/All/"+x
-                                       elif os.path.exists(self.pkgsettings["PKGDIR"]+"/"+x):
-                                               x=self.pkgsettings["PKGDIR"]+"/"+x
+                                       if os.path.exists(
+                                               os.path.join(pkgsettings["PKGDIR"], "All", x)):
+                                               x = os.path.join(pkgsettings["PKGDIR"], "All", x)
+                                       elif os.path.exists(
+                                               os.path.join(pkgsettings["PKGDIR"], x)):
+                                               x = os.path.join(pkgsettings["PKGDIR"], x)
                                        else:
                                                print "\n\n!!! Binary package '"+str(x)+"' does not exist."
                                                print "!!! Please ensure the tbz2 exists as specified.\n"
                                                sys.exit(1)
                                mytbz2=xpak.tbz2(x)
                                mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
-                               if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x):
-                                       print red("\n*** You need to adjust PKGDIR to emerge this package.\n")
+                               if os.path.realpath(x) != \
+                                       os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)):
+                                       print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n")
                                        sys.exit(1)
-                               if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts):
+                               if not self.create(["binary", myroot, mykey],
+                                       None, "--onlydeps" not in self.myopts):
                                        return (0,myfavorites)
-                               elif not "--oneshot" in myopts:
+                               elif not "--oneshot" in self.myopts:
                                        myfavorites.append(mykey)
                        elif ext==".ebuild":
                                x = os.path.realpath(x)
                                mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
-                               ebuild_path = portage.db["/"]["porttree"].dbapi.findname(mykey)
+                               ebuild_path = portdb.findname(mykey)
                                if ebuild_path:
                                        if os.path.realpath(ebuild_path) != x:
-                                               print red("\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
+                                               print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
                                                sys.exit(1)
-                                       if mykey not in portage.db["/"]["porttree"].dbapi.xmatch("match-visible", portage.dep_getkey(mykey)):
-                                               print red("\n*** You are emerging a masked package. It is MUCH better to use")
-                                               print red("*** /etc/portage/package.* to accomplish this. See portage(5) man")
-                                               print red("*** page for details.")
-                                               countdown(EMERGE_WARNING_DELAY, "Continuing...")
+                                       if mykey not in portdb.xmatch(
+                                               "match-visible", portage.dep_getkey(mykey)):
+                                               print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use")
+                                               print colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man")
+                                               print colorize("BAD", "*** page for details.")
+                                               countdown(int(self.settings["EMERGE_WARNING_DELAY"]),
+                                                       "Continuing...")
                                else:
-                                       print red("\n*** %s is not in a valid PORTDIR heirarchy or does not exist" % x)
-                                       sys.exit(1)
-                               if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts):
+                                       raise portage_exception.PackageNotFound(
+                                               "%s is not in a valid portage tree hierarchy or does not exist" % x)
+                               if not self.create(["ebuild", myroot, mykey],
+                                       None, "--onlydeps" not in self.myopts):
                                        return (0,myfavorites)
-                               elif not "--oneshot" in myopts:
+                               elif not "--oneshot" in self.myopts:
                                        myfavorites.append(mykey)
                        else:
                                if not is_valid_package_atom(x):
-                                       portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x)
+                                       portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
+                                               noiselevel=-1)
                                        portage.writemsg("!!! Please check ebuild(5) for full details.\n")
                                        portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
                                        return (0,[])
                                try:
-                                       mykey=portage.dep_expand(x,mydb=portage.portdb)
+                                       mykey = None
+                                       if "--usepkg" in self.myopts:
+                                               mykey = portage.dep_expand(x, mydb=bindb,
+                                                       settings=pkgsettings)
+                                       if (mykey and not mykey.startswith("null/")) or \
+                                               "--usepkgonly" in self.myopts:
+                                               arg_atoms.append((x, mykey))
+                                               continue
+
+                                       mykey = portage.dep_expand(x,
+                                               mydb=portdb, settings=pkgsettings)
+                                       arg_atoms.append((x, mykey))
                                except ValueError, errpkgs:
                                        print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous.  Please specify"
                                        print "!!! one of the following fully-qualified ebuild names instead:\n"
@@ -1097,149 +948,292 @@ class depgraph:
                                        print
                                        sys.exit(1)
 
-                               # select needs to return 0 on dep_check failure
-
-                               sys.stdout.flush()
-                               sys.stderr.flush()
-
+               if "--update" in self.myopts:
+                       """Make sure all installed slots are updated when possible. Do this
+                       with --emptytree also, to ensure that all slots are remerged."""
+                       vardb = self.trees[self.target_root]["vartree"].dbapi
+                       greedy_atoms = []
+                       for myarg, myatom in arg_atoms:
+                               greedy_atoms.append((myarg, myatom))
+                               myslots = set()
+                               for cpv in vardb.match(myatom):
+                                       myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
+                               if len(myslots) > 1:
+                                       for myslot in myslots:
+                                               myslot_atom = "%s:%s" % \
+                                                       (portage.dep_getkey(myatom), myslot)
+                                               available = False
+                                               if "--usepkgonly" not in self.myopts and \
+                                                       self.trees[self.target_root][
+                                                       "porttree"].dbapi.match(myslot_atom):
+                                                       available = True
+                                               elif "--usepkg" in self.myopts and \
+                                                       self.trees[self.target_root][
+                                                       "bintree"].dbapi.match(myslot_atom):
+                                                       available = True
+                                               if available:
+                                                       greedy_atoms.append((myarg, myslot_atom))
+                       arg_atoms = greedy_atoms
+
+               """ These are used inside self.create() in order to ensure packages
+               that happen to match arguments are not incorrectly marked as nomerge."""
+               self.args_keys = [x[1] for x in arg_atoms]
+               for myarg, myatom in arg_atoms:
                                try:
-                                       self.mysd = self.select_dep(portage.root,mykey,arg=x)
+                                       self.mysd = self.select_dep(myroot, myatom, arg=myarg)
                                except portage_exception.MissingSignature, e:
                                        portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n")
                                        portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
                                        portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
                                        portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
-                                       portage.writemsg("!!! Affected file: %s\n" % (e))
+                                       portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
                                        sys.exit(1)
                                except portage_exception.InvalidSignature, e:
                                        portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n")
                                        portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
                                        portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
                                        portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
-                                       portage.writemsg("!!! Affected file: %s\n" % (e))
+                                       portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
                                        sys.exit(1)
                                except SystemExit, e:
                                        raise # Needed else can't exit
                                except Exception, e:
-                                       if "--debug" in myopts:
-                                               raise
-                                       print "\n\n!!! Problem in",mykey,"dependencies."
-                                       print "!!!",str(e),e.__module__
-                                       sys.exit(1)
+                                       print >> sys.stderr, "\n\n!!! Problem in '%s' dependencies." % mykey
+                                       print >> sys.stderr, "!!!", str(e), e.__module__
+                                       raise
 
                                if not self.mysd:
                                        return (0,myfavorites)
-                               elif not "--oneshot" in myopts:
-                                       myfavorites.append(portage.dep_getkey(mykey))
+                               elif not "--oneshot" in self.myopts:
+                                       mykey = portage.dep_getkey(myatom)
+                                       if mykey not in myfavorites:
+                                               myfavorites.append(mykey)
 
                missing=0
-               if "--usepkgonly" in myopts:
-                       for x in self.digraph.dict.keys():
-                               xs=string.split(x," ")
-                               if (xs[0] != "binary") and (xs[3]=="merge"):
+               if "--usepkgonly" in self.myopts:
+                       for x in self.digraph.all_nodes():
+                               xs = x.split()
+                               if len(xs) >= 4 and xs[0] != "binary" and xs[3] == "merge":
                                        if missing == 0:
                                                print
                                        missing += 1
                                        print "Missing binary for:",xs[2]
 
+               self.validate_blockers()
+               
                # We're true here unless we are missing binaries.
                return (not missing,myfavorites)
 
        def is_newer_ver_installed(self,myroot,pkg,pkgver):
                "if there is a version of pkg installed newer than pkgver, return it"
-               vardbapi=portage.db[myroot]["vartree"].dbapi
+               vardbapi = self.trees[myroot]["vartree"].dbapi
 
-               matches=portage.db[myroot]["vartree"].dbapi.match(pkg)
+               matches = self.trees[myroot]["vartree"].dbapi.match(pkg)
                if matches:
-                       myslot=portage.db["/"]["porttree"].getslot(pkgver)
+                       myslot = self.trees[myroot]["porttree"].getslot(pkgver)
                        for match in matches:
                                if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(match)[1:]) < 0:
-                                       curslot=portage.db[myroot]["vartree"].getslot(match)
+                                       curslot = self.trees[myroot]["vartree"].getslot(match)
                                        if curslot == myslot:
                                                return match
 
-       def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None,raise_on_missing=False):
-               "given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure"
-               if "--debug" in myopts:
+       def select_dep(self, myroot, depstring, myparent=None, arg=None,
+               myuse=None, raise_on_missing=False, priority=digraph.HARD, rev_deps=False,
+               parent_arg=None):
+               """ Given a depstring, create the depgraph such that all dependencies are satisfied.
+                   myroot = $ROOT from environment, where {R,P}DEPENDs are merged to.
+                   myparent = the node whose depstring is being passed in
+                   arg = package was specified on the command line, merge even if it's already installed
+                   myuse = USE flags at present
+                   raise_on_missing = Given that the depgraph is not proper, raise an exception if true
+                   else continue trying.
+                   return 1 on success, 0 for failure
+               """
+
+               portdb = self.trees[myroot]["porttree"].dbapi
+               bindb  = self.trees[myroot]["bintree"].dbapi
+               vardb  = self.trees[myroot]["vartree"].dbapi
+               pkgsettings = self.pkgsettings[myroot]
+
+               if "--debug" in self.myopts:
                        print
                        print "Parent:   ",myparent
                        print "Depstring:",depstring
-               if not arg:
-                       #processing dependencies
-                       mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkgonly" in myopts),myroot=myroot)
-
-                       if not mycheck[0]:
-                               mymerge=[]
-                       else:
-                               mymerge=mycheck[1]
-
-               else:
-                       #we're processing a command-line argument; unconditionally merge it even if it's already merged
-                       mymerge=[depstring]
+                       if rev_deps:
+                               print "Reverse:", rev_deps
+                       print "Priority:", priority
+
+               #processing dependencies
+               """ Call portage.dep_check to evaluate the use? conditionals and make sure all
+               dependencies are satisfiable. """
+               mycheck = portage.dep_check(depstring, self.mydbapi[myroot],
+                       pkgsettings, myuse=myuse,
+                       use_binaries=("--usepkgonly" in self.myopts),
+                       myroot=myroot, trees=self.trees, return_all_deps=True)
+
+               if not mycheck[0]:
+                       sys.stderr.write("\n\n%s\n\n" % mycheck[1])
+                       sys.stderr.write("%s\n\n" % depstring)
+                       return 0
+               mymerge = mycheck[1]
 
-               # dep_check has been run so we can now add our parent to our
-               # build state to update virtuals and other settings. This
-               # happens after the package is added to the tree so that a
-               # package can depend on a virtual which it satisfies.
                if myparent:
-                       myp = myparent.split()
-                       if myp[3]=="merge":
-                               self.mydbapi[myroot].cpv_inject(myp[2])
-                               if myp[0]=="binary":
-                                       self.pkgsettings.setinst(myp[2],portage.db["/"]["bintree"].dbapi)
-                               else:
-                                       self.pkgsettings.setinst(myp[2],portage.db[myroot]["porttree"].dbapi)
-
-               if not mymerge:
-                       return 1
-
-               if "--debug" in myopts:
+                       # In order to get past circular dependencies (in
+                       # `emerge -e world`, for example), the parent must be allowed
+                       # to satisfy dependencies of it's children.
+
+                       # The parent is added after it's own dep_check call so that it
+                       # isn't allowed to satisfy a direct bootstrap dependency on itself
+                       # or an old-style virtual that it satisfies (unfortunately, this
+                       # only works for one level of deps, so it won't work for new-style
+                       # virtuals since they introduce an additional level of dependency
+                       # indirection).
+
+                       p_type, p_root, p_key, p_status = myparent.split()
+                       if p_status == "merge":
+                               """ This fakedbapi data is used in dep_check calls to determine
+                               satisfied deps via dep_wordreduce"""
+                               myslot = self.trees[p_root][
+                                       self.pkg_tree_map[p_type]].dbapi.aux_get(
+                                               p_key, ["SLOT"])[0]
+                               self.mydbapi[p_root].cpv_inject(p_key, myslot=myslot)
+
+                               # Update old-style virtuals if this package provides any.
+                               # These are needed for dep_virtual calls inside dep_check.
+                               self.pkgsettings[p_root].setinst(p_key,
+                                       self.trees[p_root][self.pkg_tree_map[p_type]].dbapi)
+
+               if "--debug" in self.myopts:
                        print "Candidates:",mymerge
                for x in mymerge:
-                       myk=None
-                       binpkguseflags=None
+                       selected_pkg = None
                        if x[0]=="!":
                                # if this package is myself, don't append it to block list.
-                               if "--debug" in myopts:
+                               if "--debug" in self.myopts:
                                        print "Myparent",myparent
                                if (myparent):
-                                       if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]):
+                                       if myparent.split()[2] in \
+                                               portdb.xmatch("match-all", x[1:]):
                                                # myself, so exit.
                                                continue
                                # adding block
-                               myk=["blocks",myroot,x[1:]]
+                               selected_pkg = ["blocks", myroot, x[1:], None]
                        else:
                                #We are not processing a blocker but a normal dependency
-                               myeb=None
-                               myeb_matches = portage.portdb.xmatch("match-visible",x)
-                               if ("--usepkgonly" not in myopts):
-                                       myeb=portage.best(myeb_matches)
+                               if myparent:
+                                       """In some cases, dep_check will return deps that shouldn't
+                                       be proccessed any further, so they are identified and
+                                       discarded here."""
+                                       if "empty" not in self.myparams and \
+                                               "deep" not in self.myparams and \
+                                               not ("--update" in self.myopts and parent_arg) and \
+                                               vardb.match(x):
+                                               continue
+
+                                       pkg_key = portage.dep_getkey(x)
+                                       if pkg_key in pkgsettings.pprovideddict and \
+                                               portage.match_from_list(
+                                                       x, pkgsettings.pprovideddict[pkg_key]):
+                                                       continue
+
+                               # List of acceptable packages, ordered by type preference.
+                               matched_packages = []
+                               myeb_matches = portdb.xmatch("match-visible", x)
+                               myeb = None
+                               if "--usepkgonly" not in self.myopts:
+                                       myeb = portage.best(myeb_matches)
 
                                myeb_pkg=None
-                               if ("--usepkg" in myopts):
+                               if "--usepkg" in self.myopts:
                                        # The next line assumes the binarytree has been populated.
                                        # XXX: Need to work out how we use the binary tree with roots.
-                                       myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x)
-                                       if ("--usepkgonly" not in myopts):
+                                       myeb_pkg_matches = bindb.match(x)
+                                       if "--usepkgonly" not in self.myopts:
                                                # Remove any binary package entries that are masked in the portage tree (#55871)
-                                               for idx in range(len(myeb_pkg_matches)-1,-1,-1):
-                                                       if myeb_pkg_matches[idx] not in myeb_matches:
-                                                               del myeb_pkg_matches[idx]
-                                       myeb_pkg = portage.best(myeb_pkg_matches)
-
-                               if not myeb_pkg:
-                                       myeb_pkg = None
-                               elif ("--newuse" in myopts):
-                                       iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["IUSE"])[0])
-                                       old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["USE"])[0])
-                                       self.pkgsettings.setcpv(myeb_pkg)
-                                       now_use=string.split(self.pkgsettings["USE"])
-                                       for x in iuses:
-                                               if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)):
-                                                       myeb_pkg = None
-                                                       break
-
-                               if (not myeb) and (not myeb_pkg):
+                                               myeb_pkg_matches = [pkg for pkg in myeb_pkg_matches \
+                                                       if pkg in myeb_matches or  \
+                                                       not portdb.cpv_exists(pkg)]
+                                       if myeb_pkg_matches:
+                                               myeb_pkg = portage.best(myeb_pkg_matches)
+
+                               if myeb_pkg and "--newuse" in self.myopts:
+                                       iuses = set(bindb.aux_get(myeb_pkg, ["IUSE"])[0].split())
+                                       old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split()
+                                       pkgsettings.setcpv(myeb_pkg)
+                                       now_use = pkgsettings["USE"].split()
+                                       forced_flags = set()
+                                       forced_flags.update(pkgsettings.useforce)
+                                       forced_flags.update(pkgsettings.puseforce)
+                                       forced_flags.update(pkgsettings.usemask)
+                                       forced_flags.update(pkgsettings.pusemask)
+                                       cur_iuse = iuses
+                                       if "--usepkgonly" not in self.myopts and myeb:
+                                               cur_iuse = set(portdb.aux_get(myeb, ["IUSE"])[0].split())
+                                       if iuses.symmetric_difference(
+                                               cur_iuse).difference(forced_flags):
+                                               myeb_pkg = None
+                                       elif iuses.intersection(old_use) != \
+                                               cur_iuse.intersection(now_use):
+                                               myeb_pkg = None
+                               if myeb_pkg:
+                                       binpkguseflags = \
+                                               self.trees[myroot]["bintree"].dbapi.aux_get(
+                                                       myeb_pkg, ["USE"])[0].split()
+                                       matched_packages.append(
+                                               ["binary", myroot, myeb_pkg, binpkguseflags])
+
+                               if "--usepkgonly" not in self.myopts and myeb_matches:
+                                       matched_packages.append(
+                                               ["ebuild", myroot, myeb, None])
+
+                               if not matched_packages:
+                                       """Fall back to the installed package database.  This is a
+                                       last resort because the metadata tends to diverge from that
+                                       of the ebuild in the tree."""
+                                       myeb_inst_matches = vardb.match(x)
+                                       if "--usepkgonly" not in self.myopts:
+                                               """ TODO: Improve masking check for installed and
+                                               binary packages. bug #149816"""
+                                               myeb_inst_matches = [pkg for pkg in myeb_inst_matches \
+                                                       if not portdb.cpv_exists(pkg)]
+                                       myeb_inst = None
+                                       if myeb_inst_matches:
+                                               myeb_inst = portage.best(myeb_inst_matches)
+                                       if myeb_inst:
+                                               binpkguseflags = vardb.aux_get(
+                                                       myeb_inst, ["USE"])[0].split()
+                                               matched_packages.append(
+                                                       ["installed", myroot, myeb_inst, binpkguseflags])
+                                               """Now make sure that *DEPEND atoms are up to date.
+                                               This is done on the fly for single packages only when
+                                               necessary, since it can be time consuming to run this
+                                               on all installed packages."""
+                                               from portage_update import grab_updates, \
+                                                       parse_updates, update_dbentries
+                                               if myroot not in self.global_updates:
+                                                       updpath = os.path.join(
+                                                               pkgsettings["PORTDIR"], "profiles", "updates")
+                                                       try:
+                                                               rawupdates = grab_updates(updpath)
+                                                       except portage_exception.DirectoryNotFound:
+                                                               rawupdates = []
+                                                       upd_commands = []
+                                                       for mykey, mystat, mycontent in rawupdates:
+                                                               commands, errors = parse_updates(mycontent)
+                                                               upd_commands.extend(commands)
+                                                       del updpath, rawupdates
+                                                       self.global_updates[myroot] = upd_commands
+                                               upd_commands = self.global_updates[myroot]
+                                               aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
+                                               aux_vals = vardb.aux_get(myeb_inst, aux_keys)
+                                               aux_dict = dict(zip(aux_keys, aux_vals))
+                                               updates = update_dbentries(upd_commands, aux_dict)
+                                               if updates:
+                                                       vardb.aux_update(myeb_inst, updates)
+                                               del binpkguseflags, myeb_inst, upd_commands, \
+                                                       aux_keys, aux_vals, aux_dict, updates
+
+                               if not matched_packages:
                                        if raise_on_missing:
                                                raise ValueError
                                        if not arg:
@@ -1248,16 +1242,18 @@ class depgraph:
                                                xinfo='"'+arg+'"'
                                        if myparent:
                                                xfrom = '(dependency required by '+green('"'+myparent.split()[2]+'"')+red(' ['+myparent.split()[0]+"]")+')'
-                                       alleb=portage.portdb.xmatch("match-all",x)
+                                       alleb = portdb.xmatch("match-all", x)
                                        if alleb:
-                                               if "--usepkgonly" not in myopts:
+                                               if "--usepkgonly" not in self.myopts:
                                                        print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.")
                                                        print "!!! One of the following masked packages is required to complete your request:"
                                                        oldcomment = ""
                                                        for p in alleb:
-                                                               mreasons = portage.getmaskingstatus(p)
+                                                               mreasons = portage.getmaskingstatus(p,
+                                                                       settings=pkgsettings, portdb=portdb)
                                                                print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")"
-                                                               comment = portage.getmaskingreason(p)
+                                                               comment = portage.getmaskingreason(p,
+                                                                       settings=pkgsettings, portdb=portdb)
                                                                if comment and comment != oldcomment:
                                                                        print comment
                                                                        oldcomment = comment
@@ -1274,102 +1270,136 @@ class depgraph:
                                        print
                                        return 0
 
-                               if "--debug" in myopts:
-                                       print "ebuild:",myeb
-                                       print "binpkg:",myeb_pkg
+                               if "--debug" in self.myopts:
+                                       for pkg in matched_packages:
+                                               print (pkg[0] + ":").rjust(10), pkg[2]
 
-                               if myeb and myeb_pkg:
-                                       myeb_s     = portage.catpkgsplit(myeb)
-                                       myeb_s     = [myeb_s[0]+"/"+myeb_s[1], myeb_s[2], myeb_s[3]]
-                                       myeb_pkg_s = portage.catpkgsplit(myeb_pkg)
-                                       myeb_pkg_s = [myeb_pkg_s[0]+"/"+myeb_pkg_s[1], myeb_pkg_s[2], myeb_pkg_s[3]]
+                               if len(matched_packages) > 1:
+                                       bestmatch = portage.best(
+                                               [pkg[2] for pkg in matched_packages])
+                                       matched_packages = [pkg for pkg in matched_packages \
+                                               if pkg[2] == bestmatch]
 
-                                       if portage.pkgcmp(myeb_s, myeb_pkg_s) == 0: # pkg is same version as ebuild
-                                               myeb = None
-                                       else:
-                                               myeb_pkg = None
+                               # ordered by type preference ("ebuild" type is the last resort)
+                               selected_pkg =  matched_packages[0]
 
-                               if myeb:
-                                       myk=["ebuild",myroot,myeb]
-                               elif myeb_pkg:
-                                       binpkguseflags=portage.db[portage.root]["bintree"].get_use(myeb_pkg)
-                                       myk=["binary",myroot,myeb_pkg]
-                               else:
-                                       sys.stderr.write("!!! Confused... Don't know what's being used for dependency info. :(\n")
-                                       sys.exit(1)
-
-                               #if "--usepkg" in myopts:
-                               #       #If we want to use packages, see if we have a pre-built one...
-                               #       mypk=portage.db["/"]["bintree"].dbapi.match(x)
-                               #       if myeb in mypk:
-                               #               #Use it only if it's exactly the version we want.
-                               #               myk=["binary",myroot,myeb]
-                               #       else:
-                               #               myk=["ebuild",myroot,myeb]
-                               #else:
-                               #       myk=["ebuild",myroot,myeb]
                        if myparent:
                                #we are a dependency, so we want to be unconditionally added
-                               if not self.create(myk,myparent,myuse=binpkguseflags):
+                               mypriority = priority
+                               if mypriority > digraph.SOFT and vardb.match(x):
+                                       mypriority = digraph.SOFT
+                               if not self.create(selected_pkg[0:3], myparent,
+                                       myuse=selected_pkg[-1], priority=mypriority,
+                                       rev_dep=rev_deps, arg=arg):
                                        return 0
                        else:
                                #if mysource is not set, then we are a command-line dependency and should not be added
                                #if --onlydeps is specified.
-                               if not self.create(myk,myparent,"--onlydeps" not in myopts,myuse=binpkguseflags):
+                               if not self.create(selected_pkg[0:3], myparent,
+                                       addme=("--onlydeps" not in self.myopts),
+                                       myuse=selected_pkg[-1], rev_dep=rev_deps, arg=arg):
                                        return 0
 
-               if "--debug" in myopts:
+               if "--debug" in self.myopts:
                        print "Exiting...",myparent
                return 1
 
-
-       def altlist(self):
+       def validate_blockers(self):
+               """Remove any blockers from the digraph that do not match any of the
+               packages within the graph.  Blockers are only matched against the
+               final state of the graph.  Thus, it's possible that mutually blocking
+               packages will be installed simultaneously a some point(s) during the
+               transition from the initial to the final state."""
+
+               """ It's possible that some of the nodes haven't been added to the
+               fakedb yet, so make sure they're all accounted for."""
+               for node in self.digraph.all_nodes():
+                       node_split = node.split()
+                       mytype, myroot, mykey = node_split[0:3]
+                       if mytype in self.pkg_tree_map:
+                               mydb = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi
+                               myslot = mydb.aux_get(mykey, ["SLOT"])[0]
+                               self.mydbapi[myroot].cpv_inject(mykey, myslot=myslot)
+
+               all_blockers = [node for node in self.digraph.all_nodes()
+                               if node.split()[0] == "blocks"]
+               for blocker in all_blockers:
+                       mytype, myroot, mydep = blocker.split()
+                       """Prior to being added to the digraph, any blockers against
+                       old-style virtuals have been expanded to real packages via
+                       dep_virtual calls inside dep_check."""
+                       if not self.mydbapi[myroot].match(mydep):
+                               self.digraph.remove(blocker)
+
+       def altlist(self, reversed=False):
                mygraph=self.digraph.copy()
-               dolist=["/"]
                retlist=[]
-               for x in portage.db.keys():
-                       portage.db[x]["merge"]=[]
-                       if x not in dolist:
-                               dolist.append(x)
-               while (not mygraph.empty()):
-                       mycurkey=mygraph.firstzero()
-                       if not mycurkey:
+               if reversed:
+                       get_nodes = mygraph.root_nodes
+               else:
+                       get_nodes = mygraph.leaf_nodes
+               while not mygraph.empty():
+                       for ignore_priority in \
+                               (digraph.NONE, digraph.SOFT, digraph.MEDIUM):
+                               nodes = get_nodes(ignore_priority=ignore_priority)
+                               if nodes:
+                                       break
+                       selected_nodes = None
+                       if nodes:
+                               if ignore_priority <= digraph.SOFT:
+                                       selected_nodes = [nodes[0]]
+                               else:
+                                       """Recursively gather a group of nodes that RDEPEND on
+                                       eachother.  This ensures that they are merged as a group
+                                       and get their RDEPENDs satisfied as soon as possible."""
+                                       def gather_deps(mergeable_nodes, selected_nodes, node):
+                                               if node in selected_nodes:
+                                                       return True
+                                               if node not in mergeable_nodes:
+                                                       return False
+                                               selected_nodes.add(node)
+                                               for child in mygraph.child_nodes(node,
+                                                       ignore_priority=digraph.SOFT):
+                                                       if not gather_deps(
+                                                               mergeable_nodes, selected_nodes, child):
+                                                               return False
+                                               return True
+                                       mergeable_nodes = set(nodes)
+                                       for node in nodes:
+                                               selected_nodes = set()
+                                               if gather_deps(
+                                                       mergeable_nodes, selected_nodes, node):
+                                                       break
+                                               else:
+                                                       selected_nodes = None
+
+                       if not selected_nodes:
                                print "!!! Error: circular dependencies:"
                                print
-                               for x in mygraph.dict.keys():
-                                       for y in mygraph.dict[x][1]:
-                                               print y,"depends on",x
-                               print
+                               mygraph.debug_print()
                                sys.exit(1)
-                       splitski=string.split(mycurkey)
-                       #I'm not sure of the significance of the following lines (vestigal?) so I'm commenting 'em out.
-                       #These lines remove already-merged things from our alt-list
-                       #if "--update" in myopts:
-                       #       if not portage.db["/"]["vartree"].exists_specific(splitski[2]):
-                       #               portage.db["/"]["merge"].append(splitski)
-                       #else:
-                       portage.db[splitski[1]]["merge"].append(splitski)
-                       mygraph.delnode(mycurkey)
-               for x in dolist:
-                       for y in portage.db[x]["merge"]:
-                               retlist.append(y)
+
+                       for node in selected_nodes:
+                               retlist.append(node.split())
+                               mygraph.remove(node)
+
                return retlist
 
        def xcreate(self,mode="system"):
-               global syslist
+               vardb = self.trees[self.target_root]["vartree"].dbapi
                world_problems = False
                if mode=="system":
-                       mylist=syslist
+                       mylist = getlist(self.settings, "system")
                else:
                        #world mode
-                       worldlist=getlist("world")
-                       sysdict=genericdict(syslist)
+                       worldlist = getlist(self.settings, "world")
+                       sysdict = genericdict(getlist(self.settings, "system"))
                        worlddict=genericdict(worldlist)
 
                        for x in worlddict.keys():
                                if not portage.isvalidatom(x):
                                        world_problems = True
-                               elif not portage.db["/"]["vartree"].dbapi.match(x):
+                               elif not self.trees[self.target_root]["vartree"].dbapi.match(x):
                                        world_problems = True
                                else:
                                        sysdict[x]=worlddict[x]
@@ -1378,36 +1408,61 @@ class depgraph:
 
                newlist = []
                for atom in mylist:
-                       if portage.dep_getkey(atom).split("/")[-1] == "portage":
+                       mykey = portage.dep_getkey(atom)
+                       if portage.catsplit(mykey)[-1] == "portage":
                                newlist.insert(0, atom)
                        else:
                                newlist.append(atom)
+                               """Make sure all installed slots are updated when possible.
+                               Do this with --emptytree also, to ensure that all slots are
+                               remerged."""
+                               myslots = set()
+                               for cpv in vardb.match(mykey):
+                                       myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
+                               if len(myslots) > 1:
+                                       for myslot in myslots:
+                                               myslot_atom = "%s:%s" % (mykey, myslot)
+                                               available = False
+                                               if "--usepkgonly" not in self.myopts and \
+                                                       self.trees[self.target_root][
+                                                       "porttree"].dbapi.match(myslot_atom):
+                                                       available = True
+                                               elif "--usepkg" in self.myopts and \
+                                                       self.trees[self.target_root][
+                                                       "bintree"].dbapi.match(myslot_atom):
+                                                       available = True
+                                               if available:
+                                                       newlist.append(myslot_atom)
                mylist = newlist
                
                missing_atoms = []
                for mydep in mylist:
                        try:
-                               if not self.select_dep(portage.root, mydep, raise_on_missing=True):
-                                       print "\n\n!!! Problem resolving dependencies for", mydep
+                               if not self.select_dep(
+                                       self.target_root, mydep, raise_on_missing=True, arg=mydep):
+                                       print >> sys.stderr, "\n\n!!! Problem resolving dependencies for", mydep
                                        return 0
                        except ValueError:
-                               if "--debug" in myopts:
-                                       raise
                                missing_atoms.append(mydep)
 
+               self.validate_blockers()
+
                if world_problems:
-                       print "\n!!! Problems have been detected with your world file"
-                       print "!!! Please run "+green("emaint --check world")+"\n"
+                       print >> sys.stderr, "\n!!! Problems have been detected with your world file"
+                       print >> sys.stderr, "!!! Please run "+green("emaint --check world")+"\n"
 
-               if missing_atoms and "--verbose" in myopts:
-                       print "\n!!! Packages for the following atoms are either all"
-                       print "!!! masked or don't exist:"
-                       print " ".join(missing_atoms) + "\n"
+               if missing_atoms:
+                       print >> sys.stderr, "\n" + colorize("BAD", "!!!") + \
+                               " Ebuilds for the following packages are either all"
+                       print >> sys.stderr, colorize("BAD", "!!!") + " masked or don't exist:"
+                       print >> sys.stderr, " ".join(missing_atoms) + "\n"
 
                return 1
 
-       def match(self,mydep,myroot=portage.root,mykey=None):
+       def match(self, mydep, myroot=None, mykey=None):
                # support mutual exclusive deps
+               if myroot is None:
+                       myroot = self.target_root
                mydep2=mydep
                if mydep2[0]=="!":
                        mydep2=mydep[1:]
@@ -1416,7 +1471,7 @@ class depgraph:
                        #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example)
                        myk="blocks "+myroot+" "+mydep2
                else:
-                       myeb=portage.db[portage.root]["porttree"].dep_bestmatch(mydep2)
+                       myeb = self.trees[myroot]["porttree"].dep_bestmatch(mydep2)
                        if not myeb:
                                if not mykey:
                                        print "\n!!! Error: couldn't find match for",mydep
@@ -1425,90 +1480,124 @@ class depgraph:
                                print
                                sys.exit(1)
 
-                       if "--usepkg" in myopts:
-                               mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep)
+                       if "--usepkg" in self.myopts:
+                               mypk = self.trees[myroot]["bintree"].dep_bestmatch(mydep)
                                if myeb==mypk:
-                                       myk="binary "+portage.root+" "+mypk
+                                       myk = " ".join(("binary", myroot, mypk))
                                else:
-                                       myk="ebuild "+myroot+" "+myeb
+                                       myk = " ".join(("ebuild", myroot, myeb))
                        else:
                                myk="ebuild "+myroot+" "+myeb
 
                return myk
 
-       def display(self,mylist,verbosity=("--quiet" in myopts and 1 or "--verbose" in myopts and 3 or 2)):
+       def display(self,mylist,verbosity=None):
+               if verbosity is None:
+                       verbosity = ("--quiet" in self.myopts and 1 or \
+                               "--verbose" in self.myopts and 3 or 2)
                changelogs=[]
                p=[]
                totalsize=0
 
-               if verbosity == 1:
+               if verbosity == 1 and "--verbose" not in self.myopts:
                        def create_use_string(*args):
                                return ""
                else:
-                       def create_use_string(name, cur_iuse, cur_use, old_iuse, old_use, is_new,
-                                       all_flags=(verbosity == 3), alphabetical=("--alphabetical" in myopts)):
+                       def create_use_string(name, cur_iuse, iuse_forced, cur_use,
+                               old_iuse, old_use,
+                               is_new, all_flags=(verbosity == 3 or "--quiet" in self.myopts),
+                               alphabetical=("--alphabetical" in self.myopts)):
                                enabled = []
                                if alphabetical:
                                        disabled = enabled
+                                       removed = enabled
                                else:
                                        disabled = []
-                               for flag in cur_iuse:
-                                       if flag in cur_use:
+                                       removed = []
+                               cur_iuse = set(cur_iuse)
+                               enabled_flags = cur_iuse.intersection(cur_use)
+                               removed_iuse = set(old_iuse).difference(cur_iuse)
+                               any_iuse = cur_iuse.union(old_iuse)
+                               any_iuse = list(any_iuse)
+                               any_iuse.sort()
+                               for flag in any_iuse:
+                                       flag_str = None
+                                       isEnabled = False
+                                       if flag in enabled_flags:
+                                               isEnabled = True
                                                if is_new or flag in old_use and all_flags:
-                                                       enabled.append(red(flag))
+                                                       flag_str = red(flag)
                                                elif flag not in old_iuse:
-                                                       enabled.append(yellow(flag)+"%")
+                                                       flag_str = yellow(flag) + "%*"
                                                elif flag not in old_use:
-                                                       enabled.append(green(flag)+"*")
+                                                       flag_str = green(flag) + "*"
+                                       elif flag in removed_iuse:
+                                               if all_flags:
+                                                       flag_str = yellow("-" + flag) + "%"
+                                                       if flag in old_use:
+                                                               flag_str += "*"
+                                                       flag_str = "(" + flag_str + ")"
+                                                       removed.append(flag_str)
+                                               continue
                                        else:
                                                if is_new or flag in old_iuse and flag not in old_use and all_flags:
-                                                       disabled.append(blue("-"+flag))
+                                                       flag_str = blue("-" + flag)
                                                elif flag not in old_iuse:
-                                                       disabled.append(yellow("-"+flag)+"%")
+                                                       flag_str = yellow("-" + flag)
+                                                       if flag not in iuse_forced:
+                                                               flag_str += "%"
                                                elif flag in old_use:
-                                                       disabled.append(green("-"+flag)+"*")
+                                                       flag_str = green("-" + flag) + "*"
+                                       if flag_str:
+                                               if flag in iuse_forced:
+                                                       flag_str = "(" + flag_str + ")"
+                                               if isEnabled:
+                                                       enabled.append(flag_str)
+                                               else:
+                                                       disabled.append(flag_str)
 
-                               enabled = " ".join(enabled)
                                if alphabetical:
-                                       disabled = ""
-                               else:
-                                       disabled = " ".join(disabled)
-                               if enabled and disabled:
-                                       ret = enabled + " " + disabled
-                               elif enabled:
-                                       ret = enabled
+                                       ret = " ".join(enabled)
                                else:
-                                       ret = disabled
+                                       ret = " ".join(enabled + disabled + removed)
                                if ret:
                                        ret = '%s="%s" ' % (name, ret)
                                return ret
 
                if verbosity == 3:
-                       overlays = string.split(portage.settings['PORTDIR_OVERLAY'])
-
-               if "--tree" in myopts:
-                       mylist.reverse()
-                       mygraph=self.digraph.copy()
-
+                       # FIXME: account for the possibility of different overlays in
+                       # /etc/make.conf vs. ${PORTAGE_CONFIGROOT}/etc/make.conf
+                       overlays = self.settings["PORTDIR_OVERLAY"].split()
+                       overlays_real = [os.path.realpath(t) \
+                               for t in self.settings["PORTDIR_OVERLAY"].split()]
+
+               tree_nodes = []
+               node_depth = {}
                i = 0
-               while i < len(mylist):
-                       if mylist[i][-1]=="nomerge":
-                               if not ("--tree" in myopts):
-                                       # we don't care about this elements
-                                       mylist.pop(i)
-                                       continue
-                               if (i == (len(mylist) - 1)) \
-                                  or (mygraph.depth(string.join(mylist[i])) \
-                                      >= mygraph.depth(string.join(mylist[i+1]))):
-                                       # end of a useless branch (may be the last one)
-                                       # -> delete the element and test the previous one
-                                       mylist.pop(i)
-                                       if i > 0:
-                                               i -= 1
-                                       continue
-                       # the branch continues, or we've found a good element.
-                       # -> let's see what's next, if anything
-                       i += 1
+               depth = 0
+               for x in mylist:
+                       graph_key = " ".join(x)
+                       if "--tree" in self.myopts:
+                               depth = len(tree_nodes)
+                               while depth and graph_key not in \
+                                       self.digraph.child_nodes(tree_nodes[depth-1]):
+                                               depth -= 1
+                               tree_nodes = tree_nodes[:depth]
+                               tree_nodes.append(graph_key)
+                       node_depth[graph_key] = depth
+
+               last_merge_depth = 0
+               for i in xrange(len(mylist)-1,-1,-1):
+                       graph_key = " ".join(mylist[i])
+                       if mylist[i][-1] != "nomerge":
+                               last_merge_depth = node_depth[graph_key]
+                               continue
+                       if node_depth[graph_key] >= last_merge_depth or \
+                               i < len(mylist) - 1 and \
+                               node_depth[graph_key] >= node_depth[" ".join(mylist[i+1])]:
+                                       del mylist[i]
+                                       del node_depth[graph_key]
+               del tree_nodes
 
                display_overlays=False
                # files to fetch list - avoids counting a same file twice
@@ -1516,48 +1605,57 @@ class depgraph:
                myfetchlist=[]
                for x in mylist:
                        pkg_type = x[0]
+                       myroot = x[1]
                        pkg_key = x[2]
-                       if pkg_key not in self.applied_useflags:
+                       portdb = self.trees[myroot]["porttree"].dbapi
+                       bindb  = self.trees[myroot]["bintree"].dbapi
+                       vartree = self.trees[myroot]["vartree"]
+                       pkgsettings = self.pkgsettings[myroot]
+                       pkgsettings.setcpv(pkg_key)
+                       if pkg_key not in self.useFlags[myroot]:
                                if "binary" == pkg_type:
-                                       self.applied_useflags[pkg_key] = portage.db["/"]["bintree"].dbapi.aux_get(pkg_key, ["USE"])[0].split()
+                                       self.useFlags[myroot][pkg_key] = bindb.aux_get(
+                                                       pkg_key, ["USE"])[0].split()
                                elif "ebuild" == pkg_type:
-                                       self.pkgsettings.setcpv(pkg_key)
-                                       self.applied_useflags[pkg_key] = self.pkgsettings["USE"].split()
+                                       self.useFlags[myroot][pkg_key] = pkgsettings["USE"].split()
 
                        fetch=" "
 
                        if x[0]=="blocks":
                                addl=""+red("B")+"  "+fetch+"  "
-                               resolved=portage.db[x[1]]["vartree"].resolve_key(x[2])
+                               resolved = self.trees[x[1]]["vartree"].resolve_key(x[2])
                                print "["+x[0]+" "+addl+"]",red(resolved),
+                               block_parents = self.digraph.parent_nodes(" ".join(x))
+                               block_parents = [pnode.split()[2] for pnode in block_parents]
+                               block_parents = ", ".join(block_parents)
                                if resolved!=x[2]:
-                                       if x[3]:
-                                               print red("(\""+x[2]+"\" is blocking "+x[3]+")")
-                                       else:
-                                               print red("(\""+x[2]+"\")")
+                                       print bad("(\"%s\" is blocking %s)") % \
+                                               (pkg_key, block_parents)
                                else:
-                                       if x[3]:
-                                               print red("(is blocking "+x[3]+")")
-                                       else:
-                                               print
+                                       print bad("(is blocking %s)") % block_parents
                        else:
-                               if (x[0]!="binary") and ("fetch" in string.split(portage.portdb.aux_get(x[2],["RESTRICT"])[0])):
+                               mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
+                               if "ebuild" == pkg_type and x[3] != "nomerge" and \
+                                       "fetch" in portdb.aux_get(
+                                       x[2], ["RESTRICT"])[0].split():
                                        fetch = red("F")
-                                       if portage.portdb.fetch_check(x[2], self.applied_useflags[x[2]]):
+                                       if portdb.fetch_check(
+                                               pkg_key, self.useFlags[myroot][pkg_key]):
                                                fetch = green("f")
 
                                #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty"
                                #param is used for -u, where you still *do* want to see when something is being upgraded.
                                myoldbest=""
-                               if (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]):
+                               if "--emptytree" not in self.myopts and \
+                                       self.trees[x[1]]["vartree"].exists_specific(x[2]):
                                        addl="  "+yellow("R")+fetch+"  "
-                               elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]):
-                                       if x[0] == "binary":
-                                               mynewslot=portage.db["/"]["bintree"].getslot(x[2])
-                                       elif x[0] == "ebuild":
-                                               mynewslot=portage.db["/"]["porttree"].getslot(x[2])
-                                       myoldlist=portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0])
-                                       myinslotlist=filter((lambda p: portage.db[portage.root]["vartree"].getslot(p)==mynewslot),myoldlist)
+                               elif "--emptytree" not in self.myopts and \
+                                       self.trees[x[1]]["vartree"].exists_specific_cat(x[2]):
+                                       mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0]
+                                       myoldlist = self.trees[x[1]]["vartree"].dbapi.match(
+                                               portage.pkgsplit(x[2])[0])
+                                       myinslotlist = [inst_pkg for inst_pkg in myoldlist
+                                               if mynewslot == vartree.getslot(inst_pkg)]
                                        if myinslotlist:
                                                myoldbest=portage.best(myinslotlist)
                                                addl="   "+fetch
@@ -1571,38 +1669,39 @@ class depgraph:
                                                # New slot, mark it new.
                                                addl=" "+green("NS")+fetch+"  "
 
-                                       if "--changelog" in myopts:
+                                       if "--changelog" in self.myopts:
                                                changelogs.extend(self.calc_changelog(
-                                                       portage.portdb.findname(x[2]),
-                                                       portage.db[x[1]]["vartree"].dep_bestmatch('/'.join(portage.catpkgsplit(x[2])[:2])),
-                                                       x[2]
-                                                       ))
+                                                       portdb.findname(pkg_key),
+                                                       self.trees[x[1]]["vartree"].dep_bestmatch(
+                                                       '/'.join(portage.catpkgsplit(x[2])[:2])), x[2]))
                                else:
                                        addl=" "+green("N")+" "+fetch+"  "
 
                                verboseadd=""
                                
-                               if x[2] in self.applied_useflags:
+                               if pkg_key in self.useFlags[myroot]:
                                        # USE flag display
-                                       if x[0] == "binary":
-                                               cur_iuse = string.split(portage.db["/"]["bintree"].dbapi.aux_get(x[2],["IUSE"])[0])
-                                       elif x[0] == "ebuild":
-                                               cur_iuse = string.split(portage.portdb.aux_get(x[2],["IUSE"])[0])
-                                       else:
-                                               cur_iuse = []
+                                       cur_iuse = mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()
+
+                                       forced_flags = set()
+                                       forced_flags.update(pkgsettings.useforce)
+                                       forced_flags.update(pkgsettings.puseforce)
+                                       forced_flags.update(pkgsettings.usemask)
+                                       forced_flags.update(pkgsettings.pusemask)
 
                                        cur_iuse = portage.unique_array(cur_iuse)
-                                       cur_iuse = [flag for flag in cur_iuse if flag not in portage.settings.usemask]
                                        cur_iuse.sort()
-                                       cur_use = self.applied_useflags[x[2]]
+                                       cur_use = self.useFlags[myroot][pkg_key]
                                        cur_use = [flag for flag in cur_use if flag in cur_iuse]
 
                                        if myoldbest:
                                                pkg = myoldbest
                                        else:
                                                pkg = x[2]
-                                       if portage.db[x[1]]["vartree"].dbapi.cpv_exists(pkg):
-                                               (old_iuse, old_use) = portage.db[x[1]]["vartree"].dbapi.aux_get(pkg, ["IUSE", "USE"])
+                                       if self.trees[x[1]]["vartree"].dbapi.cpv_exists(pkg):
+                                               old_iuse, old_use = \
+                                                       self.trees[x[1]]["vartree"].dbapi.aux_get(
+                                                               pkg, ["IUSE", "USE"])
                                                old_iuse = portage.unique_array(old_iuse.split())
                                                old_iuse.sort()
                                                old_use = old_use.split()
@@ -1611,29 +1710,39 @@ class depgraph:
                                                old_iuse = []
                                                old_use = []
                                                is_new = True
-                                       old_iuse = [flag for flag in old_iuse if flag not in portage.settings.usemask]
+
                                        old_use = [flag for flag in old_use if flag in old_iuse]
 
-                                       use_expand = portage.settings["USE_EXPAND"].lower().split()
+                                       use_expand = pkgsettings["USE_EXPAND"].lower().split()
                                        use_expand.sort()
                                        use_expand.reverse()
-                                       use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].lower().split()
+                                       use_expand_hidden = \
+                                               pkgsettings["USE_EXPAND_HIDDEN"].lower().split()
 
-                                       def map_to_use_expand(myvals):
+                                       def map_to_use_expand(myvals, forcedFlags=False):
                                                ret = {}
+                                               forced = {}
                                                for exp in use_expand:
                                                        ret[exp] = []
+                                                       forced[exp] = set()
                                                        for val in myvals[:]:
                                                                if val.startswith(exp.lower()+"_"):
+                                                                       if val in forced_flags:
+                                                                               forced[exp].add(val[len(exp)+1:])
                                                                        ret[exp].append(val[len(exp)+1:])
                                                                        myvals.remove(val)
                                                ret["USE"] = myvals
+                                               forced["USE"] = [val for val in myvals \
+                                                       if val in forced_flags]
                                                for exp in use_expand_hidden:
                                                        if exp in ret:
                                                                del ret[exp]
+                                               if forcedFlags:
+                                                       return ret, forced
                                                return ret
 
-                                       cur_iuse_map = map_to_use_expand(cur_iuse)
+                                       cur_iuse_map, iuse_forced = \
+                                               map_to_use_expand(cur_iuse, forcedFlags=True)
                                        cur_use_map = map_to_use_expand(cur_use)
                                        old_iuse_map = map_to_use_expand(old_iuse)
                                        old_use_map = map_to_use_expand(old_use)
@@ -1642,15 +1751,21 @@ class depgraph:
                                        use_expand.insert(0, "USE")
                                        
                                        for key in use_expand:
-                                               verboseadd += create_use_string(key.upper(), cur_iuse_map[key], cur_use_map[key],
-                                                                               old_iuse_map[key], old_use_map[key], is_new)
+                                               if key in use_expand_hidden:
+                                                       continue
+                                               verboseadd += create_use_string(key.upper(),
+                                                       cur_iuse_map[key], iuse_forced[key],
+                                                       cur_use_map[key], old_iuse_map[key],
+                                                       old_use_map[key], is_new)
 
                                if verbosity == 3:
                                        # size verbose
                                        mysize=0
                                        if x[0] == "ebuild" and x[-1]!="nomerge":
-                                               myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug)
-                                               if myfilesdict==None:
+                                               myfilesdict = portdb.getfetchsizes(
+                                                       pkg_key, useflags=self.useFlags[myroot][pkg_key],
+                                                       debug=self.edebug)
+                                               if myfilesdict is None:
                                                        myfilesdict="[empty/missing/bad digest]"
                                                else:
                                                        for myfetchfile in myfilesdict.keys():
@@ -1663,33 +1778,36 @@ class depgraph:
                                        # overlay verbose
                                        # XXX: Invalid binaries have caused tracebacks here. 'if file_name'
                                        # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge']
-                                       file_name=portage.portdb.findname(x[2])
+                                       file_name = portdb.findname(pkg_key)
                                        if file_name: # It might not exist in the tree
                                                dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..")
-                                               if (overlays.count(dir_name)>0):
-                                                       verboseadd+=teal("["+str(overlays.index(os.path.normpath(dir_name))+1)+"]")+" "
+                                               if (overlays_real.count(dir_name)>0):
+                                                       verboseadd+=teal("["+str(overlays_real.index(
+                                                               os.path.normpath(dir_name))+1)+"]")+" "
                                                        display_overlays=True
                                        else:
                                                verboseadd += "[No ebuild?]"
 
-                                       verboseadd+="EAPI: "+blue(str(portage.portdb.aux_get(x[2],["EAPI"])[0]))
-
                                xs=portage.pkgsplit(x[2])
                                if xs[2]=="r0":
                                        xs[2]=""
                                else:
                                        xs[2]="-"+xs[2]
 
-                               if self.pkgsettings.has_key("COLUMNWIDTH"):
-                                       mywidth=int(self.pkgsettings.settings["COLUMNWIDTH"])
-                               else:
-                                       mywidth=130
+                               mywidth = 130
+                               if "COLUMNWIDTH" in self.settings:
+                                       try:
+                                               mywidth = int(self.settings["COLUMNWIDTH"])
+                                       except ValueError, e:
+                                               portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+                                               portage.writemsg(
+                                                       "!!! Unable to parse COLUMNWIDTH='%s'\n" % \
+                                                       self.settings["COLUMNWIDTH"], noiselevel=-1)
+                                               del e
                                oldlp=mywidth-30
                                newlp=oldlp-30
 
-                               indent=""
-                               if ("--tree" in myopts):
-                                       indent=" "*mygraph.depth(string.join(x))
+                               indent = " " * node_depth[" ".join(x)]
 
                                if myoldbest:
                                        myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2]
@@ -1698,12 +1816,14 @@ class depgraph:
                                        myoldbest=blue("["+myoldbest+"]")
 
                                if x[1]!="/":
-                                       if "--columns" in myopts:
-                                               if "--quiet" in myopts:
+                                       if myoldbest:
+                                               myoldbest +=" "
+                                       if "--columns" in self.myopts:
+                                               if "--quiet" in self.myopts:
                                                        myprint=addl+" "+indent+darkgreen(xs[0])
-                                                       myprint=myprint+darkblue(xs[1]+xs[2])+" "
+                                                       myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
                                                        myprint=myprint+myoldbest
-                                                       myprint=myprint+darkgreen(" to "+x[1])
+                                                       myprint=myprint+darkgreen("to "+x[1])
                                                else:
                                                        myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
                                                        if (newlp-nc_len(myprint)) > 0:
@@ -1712,12 +1832,12 @@ class depgraph:
                                                        if (oldlp-nc_len(myprint)) > 0:
                                                                myprint=myprint+" "*(oldlp-nc_len(myprint))
                                                        myprint=myprint+myoldbest
-                                                       myprint=myprint+darkgreen("  to "+x[1])+" "+verboseadd
+                                                       myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
                                        else:
-                                               myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd
+                                               myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+darkgreen("to "+x[1])+" "+verboseadd
                                else:
-                                       if "--columns" in myopts:
-                                               if "--quiet" in myopts:
+                                       if "--columns" in self.myopts:
+                                               if "--quiet" in self.myopts:
                                                        myprint=addl+" "+indent+darkgreen(xs[0])
                                                        myprint=myprint+" "+green(xs[1]+xs[2])+" "
                                                        myprint=myprint+myoldbest
@@ -1736,27 +1856,28 @@ class depgraph:
                                                        myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd
                                p.append(myprint)
 
-                       if ("--tree" not in myopts):
-                               mysplit=portage.pkgsplit(x[2])
-
-                               # XXX mysplit _can_ be None.... Why?
-                               if mysplit and (len(mysplit)==3):
-                                       if "--emptytree" not in myopts:
-                                               if mysplit[0]=="sys-apps/portage":
-                                                       if ((mysplit[1]+mysplit[2]) != portage.VERSION) and \
-                                                          ("livecvsportage" not in portage.settings.features):
-                                                               if mylist.index(x)<len(mylist)-1:
-                                                                       p.append(red("*** Portage will stop merging at this point and reload itself,"))
-                                                                       p.append(red("    then resume the merge."))
-                                                                       print
-                                       else:
-                                               if mysplit[0]=="sys-apps/portage" and ("--emptytree" in myopts):
-                                                       if mysplit[1]+mysplit[2]!=portage.VERSION:
-                                                               p.append(red("***")+" Please update portage to the above version before proceeding.")
-                                                               p.append("    Failure to do so may result in failed or improper merges.")
-                                                               p.append("    A simple '"+green("emerge -u portage")+"' is sufficient.")
-                                                               p.append("")
-                               del mysplit
+                       mysplit = portage.pkgsplit(x[2])
+                       if "--tree" not in self.myopts and mysplit and \
+                               len(mysplit) == 3 and mysplit[0] == "sys-apps/portage" and \
+                               x[1] == "/":
+
+                               if mysplit[2] == "r0":
+                                       myversion = mysplit[1]
+                               else:
+                                       myversion = "%s-%s" % (mysplit[1], mysplit[2])
+
+                               if myversion != portage.VERSION :
+                                       if "--emptytree" in self.myopts:
+                                               p.append(colorize("WARN", "***")+" Please update portage to the above version before proceeding.")
+                                               p.append("    Failure to do so may result in failed or improper merges.")
+                                               p.append("    A simple '"+green("emerge portage")+"' is sufficient.")
+                                               p.append("")
+                                       elif mylist.index(x) < len(mylist) - 1 and \
+                                               "livecvsportage" not in self.settings.features:
+                                               p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,"))
+                                               p.append(colorize("WARN", "    then resume the merge."))
+                                               print
+                       del mysplit
 
                for x in p:
                        print x
@@ -1771,7 +1892,7 @@ class depgraph:
                                        y=y+1
                                        print " "+teal("["+str(y)+"]"),x
 
-               if "--changelog" in myopts:
+               if "--changelog" in self.myopts:
                        print
                        for revision,text in changelogs:
                                print bold('*'+revision)
@@ -1811,7 +1932,7 @@ class depgraph:
                divs = []
                release = None
                while 1:
-                       match = re.search(r'^\*\ ?([-a-zA-Z0-9_.]*)(?:\ .*)?\n',changelog,re.M)
+                       match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M)
                        if match is None:
                                if release is not None:
                                        divs.append((release,changelog))
@@ -1828,41 +1949,60 @@ class depgraph:
        def outdated(self):
                return self.outdatedpackages
 
-       def merge(self,mylist):
+class MergeTask(object):
+
+       def __init__(self, settings, trees, myopts):
+               self.settings = settings
+               self.target_root = settings["ROOT"]
+               self.trees = trees
+               self.myopts = myopts
+               self.edebug = 0
+               if settings.get("PORTAGE_DEBUG", "") == "1":
+                       self.edebug = 1
+               self.pkgsettings = {}
+               self.pkgsettings[self.target_root] = portage.config(clone=settings)
+               if self.target_root != "/":
+                       self.pkgsettings["/"] = \
+                               portage.config(clone=trees["/"]["vartree"].settings)
+
+       def merge(self, mylist, favorites, mtimedb):
                returnme=0
                mymergelist=[]
+               ldpath_mtimes = mtimedb["ldpath"]
+               xterm_titles = "notitles" not in self.settings.features
 
                #check for blocking dependencies
-               if ("--fetchonly" not in myopts) and ("--buildpkgonly" not in myopts):
+               if "--fetchonly" not in self.myopts and \
+                       "--buildpkgonly" not in self.myopts:
                        for x in mylist:
                                if x[0]=="blocks":
                                        print "\n!!! Error: the "+x[2]+" package conflicts with another package;"
                                        print   "!!!        the two packages cannot be installed on the same system together."
                                        print   "!!!        Please use 'emerge --pretend' to determine blockers."
-                                       print
-                                       if ("--pretend" not in myopts):
+                                       if "--quiet" not in self.myopts:
+                                               show_blocker_docs_link()
+                                       if "--pretend" not in self.myopts:
+                                               try:
+                                                       del mtimedb["resume"]
+                                               except KeyError:
+                                                       pass
                                                sys.exit(1)
 
                #buildsyspkg: I need mysysdict also on resume (moved from the else block)
-               mysysdict=genericdict(syslist)
-               if ("--resume" in myopts):
+               mysysdict = genericdict(getlist(self.settings, "system"))
+               if "--resume" in self.myopts:
                        # We're resuming.
-                       print green("*** Resuming merge...")
-                       emergelog(" *** Resuming merge...")
-                       mymergelist=portage.mtimedb["resume"]["mergelist"][:]
-                       if ("--skipfirst" in myopts) and mymergelist:
-                               del portage.mtimedb["resume"]["mergelist"][0]
+                       print colorize("GOOD", "*** Resuming merge...")
+                       emergelog(xterm_titles, " *** Resuming merge...")
+                       mymergelist=mtimedb["resume"]["mergelist"][:]
+                       if "--skipfirst" in self.myopts and mymergelist:
+                               del mtimedb["resume"]["mergelist"][0]
                                del mymergelist[0]
-                       for bigkey in mymergelist:
-                               (pkgtype, root, cpv, action) = bigkey
-                               if pkgtype == "binary" and not portage.db["/"]["bintree"].dbapi.match("="+cpv) or \
-                                  pkgtype == "ebuild" and not portage.db["/"]["porttree"].dbapi.xmatch("match-all", "="+cpv):
-                                       print red("!!! Error: The resume list contains packages that no longer")
-                                       print red("!!!        available to be emerged. Please restart/continue")
-                                       print red("!!!        the merge operation manually.")
-                                       sys.exit(1)
+                               mtimedb.commit()
+                       validate_merge_list(self.trees, mymergelist)
                else:
-                       myfavs = portage.grabfile(os.path.join(portage.root, portage.WORLD_FILE))
+                       myfavs = portage.grabfile(
+                               os.path.join(self.target_root, portage.WORLD_FILE))
                        myfavdict=genericdict(myfavs)
                        for x in range(len(mylist)):
                                if mylist[x][3]!="nomerge":
@@ -1870,33 +2010,33 @@ class depgraph:
                                        mymergelist.append(mylist[x])
                                else:
                                        myfavkey=portage.cpv_getkey(mylist[x][2])
-                                       if "--onlydeps" in myopts:
+                                       if "--onlydeps" in self.myopts:
                                                continue
                                        # Add to the world file. Since we won't be able to later.
-                                       if (not "--fetchonly" in myopts) and (myfavkey in favorites):
+                                       if "--fetchonly" not in self.myopts and \
+                                               myfavkey in favorites:
                                                #don't record if already in system profile or already recorded
                                                if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
                                                        #we don't have a favorites entry for this package yet; add one
                                                        myfavdict[myfavkey]=myfavkey
                                                        print ">>> Recording",myfavkey,"in \"world\" favorites file..."
-                       if not "--fetchonly" in myopts:
+                       if not ("--fetchonly" in self.myopts or \
+                               "--fetch-all-uri" in self.myopts or \
+                               "--pretend" in self.myopts):
                                portage.write_atomic(
-                               os.path.join(portage.root, portage.WORLD_FILE),
-                               "\n".join(myfavdict.values()))
-
-                       portage.mtimedb["resume"]["mergelist"]=mymergelist[:]
-
-               # We need to yank the harmful-to-new-builds settings from features.
-               myorigfeat=self.pkgsettings["FEATURES"]
-               myfeat=myorigfeat.split()
-               while ("keeptemp" in myfeat):
-                       del myfeat[myfeat.index("keeptemp")]
-               while ("keepwork" in myfeat):
-                       del myfeat[myfeat.index("keepwork")]
-
-               self.pkgsettings["FEATURES"]=string.join(myfeat)
-
-               if "parallel-fetch" in myfeat and not ("--ask" in myopts or "--pretend" in myopts or "--fetchonly" in myopts):
+                                       os.path.join(self.target_root, portage.WORLD_FILE),
+                                       "\n".join(myfavdict.values()))
+
+                       mtimedb["resume"]["mergelist"]=mymergelist[:]
+                       mtimedb.commit()
+
+               myfeat = self.settings.features[:]
+               bad_resume_opts = set(["--ask", "--tree", "--changelog", "--skipfirst",
+                       "--resume"])
+               if "parallel-fetch" in myfeat and \
+                       not ("--pretend" in self.myopts or \
+                       "--fetch-all-uri" in self.myopts or \
+                       "--fetchonly" in self.myopts):
                        if "distlocks" not in myfeat:
                                print red("!!!")
                                print red("!!!")+" parallel-fetching requires the distlocks feature enabled"
@@ -1904,245 +2044,329 @@ class depgraph:
                                print red("!!!")
                        elif len(mymergelist) > 1:
                                print ">>> starting parallel fetching"
-                               pid = os.fork()
-                               if not pid:
-                                       sys.stdin.close()
-                                       sys.stdout.close()
-                                       sys.stderr.close()
-                                       time.sleep(3) # allow the parent to have first fetch
-                                       sys.stdout = open("/dev/null","w")
-                                       sys.stderr = open("/dev/null","w")
-                                       os.dup2(sys.stdout.fileno(), 1)
-                                       os.dup2(sys.stdout.fileno(), 2)
-                                       # wipe the mtimedb so that portage doesn't attempt to flush it.
-                                       # do not convert this code away from a fork without correcting this.
-                                       portage.mtimedb = None
-                                       for x in ("autoaddcvs", "cvs"):
-                                               try:    myfeat.remove(x)
-                                               except ValueError: pass
-                                       self.pkgsettings["FEATURES"] = " ".join(myfeat)
-                                       ret = 0
-                                       for x in mymergelist:
-                                               if x[0] != "ebuild":
-                                                       continue
-                                               try:
-                                                       ret = portage.doebuild(portage.portdb.findname(x[2]), "fetch", x[1], self.pkgsettings,
-                                                               cleanup=0, fetchonly=True, tree="porttree")
-                                               except SystemExit:
-                                                       raise
-                                               except Exception:
-                                                       ret = 1
-                                       sys.exit(0)
-                               portage.portage_exec.spawned_pids.append(pid)
+                               fetch_log = "/var/log/emerge-fetch.log"
+                               logfile = open(fetch_log, "w")
+                               fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()}
+                               portage_util.apply_secpass_permissions(fetch_log,
+                                       uid=portage.portage_uid, gid=portage.portage_gid,
+                                       mode=0660)
+                               fetch_env = os.environ.copy()
+                               fetch_env["FEATURES"] = fetch_env.get("FEATURES", "") + " -cvs"
+                               fetch_env["PORTAGE_NICENESS"] = "0"
+                               fetch_args = [sys.argv[0], "--resume", "--fetchonly"]
+                               for myopt, myarg in self.myopts.iteritems():
+                                       if myopt not in bad_resume_opts:
+                                               if myarg is True:
+                                                       fetch_args.append(myopt)
+                                               else:
+                                                       fetch_args.append(myopt +"="+ myarg)
+                               portage.portage_exec.spawn(fetch_args, env=fetch_env,
+                                       fd_pipes=fd_pipes, returnpid=True)
+                               logfile.close() # belongs to the spawned process
 
                mergecount=0
                for x in mymergelist:
                        mergecount+=1
                        myroot=x[1]
+                       pkg_key = x[2]
                        pkgindex=2
+                       portdb = self.trees[myroot]["porttree"].dbapi
+                       bindb  = self.trees[myroot]["bintree"].dbapi
+                       vartree = self.trees[myroot]["vartree"]
+                       pkgsettings = self.pkgsettings[myroot]
                        if x[0]=="blocks":
                                pkgindex=3
-                       y=portage.portdb.findname(x[pkgindex])
-                       if not "--pretend" in myopts:
-                               print ">>> Emerging ("+str(mergecount)+" of "+str(len(mymergelist))+")",x[pkgindex],"to",x[1]
-                               emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1])
-
-                       self.pkgsettings["EMERGE_FROM"] = x[0][:]
-                       self.pkgsettings.backup_changes("EMERGE_FROM")
-                       self.pkgsettings.reset()
+                       y = portdb.findname(pkg_key)
+                       if "--pretend" not in self.myopts:
+                               print "\n>>> Emerging (" + \
+                                       colorize("MERGE_LIST_PROGRESS", str(mergecount)) + " of " + \
+                                       colorize("MERGE_LIST_PROGRESS", str(len(mymergelist))) + ") " + \
+                                       colorize("GOOD", x[pkgindex]) + " to " + x[1]
+                               emergelog(xterm_titles, " >>> emerge ("+\
+                                       str(mergecount)+" of "+str(len(mymergelist))+\
+                                       ") "+x[pkgindex]+" to "+x[1])
+
+                       pkgsettings["EMERGE_FROM"] = x[0]
+                       pkgsettings.backup_changes("EMERGE_FROM")
+                       pkgsettings.reset()
 
                        #buildsyspkg: Check if we need to _force_ binary package creation
                        issyspkg = ("buildsyspkg" in myfeat) \
                                        and x[0] != "blocks" \
                                        and mysysdict.has_key(portage.cpv_getkey(x[2])) \
-                                       and not ("--buildpkg" in myopts)
+                                       and "--buildpkg" not in self.myopts
                        if x[0] in ["ebuild","blocks"]:
-                               if (x[0]=="blocks") and ("--fetchonly" not in myopts):
+                               if x[0] == "blocks" and "--fetchonly" not in self.myopts:
                                        raise Exception, "Merging a blocker"
-                               elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts):
-                                       if ("--fetch-all-uri" in myopts):
-                                               retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1,tree="porttree")
+                               elif "--fetchonly" in self.myopts or \
+                                       "--fetch-all-uri" in self.myopts:
+                                       if "--fetch-all-uri" in self.myopts:
+                                               retval = portage.doebuild(y, "fetch", myroot,
+                                                       pkgsettings, self.edebug,
+                                                       "--pretend" in self.myopts, fetchonly=1,
+                                                       fetchall=1, mydbapi=portdb, tree="porttree")
                                        else:
-                                               retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,tree="porttree")
-                                       if (retval == None) or retval:
+                                               retval = portage.doebuild(y, "fetch", myroot,
+                                                       pkgsettings, self.edebug,
+                                                       "--pretend" in self.myopts, fetchonly=1,
+                                                       mydbapi=portdb, tree="porttree")
+                                       if (retval is None) or retval:
                                                print
                                                print "!!! Fetch for",y,"failed, continuing..."
                                                print
                                                returnme=1
                                        continue
-                               elif "--buildpkg" in myopts or issyspkg:
-                                       #buildsyspkg: Sounds useful to display something, but I don't know if we should also log it
-                                       if issyspkg:
-                                               print ">>> This is a system package, let's pack a rescue tarball."
-                                               #emergelog(">>> This is a system package, let's pack a rescue tarball.")
-                                       #create pkg, then merge pkg
-                                       short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean"
-                                       emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-                                       retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree")
-                                       if (retval == None):
-                                               portage_util.writemsg("Unable to run required binary.\n")
-                                               sys.exit(127)
-                                       if retval:
-                                               sys.exit(retval)
-                                       short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile"
-                                       emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-                                       retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug,tree="porttree")
-                                       if (retval == None):
-                                               portage_util.writemsg("Unable to run required binary.\n")
-                                               sys.exit(127)
-                                       if retval:
-                                               sys.exit(retval)
-                                       #dynamically update our database
-                                       if "--buildpkgonly" not in myopts:
-                                               portage.db[portage.root]["bintree"].inject(x[2])
-                                               mytbz2=portage.db[portage.root]["bintree"].getname(x[2])
-                                               short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge"
-                                               emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-
-                                               self.pkgsettings["EMERGE_FROM"] = "binary"
-                                               self.pkgsettings.backup_changes("EMERGE_FROM")
-
-                                               retval=portage.pkgmerge(mytbz2,myroot,self.pkgsettings)
-                                               if retval==None:
-                                                       sys.exit(1)
-                               else:
-                                       short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean"
-                                       emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-                                       retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree")
-                                       if (retval == None):
-                                               portage_util.writemsg("Unable to run required binary.\n")
-                                               sys.exit(127)
-                                       if retval:
-                                               sys.exit(retval)
-                                       short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile"
-                                       emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-                                       retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug,tree="porttree")
-                                       if (retval == None):
-                                               portage_util.writemsg("Unable to run required binary.\n")
-                                               sys.exit(127)
-                                       if retval:
-                                               sys.exit(retval)
-                                       #dynamically update our database
+
+                               portage.doebuild_environment(y, "setup", myroot,
+                                       pkgsettings, self.edebug, 1, portdb)
+                               catdir = os.path.dirname(pkgsettings["PORTAGE_BUILDDIR"])
+                               portage_util.ensure_dirs(os.path.dirname(catdir),
+                                       uid=portage.portage_uid, gid=portage.portage_gid,
+                                       mode=070, mask=0)
+                               builddir_lock = None
+                               catdir_lock = None
+                               try:
+                                       catdir_lock = portage_locks.lockdir(catdir)
+                                       portage_util.ensure_dirs(catdir,
+                                               uid=portage.portage_uid, gid=portage.portage_gid,
+                                               mode=070, mask=0)
+                                       builddir_lock = portage_locks.lockdir(
+                                               pkgsettings["PORTAGE_BUILDDIR"])
+                                       try:
+                                               portage_locks.unlockdir(catdir_lock)
+                                       finally:
+                                               catdir_lock = None
+                                       msg = " === (%s of %s) Cleaning (%s::%s)" % \
+                                               (mergecount, len(mymergelist), pkg_key, y)
+                                       short_msg = "emerge: (%s of %s) %s Clean" % \
+                                               (mergecount, len(mymergelist), pkg_key)
+                                       emergelog(xterm_titles, msg, short_msg=short_msg)
+                                       retval = portage.doebuild(y, "clean", myroot,
+                                               pkgsettings, self.edebug, cleanup=1,
+                                               mydbapi=portdb, tree="porttree")
+                                       if retval != os.EX_OK:
+                                               return retval
+                                       if "--buildpkg" in self.myopts or issyspkg:
+                                               if issyspkg:
+                                                       print ">>> This is a system package, " + \
+                                                               "let's pack a rescue tarball."
+                                               msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
+                                                       (mergecount, len(mymergelist), pkg_key, y)
+                                               short_msg = "emerge: (%s of %s) %s Compile" % \
+                                                       (mergecount, len(mymergelist), pkg_key)
+                                               emergelog(xterm_titles, msg, short_msg=short_msg)
+                                               retval = portage.doebuild(y, "package", myroot,
+                                                       pkgsettings, self.edebug, mydbapi=portdb,
+                                                       tree="porttree")
+                                               if retval != os.EX_OK:
+                                                       return retval
+                                               if "--buildpkgonly" not in self.myopts:
+                                                       bintree = self.trees[myroot]["bintree"]
+                                                       bintree.inject(pkg_key)
+                                                       mytbz2 = bintree.getname(pkg_key)
+                                                       msg = " === (%s of %s) Merging (%s::%s)" % \
+                                                               (mergecount, len(mymergelist), pkg_key, y)
+                                                       short_msg = "emerge: (%s of %s) %s Merge" % \
+                                                               (mergecount, len(mymergelist), pkg_key)
+                                                       emergelog(xterm_titles, msg, short_msg=short_msg)
+                                                       retval = portage.merge(pkgsettings["CATEGORY"],
+                                                               pkgsettings["PF"], pkgsettings["D"],
+                                                               os.path.join(pkgsettings["PORTAGE_BUILDDIR"],
+                                                               "build-info"), myroot, pkgsettings,
+                                                               myebuild=pkgsettings["EBUILD"],
+                                                               mytree="porttree", mydbapi=portdb,
+                                                               vartree=vartree, prev_mtimes=ldpath_mtimes)
+                                                       if retval != os.EX_OK:
+                                                               return retval
+                                               elif "noclean" not in pkgsettings.features:
+                                                       portage.doebuild(y, "clean", myroot,
+                                                               pkgsettings, self.edebug, mydbapi=portdb,
+                                                               tree="porttree")
+                                       else:
+                                               msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
+                                                       (mergecount, len(mymergelist), pkg_key, y)
+                                               short_msg = "emerge: (%s of %s) %s Compile" % \
+                                                       (mergecount, len(mymergelist), pkg_key)
+                                               emergelog(xterm_titles, msg, short_msg=short_msg)
+                                               retval = portage.doebuild(y, "merge", myroot,
+                                                       pkgsettings, self.edebug, vartree=vartree,
+                                                       mydbapi=portdb, tree="porttree",
+                                                       prev_mtimes=ldpath_mtimes)
+                                               if retval != os.EX_OK:
+                                                       return retval
+                               finally:
+                                       if builddir_lock:
+                                               portage_locks.unlockdir(builddir_lock)
+                                       try:
+                                               if not catdir_lock:
+                                                       # Lock catdir for removal if empty.
+                                                       catdir_lock = portage_locks.lockdir(catdir)
+                                       finally:
+                                               if catdir_lock:
+                                                       try:
+                                                               os.rmdir(catdir)
+                                                       except OSError, e:
+                                                               if e.errno != errno.ENOTEMPTY:
+                                                                       raise
+                                                               del e
+                                                       portage_locks.unlockdir(catdir_lock)
+
                        elif x[0]=="binary":
                                #merge the tbz2
-                               mytbz2=portage.db[portage.root]["bintree"].getname(x[2])
-                               if portage.db[portage.root]["bintree"].isremote(x[2]):
+                               mytbz2 = self.trees[myroot]["bintree"].getname(pkg_key)
+                               if self.trees[myroot]["bintree"].isremote(pkg_key):
                                        short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch"
-                                       emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
-                                       if not portage.db[portage.root]["bintree"].gettbz2(x[2]):
+                                       emergelog(xterm_titles, " --- ("+str(mergecount)+\
+                                               " of "+str(len(mymergelist))+\
+                                               ") Fetching Binary ("+x[pkgindex]+\
+                                               "::"+mytbz2+")", short_msg=short_msg)
+                                       if not self.trees[myroot]["bintree"].gettbz2(pkg_key):
                                                sys.exit(1)
 
-                               if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts):
+                               if "--fetchonly" in self.myopts or \
+                                       "--fetch-all-uri" in self.myopts:
                                        continue
 
                                short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary"
-                               emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
-                               retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings)
-                               if retval==None:
+                               emergelog(xterm_titles, " === ("+str(mergecount)+\
+                                       " of "+str(len(mymergelist))+") Merging Binary ("+\
+                                       x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
+                               retval = portage.pkgmerge(mytbz2, x[1], pkgsettings,
+                                       mydbapi=bindb,
+                                       vartree=self.trees[myroot]["vartree"],
+                                       prev_mtimes=ldpath_mtimes)
+                               if retval is None:
                                        sys.exit(1)
                                #need to check for errors
-                       if "--buildpkgonly" not in myopts:
-                               portage.db[x[1]]["vartree"].inject(x[2])
+                       if "--buildpkgonly" not in self.myopts:
+                               self.trees[x[1]]["vartree"].inject(x[2])
                                myfavkey=portage.cpv_getkey(x[2])
-                               if "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts and myfavkey in favorites:
+                               if "--fetchonly" not in self.myopts and \
+                                       "--fetch-all-uri" not in self.myopts and \
+                                       myfavkey in favorites:
                                        myfavs = portage.grabfile(os.path.join(myroot, portage.WORLD_FILE))
                                        myfavdict=genericdict(myfavs)
-                                       mysysdict=genericdict(syslist)
                                        #don't record if already in system profile or already recorded
                                        if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
                                                #we don't have a favorites entry for this package yet; add one
                                                myfavdict[myfavkey]=myfavkey
                                                print ">>> Recording",myfavkey,"in \"world\" favorites file..."
-                                               emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")")
+                                               emergelog(xterm_titles, " === ("+\
+                                                       str(mergecount)+" of "+\
+                                                       str(len(mymergelist))+\
+                                                       ") Updating world file ("+x[pkgindex]+")")
                                                portage.write_atomic(
                                                os.path.join(myroot, portage.WORLD_FILE),
                                                "\n".join(myfavdict.values()))
 
-                               if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
+                               if "--pretend" not in self.myopts and \
+                                       "--fetchonly" not in self.myopts and \
+                                       "--fetch-all-uri" not in self.myopts:
                                        # Clean the old package that we have merged over top of it.
-                                       if self.pkgsettings["AUTOCLEAN"]=="yes":
+                                       if pkgsettings.get("AUTOCLEAN", "yes") == "yes":
                                                xsplit=portage.pkgsplit(x[2])
-                                               emergelog(" >>> AUTOCLEAN: "+xsplit[0])
-                                               retval=unmerge("clean", [xsplit[0]])
+                                               emergelog(xterm_titles, " >>> AUTOCLEAN: " + xsplit[0])
+                                               retval = unmerge(pkgsettings, self.myopts, vartree,
+                                                       "clean", [xsplit[0]], ldpath_mtimes)
                                                if not retval:
-                                                       emergelog(" --- AUTOCLEAN: Nothing unmerged.")
+                                                       emergelog(xterm_titles,
+                                                               " --- AUTOCLEAN: Nothing unmerged.")
+                                       else:
+                                               portage.writemsg_stdout(colorize("WARN", "WARNING:")
+                                                       + " AUTOCLEAN is disabled.  This can cause serious"
+                                                       + " problems due to overlapping packages.\n")
 
                                        # Figure out if we need a restart.
                                        mysplit=portage.pkgsplit(x[2])
-                                       if mysplit[0]=="sys-apps/portage":
+                                       if mysplit[0] == "sys-apps/portage" and x[1] == "/":
                                                myver=mysplit[1]+"-"+mysplit[2]
                                                if myver[-3:]=='-r0':
                                                        myver=myver[:-3]
                                                if (myver != portage.VERSION) and \
-                                                  ("livecvsportage" not in portage.settings.features):
+                                                  "livecvsportage" not in self.settings.features:
                                                        if len(mymergelist) > mergecount:
-                                                               emergelog(" *** RESTARTING emerge via exec() after change of portage version.")
-                                                               del portage.mtimedb["resume"]["mergelist"][0]
+                                                               emergelog(xterm_titles,
+                                                                       " ::: completed emerge ("+ \
+                                                                       str(mergecount)+" of "+ \
+                                                                       str(len(mymergelist))+") "+ \
+                                                                       x[2]+" to "+x[1])
+                                                               emergelog(xterm_titles, " *** RESTARTING " + \
+                                                                       "emerge via exec() after change of " + \
+                                                                       "portage version.")
+                                                               del mtimedb["resume"]["mergelist"][0]
+                                                               mtimedb.commit()
                                                                portage.run_exitfuncs()
                                                                mynewargv=[sys.argv[0],"--resume"]
-                                                               badlongopts = ("--ask","--tree","--changelog","--skipfirst","--resume")
-                                                               for arg in myopts:
-                                                                       if arg in badlongopts:
-                                                                               continue
-                                                                       mynewargv.append(arg)
+                                                               for myopt, myarg in self.myopts.iteritems():
+                                                                       if myopt not in bad_resume_opts:
+                                                                               if myarg is True:
+                                                                                       mynewargv.append(myopt)
+                                                                               else:
+                                                                                       mynewargv.append(myopt +"="+ myarg)
+                                                               # priority only needs to be adjusted on the first run
+                                                               os.environ["PORTAGE_NICENESS"] = "0"
                                                                os.execv(mynewargv[0], mynewargv)
 
-                       if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
-                               if "noclean" not in portage.features:
+                       if "--pretend" not in self.myopts and \
+                               "--fetchonly" not in self.myopts and \
+                               "--fetch-all-uri" not in self.myopts:
+                               if "noclean" not in self.settings.features:
                                        short_msg = "emerge: (%s of %s) %s Clean Post" % \
                                                (mergecount, len(mymergelist), x[pkgindex])
-                                       emergelog(" === (%s of %s) Post-Build Cleaning (%s::%s)" % \
-                                               (mergecount, len(mymergelist), x[pkgindex], y), short_msg=short_msg)
-                               emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1])
+                                       emergelog(xterm_titles, (" === (%s of %s) " + \
+                                               "Post-Build Cleaning (%s::%s)") % \
+                                               (mergecount, len(mymergelist), x[pkgindex], y),
+                                               short_msg=short_msg)
+                               emergelog(xterm_titles, " ::: completed emerge ("+\
+                                       str(mergecount)+" of "+str(len(mymergelist))+") "+\
+                                       x[2]+" to "+x[1])
 
                        # Unsafe for parallel merges
-                       del portage.mtimedb["resume"]["mergelist"][0]
+                       del mtimedb["resume"]["mergelist"][0]
                        # Commit after each merge so that --resume may still work in
                        # in the event that portage is not allowed to exit normally
                        # due to power failure, SIGKILL, etc...
-                       portage.commit_mtimedb()
+                       mtimedb.commit()
 
-               emergelog(" *** Finished. Cleaning up...")
+               if "--pretend" not in self.myopts:
+                       emergelog(xterm_titles, " *** Finished. Cleaning up...")
 
                # We're out of the loop... We're done. Delete the resume data.
-               if portage.mtimedb.has_key("resume"):
-                       del portage.mtimedb["resume"]
-
-               if ("--pretend" not in myopts):
-                       if ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
-                               if (mergecount>0):
-                                       if retval:
-                                               portage.env_update()
+               if mtimedb.has_key("resume"):
+                       del mtimedb["resume"]
+               mtimedb.commit()
 
                #by doing an exit this way, --fetchonly can continue to try to
                #fetch everything even if a particular download fails.
-               if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
+               if "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts:
                        if returnme:
                                print "\n\n!!! Some fetch errors were encountered.  Please see above for details.\n\n"
                                sys.exit(returnme)
                        else:
                                sys.exit(0)
+               return os.EX_OK
 
-def unmerge(unmerge_action, unmerge_files):
+def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files,
+       ldpath_mtimes, raise_on_missing=True):
        candidate_catpkgs=[]
        global_unmerge=0
+       xterm_titles = "notitles" not in settings.features
 
-       realsyslist = getlist("system")
+       realsyslist = getlist(settings, "system")
        syslist = []
        for x in realsyslist:
                mycp = portage.dep_getkey(x)
-               if mycp in portage.settings.getvirtuals():
+               if mycp in settings.getvirtuals():
                        providers = []
-                       for provider in portage.settings.getvirtuals()[mycp]:
-                               if portage.db[portage.root]["vartree"].dbapi.match(provider):
+                       for provider in settings.getvirtuals()[mycp]:
+                               if vartree.dbapi.match(provider):
                                        providers.append(provider)
                        if len(providers) == 1:
                                syslist.extend(providers)
                else:
                        syslist.append(mycp)
 
-       global myopts
-       mysettings = portage.config(clone=portage.settings)
+       mysettings = portage.config(clone=settings)
 
        if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files:
                if "unmerge"==unmerge_action:
@@ -2154,13 +2378,13 @@ def unmerge(unmerge_action, unmerge_files):
                else:
                        global_unmerge=1
 
-       localtree=portage.db[portage.root]["vartree"]
+       localtree = vartree
        # process all arguments and add all valid db entries to candidate_catpkgs
        if global_unmerge:
                if not unmerge_files or "world" in unmerge_files:
                        candidate_catpkgs.extend(localtree.getallnodes())
                elif "system" in unmerge_files:
-                       candidate_catpkgs.extend(getlist("system"))
+                       candidate_catpkgs.extend(getlist(settings, "system"))
        else:
                #we've got command-line arguments
                if not unmerge_files:
@@ -2189,7 +2413,7 @@ def unmerge(unmerge_action, unmerge_files):
 
                                sp_absx_len = len(sp_absx)
 
-                               vdb_path = portage.root+portage.VDB_PATH
+                               vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH)
                                vdb_len  = len(vdb_path)
 
                                sp_vdb     = vdb_path.split("/")
@@ -2201,23 +2425,28 @@ def unmerge(unmerge_action, unmerge_files):
 
                                if sp_absx_len <= sp_vdb_len:
                                        # The Path is shorter... so it can't be inside the vdb.
-                                       print spabsx
+                                       print sp_absx
                                        print absx
-                                       print "\n!!!",x,"cannot be inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n"
+                                       print "\n!!!",x,"cannot be inside "+vdb_path+"; aborting.\n"
                                        return 0
 
                                for idx in range(0,sp_vdb_len):
                                        if (idx >= sp_absx_len) or (sp_vdb[idx] != sp_absx[idx]):
                                                print sp_absx
                                                print absx
-                                               print "\n!!!",x,"is not inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n"
+                                               print "\n!!!",x,"is not inside "+vdb_path+"; aborting.\n"
                                                return 0
 
                                print "="+string.join(sp_absx[sp_vdb_len:],"/")
                                candidate_catpkgs.append("="+string.join(sp_absx[sp_vdb_len:],"/"))
 
+       newline=""
+       if (not "--quiet" in myopts):
+               newline="\n"
+       if settings["ROOT"] != "/":
+               print darkgreen(newline+">>> Using system located in ROOT tree "+settings["ROOT"])
        if (("--pretend" in myopts) or ("--ask" in myopts)) and not ("--quiet" in myopts):
-               print darkgreen("\n>>> These are the packages that would be unmerged:")
+               print darkgreen(newline+">>> These are the packages that would be unmerged:")
 
        pkgmap={}
        numselected=0
@@ -2239,9 +2468,15 @@ def unmerge(unmerge_action, unmerge_files):
                        #add a "=" if missing
                        mymatch=localtree.dep_match("="+x)
                if not mymatch:
-                       print "\n--- Couldn't find " + white(x) + " to "+unmerge_action+"."
-                       continue
-               mykey=portage.key_expand(portage.dep_getkey(mymatch[0]),portage.db["/"]["vartree"].dbapi)
+                       if raise_on_missing:
+                               raise portage_exception.PackageNotFound(x)
+                       else:
+                               portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \
+                                       (x, unmerge_action), noiselevel=-1)
+                               continue
+               mykey = portage.key_expand(
+                       portage.dep_getkey(
+                               mymatch[0]), mydb=vartree.dbapi, settings=settings)
                if not pkgmap.has_key(mykey):
                        pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] }
                if unmerge_action=="unmerge":
@@ -2293,14 +2528,14 @@ def unmerge(unmerge_action, unmerge_files):
                        #avoid cluttering the preview printout with stuff that isn't getting unmerged
                        continue
                if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist):
-                       print red("\a\n\n!!! '%s' is part of your system profile." % mykey)
-                       print yellow("\a!!! Unmerging it may be damaging to your system.\n")
+                       print colorize("BAD","\a\n\n!!! '%s' is part of your system profile." % x)
+                       print colorize("WARN","\a!!! Unmerging it may be damaging to your system.\n")
                        if "--pretend" not in myopts and "--ask" not in myopts:
-                               global EMERGE_WARNING_DELAY
-                               countdown(EMERGE_WARNING_DELAY,red("Press Ctrl-C to Stop"))
+                               countdown(int(settings["EMERGE_WARNING_DELAY"]),
+                                       colorize("UNMERGE_WARN", "Press Ctrl-C to Stop"))
                print "\n "+white(x)
                for mytype in ["selected","protected","omitted"]:
-                       print string.rjust(mytype,12)+":",
+                       portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
                        if pkgmap[x][mytype]:
                                for mypkg in pkgmap[x][mytype]:
                                        mysplit=portage.catpkgsplit(mypkg)
@@ -2309,86 +2544,65 @@ def unmerge(unmerge_action, unmerge_files):
                                        else:
                                                myversion=mysplit[2]+"-"+mysplit[3]
                                        if mytype=="selected":
-                                               print red(myversion),
+                                               portage.writemsg_stdout(
+                                                       colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1)
                                        else:
-                                               print green(myversion),
+                                               portage.writemsg_stdout(
+                                                       colorize("GOOD", myversion + " "), noiselevel=-1)
                        else:
-                                       print "none",
-                       print
-        
-       if portage.settings["ROOT"]:
-               print string.rjust("ROOT:", 12) + " " + white(portage.settings["ROOT"])
+                               portage.writemsg_stdout("none", noiselevel=-1)
+                       portage.writemsg_stdout("\n", noiselevel=-1)
 
-       print "\n>>>",red("'Selected'"),"packages are slated for removal."
-       print ">>>",green("'Protected'"),"and",green("'omitted'"),"packages will not be removed.\n"
+       portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \
+               " packages are slated for removal.\n")
+       portage.writemsg_stdout(">>> " + colorize("GOOD", "'Protected'") + \
+                       " and " + colorize("GOOD", "'omitted'") + \
+                       " packages will not be removed.\n\n")
 
        if "--pretend" in myopts:
                #we're done... return
                return 0
        if "--ask" in myopts:
-               if userquery("Do you want me to unmerge these packages?")=="No":
+               if userquery("Would you like to unmerge these packages?")=="No":
                        # enter pretend mode for correct formatting of results
-                       myopts+=["--pretend"]
+                       myopts["--pretend"] = True
                        print
                        print "Quitting."
                        print
                        return 0
        #the real unmerging begins, after a short delay....
-
-       global CLEAN_DELAY
-       countdown(CLEAN_DELAY, ">>> Unmerging")
+       countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging")
 
        for x in pkgmap.keys():
                for y in pkgmap[x]["selected"]:
                        print ">>> Unmerging "+y+"..."
-                       emergelog("=== Unmerging... ("+y+")")
+                       emergelog(xterm_titles, "=== Unmerging... ("+y+")")
                        mysplit=string.split(y,"/")
                        #unmerge...
-                       retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,mysettings,unmerge_action not in ["clean","prune"])
-                       if retval:
-                               emergelog(" !!! unmerge FAILURE: "+y)
+                       retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"],
+                               mysettings, unmerge_action not in ["clean","prune"],
+                               vartree=vartree, ldpath_mtimes=ldpath_mtimes)
+                       if retval != os.EX_OK:
+                               emergelog(xterm_titles, " !!! unmerge FAILURE: "+y)
                        else:
-                               emergelog(" >>> unmerge success: "+y)
-       #run ldconfig, etc...
-       portage.env_update()
-       if not numselected:
-               return 0
-       else:
-               return 1
-
+                               clean_world(vartree.dbapi, y)
+                               emergelog(xterm_titles, " >>> unmerge success: "+y)
+       return 1
 
-def chk_updated_info_files(retval):
-       root=portage.root
-
-       infodirs=[]
-       infodirs.extend(string.split(portage.settings["INFOPATH"], ":"))
-       infodirs.extend(string.split(portage.settings["INFODIR"], ":"))
+def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
 
        print
-       if os.path.exists("install-info"):
+       if os.path.exists(portage_const.EPREFIX+"/usr/bin/install-info"):
                regen_infodirs=[]
                for z in infodirs:
                        if z=='':
                                continue
                        inforoot=normpath(root+z)
                        if os.path.isdir(inforoot):
-                               try:
-                                       infomtime=os.stat(inforoot)[ST_MTIME]
-                               except SystemExit, e:
-                                       raise # Needed else can't exit
-                               except:
-                                       infomtime=0
-
-                               if not portage.mtimedb.has_key("info"):
-                                       portage.mtimedb["info"]={}
-                               if portage.mtimedb["info"].has_key(inforoot):
-                                       if portage.mtimedb["info"][inforoot]==infomtime:
-                                               pass
-                                       else:
-                                               portage.mtimedb["info"][inforoot]=infomtime
+                               infomtime = long(os.stat(inforoot).st_mtime)
+                               if inforoot not in prev_mtimes or \
+                                       prev_mtimes[inforoot] != infomtime:
                                                regen_infodirs.append(inforoot)
-                               else:
-                                       regen_infodirs.append(inforoot)
 
                if not regen_infodirs:
                        print " "+green("*")+" GNU info directory index is up-to-date."
@@ -2410,10 +2624,12 @@ def chk_updated_info_files(retval):
                                if not os.path.isdir(inforoot):
                                        continue
                                errmsg = ""
-                               for x in os.listdir(inforoot):
+                               file_list = os.listdir(inforoot)
+                               file_list.sort()
+                               for x in file_list:
                                        if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)):
                                                continue
-                                       myso=commands.getstatusoutput("LANG=C LANGUAGE=C install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
+                                       myso=commands.getstatusoutput("LANG=C LANGUAGE=C "+portage_const.EPREFIX+"/usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
                                        existsstr="already exists, for file `"
                                        if myso!="":
                                                if re.search(existsstr,myso):
@@ -2430,7 +2646,7 @@ def chk_updated_info_files(retval):
                                        icount=icount+1
 
                                #update mtime so we can potentially avoid regenerating.
-                               portage.mtimedb["info"][inforoot]=os.stat(inforoot)[ST_MTIME]
+                               prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime)
 
                        if badcount:
                                print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors."
@@ -2439,36 +2655,55 @@ def chk_updated_info_files(retval):
                                print " "+green("*")+" Processed",icount,"info files."
 
 
-def post_emerge(retval=0):
-       global myopts
+def post_emerge(settings, mtimedb, retval):
+       target_root = settings["ROOT"]
+       info_mtimes = mtimedb["info"]
+       config_protect = settings.get("CONFIG_PROTECT","").split()
+       infodirs = settings.get("INFOPATH","").split(":") + \
+               settings.get("INFODIR","").split(":")
+
        os.chdir("/")
-       if "--pretend" in myopts:
-               sys.exit(retval)
 
-       emergelog(" *** exiting successfully.")
+       emergelog("notitles" not in settings.features,
+               " *** exiting successfully.")
 
-       if "noinfo" not in portage.settings.features:
-               chk_updated_info_files(retval)
+       if "noinfo" not in settings.features:
+               chk_updated_info_files(target_root, infodirs, info_mtimes, retval)
 
-       chk_updated_cfg_files()
+       chk_updated_cfg_files(target_root, config_protect)
+       mtimedb.commit()
        sys.exit(retval)
 
 
-def chk_updated_cfg_files():
-       if portage.settings["CONFIG_PROTECT"]:
+def chk_updated_cfg_files(target_root, config_protect):
+       if config_protect:
                #number of directories with some protect files in them
                procount=0
-               for x in string.split(portage.settings["CONFIG_PROTECT"]):
-                       x = portage_const.EPREFIX + x
-                       if os.path.isdir(x):
-                               a=commands.getstatusoutput("cd "+x+"; find . -iname '._cfg????_*'")
-                               if a[0]!=0:
-                                       print " "+red("*")+" error scanning",x
-                               else:
-                                       files=string.split(a[1])
-                                       if files:
-                                               procount=procount+1
-                                               print " "+yellow("* IMPORTANT:")+"",len(files),"config files in",x,"need updating."
+               for x in config_protect:
+                       x = os.path.join(target_root, x.lstrip(os.path.sep))
+                       try:
+                               mymode = os.lstat(x).st_mode
+                       except OSError:
+                               continue
+                       if stat.S_ISDIR(mymode):
+                               mycommand = "cd '%s'; find . -iname '._cfg????_*'" % x
+                       else:
+                               mycommand = "cd '%s'; find . -maxdepth 1 -iname '._cfg????_%s'" % \
+                                       os.path.split(x.rstrip(os.path.sep))
+                       a = commands.getstatusoutput(mycommand)
+                       if a[0] != 0:
+                               print >> sys.stderr, " " + bad("*")+ " error scanning '%s'" % x
+                       else:
+                               files = a[1].split()
+                               if files:
+                                       procount += 1
+                                       print colorize("WARN", " * IMPORTANT:"),
+                                       if stat.S_ISDIR(mymode):
+                                                print "%d config files in '%s' need updating." % \
+                                                       (len(files), x)
+                                       else:
+                                                print "config file '%s' needs updating." % x
+
                if procount:
                        #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
                        print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
@@ -2484,28 +2719,43 @@ def is_valid_package_atom(x):
                testatom = x
        return portage.isvalidatom(testatom)
 
-# general options that should be taken into account before any action
-if "--debug" in myopts:
-       edebug=1
+def validate_merge_list(trees, mergelist):
+       """Validate the list to make sure all the packages are still available.
+       This is needed for --resume."""
+       for (pkg_type, myroot, pkg_key, action) in mergelist:
+               if pkg_type == "binary" and \
+                       not trees[myroot]["bintree"].dbapi.match("="+pkg_key) or \
+                       pkg_type == "ebuild" and \
+                       not trees[myroot]["porttree"].dbapi.xmatch(
+                       "match-all", "="+pkg_key):
+                       print red("!!! Error: The resume list contains packages that are no longer")
+                       print red("!!!        available to be emerged. Please restart/continue")
+                       print red("!!!        the merge operation manually.")
+                       sys.exit(1)
 
-if myaction in ["sync","metadata"] and (not "--help" in myopts):
-       if "--pretend" in myopts:
-               print "emerge: \"sync\" actions do not support \"--pretend.\""
-               sys.exit(1)
+def show_blocker_docs_link():
+       print
+       print "For more information about " + bad("Blocked Packages") + ", please refer to the following"
+       print "section of the Gentoo Linux x86 Handbook (architecture is irrelevant):"
+       print
+       print "http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked"
+       print
 
-       emergelog(" === "+str(myaction))
-       myportdir=portage.settings["PORTDIR"]
+def action_sync(settings, trees, mtimedb, myopts, myaction):
+       xterm_titles = "notitles" not in settings.features
+       emergelog(xterm_titles, " === sync")
+       myportdir = settings.get("PORTDIR", None)
+       if not myportdir:
+               sys.stderr.write("!!! PORTDIR is undefined.  Is /etc/make.globals missing?\n")
+               sys.exit(1)
        if myportdir[-1]=="/":
                myportdir=myportdir[:-1]
        if not os.path.exists(myportdir):
                print ">>>",myportdir,"not found, creating it."
                os.makedirs(myportdir,0755)
-       syncuri=string.rstrip(portage.settings["SYNC"])
+       syncuri=string.rstrip(settings["SYNC"])
        os.umask(0022)
        if myaction == "metadata":
-               if "--ask" in myopts:
-                       if userquery("Are you sure?") == "No":
-                               sys.exit(1)
                print "skipping sync"
                updatecache_flg = True
                tmpservertimestampfile = None
@@ -2518,7 +2768,7 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
 
                rsync_opts = []
 
-               if portage.settings["PORTAGE_RSYNC_OPTS"] == "":
+               if settings["PORTAGE_RSYNC_OPTS"] == "":
                        portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n")
                        rsync_opts.extend([
                                "--recursive",    # Recurse directories
@@ -2542,8 +2792,8 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                        # The below validation is not needed when using the above hardcoded
                        # defaults.
 
-                       portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n")
-                       rsync_opts.extend(portage.settings["PORTAGE_RSYNC_OPTS"].split())
+                       portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1)
+                       rsync_opts.extend(settings["PORTAGE_RSYNC_OPTS"].split())
 
                        for opt in ("--recursive", "--times"):
                                if opt not in rsync_opts:
@@ -2552,18 +2802,18 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                        rsync_opts.append(opt)
        
                        for exclude in ("distfiles", "local", "packages"):
-                               opt = "--exclude='/%s'" % exclude
+                               opt = "--exclude=/%s" % exclude
                                if opt not in rsync_opts:
                                        portage.writemsg(yellow("WARNING:") + \
                                        " adding required option %s not included in "  % opt + \
-                                       "PORTAGE_RSYNC_OPTS (override with --exclude='!')\n")
+                                       "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n")
                                        rsync_opts.append(opt)
        
-                       if portage.settings["RSYNC_TIMEOUT"] != "":
+                       if settings["RSYNC_TIMEOUT"] != "":
                                portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \
                                "use PORTAGE_RSYNC_EXTRA_OPTS instead\n")
                                try:
-                                       mytimeout = int(portage.settings["RSYNC_TIMEOUT"])
+                                       mytimeout = int(settings["RSYNC_TIMEOUT"])
                                        rsync_opts.append("--timeout=%d" % mytimeout)
                                except ValueError, e:
                                        portage.writemsg("!!! %s\n" % str(e))
@@ -2589,36 +2839,36 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                if "--quiet" in myopts:
                        rsync_opts.append("--quiet")    # Shut up a lot
                else:
-                       rsync_opts.append("--progress") # Progress meter for each file
+                       rsync_opts.append("--verbose")  # Print filelist
 
                if "--verbose" in myopts:
-                       rsync_opts.append("--verbose")  # More noise? Not really sure what
+                       rsync_opts.append("--progress")  # Progress meter for each file
 
                if "--debug" in myopts:
                        rsync_opts.append("--checksum") # Force checksum on all files
 
-               if portage.settings["RSYNC_EXCLUDEFROM"] != "":
+               if settings["RSYNC_EXCLUDEFROM"] != "":
                        portage.writemsg(yellow("WARNING:") + \
                        " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \
                        "PORTAGE_RSYNC_EXTRA_OPTS instead\n")
-                       if os.path.exists(portage.settings["RSYNC_EXCLUDEFROM"]):
+                       if os.path.exists(settings["RSYNC_EXCLUDEFROM"]):
                                rsync_opts.append("--exclude-from=%s" % \
-                               portage.settings["RSYNC_EXCLUDEFROM"])
+                               settings["RSYNC_EXCLUDEFROM"])
                        else:
                                portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \
                                " but file does not exist.\n")
 
-               if portage.settings["RSYNC_RATELIMIT"] != "":
+               if settings["RSYNC_RATELIMIT"] != "":
                        portage.writemsg(yellow("WARNING:") + \
                        " usage of RSYNC_RATELIMIT is deprecated, use " + \
                        "PORTAGE_RSYNC_EXTRA_OPTS instead")
                        rsync_opts.append("--bwlimit=%s" % \
-                       portage.settings["RSYNC_RATELIMIT"])
+                       settings["RSYNC_RATELIMIT"])
 
-               servertimestampdir  = portage.settings.depcachedir+"/"
-               servertimestampfile = portage.settings.depcachedir+"/timestamp.chk"
-               tmpservertimestampdir  = portage.settings["PORTAGE_TMPDIR"]+"/"
-               tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk"
+               servertimestampdir  = settings.depcachedir+"/"
+               servertimestampfile = settings.depcachedir+"/timestamp.chk"
+               tmpservertimestampdir  = settings["PORTAGE_TMPDIR"]+"/"
+               tmpservertimestampfile = settings["PORTAGE_TMPDIR"]+"/timestamp.chk"
 
                # We only use the backup if a timestamp exists in the portdir.
                content=None
@@ -2642,29 +2892,46 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
 
                #exitcode=0
                try:
-                       if portage.settings.has_key("RSYNC_RETRIES"):
+                       if settings.has_key("RSYNC_RETRIES"):
                                print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead"
-                               maxretries=int(portage.settings["RSYNC_RETRIES"])                               
+                               maxretries=int(settings["RSYNC_RETRIES"])                               
                        else:
-                               maxretries=int(portage.settings["PORTAGE_RSYNC_RETRIES"])
+                               maxretries=int(settings["PORTAGE_RSYNC_RETRIES"])
                except SystemExit, e:
                        raise # Needed else can't exit
                except:
                        maxretries=3 #default number of retries
 
                retries=0
-               hostname, port=re.split("rsync://([^:/]*)(:[0-9]+)?", syncuri)[1:3];
-               if port==None:
+               user_name, hostname, port = re.split(
+                       "rsync://([^:/]+@)?([^:/]*)(:[0-9]+)?", syncuri, maxsplit=3)[1:4]
+               if port is None:
                        port=""
+               if user_name is None:
+                       user_name=""
                updatecache_flg=True
-
+               all_rsync_opts = set(rsync_opts)
+               all_rsync_opts.update(
+                       settings.get("PORTAGE_RSYNC_EXTRA_OPTS","").split())
+               family = socket.AF_UNSPEC
+               if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts:
+                       family = socket.AF_INET
+               elif socket.has_ipv6 and \
+                       ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
+                       family = socket.AF_INET6
                ips=[]
                while (1):
                        if ips:
                                del ips[0]
                        if ips==[]:
                                try:
-                                       ips=socket.gethostbyname_ex(hostname)[2]
+                                       for addrinfo in socket.getaddrinfo(
+                                               hostname, None, family, socket.SOCK_STREAM):
+                                               if addrinfo[0] == socket.AF_INET6:
+                                                       # IPv6 addresses need to be enclosed in square brackets
+                                                       ips.append("[%s]" % addrinfo[4][0])
+                                               else:
+                                                       ips.append(addrinfo[4][0])
                                except SystemExit, e:
                                        raise # Needed else can't exit
                                except Exception, e:
@@ -2673,7 +2940,9 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
 
                        if ips:
                                try:
-                                       dosyncuri=string.replace(syncuri, "//"+hostname+port+"/", "//"+ips[0]+port+"/", 1)
+                                       dosyncuri = syncuri.replace(
+                                               "//" + user_name + hostname + port + "/",
+                                               "//" + user_name + ips[0] + port + "/", 1)
                                except SystemExit, e:
                                        raise # Needed else can't exit
                                except Exception, e:
@@ -2687,19 +2956,20 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                                print "Quitting."
                                                print
                                                sys.exit(0)
-                               emergelog(">>> Starting rsync with "+dosyncuri)
+                               emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri)
                                if "--quiet" not in myopts:
                                        print ">>> Starting rsync with "+dosyncuri+"..."
                        else:
-                               emergelog(">>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri))
+                               emergelog(xterm_titles,
+                                       ">>> Starting retry %d of %d with %s" % \
+                                               (retries,maxretries,dosyncuri))
                                print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)
 
                        if "--quiet" not in myopts:
                                print ">>> Checking server timestamp ..."
 
-                       rsynccommand = " ".join([portage_const.EPREFIX+"/usr/bin/rsync",
-                               portage.settings["PORTAGE_RSYNC_EXTRA_OPTS"],
-                               " ".join(rsync_opts)])
+                       rsynccommand = " ".join([portage_const.EPREFIX, "/usr/bin/rsync", " ".join(rsync_opts),
+                               settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")])
 
                        if "--debug" in myopts:
                                print rsynccommand
@@ -2707,7 +2977,7 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                        mycommand = " ".join([rsynccommand,
                                dosyncuri + "/metadata/timestamp.chk",
                                tmpservertimestampdir])
-                       exitcode=portage.spawn(mycommand,portage.settings,free=1)
+                       exitcode=portage.spawn(mycommand,settings,free=1)
                        if (exitcode==0):
                                try:
                                        servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000"))
@@ -2717,7 +2987,8 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                        servertimestamp = 0
 
                                if (servertimestamp != 0) and (servertimestamp == mytimestamp):
-                                       emergelog(">>> Cancelling sync -- Already current.")
+                                       emergelog(xterm_titles,
+                                               ">>> Cancelling sync -- Already current.")
                                        print
                                        print ">>>"
                                        print ">>> Timestamps on the server and in the local repository are the same."
@@ -2726,7 +2997,8 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                        print
                                        sys.exit(0)
                                elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
-                                       emergelog(">>> Server out of date: %s" % dosyncuri)
+                                       emergelog(xterm_titles,
+                                               ">>> Server out of date: %s" % dosyncuri)
                                        print
                                        print ">>>"
                                        print ">>> SERVER OUT OF DATE: %s" % dosyncuri
@@ -2735,7 +3007,7 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
                                        # actual sync
                                        mycommand=rsynccommand+" "+dosyncuri+"/ "+myportdir
-                                       exitcode=portage.spawn(mycommand,portage.settings,free=1)
+                                       exitcode=portage.spawn(mycommand,settings,free=1)
                                        if exitcode in [0,1,2,3,4,11,14,20,21]:
                                                break
                        elif exitcode in [0,1,2,3,4,11,14,20,21]:
@@ -2753,19 +3025,31 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                                break
 
                if (exitcode==0):
-                       emergelog("=== Sync completed with %s" % dosyncuri)
+                       emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri)
+                       # save timestamp.chk for next timestamp check.
+                       try:
+                               if tmpservertimestampfile is not None:
+                                       portage.movefile(tmpservertimestampfile,
+                                               servertimestampfile, mysettings=settings)
+                       except SystemExit, e:
+                               raise
+                       except Exception, e:
+                               portage.writemsg("!!! Failed to save current timestamp.\n",
+                                       noiselevel=-1)
+                               portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+                               del e
                elif (exitcode>0):
                        print
                        if exitcode==1:
                                print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure")
                                print darkred("!!!")+green(" that your SYNC statement is proper.")
-                               print darkred("!!!")+green(" SYNC="+portage.settings["SYNC"])
+                               print darkred("!!!")+green(" SYNC="+settings["SYNC"])
                        elif exitcode==11:
                                print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally")
                                print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption")
                                print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate")
                                print darkred("!!!")+green(" and try again after the problem has been fixed.")
-                               print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"])
+                               print darkred("!!!")+green(" PORTDIR="+settings["PORTDIR"])
                        elif exitcode==20:
                                print darkred("!!!")+green(" Rsync was killed before it finished.")
                        else:
@@ -2777,7 +3061,7 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                        print
                        sys.exit(exitcode)
        elif syncuri[:6]=="cvs://":
-               if not os.path.exists("cvs"):
+               if not os.path.exists(portage_const.EPREFIX+"/usr/bin/cvs"):
                        print "!!! cvs does not exist, so CVS support is disabled."
                        print "!!! Type \"emerge dev-util/cvs\" to enable CVS support."
                        sys.exit(1)
@@ -2786,149 +3070,52 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                if not os.path.exists(myportdir+"/CVS"):
                        #initial checkout
                        print ">>> Starting initial cvs checkout with "+syncuri+"..."
-                       if not portage.spawn("cd "+cvsdir+"; cvs -d "+cvsroot+" login",portage.settings,free=1):
-                               print "!!! cvs login error; exiting."
-                               sys.exit(1)
                        if os.path.exists(cvsdir+"/gentoo-x86"):
                                print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting."
                                sys.exit(1)
-                       if not portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",portage.settings,free=1):
+                       if portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",settings,free=1):
                                print "!!! cvs checkout error; exiting."
                                sys.exit(1)
                        if cvsdir!=myportdir:
-                               portage.movefile(cvsdir,portage.settings["PORTDIR"])
+                               portage.movefile(cvsdir,settings["PORTDIR"])
                        sys.exit(0)
                else:
                        #cvs update
                        print ">>> Starting cvs update with "+syncuri+"..."
-                       sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",portage.settings,free=1))
+                       sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",settings,free=1))
        else:
                print "!!! rsync setting: ",syncuri,"not recognized; exiting."
                sys.exit(1)
 
-       try: # Prevent users from affecting ebuild.sh.
-               os.close(sys.stdin.fileno())
-       except SystemExit, e:
-               raise # Needed else can't exit
-       except:
-               pass
-
        if updatecache_flg and  \
                myaction != "metadata" and \
-               "metadata-transfer" not in portage.settings.features:
+               "metadata-transfer" not in settings.features:
                updatecache_flg = False
 
-       if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
-               if "--quiet" not in myopts:
-                       print "\n>>> Updating Portage cache:      ",
-               os.umask(0002)
-               cachedir = os.path.normpath(portage.settings.depcachedir)
-               if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
-                               "/lib", "/opt", "/proc", "/root", "/sbin",
-                               "/sys", "/tmp", "/usr",  "/var"]:
-                       print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM."
-                       print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir)
-                       sys.exit(73)
-               if not os.path.exists(cachedir):
-                       os.mkdir(cachedir)
-
-               # Potentially bad
-               #if os.path.exists(cachedir+"/"+myportdir):
-               #       portage.spawn("rm -Rf "+cachedir+"/"+myportdir+"/*",portage.settings,free=1)
-
-               # save timestamp.chk for next timestamp check.
-               try:
-                       if tmpservertimestampfile != None:
-                               portage.movefile(tmpservertimestampfile, servertimestampfile)
-               except SystemExit, e:
-                       raise # Needed else can't exit
-               except Exception, e:
-                       print "!!! Failed to save current timestamp."
-                       print "!!!",e
-
-               portage.portdb.flush_cache()
-
-               ec = portage.eclass_cache.cache(portage.portdb.porttree_root)
-               # kinda ugly.
-               # XXX: nuke the filter when mr UNUSED_0? keys are dead
-               cm = portage.settings.load_best_module("portdbapi.metadbmodule")(myportdir, "metadata/cache", 
-                       filter(lambda x: not x.startswith("UNUSED_0"), portage.auxdbkeys))
-
-               # we don't make overlay trees cache here, plus we don't trust portage.settings.categories
-               porttree_root = portage.portdb.porttree_root
-               conf = portage.config(config_profile_path=portage.settings.profile_path[:], \
-                       config_incrementals=portage.settings.incrementals[:])
-
-               conf["PORTDIR_OVERLAY"] = ''
-               conf.categories = portage.grabfile(os.path.join(porttree_root, "profiles", "categories"))
-               try:
-                       i = conf.categories.index("virtual")
-                       if i != -1:
-                               conf.categories.remove(i)
-               except (ValueError, IndexError):
-                       pass
-
-               pdb = portage.portdbapi(porttree_root, conf)
-
-               cp_all_list = pdb.cp_all()
-               import cache.util
-
-               class percentage_noise_maker(cache.util.quiet_mirroring):
-                       def __init__(self, dbapi):
-                               self.dbapi = dbapi
-                               self.cp_all = dbapi.cp_all()
-                               l = len(self.cp_all)
-                               self.call_update_min = 100000000
-                               self.min_cp_all = l/100.0
-                               self.count = 1
-                               self.pstr = ''
-
-                       def __iter__(self):
-                               for x in self.cp_all:
-                                       self.count += 1
-                                       if self.count > self.min_cp_all:
-                                               self.call_update_min = 0
-                                               self.count = 0
-                                       for y in self.dbapi.cp_list(x):
-                                               yield y
-                               self.call_update_mine = 0
-
-                       def update(self, *arg):
-                               try:                            self.pstr = int(self.pstr) + 1
-                               except ValueError:      self.pstr = 1
-                               sys.stdout.write("%s%i%%" % ("\b" * (len(str(self.pstr))+1), self.pstr))
-                               sys.stdout.flush()
-                               self.call_update_min = 10000000
-
-                       def finish(self, *arg):
-                               sys.stdout.write("\b\b\b\b100%\n")
-                               sys.stdout.flush()
-
+       # Reload the whole config from scratch.
+       settings, trees, mtimedb = load_emerge_config(trees=trees)
+       portdb = trees[settings["ROOT"]]["porttree"].dbapi
 
-               if "--quiet" in myopts:
-                       def quicky_cpv_generator(cp_all_list):
-                               for x in cp_all_list:
-                                       for y in pdb.cp_list(x):
-                                               yield y
-                       source = quicky_cpv_generator(pdb.cp_all())
-                       noise_maker = cache.util.quiet_mirroring()
-               else:
-                       noise_maker = source = percentage_noise_maker(pdb)
-               cache.util.mirror_cache(source, cm, pdb.auxdb[porttree_root], eclass_cache=ec, verbose_instance=noise_maker)
+       if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
+               action_metadata(settings, portdb, myopts)
 
-               sys.stdout.flush()
+       portage.global_updates(
+               settings, trees, mtimedb["updates"])
+       mtimedb.commit()
+       # Reload the whole config from scratch.
+       settings, trees, mtimedb = load_emerge_config(trees=trees)
+       portdb = trees[settings["ROOT"]]["porttree"].dbapi
 
-       portage.portageexit()
-       reload(portage)
-       mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage")
-       mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage"))
+       mybestpv = portdb.xmatch("bestmatch-visible", "sys-apps/portage")
+       mypvs = portage.best(
+               trees[settings["ROOT"]]["vartree"].dbapi.match("sys-apps/portage"))
 
-       chk_updated_cfg_files()
+       chk_updated_cfg_files("/", settings.get("CONFIG_PROTECT","").split())
 
        if myaction != "metadata":
                if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK):
                        try:
-                               portage.spawn(portage.USER_CONFIG_PATH + "/bin/post_sync " + dosyncuri, portage.settings, free=1)
+                               portage.spawn(portage.USER_CONFIG_PATH + "/bin/post_sync " + dosyncuri, settings, free=1)
                        except:
                                print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync")
 
@@ -2938,9 +3125,81 @@ if myaction in ["sync","metadata"] and (not "--help" in myopts):
                print red(" * ")+"that you update portage now, before any other packages are updated."
                print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your"
                print red(" * ")+"configuration files."
+               print red(" * ")+"To update portage, run 'emerge portage'."
                print
-elif myaction=="regen":
-       emergelog(" === regen")
+
+def action_metadata(settings, portdb, myopts):
+       portage.writemsg_stdout("\n>>> Updating Portage cache:      ")
+       old_umask = os.umask(0002)
+       cachedir = os.path.normpath(settings.depcachedir)
+       if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
+                                       "/lib", "/opt", "/proc", "/root", "/sbin",
+                                       "/sys", "/tmp", "/usr",  "/var"]:
+               print >> sys.stderr, "!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \
+                       "ROOT DIRECTORY ON YOUR SYSTEM."
+               print >> sys.stderr, \
+                       "!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir
+               sys.exit(73)
+       if not os.path.exists(cachedir):
+               os.mkdir(cachedir)
+
+       ec = portage.eclass_cache.cache(portdb.porttree_root)
+       myportdir = os.path.realpath(settings["PORTDIR"])
+       cm = settings.load_best_module("portdbapi.metadbmodule")(
+               myportdir, "metadata/cache", portage.auxdbkeys[:])
+
+       import cache.util
+
+       class percentage_noise_maker(cache.util.quiet_mirroring):
+               def __init__(self, dbapi):
+                       self.dbapi = dbapi
+                       self.cp_all = dbapi.cp_all()
+                       l = len(self.cp_all)
+                       self.call_update_min = 100000000
+                       self.min_cp_all = l/100.0
+                       self.count = 1
+                       self.pstr = ''
+
+               def __iter__(self):
+                       for x in self.cp_all:
+                               self.count += 1
+                               if self.count > self.min_cp_all:
+                                       self.call_update_min = 0
+                                       self.count = 0
+                               for y in self.dbapi.cp_list(x):
+                                       yield y
+                       self.call_update_mine = 0
+
+               def update(self, *arg):
+                       try:                            self.pstr = int(self.pstr) + 1
+                       except ValueError:      self.pstr = 1
+                       sys.stdout.write("%s%i%%" % \
+                               ("\b" * (len(str(self.pstr))+1), self.pstr))
+                       sys.stdout.flush()
+                       self.call_update_min = 10000000
+
+               def finish(self, *arg):
+                       sys.stdout.write("\b\b\b\b100%\n")
+                       sys.stdout.flush()
+
+       if "--quiet" in myopts:
+               def quicky_cpv_generator(cp_all_list):
+                       for x in cp_all_list:
+                               for y in portdb.cp_list(x):
+                                       yield y
+               source = quicky_cpv_generator(portdb.cp_all())
+               noise_maker = cache.util.quiet_mirroring()
+       else:
+               noise_maker = source = percentage_noise_maker(portdb)
+       cache.util.mirror_cache(source, cm, portdb.auxdb[myportdir],
+               eclass_cache=ec, verbose_instance=noise_maker)
+
+       sys.stdout.flush()
+       os.umask(old_umask)
+
+def action_regen(settings, portdb):
+       xterm_titles = "notitles" not in settings.features
+       emergelog(xterm_titles, " === regen")
        #regenerate cache entries
        print "Regenerating cache entries... "
        try:
@@ -2950,32 +3209,36 @@ elif myaction=="regen":
        except:
                pass
        sys.stdout.flush()
-       mynodes=portage.portdb.cp_all()
+       mynodes = portdb.cp_all()
        for x in mynodes:
-               mymatches=portage.portdb.xmatch("match-all",x)
-               if not "--quiet" in myopts:
-                       print "processing",x
+               mymatches = portdb.xmatch("match-all",x)
+               portage.writemsg_stdout("processing %s\n" % x)
                for y in mymatches:
                        try:
-                               foo=portage.portdb.aux_get(y,["DEPEND"])
+                               foo = portdb.aux_get(y,["DEPEND"])
                        except SystemExit, e:
                                # sys.exit is an exception... And consequently, we can't catch it.
                                raise
                        except Exception, e:
                                print "\n  error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)}
        print "done!"
-# HELP action
-elif "config"==myaction:
+
+def action_config(settings, trees, myopts, myfiles):
        if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles:
                print red("!!! config can only take a single package atom at this time\n")
                sys.exit(1)
        if not is_valid_package_atom(myfiles[0]):
-               portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0])
+               portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0],
+                       noiselevel=-1)
                portage.writemsg("!!! Please check ebuild(5) for full details.\n")
                portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
                sys.exit(1)
        print
-       pkgs = portage.db[portage.root]["vartree"].dbapi.match(myfiles[0])
+       try:
+               pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0])
+       except ValueError, e:
+               # Multiple matches thrown from cpv_expand
+               pkgs = e.args[0]
        if len(pkgs) == 0:
                print "No packages found.\n"
                sys.exit(0)
@@ -3010,26 +3273,43 @@ elif "config"==myaction:
        else:
                print "Configuring pkg..."
        print
-       ebuildpath = portage.db[portage.root]["vartree"].dbapi.findname(pkg)
-       mysettings = portage.config(clone=portage.settings)
-       portage.doebuild(ebuildpath,"config",portage.root,mysettings,debug=("--debug" in myopts),cleanup=True,tree="vartree")
+       ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg)
+       mysettings = portage.config(clone=settings)
+       portage.doebuild(ebuildpath, "config", settings["ROOT"], mysettings,
+               debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True,
+               mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree")
        print
 
-# INFO action
-elif "info"==myaction:
+def action_info(settings, trees, myopts, myfiles):
        unameout=commands.getstatusoutput("uname -mrp")[1]
-       print getportageversion()
-       print "================================================================="
+       print getportageversion(settings["PORTDIR"], settings["ROOT"],
+               settings.profile_path, settings["CHOST"],
+               trees[settings["ROOT"]]["vartree"].dbapi)
+       header_width = 65
+       header_title = "System Settings"
+       if myfiles:
+               print header_width * "="
+               print header_title.rjust(int(header_width/2 + len(header_title)/2))
+       print header_width * "="
        print "System uname: "+unameout
-       if os.path.exists(portage_const.EPREFIX+"/etc/gentoo-release"):
-               os.system("cat "+portage_const.EPREFIX+"/etc/gentoo-release")
+       gentoo_release = portage.grabfile(os.path.join(
+               settings["PORTAGE_CONFIGROOT"], "etc", "gentoo-release"))
+       if gentoo_release:
+               print gentoo_release[0]
        else:
                print "Unknown Host Operating System"
+       lastSync = portage.grabfile(os.path.join(
+               settings["PORTDIR"], "metadata", "timestamp.chk"))
+       print "Last Sync:",
+       if lastSync:
+               print lastSync[0]
+       else:
+               print "Unknown"
 
        output=commands.getstatusoutput("distcc --version")
        if not output[0]:
                print str(string.split(output[1],"\n",1)[0]),
-               if "distcc" in portage.features:
+               if "distcc" in settings.features:
                        print "[enabled]"
                else:
                        print "[disabled]"
@@ -3037,20 +3317,20 @@ elif "info"==myaction:
        output=commands.getstatusoutput("ccache -V")
        if not output[0]:
                print str(string.split(output[1],"\n",1)[0]),
-               if "ccache" in portage.features:
+               if "ccache" in settings.features:
                        print "[enabled]"
                else:
                        print "[disabled]"
 
        myvars  = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
-                  "sys-devel/binutils","sys-devel/odcctools" ,"sys-devel/libtool",  "dev-lang/python"]
-       myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs")
+                  "sys-devel/binutils", "sys-devel/libtool",  "dev-lang/python"]
+       myvars += portage_util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs")
        myvars  = portage_util.unique_array(myvars)
        myvars.sort()
 
        for x in myvars:
                if portage.isvalidatom(x):
-                       pkg_matches = portage.db["/"]["vartree"].dbapi.match(x)
+                       pkg_matches = trees["/"]["vartree"].dbapi.match(x)
                        pkgs = []
                        for y in pkg_matches:
                                mycpv   = portage.catpkgsplit(y)
@@ -3066,24 +3346,24 @@ elif "info"==myaction:
                else:
                        print "%-20s %s" % (x+":", "[NOT VALID]")
 
-       libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",")
+       libtool_vers = string.join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",")
 
        if "--verbose" in myopts:
-               myvars=portage.settings.keys()
+               myvars=settings.keys()
        else:
-               myvars = ['DEFAULT_PATH', 'GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
+               myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
                          'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
-                         'PORTDIR_OVERLAY', 'PREFIX', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
+                         'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
                          'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS']
 
-               myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars"))
+               myvars.extend(portage_util.grabfile(settings["PORTDIR"]+"/profiles/info_vars"))
 
        myvars = portage_util.unique_array(myvars)
        unset_vars = []
        myvars.sort()
        for x in myvars:
-               if portage.settings.has_key(x):
-                       print x+'="'+portage.settings[x]+'"'
+               if settings.has_key(x):
+                       print x+'="'+settings[x]+'"'
                else:
                        unset_vars.append(x)
        if unset_vars:
@@ -3096,12 +3376,76 @@ elif "info"==myaction:
                        if "cvs_id_string" in dir(module):
                                print "%s: %s" % (str(x), str(module.cvs_id_string))
 
-# SEARCH action
-elif "search"==myaction:
+       # See if we can find any packages installed matching the strings
+       # passed on the command line
+       mypkgs = []
+       vardb = trees[settings["ROOT"]]["vartree"].dbapi
+       for x in myfiles:
+               mypkgs.extend(vardb.match(x))
+
+       # If some packages were found...
+       if mypkgs:
+               # Get our global settings (we only print stuff if it varies from
+               # the current config)
+               mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS' ]
+               auxkeys = mydesiredvars + [ "USE", "IUSE"]
+               global_vals = {}
+               pkgsettings = portage.config(clone=settings)
+
+               for myvar in mydesiredvars:
+                       global_vals[myvar] = set(settings.get(myvar, "").split())
+
+               # Loop through each package
+               # Only print settings if they differ from global settings
+               header_printed = False
+               for pkg in mypkgs:
+                       # Get all package specific variables
+                       auxvalues = vardb.aux_get(pkg, auxkeys)
+                       valuesmap = {}
+                       for i in xrange(len(auxkeys)):
+                               valuesmap[auxkeys[i]] = set(auxvalues[i].split())
+                       diff_values = {}
+                       for myvar in mydesiredvars:
+                               # If the package variable doesn't match the
+                               # current global variable, something has changed
+                               # so set diff_found so we know to print
+                               if valuesmap[myvar] != global_vals[myvar]:
+                                       diff_values[myvar] = valuesmap[myvar]
+                       valuesmap["USE"] = valuesmap["USE"].intersection(valuesmap["IUSE"])
+                       pkgsettings.reset()
+                       pkgsettings.setcpv(pkg)
+                       if valuesmap["IUSE"].intersection(pkgsettings["USE"].split()) != \
+                               valuesmap["USE"]:
+                               diff_values["USE"] = valuesmap["USE"]
+                       # If a difference was found, print the info for
+                       # this package.
+                       if diff_values:
+
+                               # If we have not yet printed the header, 
+                               # print it now
+                               if not header_printed:
+                                       header_title = "Package Settings"
+                                       print header_width * "="
+                                       print header_title.rjust(int(header_width/2 + len(header_title)/2))
+                                       print header_width * "="
+                                       header_printed = True
+
+                               # Print package info
+                               print "%s was built with the following:" % pkg
+                               for myvar in mydesiredvars + ["USE"]:
+                                       if myvar in diff_values:
+                                               mylist = list(diff_values[myvar])
+                                               mylist.sort()
+                                               print "%s=\"%s\"" % (myvar, " ".join(mylist))
+                               print
+
+def action_search(settings, portdb, vartree, myopts, myfiles, spinner):
        if not myfiles:
                print "emerge: no search terms provided."
        else:
-               searchinstance = search()
+               searchinstance = search(settings, portdb,
+                       vartree, spinner, "--searchdesc" in myopts,
+                       "--quiet" not in myopts)
                for mysearch in myfiles:
                        try:
                                searchinstance.execute(mysearch)
@@ -3109,30 +3453,37 @@ elif "search"==myaction:
                                print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment )
                                sys.exit(1)
                        searchinstance.output()
-elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
-       if 1==unmerge(myaction, myfiles):
-               post_emerge()
 
-elif "depclean"==myaction:
+def action_depclean(settings, trees, ldpath_mtimes,
+       myopts, spinner):
        # Kill packages that aren't explicitly merged or are required as a
        # dependency of another package. World file is explicit.
 
+       warn_prefix = colorize("BAD", "*** WARNING ***  ")
        print
-       print red("*** WARNING ***")+"  --depclean is known to be broken. It is highly recommended"
-       print red("*** WARNING ***")+"  that "+green("`emerge --update --newuse --deep world`")+" be ran before"
-       print red("*** WARNING ***")+"  commencing. However, using --depclean may still break link"
-       print red("*** WARNING ***")+"  level consistency within your system. "+green("`revdep-rebuild`")
-       print red("*** WARNING ***")+"  from app-portage/gentoolkit can help to detect breakage."
-       print red("*** WARNING ***")
-       print red("*** WARNING ***")+"  Also study the list of packages to be cleaned for any"
-       print red("*** WARNING ***")+"  obvious mistakes. Packages can be manually added to the"
-       print red("*** WARNING ***")+"  world list by running "+green("`emerge --noreplace <atom>`")+"."
-       print red("*** WARNING ***")
-       print red("*** WARNING ***")+"  "+bold("Make sure you have a backup.")
-
-       syslist=getlist("system")
-       worldlist=getlist("world")
-       myvarlist=portage.vardbapi(portage.root).cp_all()
+       print warn_prefix + "Depclean may break link level dependencies.  Thus, it is"
+       print warn_prefix + "recommended to use a tool such as " + good("`revdep-rebuild`") + " (from"
+       print warn_prefix + "app-portage/gentoolkit) in order to detect such breakage."
+       print warn_prefix
+       print warn_prefix + "Also study the list of packages to be cleaned for any obvious"
+       print warn_prefix + "mistakes. Packages that are part of the world set will always"
+       print warn_prefix + "be kept.  They can be manually added to this set with"
+       print warn_prefix + good("`emerge --noreplace <atom>`") + "."
+       print warn_prefix
+       print warn_prefix + "As a safety measure, depclean will not remove any packages"
+       print warn_prefix + "unless *all* required dependencies have been resolved.  As a"
+       print warn_prefix + "consequence, it is often necessary to run "
+       print warn_prefix + good("`emerge --update --deep world`") + " prior to depclean."
+
+       xterm_titles = "notitles" not in settings.features
+       portdb = trees[settings["ROOT"]]["porttree"].dbapi
+       vartree = trees[settings["ROOT"]]["vartree"]
+       vardb = vartree.dbapi
+       syslist = getlist(settings, "system")
+       worldlist = getlist(settings, "world")
+       fakedb = portage.fakedbapi(settings=settings)
+       emptydb = portage.fakedbapi(settings=settings)
+       myvarlist = vardb.cpv_all()
 
        if not syslist:
                print "\n!!! You have no system list.",
@@ -3142,95 +3493,89 @@ elif "depclean"==myaction:
                print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH,
 
        if not (syslist and worldlist and myvarlist):
-               print "\n!!! Proceeding will break your installation.\n"
-               countdown(EMERGE_WARNING_DELAY, ">>> Depclean")
+               print "\n!!! Proceeding "+(syslist and myvarlist and "may" or "will")
+               print " break your installation.\n"
+               if "--pretend" not in myopts:
+                       countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean")
 
        if not "--pretend" in myopts: #just check pretend, since --ask implies pretend
-               emergelog(" >>> depclean")
-       
-       mydepgraph=depgraph(myaction,myopts)
+               emergelog(xterm_titles, " >>> depclean")
 
-       if not ("--quiet" in myopts):
+       if "--quiet" not in myopts:
                print "\nCalculating dependencies  ",
-       if not mydepgraph.xcreate("world"):
-               print "\n!!! Failed to create deptree."
-               sys.exit(1)
-       if not ("--quiet" in myopts):
-               print "\b\b... done!"
-
-       if ("--usepkgonly" in myopts) and mydepgraph.missingbins:
-               sys.stderr.write(red("The following binaries are not available for merging...\n"))
-               for x in mydepgraph.missingbins:
-                       sys.stderr.write("   "+str(x)+"\n")
-               sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
-               sys.exit(1)
-
-       alldeps=mydepgraph.digraph.allnodes()
-
-       if not alldeps:
-               print "!!! You have no dependencies. Impossible. Bug."
-               sys.exit(1)
 
-       reallist=[]
-       for x in alldeps:
-               myparts=portage.catpkgsplit(string.split(x)[2])
-               if not myparts:
-                       sys.stderr.write(
-                         red("!!! There appears to be a problem with the following package:\n")+
-                               red("!!! "+str(string.split(x)[2])+"\n\n")+
-                                   "!!! Please ensure that blocking/conflicting packages are not merged."+
-                                               "!!! 'emerge -p "+str(string.split(x)[2])+"\n\n")
-                       if ("--pretend" not in myopts) and ("--ask" not in myopts):
-                               countdown(EMERGE_WARNING_DELAY, "*** Continuing")
+       remaining_atoms = [(atom, 'world') for atom in worldlist if vardb.match(atom)]
+       remaining_atoms += [(atom, 'system') for atom in syslist if vardb.match(atom)]
+       unresolveable = {}
+
+       while remaining_atoms:
+               atom, parent = remaining_atoms.pop()
+               pkgs = vardb.match(atom)
+               if not pkgs:
+                       if not atom.startswith("!"):
+                               if atom in unresolveable:
+                                       unresolveable[atom].append(parent)
+                               else:
+                                       unresolveable[atom] = [parent]
                        continue
+               # Could put slot checking here to ensure that there aren't two
+               # packages with the same slot...
+               for pkg in pkgs:
+                       if fakedb.cpv_exists(pkg):
+                               continue
+                       spinner.update()
+                       fakedb.cpv_inject(pkg)
+                       mydb = portdb.xmatch("match-visible", "="+pkg) and portdb or vardb
+                       if myopts.get("--with-bdeps", "y") == "y":
+                               depstr = " ".join(mydb.aux_get(pkg,
+                                       ["DEPEND", "RDEPEND", "PDEPEND"]))
+                       else:
+                               depstr = " ".join(mydb.aux_get(pkg,
+                                       ["RDEPEND", "PDEPEND"]))
+                       usedef = vardb.aux_get(pkg, ["USE"])[0].split()
+                       success, atoms = portage.dep_check(depstr, emptydb, settings,
+                               myuse=usedef, trees=trees, myroot=settings["ROOT"])
+                       if not success:
+                               print "\n\n"
+                               print "Error occurred while processing",pkg
+                               print str(atoms)
+                               return
+                       for atom in atoms:
+                               remaining_atoms.append((atom, pkg))
+
+       if "--quiet" not in myopts:
+               print "\b\b... done!\n"
+
+       if unresolveable:
+               print "Dependencies could not be completely resolved due to"
+               print "the following required packages not being installed:"
+               print
+               for atom in unresolveable:
+                       print atom, "required by", " ".join(unresolveable[atom])
+               print
+               print "Have you forgotten to run " + good("`emerge --update --deep world`") + " prior to depclean?"
+               print
+               return
 
-               catpack=myparts[0]+"/"+myparts[1]
-               if catpack not in reallist:
-                       reallist.append(catpack)
-
-       cleanlist=[]
-       for x in myvarlist:
-               if x not in reallist:
-                       if x not in cleanlist:
-                               cleanlist.append(x)
-
-       for x in syslist+worldlist:
-               myparts = portage.catpkgsplit(x)
-               if myparts:
-                       if myparts[0][0] in ('<','>','='):
-                               myparts[0] = myparts[0][1:]
-                       if myparts[0][0] in ('<','>','='):
-                               myparts[0] = myparts[0][1:]
-                       catpack=myparts[0]+"/"+myparts[1]
-               else:
-                       catpack=x
-               if catpack in cleanlist:
-                       cleanlist.remove(catpack)
-
-       #print "\n\n\nCleaning: "
-       #for x in cleanlist:
-       #       print x
-       #print
+       cleanlist = [pkg for pkg in vardb.cpv_all() if not fakedb.cpv_exists(pkg)]
 
        if len(cleanlist):
-               unmerge("unmerge", cleanlist)
+               unmerge(settings, myopts, vartree, "unmerge", cleanlist, ldpath_mtimes)
 
-       print
        print "Packages installed:   "+str(len(myvarlist))
        print "Packages in world:    "+str(len(worldlist))
        print "Packages in system:   "+str(len(syslist))
-       print "Unique package names: "+str(len(reallist))
-       print "Required packages:    "+str(len(alldeps))
+       print "Unique package names: "+str(len(myvarlist))
+       print "Required packages:    "+str(len(fakedb.cpv_all()))
        if "--pretend" in myopts:
                print "Number to remove:     "+str(len(cleanlist))
        else:
                print "Number removed:       "+str(len(cleanlist))
-               post_emerge()
 
-# "update", "system", or just process files:
-else:
+def action_build(settings, trees, mtimedb,
+       myopts, myaction, myfiles, spinner):
+       ldpath_mtimes = mtimedb["ldpath"]
        favorites=[]
-       syslist=getlist("system")
        if ("--ask" in myopts or "--pretend" in myopts) and not "--quiet" in myopts:
                action = ""
                if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
@@ -3246,33 +3591,44 @@ else:
                        print darkgreen("These are the packages that would be %s, in order:") % action
                        print
 
+       # validate the state of the resume data
+       # so that we can make assumptions later.
+       for k in ("resume", "resume_backup"):
+               if k in mtimedb:
+                       if "mergelist" in mtimedb[k]:
+                               if not mtimedb[k]["mergelist"]:
+                                       del mtimedb[k]
+                       else:
+                               del mtimedb[k]
+
        if "--resume" in myopts and \
-               ("resume" in portage.mtimedb or
-               "resume_backup" in portage.mtimedb):
-               if "resume" not in portage.mtimedb:
-                       portage.mtimedb["resume"] = portage.mtimedb["resume_backup"]
-                       del portage.mtimedb["resume_backup"]
-                       portage.commit_mtimedb()
-               myresumeopts=portage.mtimedb["resume"]["myopts"][:]
+               ("resume" in mtimedb or
+               "resume_backup" in mtimedb):
+               if "resume" not in mtimedb:
+                       mtimedb["resume"] = mtimedb["resume_backup"]
+                       del mtimedb["resume_backup"]
+                       mtimedb.commit()
+               # XXX: "myopts" is a list for backward compatibility.
+               myresumeopts = dict([(k,True) for k in mtimedb["resume"]["myopts"]])
 
                for opt in ("--skipfirst", "--ask", "--tree"):
-                       while opt in myresumeopts:
-                               myresumeopts.remove(opt)
+                       myresumeopts.pop(opt, None)
 
-               for myopt in myopts:
+               for myopt, myarg in myopts.iteritems():
                        if myopt not in myresumeopts:
-                               myresumeopts.append(myopt)
+                               myresumeopts[myopt] = myarg
                myopts=myresumeopts
-               mydepgraph=depgraph("resume",myopts)
-               if "--resume" not in myopts:
-                       myopts+=["--resume"]
+               myparams = create_depgraph_params(myopts, myaction)
+               mydepgraph = depgraph(settings, trees,
+                       myopts, myparams, spinner)
        else:
                if ("--resume" in myopts):
-                       del myopts[myopts.index("--resume")]
                        print darkgreen("emerge: It seems we have nothing to resume...")
                        sys.exit(0)
 
-               mydepgraph=depgraph(myaction,myopts)
+               myparams = create_depgraph_params(myopts, myaction)
+               mydepgraph = depgraph(settings, trees,
+                       myopts, myparams, spinner)
                if myaction in ["system","world"]:
                        if not ("--quiet" in myopts):
                                print "Calculating",myaction,"dependencies  ",
@@ -3283,15 +3639,14 @@ else:
                        if not ("--quiet" in myopts):
                                print "\b\b... done!"
                else:
-                       if not myfiles:
-                               print "emerge: please tell me what to do."
-                               help()
-                               sys.exit(1)
-                               #we don't have any files to process; skip this step and exit
                        if not ("--quiet" in myopts):
                                print "Calculating dependencies  ",
                                sys.stdout.flush()
-                       retval,favorites=mydepgraph.select_files(myfiles)
+                       try:
+                               retval, favorites = mydepgraph.select_files(myfiles)
+                       except portage_exception.PackageNotFound, e:
+                               portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
+                               sys.exit(1)
                        if not retval:
                                sys.exit(1)
                        if not ("--quiet" in myopts):
@@ -3308,32 +3663,41 @@ else:
 
        if "--ask" in myopts:
                if "--resume" in myopts:
-                       mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
-                       prompt="Do you want me to resume merging these packages?"
+                       validate_merge_list(trees, mtimedb["resume"]["mergelist"])
+                       mymergelist = mtimedb["resume"]["mergelist"]
+                       if "--skipfirst" in myopts:
+                               mymergelist = mymergelist[1:]
+                       if len(mymergelist) == 0:
+                               print colorize("INFORM", "emerge: It seems we have nothing to resume...")
+                               sys.exit(0)
+                       mydepgraph.display(mymergelist)
+                       prompt="Would you like to resume merging these packages?"
                else:
-                       mydepgraph.display(mydepgraph.altlist())
+                       mydepgraph.display(
+                               mydepgraph.altlist(reversed=("--tree" in myopts)))
                        mergecount=0
                        for x in mydepgraph.altlist():
-                               if x[3]!="nomerge":
+                               if x[0] != "blocks" and x[3] != "nomerge":
                                        mergecount+=1
                                #check for blocking dependencies
                                if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts:
                                        print "\n!!! Error: The above package list contains packages which cannot be installed"
                                        print   "!!!        at the same time on the same system."
-                                       print
+                                       if "--quiet" not in myopts:
+                                               show_blocker_docs_link()
                                        sys.exit(1)
                        if mergecount==0:
-                               if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]:
-                                       prompt="Nothing to merge; do you want me to auto-clean packages?"
+                               if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
+                                       prompt="Nothing to merge; would you like to auto-clean packages?"
                                else:
                                        print
                                        print "Nothing to merge; quitting."
                                        print
                                        sys.exit(0)
                        elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
-                               prompt="Do you want me to fetch the source files for these packages?"
+                               prompt="Would you like to fetch the source files for these packages?"
                        else:
-                               prompt="Do you want me to merge these packages?"
+                               prompt="Would you like to merge these packages?"
                print
                if userquery(prompt)=="No":
                        print
@@ -3341,39 +3705,65 @@ else:
                        print
                        sys.exit(0)
                # Don't ask again (e.g. when auto-cleaning packages after merge)
-               myopts.remove("--ask")
+               del myopts["--ask"]
 
        if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
                if ("--resume" in myopts):
-                       mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
+                       validate_merge_list(trees, mtimedb["resume"]["mergelist"])
+                       mymergelist = mtimedb["resume"]["mergelist"]
+                       if "--skipfirst" in myopts:
+                               mymergelist = mymergelist[1:]
+                       if len(mymergelist) == 0:
+                               print colorize("INFORM", "emerge: It seems we have nothing to resume...")
+                               sys.exit(0)
+                       mydepgraph.display(mymergelist)
                else:
-                       mydepgraph.display(mydepgraph.altlist())
+                       mydepgraph.display(
+                               mydepgraph.altlist(reversed=("--tree" in myopts)))
        else:
                if ("--buildpkgonly" in myopts):
-                       if not mydepgraph.digraph.hasallzeros():
+                       if not mydepgraph.digraph.hasallzeros(ignore_priority=digraph.MEDIUM):
                                print "\n!!! --buildpkgonly requires all dependencies to be merged."
                                print "!!! Cannot merge requested packages. Merge deps and try again.\n"
                                sys.exit(1)
 
                if ("--resume" in myopts):
-                       favorites=portage.mtimedb["resume"]["favorites"]
-                       mydepgraph.merge(portage.mtimedb["resume"]["mergelist"])
+                       favorites=mtimedb["resume"]["favorites"]
+                       mergetask = MergeTask(settings, trees, myopts)
+                       if "--fetchonly" in myopts:
+                               """ parallel-fetch uses --resume --fetchonly and we don't want
+                               it to write the mtimedb"""
+                               mtimedb.filename = None
+                               time.sleep(3) # allow the parent to have first fetch
+                       retval = mergetask.merge(
+                               mtimedb["resume"]["mergelist"], favorites, mtimedb)
+                       if retval != os.EX_OK:
+                               sys.exit(retval)
                else:
-                       if "resume" in portage.mtimedb and \
-                       "mergelist" in portage.mtimedb["resume"] and \
-                       len(portage.mtimedb["resume"]["mergelist"]) > 1:
-                               portage.mtimedb["resume_backup"] = portage.mtimedb["resume"]
-                               del portage.mtimedb["resume"]
-                               portage.commit_mtimedb()
-                       portage.mtimedb["resume"]={}
-                       portage.mtimedb["resume"]["myopts"]=myopts
-                       portage.mtimedb["resume"]["favorites"]=favorites
+                       if "resume" in mtimedb and \
+                       "mergelist" in mtimedb["resume"] and \
+                       len(mtimedb["resume"]["mergelist"]) > 1:
+                               mtimedb["resume_backup"] = mtimedb["resume"]
+                               del mtimedb["resume"]
+                               mtimedb.commit()
+                       mtimedb["resume"]={}
+                       # XXX: Stored as a list for backward compatibility.
+                       mtimedb["resume"]["myopts"] = \
+                               [k for k in myopts if myopts[k] is True]
+                       mtimedb["resume"]["favorites"]=favorites
                        if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
                                for pkgline in mydepgraph.altlist():
                                        if pkgline[0]=="ebuild" and pkgline[3]=="merge":
-                                               y=portage.portdb.findname(pkgline[2])
-                                               tmpsettings = portage.config(clone=portage.settings)
-                                               retval=portage.doebuild(y,"digest",portage.root,tmpsettings,edebug,("--pretend" in myopts),tree="porttree")
+                                               y = trees[pkgline[1]]["porttree"].dbapi.findname(pkgline[2])
+                                               tmpsettings = portage.config(clone=settings)
+                                               edebug = 0
+                                               if settings.get("PORTAGE_DEBUG", "") == "1":
+                                                       edebug = 1
+                                               retval = portage.doebuild(
+                                                       y, "digest", settings["ROOT"], tmpsettings, edebug,
+                                                       ("--pretend" in myopts),
+                                                       mydbapi=trees[pkgline[1]]["porttree"].dbapi,
+                                                       tree="porttree")
                        if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
                                pkglist = []
                                for pkg in mydepgraph.altlist():
@@ -3381,11 +3771,494 @@ else:
                                                pkglist.append(pkg)
                        else:
                                pkglist = mydepgraph.altlist()
-                       mydepgraph.merge(pkglist)
-
-               if portage.mtimedb.has_key("resume"):
-                       del portage.mtimedb["resume"]
-               if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]:
+                       mergetask = MergeTask(settings, trees, myopts)
+                       retval = mergetask.merge(pkglist, favorites, mtimedb)
+                       if retval != os.EX_OK:
+                               sys.exit(retval)
+
+               if mtimedb.has_key("resume"):
+                       del mtimedb["resume"]
+               if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
                        print ">>> Auto-cleaning packages..."
-                       unmerge("clean", ["world"])
-       post_emerge()
+                       vartree = trees[settings["ROOT"]]["vartree"]
+                       unmerge(settings, myopts, vartree, "clean", ["world"],
+                               ldpath_mtimes)
+               else:
+                       portage.writemsg_stdout(colorize("WARN", "WARNING:")
+                               + " AUTOCLEAN is disabled.  This can cause serious"
+                               + " problems due to overlapping packages.\n")
+
+def multiple_actions(action1, action2):
+       sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
+       sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
+       sys.exit(1)
+
+def parse_opts(tmpcmdline):
+       myaction=None
+       myopts = {}
+       myfiles=[]
+
+       global actions, options, shortmapping
+
+       longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
+       argument_options = {
+               "--with-bdeps": {
+                       "help":"include unnecessary build time dependencies",
+                       "type":"choice",
+                       "choices":("y", "n")
+               }
+       }
+
+       from optparse import OptionParser
+       parser = OptionParser()
+       if parser.has_option("--help"):
+               parser.remove_option("--help")
+
+       for action_opt in actions:
+               parser.add_option("--" + action_opt, action="store_true",
+                       dest=action_opt.replace("-", "_"), default=False)
+       for myopt in options:
+               parser.add_option(myopt, action="store_true",
+                       dest=myopt.lstrip("--").replace("-", "_"), default=False)
+       for shortopt, longopt in shortmapping.iteritems():
+               parser.add_option("-" + shortopt, action="store_true",
+                       dest=longopt.lstrip("--").replace("-", "_"), default=False)
+       for myalias, myopt in longopt_aliases.iteritems():
+               parser.add_option(myalias, action="store_true",
+                       dest=myopt.lstrip("--").replace("-", "_"), default=False)
+
+       for myopt, kwargs in argument_options.iteritems():
+               parser.add_option(myopt,
+                       dest=myopt.lstrip("--").replace("-", "_"), **kwargs)
+
+       myoptions, myargs = parser.parse_args(args=tmpcmdline)
+
+       for myopt in options:
+               v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"))
+               if v:
+                       myopts[myopt] = True
+
+       for myopt in argument_options:
+               v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None)
+               if v is not None:
+                       myopts[myopt] = v
+
+       for action_opt in actions:
+               v = getattr(myoptions, action_opt.replace("-", "_"))
+               if v:
+                       if myaction:
+                               multiple_actions(myaction, action_opt)
+                               sys.exit(1)
+                       myaction = action_opt
+
+       for x in myargs:
+               if x in actions:
+                       if x not in ["system", "world"]:
+                               print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x))
+                       if myaction:
+                               multiple_actions(myaction, x)
+                               sys.exit(1)
+                       myaction=x
+               else:
+                       myfiles.append(x)
+
+       return myaction, myopts, myfiles
+
+def validate_ebuild_environment(trees):
+       for myroot in trees:
+               mysettings = trees[myroot]["vartree"].settings
+               if not mysettings.get("ARCH", None):
+                       print >> sys.stderr, bad("\a!!! ARCH is not set... " + \
+                               "Are you missing the '%setc/make.profile' symlink?" % \
+                               mysettings["PORTAGE_CONFIGROOT"])
+                       print >> sys.stderr, bad("\a!!! Is the symlink correct? " + \
+                               "Is your portage tree complete?\n")
+                       sys.exit(9)
+               del myroot, mysettings
+
+def load_emerge_config(trees=None):
+       kwargs = {}
+       for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")):
+               kwargs[k] = os.environ.get(envvar, "/")
+       trees = portage.create_trees(trees=trees, **kwargs)
+
+       settings = trees["/"]["vartree"].settings
+
+       for myroot in trees:
+               if myroot != "/":
+                       settings = trees[myroot]["vartree"].settings
+                       break
+
+       mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb")
+       mtimedb = portage.MtimeDB(mtimedbfile)
+       return settings, trees, mtimedb
+
+def adjust_config(myopts, settings):
+       """Make emerge specific adjustments to the config."""
+
+       # To enhance usability, make some vars case insensitive by forcing them to
+       # lower case.
+       for myvar in ("AUTOCLEAN", "NOCOLOR"):
+               if myvar in settings:
+                       settings[myvar] = settings[myvar].lower()
+                       settings.backup_changes(myvar)
+       del myvar
+
+       # Kill noauto as it will break merges otherwise.
+       if "noauto" in settings.features:
+               while "noauto" in settings.features:
+                       settings.features.remove("noauto")
+               settings["FEATURES"] = " ".join(settings.features)
+               settings.backup_changes("FEATURES")
+
+       CLEAN_DELAY = 5
+       try:
+               CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY)))
+       except ValueError, e:
+               portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+               portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \
+                       settings["CLEAN_DELAY"], noiselevel=-1)
+       settings["CLEAN_DELAY"] = str(CLEAN_DELAY)
+       settings.backup_changes("CLEAN_DELAY")
+
+       EMERGE_WARNING_DELAY = 10
+       try:
+               EMERGE_WARNING_DELAY = int(settings.get(
+                       "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY)))
+       except ValueError, e:
+               portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+               portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \
+                       settings["EMERGE_WARNING_DELAY"], noiselevel=-1)
+       settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY)
+       settings.backup_changes("EMERGE_WARNING_DELAY")
+
+       if "--quiet" in myopts:
+               settings["PORTAGE_QUIET"]="1"
+               settings.backup_changes("PORTAGE_QUIET")
+
+       # Set so that configs will be merged regardless of remembered status
+       if ("--noconfmem" in myopts):
+               settings["NOCONFMEM"]="1"
+               settings.backup_changes("NOCONFMEM")
+
+       # Set various debug markers... They should be merged somehow.
+       PORTAGE_DEBUG = 0
+       try:
+               PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG)))
+               if PORTAGE_DEBUG not in (0, 1):
+                       portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \
+                               PORTAGE_DEBUG, noiselevel=-1)
+                       portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n",
+                               noiselevel=-1)
+                       PORTAGE_DEBUG = 0
+       except ValueError, e:
+               portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
+               portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\
+                       settings["PORTAGE_DEBUG"], noiselevel=-1)
+               del e
+       if "--debug" in myopts:
+               PORTAGE_DEBUG = 1
+       settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG)
+       settings.backup_changes("PORTAGE_DEBUG")
+
+       # Set color output
+       if "--nocolor" in myopts:
+               settings["NOCOLOR"] = "true"
+               settings.backup_changes("NOCOLOR")
+
+def emerge_main():
+       # Portage needs to ensure a sane umask for the files it creates.
+       os.umask(022)
+       settings, trees, mtimedb = load_emerge_config()
+       portdb = trees[settings["ROOT"]]["porttree"].dbapi
+       portage.global_updates(settings, trees, mtimedb["updates"])
+       mtimedb.commit()
+       # Reload the whole config from scratch.
+       settings, trees, mtimedb = load_emerge_config(trees=trees)
+       portdb = trees[settings["ROOT"]]["porttree"].dbapi
+
+       ldpath_mtimes = mtimedb["ldpath"]
+       xterm_titles = "notitles" not in settings.features
+
+       if settings.get("NOCOLOR","").lower() in ("yes","true"):
+               nocolor()
+       elif (not sys.stdout.isatty()) and \
+               settings.get("NOCOLOR","").lower() != "no":
+               # revdep-rebuild exports NOCOLOR=false, so for now, don't allow
+               # NOCOLOR=false to override the isatty() check.  This can be fixed
+               # in revdep-rebuild by using the --nocolor option when appropriate
+               # instead of exporting NOCOLOR.
+               nocolor()
+
+       tmpcmdline = []
+       if "--ignore-default-opts" not in tmpcmdline:
+               tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split())
+       tmpcmdline.extend(sys.argv[1:])
+       myaction, myopts, myfiles = parse_opts(tmpcmdline)
+
+       for myroot in trees:
+               mysettings =  trees[myroot]["vartree"].settings
+               mysettings.unlock()
+               adjust_config(myopts, mysettings)
+               mysettings.lock()
+               del myroot, mysettings
+
+       spinner = stdout_spinner()
+       if "candy" in settings.features:
+               spinner.update = spinner.update_scroll
+
+       portage.deprecated_profile_check()
+
+       try:
+               os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
+       except (OSError, ValueError), e:
+               portage.writemsg("!!! Failed to change nice value to '%s'\n" % \
+                       settings["PORTAGE_NICENESS"])
+               portage.writemsg("!!! %s\n" % str(e))
+               del e
+
+       #Freeze the portdbapi for enhanced performance:
+       for myroot in trees:
+               trees[myroot]["porttree"].dbapi.freeze()
+               del myroot
+
+       if "moo" in myfiles:
+               print """
+
+  Larry loves Gentoo (""" + os.uname()[0] + """)
+
+ _______________________
+< Have you mooed today? >
+ -----------------------
+        \   ^__^
+         \  (oo)\_______
+            (__)\       )\/\ 
+                ||----w |
+                ||     ||
+
+"""
+
+       if (myaction in ["world", "system"]) and myfiles:
+               print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
+               sys.exit(1)
+
+       for x in myfiles:
+               ext = os.path.splitext(x)[1]
+               if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
+                       print "emerging by path implies --oneshot... adding --oneshot to options."
+                       print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")
+                       break
+
+       if ("--tree" in myopts) and ("--columns" in myopts):
+               print "emerge: can't specify both of \"--tree\" and \"--columns\"."
+               sys.exit(1)
+
+       if ("--quiet" in myopts):
+               spinner.update = spinner.update_quiet
+               portage_util.noiselimit = -1
+
+       # Always create packages if FEATURES=buildpkg
+       # Imply --buildpkg if --buildpkgonly
+       if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts):
+               if "--buildpkg" not in myopts:
+                       myopts["--buildpkg"] = True
+
+       # Also allow -S to invoke search action (-sS)
+       if ("--searchdesc" in myopts):
+               if myaction and myaction != "search":
+                       myfiles.append(myaction)
+               if "--search" not in myopts:
+                       myopts["--search"] = True
+               myaction = "search"
+
+       # Always try and fetch binary packages if FEATURES=getbinpkg
+       if ("getbinpkg" in settings.features):
+               myopts["--getbinpkg"] = True
+
+       if "--skipfirst" in myopts and "--resume" not in myopts:
+               myopts["--resume"] = True
+
+       if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts):
+               myopts["--usepkgonly"] = True
+
+       if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts):
+               myopts["--getbinpkg"] = True
+
+       if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts):
+               myopts["--usepkg"] = True
+
+       # Also allow -K to apply --usepkg/-k
+       if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts):
+               myopts["--usepkg"] = True
+
+       # Also allow -l to apply --pretend/-p, but if already in --ask mode
+       if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)):
+               print ">>> --changelog implies --pretend... adding --pretend to options."
+               myopts["--pretend"] = True
+
+       # Allow -p to remove --ask
+       if ("--pretend" in myopts) and ("--ask" in myopts):
+               print ">>> --pretend disables --ask... removing --ask from options."
+               del myopts["--ask"]
+
+       # forbid --ask when not in a terminal
+       # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
+       if ("--ask" in myopts) and (not sys.stdin.isatty()):
+               portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n",
+                       noiselevel=-1)
+               sys.exit(1)
+
+       if settings.get("PORTAGE_DEBUG", "") == "1":
+               portage.debug=1
+               if "python-trace" in settings.features:
+                       import portage_debug
+                       portage_debug.set_trace(True)
+
+       if ("--resume" in myopts):
+               if "--tree" in myopts:
+                       print "* --tree is currently broken with --resume. Disabling..."
+                       del myopts["--tree"]
+
+       # Set color output
+       if "--nocolor" in myopts or \
+       settings["NOCOLOR"] in ("yes","true"):
+               nocolor()
+
+       if not ("--quiet" in myopts):
+               if not sys.stdout.isatty() or ("--nospinner" in myopts):
+                       spinner.update = spinner.update_basic
+
+       if "--version" in myopts:
+               print getportageversion(settings["PORTDIR"], settings["ROOT"],
+                       settings.profile_path, settings["CHOST"],
+                       trees[settings["ROOT"]]["vartree"].dbapi)
+               sys.exit(0)
+       elif "--help" in myopts:
+               emergehelp.help(myaction, myopts, havecolor)
+               sys.exit(0)
+
+       if portage.wheelgid == portage.portage_gid:
+               print "emerge: wheel group use is being deprecated. Please update group and passwd to"
+               print "        include the portage user as noted above, and then use group portage."
+
+       if "--debug" in myopts:
+               print "myaction", myaction
+               print "myopts", myopts
+
+       if not myaction and not myfiles and "--resume" not in myopts:
+               emergehelp.help(myaction, myopts, havecolor)
+               sys.exit(1)
+
+       # check if root user is the current user for the actions where emerge needs this
+       if portage.secpass < 2:
+               # We've already allowed "--version" and "--help" above.
+               if "--pretend" not in myopts and \
+               myaction not in ("search","info"):
+                       if portage.secpass >= 1:
+                               if "--fetchonly" not in myopts and \
+                               "--fetch-all-uri" not in myopts and \
+                               myaction not in ("metadata", "regen"):
+                                       print "emerge: root access required."
+                                       sys.exit(1)
+                       else:
+                               print "emerge: root access required."
+                               sys.exit(1)
+
+       disable_emergelog = False
+       for x in ("--pretend", "--fetchonly", "--fetch-all-uri"):
+               if x in myopts:
+                       disable_emergelog = True
+                       break
+       if myaction in ("search", "info"):
+               disable_emergelog = True
+       if disable_emergelog:
+               """ Disable emergelog for everything except build or unmerge
+               operations.  This helps minimize parallel emerge.log entries that can
+               confuse log parsers.  We especially want it disabled during
+               parallel-fetch, which uses --resume --fetchonly."""
+               global emergelog
+               def emergelog(*pargs, **kargs):
+                       pass
+
+       if not "--pretend" in myopts:
+               emergelog(xterm_titles, "Started emerge on: "+\
+                       time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
+               myelogstr=""
+               if myopts:
+                       myelogstr=string.join(myopts, " ")
+               if myaction:
+                       myelogstr+=" "+myaction
+               if myfiles:
+                       myelogstr+=" "+string.join(myfiles, " ")
+               emergelog(xterm_titles, " *** emerge " + myelogstr)
+
+       def emergeexitsig(signum, frame):
+               signal.signal(signal.SIGINT, signal.SIG_IGN)
+               signal.signal(signal.SIGTERM, signal.SIG_IGN)
+               portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
+               sys.exit(100+signum)
+       signal.signal(signal.SIGINT, emergeexitsig)
+       signal.signal(signal.SIGTERM, emergeexitsig)
+
+       def emergeexit():
+               """This gets out final log message in before we quit."""
+               if "--pretend" not in myopts:
+                       emergelog(xterm_titles, " *** terminating.")
+               if "notitles" not in settings.features:
+                       xtermTitleReset()
+       portage.atexit_register(emergeexit)
+
+       if myaction in ["sync","metadata"] and "--help" not in myopts:
+               if "--pretend" in myopts:
+                       print "emerge: \"sync\" actions do not support \"--pretend.\""
+                       sys.exit(1)
+               if "sync" == myaction:
+                       action_sync(settings, trees, mtimedb, myopts, myaction)
+               else:
+                       action_metadata(settings, portdb, myopts)
+       elif myaction=="regen":
+               validate_ebuild_environment(trees)
+               action_regen(settings, portdb)
+       # HELP action
+       elif "config"==myaction:
+               if "--pretend" in myopts:
+                       sys.stderr.write("emerge: The --config action " + \
+                               "does not support --pretend.\n")
+                       return 1
+               validate_ebuild_environment(trees)
+               action_config(settings, trees, myopts, myfiles)
+       
+       # INFO action
+       elif "info"==myaction:
+               action_info(settings, trees, myopts, myfiles)
+
+       # SEARCH action
+       elif "search"==myaction:
+               validate_ebuild_environment(trees)
+               action_search(settings, portdb, trees["/"]["vartree"],
+                       myopts, myfiles, spinner)
+       elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
+               validate_ebuild_environment(trees)
+               vartree = trees[settings["ROOT"]]["vartree"]
+               if 1 == unmerge(settings, myopts, vartree, myaction, myfiles,
+                       ldpath_mtimes, raise_on_missing=False):
+                       if "--pretend" not in myopts:
+                               post_emerge(settings, mtimedb, 0)
+
+       elif "depclean"==myaction:
+               validate_ebuild_environment(trees)
+               action_depclean(settings, trees, ldpath_mtimes,
+                       myopts, spinner)
+               if "--pretend" not in myopts:
+                       post_emerge(settings, mtimedb, 0)
+       # "update", "system", or just process files:
+       else:
+               validate_ebuild_environment(trees)
+               action_build(settings, trees, mtimedb,
+                       myopts, myaction, myfiles, spinner)
+               if "--pretend" not in myopts:
+                       post_emerge(settings, mtimedb, 0)
+
+if __name__ == "__main__":
+       retval = emerge_main()
+       sys.exit(retval)
index 91c32f5f7607e17b678c4e51b5713b891575c917..bee4761f4265fe0c007e415da154021e5eee9ba8 100755 (executable)
@@ -1,26 +1,22 @@
 #!@BASH@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/Attic/emerge-webrsync,v 1.8.2.4 2005/02/26 11:22:38 carpaski Exp $
+# $Id$
 # Author: Karl Trygve Kalleberg <karltk@gentoo.org>
 # Rewritten from the old, Perl-based emerge-webrsync script
 
+eval $("@PORTAGE_BASE@"/bin/portageq envvar -v FEATURES FETCHCOMMAND \
+       GENTOO_MIRRORS PORTAGE_INST_UID PORTAGE_INST_GID PORTAGE_NICENESS \
+       PORTAGE_TMPDIR PORTDIR USERLAND)
+DISTDIR="${PORTAGE_TMPDIR}/emerge-webrsync"
+
 # If PORTAGE_NICENESS is overriden via the env then it will
 # still pass through the portageq call and override properly.
-PORTAGE_NICENESS="$(@PORTAGE_BASE@/bin/portageq envvar PORTAGE_NICENESS)"
 if [ -n "${PORTAGE_NICENESS}" ]; then
        renice $PORTAGE_NICENESS $$ > /dev/null
 fi
 
-source @PORTAGE_BASE@/bin/isolated-functions.sh || exit 1
-FEATURES="$(@PORTAGE_BASE@/bin/portageq envvar FEATURES)"
-GENTOO_MIRRORS="${GENTOO_MIRRORS} $(@PORTAGE_BASE@/bin/portageq gentoo_mirrors)"
-PORTDIR="$(@PORTAGE_BASE@/bin/portageq portdir)"
-FETCHCOMMAND="$(@PORTAGE_BASE@/bin/portageq envvar FETCHCOMMAND)"
-USERLAND="$(@PORTAGE_BASE@/bin/portageq envvar USERLAND)"
-DISTDIR="$(@PORTAGE_BASE@/bin/portageq envvar PORTAGE_TMPDIR)/emerge-webrsync"
-PORTAGE_INST_UID="$(@PORTAGE_BASE@/bin/portageq envvar PORTAGE_INST_UID)"
-PORTAGE_INST_GID="$(@PORTAGE_BASE@/bin/portageq envvar PORTAGE_INST_GID)"
+source "@PORTAGE_BASE@"/bin/isolated-functions.sh || exit 1
 
 if [ ! -d $DISTDIR ] ; then
        mkdir -p $DISTDIR
@@ -54,7 +50,10 @@ fi
 sync_local() {
        echo Syncing local tree...
        if type -p tarsync &> /dev/null; then
-               if ! tarsync "${FILE}" "${PORTDIR}" -v -s 1 -o ${PORTAGE_INST_UID:-0} -g ${PORTAGE_INST_GID:-0} -e /distfiles -e /packages -e /local; then
+               # tarsync doesn't take numeric uid/gid so we need to convert them.
+               local inst_user="$(python -c "import pwd; print pwd.getpwuid(int('${PORTAGE_INST_UID:-0}'))[0]")"
+               local inst_group="$(python -c "import grp; print grp.getgrgid(int('${PORTAGE_INST_GID:-0}'))[0]")"
+               if ! tarsync "${FILE}" "${PORTDIR}" -v -s 1 -o ${inst_user} -g ${inst_group} -e /distfiles -e /packages -e /local; then
                        echo "tarsync failed; tarball is corrupt?"
                        exit 1;
                fi
index d5e5e04d284e9e2e5e746e1afc2c0dc0c5659f0f..bbb159127bd5e7a69765d4873e8d87a06573f3e6 100755 (executable)
@@ -4,7 +4,6 @@
 # $Id: /var/cvsroot/gentoo-src/portage/bin/env-update,v 1.9 2004/10/04 13:56:50 vapier Exp $
 
 import os,sys
-os.environ["PORTAGE_CALLER"] = "env-update"
 sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
 
 def usage(status):
index 3f214b8ee744c81322d45d11917035d123ff4d39..166a5f1083639ecd022af6e09c3721d7608141ef 100755 (executable)
@@ -1,7 +1,7 @@
 #!@BASH@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: etc-update 2221 2005-11-01 01:32:07Z vapier $
+# $Id$
 
 # Author Brandon Low <lostlogic@gentoo.org>
 #
 # Leo Lipelis <aeoo@gentoo.org>
 # Karl Trygve Kalleberg <karltk@gentoo.org>
 
-export PORTAGE_CALLER="etc-update"
-
-eval $(python -c 'import portage_const;print "export EPREFIX="+portage_const.EPREFIX;print "export PORTAGE_BIN_PATH="+portage_const.PORTAGE_BIN_PATH;')
-
 if type -p gsed >/dev/null ; then
        function sed() { gsed "$@"; }
 fi
@@ -24,8 +20,10 @@ function get_config() {
        # First strip off comment lines, then grab the configuration
        # item. If there's more than one of the same configuration item,
        # then allow the last setting to take precedence.
-       cut -d'#' -f1-1 ${EPREFIX}/etc/etc-update.conf | \
-               sed -ne "s/^ *$item *= *\([\"']\{0,1\}\)\(.*\)\1/\2/p" |sed -e '$p;d'
+       local result
+       result=$(cut -d'#' -f1-1 ${PORTAGE_CONFIGROOT}etc/etc-update.conf | \
+               sed -ne "s/^ *$item *= *\([\"']\{0,1\}\)\(.*\)\1/\2/p" |sed -e '$p;d')
+       eval echo $result
 }
 
 function scan() {
@@ -35,7 +33,9 @@ function scan() {
        mkdir ${TMP}/files || die "Failed mkdir command!" 1
        count=0
        input=0
-       
+       local find_opts
+       local my_basename
+
        # Sanity check to make sure diff exists and works
        if ! diff -v &>/dev/null ; then
                echo "ERROR: 'diff' does not seem to work, aborting"
@@ -43,15 +43,24 @@ function scan() {
        fi
 
        for path in ${CONFIG_PROTECT} ; do
-               [ ! -d ${path} ] && continue
+               path="${ROOT}${path}"
+               find_opts="-iname ._cfg????_*"
+               if [ ! -d "${path}" ]; then
+                       [ ! -f "${path}" ] && continue
+                       my_basename="${path##*/}"
+                       path="${path%/*}"
+                       find_opts="-maxdepth 1 -iname ._cfg????_${my_basename}"
+               fi
 
                ofile=""
-               for file in `find ${path}/ -iname "._cfg????_*" |
+               # The below set -f turns off file name globbing in the ${find_opts} expansion.
+               for file in $(set -f; find ${path}/ ${find_opts} ! -iname '.*~' ! -iname '.*.bak' |
                           sed -e "s:\(^.*/\)\(\._cfg[0-9]*_\)\(.*$\):\1\2\3\%\2\%\3:" |
-                          sort -t'%' -k3 -k2 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'`; do
-                       rpath=`echo "${file/\/\///}" | sed -e "s:/[^/]*$::"`
-                       rfile=`echo "${file/\/\///}" | sed -e "s:^.*/::"`
+                          sort -t'%' -k3 -k2 | LANG=POSIX LC_ALL=POSIX cut -f1 -d'%'); do
+                       rpath=$(echo "${file/\/\///}" | sed -e "s:/[^/]*$::")
+                       rfile=$(echo "${file/\/\///}" | sed -e "s:^.*/::")
                        for mpath in ${CONFIG_PROTECT_MASK}; do
+                               mpath="${ROOT}${path}"
                                if [[ "${rpath}" == "${mpath}"* ]]; then
                                        mv ${rpath}/${rfile} ${rpath}/${rfile:10}
                                        break
@@ -60,22 +69,22 @@ function scan() {
                        [ ! -f ${file} ] && continue
 
 
-                       if [[ "${ofile:10}" != "${rfile:10}" ]] || 
+                       if [[ "${ofile:10}" != "${rfile:10}" ]] ||
                           [[ ${opath} != ${rpath} ]]; then
                                MATCHES=0
                                if [[ "${EU_AUTOMERGE}" == "yes" ]]; then
                                        if [ ! -e "${rpath}/${rfile}" ] || [ ! -e "${rpath}/${rfile:10}" ]; then
                                                MATCHES=0
                                        else
-                                               diff -Bbua ${rpath}/${rfile} ${rpath}/${rfile:10} | ${EPREFIX}/bin/grep -E '^[+-]' | ${EPREFIX}/bin/grep -E -v '^[+-][\t ]*#|^--- |^\+\+\+ ' | ${EPREFIX}/bin/grep -E -qv '^[-+][\t ]*$'
+                                               diff -Bbua ${rpath}/${rfile} ${rpath}/${rfile:10} | egrep '^[+-]' | egrep -v '^[+-][\t ]*#|^--- |^\+\+\+ ' | egrep -qv '^[-+][\t ]*$'
                                                MATCHES=$?
                                        fi
-                               elif [[ -z `diff -Nua ${rpath}/${rfile} ${rpath}/${rfile:10}|
-                                                         grep "^[+-][^+-]"|grep -v '# .Header:.*'` ]]; then
+                               elif [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${rfile:10}|
+                                                         grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
                                        MATCHES=1
                                fi
                                if [[ "${MATCHES}" == "1" ]]; then
-                                       echo "Automerging trivial changes in: ${rfile:10}"
+                                       echo "Automerging trivial changes in: ${rpath}/${rfile:10}"
                                        mv ${rpath}/${rfile} ${rpath}/${rfile:10}
                                        continue
                                else
@@ -88,8 +97,8 @@ function scan() {
                                fi
                        fi
 
-                       if [[ -z `diff -Nua ${rpath}/${rfile} ${rpath}/${ofile}|
-                                         grep "^[+-][^+-]"|grep -v '# .Header:.*'` ]]; then
+                       if [[ -z $(diff -Nua ${rpath}/${rfile} ${rpath}/${ofile}|
+                                         grep "^[+-][^+-]"|grep -v '# .Header:.*') ]]; then
                                mv ${rpath}/${rfile} ${rpath}/${ofile}
                                continue
                        else
@@ -104,26 +113,21 @@ function scan() {
 
 function sel_file() {
        local -i isfirst=0
-       until [ -f ${TMP}/files/${input} ] || [ ${input} == -1 ] || [ ${input} == -3 ]; do
+       until [[ -f ${TMP}/files/${input} ]] || \
+             [[ ${input} == -1 ]] || \
+             [[ ${input} == -3 ]]
+       do
                local numfiles=$(ls ${TMP}/files|wc -l)
                local numwidth=${#numfiles}
                for file in $(ls ${TMP}/files|sort -n); do
-                       if (( ${isfirst} == 0 )); then
+                       if [[ ${isfirst} == 0 ]] ; then
                                isfirst=${file}
                        fi
                        numshow=$(printf "%${numwidth}i${PAR} " ${file})
-                       spacer=${numshow//?/ }
+                       numupdates=$(( $(wc -l <${TMP}/files/${file}) - 1 ))
                        echo -n "${numshow}"
-                       if (( ${mode} == 0 )); then
-                               spacedit=0
-                               for word in $(<${TMP}/files/${file}); do
-                                       if (( ${spacedit} == 1 )); then
-                                               echo -n "${spacer}"
-                                       else
-                                               spacedit=1
-                                       fi
-                                       echo ${word}
-                               done
+                       if [[ ${mode} == 0 ]] ; then
+                               echo "$(head -n1 ${TMP}/files/${file}) (${numupdates})"
                        else
                                head -n1 ${TMP}/files/${file}
                        fi
@@ -131,42 +135,86 @@ function sel_file() {
 
                if [ "${OVERWRITE_ALL}" == "yes" ]; then
                        input=0
+               elif [ "${DELETE_ALL}" == "yes" ]; then
+                       input=0
                else
-                       if (( ${mode} == 0 )); then
-                               echo "The following is the list of files which need updating, each 
+                       if [[ ${mode} == 0 ]] ; then
+                               echo "The following is the list of files which need updating, each
 configuration file is followed by a list of possible replacement files."
                        else
                                local my_title="Please select a file to update"
                        fi
 
-                       if (( ${mode} == 0 )); then
+                       if [[ ${mode} == 0 ]] ; then
                                cat ${TMP}/menuitems
                                echo    "Please select a file to edit by entering the corresponding number."
-                               echo    "              (don't use -3 or -5 if you're unsure what to do)"
+                               echo    "              (don't use -3, -5, -7 or -9 if you're unsure what to do)"
                                echo    "              (-1 to exit) (-3 to auto merge all remaining files)"
-                               echo -n "                           (-5 to auto-merge AND not use 'mv -i'): "
-                               read input
+                               echo    "                           (-5 to auto-merge AND not use 'mv -i')"
+                               echo    "                           (-7 to discard all updates)"
+                               echo -n "                           (-9 to discard all updates AND not use 'rm -i'): "
+                               input=$(read_int)
                        else
                                dialog --title "${title}" --menu "${my_title}" \
                                        0 0 0 $(echo -e "-1 Exit\n$(<${TMP}/menuitems)") \
-                                       2> ${TMP}/input
+                                       2> ${TMP}/input || die "User termination!" 0
                                input=$(<${TMP}/input)
                        fi
-                       if (( ${input} == -5 )); then
+                       if [[ ${input} == -9 ]]; then
+                               read -p "Are you sure that you want to delete all updates (type YES):" reply
+                               if [[ ${reply} != "YES" ]]; then
+                                       continue
+                               else
+                                       input=-7
+                                       export rm_opts=""
+                               fi
+                       fi
+                       if [[ ${input} == -7 ]]; then
+                               input=0
+                               export DELETE_ALL="yes"
+                       fi
+                       if [[ ${input} == -5 ]] ; then
                                input=-3
                                export mv_opts=""
                        fi
-                       if (( ${input} == -3 )); then
+                       if [[ ${input} == -3 ]] ; then
                                input=0
                                export OVERWRITE_ALL="yes"
                        fi
                fi # -3 automerge
-               if (( ${input} == 0 )); then
+               if [[ -z ${input} ]] || [[ ${input} == 0 ]] ; then
                        input=${isfirst}
                fi
        done
 }
 
+function user_special() {
+       if [ -r ${PORTAGE_CONFIGROOT}etc/etc-update.special ]; then
+               if [ -z "$1" ]; then
+                       echo "ERROR: user_special() called without arguments"
+                       return 1
+               fi
+               while read pat; do
+                       echo ${1} | grep "${pat}" > /dev/null && return 0
+               done < ${PORTAGE_CONFIGROOT}etc/etc-update.special
+       fi
+       return 1
+}
+
+function read_int() {
+       # Read an integer from stdin.  Continously loops until a valid integer is
+       # read.  This is a workaround for odd behavior of bash when an attempt is
+       # made to store a value such as "1y" into an integer-only variable.
+       local my_input
+       while true; do
+               read my_input
+               # failed integer conversions will break a loop unless they're enclosed
+               # in a subshell.
+               echo "${my_input}" | ( declare -i x; read x) && break
+       done
+       echo ${my_input}
+}
+
 function do_file() {
        echo
        local -i my_input
@@ -181,13 +229,15 @@ function do_file() {
 
                        if [ "${OVERWRITE_ALL}" == "yes" ]; then
                                my_input=0
+                       elif [ "${DELETE_ALL}" == "yes" ]; then
+                               my_input=0
                        else
                                for line in $(<${TMP}/files/${input}); do
                                        if (( ${fcount} > 0 )); then
                                                echo -n "${fcount}${PAR} "
                                                echo "${line}"
                                        else
-                                               if (( ${mode} == 0 )); then
+                                               if [[ ${mode} == 0 ]] ; then
                                                        echo "Below are the new config files for ${line}:"
                                                else
                                                        local my_title="Please select a file to process for ${line}"
@@ -196,28 +246,28 @@ function do_file() {
                                        fcount=${fcount}+1
                                done > ${TMP}/menuitems
 
-                               if (( ${mode} == 0 )); then
+                               if [[ ${mode} == 0 ]] ; then
                                        cat ${TMP}/menuitems
                                        echo -n "Please select a file to process (-1 to exit this file): "
-                                       read my_input
+                                       my_input=$(read_int)
                                else
                                        dialog --title "${title}" --menu "${my_title}" \
-                                               0 0 0 `echo -e "$(<${TMP}/menuitems)\n${fcount} Exit"` \
-                                               2> ${TMP}/input
+                                               0 0 0 $(echo -e "$(<${TMP}/menuitems)\n${fcount} Exit") \
+                                               2> ${TMP}/input || die "User termination!" 0
                                        my_input=$(<${TMP}/input)
                                fi
                        fi # OVERWRITE_ALL
 
-                       if (( ${my_input} == 0 )); then
+                       if [[ ${my_input} == 0 ]] ; then
                                my_input=1
-                       elif (( ${my_input} == -1 )); then
-                               input=0 
+                       elif [[ ${my_input} == -1 ]] ; then
+                               input=0
                                return
-                       elif (( ${my_input} == ${fcount} )); then
+                       elif [[ ${my_input} == ${fcount} ]] ; then
                                break
                        fi
                done
-               if (( ${my_input} == ${fcount} )); then
+               if [[ ${my_input} == ${fcount} ]] ; then
                        break
                fi
 
@@ -231,7 +281,7 @@ function do_file() {
                sed -e "${fcount}!p;d" ${TMP}/files/${input} > ${TMP}/files/sed
                mv ${TMP}/files/sed ${TMP}/files/${input}
 
-               if (( ${my_input} == -1 )); then
+               if [[ ${my_input} == -1 ]] ; then
                        break
                fi
        done
@@ -241,18 +291,20 @@ function do_file() {
 }
 
 function do_cfg() {
-       
+
        local file="${1}"
        local ofile="${2}"
        local -i my_input=0
-       
+
        until (( ${my_input} == -1 )) || [ ! -f ${file} ]; do
-               if [ "${OVERWRITE_ALL}" == "yes" ]; then
+               if [[ "${OVERWRITE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then
                        my_input=1
+               elif [[ "${DELETE_ALL}" == "yes" ]] && ! user_special "${ofile}"; then
+                       my_input=2
                else
-                 showdiffcmd=$(echo "${diff_command}" |
+                       showdiffcmd=$(echo "${diff_command}" |
                                sed -e "s:%file1:${ofile}:" -e "s:%file2:${file}:")
-                               
+
                        if [ "${using_editor}" == 0 ]; then
                                (
                                        echo "Showing differences between ${ofile} and ${file}"
@@ -271,22 +323,25 @@ function do_cfg() {
                                echo "-------------------------------------------------------------"
                                echo
                        fi
-                       echo -n "1) Replace original with update
+                       echo -n "File: ${file}
+1) Replace original with update
 2) Delete update, keeping original as is
 3) Interactively merge original with update
 4) Show differences again
 Please select from the menu above (-1 to ignore this update): "
-                       read my_input
+                       my_input=$(read_int)
                fi
-               
+
                case ${my_input} in
                        1) echo "Replacing ${ofile} with ${file}"
                           mv ${mv_opts} ${file} ${ofile}
-                          my_input=-1
+                          [ -n "${OVERWRITE_ALL}" ] && my_input=-1
+                          [ -e "${file}" ] || touch ${ofile}
                           continue
                           ;;
                        2) echo "Deleting ${file}"
                           rm ${rm_opts} ${file}
+                          [ -n "${DELETE_ALL}" ] && my_input=-1
                           continue
                           ;;
                        3) do_merge "${file}" "${ofile}"
@@ -303,7 +358,7 @@ Please select from the menu above (-1 to ignore this update): "
 }
 
 function do_merge() {
-       
+
        local file="${1}"
        local ofile="${2}"
        local mfile="${2}.merged"
@@ -317,29 +372,30 @@ function do_merge() {
 
        until (( ${my_input} == -1 )); do
                echo "Merging ${file} and ${ofile}"
-               `echo "${merge_command}" |
+               $(echo "${merge_command}" |
                 sed -e "s:%merged:${mfile}:g" \
                         -e "s:%orig:${ofile}:g" \
-                        -e "s:%new:${file}:g"`
-               until (( ${my_input} == -1 )); do       
+                        -e "s:%new:${file}:g")
+               until (( ${my_input} == -1 )); do
                        echo -n "1) Replace ${ofile} with merged file
 2) Show differences between merged file and original
 3) Remerge original with update
 4) Edit merged file
 5) Return to the previous menu
 Please select from the menu above (-1 to exit, losing this merge): "
-                       read my_input
+                       my_input=$(read_int)
                        case ${my_input} in
                                1) echo "Replacing ${ofile} with ${mfile}"
                                   chmod --reference=${ofile} ${mfile}
                                   mv ${mv_opts} ${mfile} ${ofile}
+                                  [ -e "${mfile}" ] || touch ${ofile}
                                   rm ${rm_opts} ${file}
                                   return 255
                                   ;;
                                2) ( echo "Showing differences between ${ofile} and ${mfile}"
-                                        `echo "${diff_command}" | \
+                                        $(echo "${diff_command}" | \
                                          sed -e "s:%file1:${ofile}:" \
-                                                 -e "s:%file2:${mfile}:"` ) | ${pager}
+                                                 -e "s:%file2:${mfile}:") ) | ${pager}
                                   continue
                                   ;;
                                3) break
@@ -360,9 +416,15 @@ Please select from the menu above (-1 to exit, losing this merge): "
 }
 
 function die() {
-       trap "" term
-       trap "" kill
+       trap "" TERM
+       trap "" KILL
        echo "Exiting: ${1}"
+
+       if [ ${2} -eq 0 ]; then
+               scan > /dev/null
+               [ ${count} -gt 0 ] && echo "NOTE: ${count} updates remaining"
+       fi
+
        rm -rf ${TMP}
        exit ${2}
 }
@@ -374,31 +436,40 @@ scriptname=$(basename $0)
 
 trap die term
 
-export PORTAGE_TMPDIR=$(${PORTAGE_BIN_PATH}/portageq envvar PORTAGE_TMPDIR)
+
+eval $(@PORTAGE_BASE@/bin/portageq envvar -v CONFIG_PROTECT \
+       CONFIG_PROTECT_MASK PORTAGE_CONFIGROOT PORTAGE_TMPDIR ROOT)
+export PORTAGE_TMPDIR
+
+[ -w ${PORTAGE_CONFIGROOT}etc ] || die "Need write access to ${PORTAGE_CONFIGROOT}etc" 1
+#echo $PORTAGE_TMPDIR
+#echo $CONFIG_PROTECT
+#echo $CONFIG_PROTECT_MASK
+#export PORTAGE_TMPDIR=$(/usr/lib/portage/bin/portageq envvar PORTAGE_TMPDIR)
 
 TMP="${PORTAGE_TMPDIR}/$$"
 rm -rf ${TMP} 2> /dev/null
 mkdir ${TMP} || die "failed mkdir command!" 1
 
 # I need the CONFIG_PROTECT value
-CONFIG_PROTECT=$(${PORTAGE_BIN_PATH}/portageq envvar CONFIG_PROTECT)
-CONFIG_PROTECT_MASK=$(${PORTAGE_BIN_PATH}/portageq envvar CONFIG_PROTECT_MASK)
+#CONFIG_PROTECT=$(@PORTAGE_BASE@/bin/portageq envvar CONFIG_PROTECT)
+#CONFIG_PROTECT_MASK=$(@PORTAGE_BASE@/bin/portageq envvar CONFIG_PROTECT_MASK)
 
 # load etc-config's configuration
-EU_AUTOMERGE=`get_config eu_automerge`
-rm_opts=`get_config rm_opts`
-mv_opts=`get_config mv_opts`
-cp_opts=`get_config cp_opts`
-pager=`get_config pager`
-diff_command=`get_config diff_command`
-using_editor=`get_config using_editor`
-merge_command=`get_config merge_command`
-declare -i mode=`get_config mode`
+EU_AUTOMERGE=$(get_config eu_automerge)
+rm_opts=$(get_config rm_opts)
+mv_opts=$(get_config mv_opts)
+cp_opts=$(get_config cp_opts)
+pager=$(get_config pager)
+diff_command=$(get_config diff_command)
+using_editor=$(get_config using_editor)
+merge_command=$(get_config merge_command)
+declare -i mode=$(get_config mode)
 [ -z ${mode} ] && mode=0
 [ -z "${pager}" ] && pager="cat"
 
 #echo "rm_opts: $rm_opts, mv_opts: $mv_opts, cp_opts: $cp_opts"
-#echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command" 
+#echo "pager: $pager, diff_command: $diff_command, merge_command: $merge_command"
 
 if (( ${mode} == 0 )); then
        PAR=")"
@@ -407,7 +478,7 @@ else
 fi
 
 declare -i count=0
-declare -i input=0
+declare input=0
 declare title="Gentoolkit's etc-update tool!"
 
 scan
index 94ff1c983810b7f9686c4d349b6e91f5a68eb8d6..de62d8611a549b6df13b618da80ca09edbecfcd3 100644 (file)
@@ -2,11 +2,15 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Header$
 
-# Internal logging function, don't use this in ebuilds
+quiet_mode() {
+       [[ ${PORTAGE_QUIET} -eq 1 ]]
+}
+
 vecho() {
-       [[ ${PORTAGE_QUIET} == "1" ]] || echo "$@"
+       quiet_mode || echo "$@"
 }
 
+# Internal logging function, don't use this in ebuilds
 elog_base() {
        local messagetype
        [ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1
@@ -200,14 +204,15 @@ set_colors() {
        ENDCOL=$'\e[A\e['${COLS}'C'    # Now, ${ENDCOL} will move us to the end of the
                                       # column;  irregardless of character width
 
-       GOOD=$'\e[32;01m'
-       WARN=$'\e[33;01m'
-       BAD=$'\e[31;01m'
-       HILITE=$'\e[36;01m'
-       BRACKET=$'\e[34;01m'
+       [ -z "${GOOD}"    ] && GOOD=$'\e[32;01m'
+       [ -z "${WARN}"    ] && WARN=$'\e[33;01m'
+       [ -z "${BAD}"     ] && BAD=$'\e[31;01m'
+       [ -z "${HILITE}"  ] && HILITE=$'\e[36;01m'
+       [ -z "${BRACKET}" ] && BRACKET=$'\e[34;01m'
        NORMAL=$'\e[0m'
 }
 
+export -n GOOD WARN BAD HILITE BRACKET
 RC_ENDCOL="yes"
 RC_INDENTATION=''
 RC_DEFAULT_INDENT=2
index bdc788dd40e0d52ad7654535e8145ef6960f4eb3..16157bd0034dc1f454d0a8f3e1af90eb8cd94566 100755 (executable)
@@ -4,7 +4,6 @@
 # $Id: /var/cvsroot/gentoo-src/portage/bin/md5check.py,v 1.4 2004/10/10 10:07:20 carpaski Exp $
 
 import os,sys,string
-os.environ["PORTAGE_CALLER"]="mirror"
 os.environ["FEATURES"]="mirror cvs"
 sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
 
index ef8440ce887ad446a4c54843537f815205ee965c..e97b4c63eebe325cac7acb074dbcf8a97f7b4ec2 100644 (file)
@@ -17,9 +17,8 @@ shift $#
 source @PORTAGE_BASE@/bin/ebuild.sh
 
 install_qa_check() {
-
+       cd "${D}" || die "cd failed"
        prepall
-       cd "${D}"
 
        declare -i UNSAFE=0
        for i in $(find "${D}/" -type f -perm -2002); do
@@ -61,7 +60,6 @@ install_qa_check() {
                        vecho "QA Notice: the following files contain insecure RUNPATH's"
                        vecho " Please file a bug about this at http://bugs.gentoo.org/"
                        vecho " with the maintaining herd of the package."
-                       vecho " Summary: $CATEGORY/$PN: insecure RPATH ${f}"
                        vecho "${f}"
                        vecho -ne '\a\n'
                        if has stricter ${FEATURES} && ! has stricter ${RESTRICT}; then
@@ -81,7 +79,8 @@ install_qa_check() {
                        vecho " LDFLAGS='-Wl,-z,now' emerge ${PN}"
                        vecho "${f}"
                        vecho -ne '\a\n'
-                       die_msg="${die_msg} setXid lazy bindings,"
+                       # Do not fail here until we have sorted out the lazy issues with security team
+                       #die_msg="${die_msg} setXid lazy bindings,"
                        sleep 1
                fi
 
@@ -161,7 +160,7 @@ install_qa_check() {
 
                if [[ ${insecure_rpath} -eq 1 ]] ; then
                        die "Aborting due to serious QA concerns with RUNPATH/RPATH"
-               elif [[ ${die_msg} != "" ]] && has stricter ${FEATURES} && ! has stricter ${RESTRICT} ; then
+               elif [[ -n ${die_msg} ]] && has stricter ${FEATURES} && ! has stricter ${RESTRICT} ; then
                        die "Aborting due to QA concerns: ${die_msg}"
                fi
 
@@ -225,13 +224,22 @@ install_qa_check() {
 
        if hasq multilib-strict ${FEATURES} && [ -x file -a -x find -a \
             -n "${MULTILIB_STRICT_DIRS}" -a -n "${MULTILIB_STRICT_DENY}" ]; then
-               MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT:-"(perl5|gcc|gcc-lib|debug|portage)"} | sed -e 's:\([(|)]\):\\\1:g')
+               local abort=no firstrun=yes
+               MULTILIB_STRICT_EXEMPT=$(echo ${MULTILIB_STRICT_EXEMPT} | sed -e 's:\([(|)]\):\\\1:g')
                for dir in ${MULTILIB_STRICT_DIRS}; do
                        [ -d "${D}/${dir}" ] || continue
                        for file in $(find ${D}/${dir} -type f | grep -v "^${D}/${dir}/${MULTILIB_STRICT_EXEMPT}"); do
-                               file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" && die "File ${file} matches a file type that is not allowed in ${dir}"
+                               if file ${file} | egrep -q "${MULTILIB_STRICT_DENY}" ; then
+                                       if [[ ${firstrun} == yes ]] ; then
+                                               echo "Files matching a file type that is not allowed:"
+                                               firstrun=no
+                                       fi
+                                       abort=yes
+                                       echo "   ${file#${D}//}"
+                               fi
                        done
                done
+               [[ ${abort} == yes ]] && die "multilib-strict check failed!"
        fi
 
 }
@@ -247,7 +255,7 @@ install_mask() {
        set -o noglob
        for no_inst in ${install_mask}; do
                set +o noglob
-               einfo "Removing ${no_inst}"
+               quiet_mode || einfo "Removing ${no_inst}"
                # normal stuff
                rm -Rf ${root}/${no_inst} >&/dev/null
 
@@ -309,7 +317,7 @@ preinst_suid_scan() {
        # total suid control.
        if hasq suidctl $FEATURES; then
                sfconf=${EPREFIX}/etc/portage/suidctl.conf
-               vecho ">>> Preforming suid scan in ${IMAGE}"
+               vecho ">>> Performing suid scan in ${IMAGE}"
                for i in $(find ${IMAGE}/ -type f \( -perm -4000 -o -perm -2000 \) ); do
                        if [ -s "${sfconf}" ]; then
                                suid="$(grep ^${i/${IMAGE}/}$ ${sfconf})"
@@ -377,6 +385,7 @@ dyn_package() {
        export SANDBOX_ON="0"
        tar cpvf - ./ | bzip2 -f > "${pkg_tmp}" || die "Failed to create tarball"
        cd ..
+       export PYTHONPATH=${PORTAGE_PYM_PATH:-/usr/lib/portage/pym}
        python -c "import xpak; t=xpak.tbz2('${pkg_tmp}'); t.recompose('${PORTAGE_BUILDDIR}/build-info')"
        if [ $? -ne 0 ]; then
                rm -f "${pkg_tmp}"
diff --git a/bin/pkgmerge b/bin/pkgmerge
deleted file mode 100755 (executable)
index 4499599..0000000
+++ /dev/null
@@ -1,59 +0,0 @@
-#!@PYTHON@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/pkgmerge,v 1.8 2004/10/04 13:56:50 vapier Exp $
-
-import sys,os,string
-sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
-
-import portage,xpak
-
-#build our package digraph
-
-def digraph_create(digraph,mykey,myprovides=None):
-       mytbz2=xpak.tbz2(bintree.getname(mykey))
-       mydep=mytbz2.getelements("RDEPEND")
-       digraph.addnode(mykey,myprovides)
-       mycheck=roottree.depcheck(string.join(mydep," "))
-       if mycheck[0]==0:
-               print "!!! Error: RDEPEND string formatted incorrectly:",mydep
-               return None 
-       for x in mycheck[1]:
-               mymatch=bintree.dep_bestmatch(x)
-               if mymatch=="":
-                       print "!!! Error: can't resolve dependency --",x
-                       return None
-               if not digraph_create(digraph,mymatch,mykey):
-                       return None
-       return 1
-
-#main program loop
-myvirtuals=portage.getvirtuals(portage.root)
-roottree=portage.vartree(portage.root,myvirtuals)
-bintree=portage.binarytree("/",myvirtuals)
-pretend=0
-if len(sys.argv)>=2:
-       if sys.argv[1]=="--pretend":
-               print "These are the packages that I would merge, in order:"
-               pretend=1
-               del sys.argv[1]
-       elif sys.argv[1]=="--help":
-               print "Usage: pkgmerge [--pretend] pkg1.tbz2 [pkg2.tbz2]..."
-               sys.exit(1)
-for mypkg in sys.argv[1:]:
-       digraph=portage.digraph()       
-       mytbz2=xpak.tbz2(mypkg)
-       mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(mypkg)[:-5]
-       digraph_create(digraph,mykey)   
-       while not digraph.empty():
-               mykey=digraph.firstzero()
-               if not mykey:
-                       print "!!! Error: circular dependencies"
-                       sys.exit(1)
-               mytbz2=bintree.getname(mykey)
-               if pretend:
-                       print mytbz2
-               else:
-                       portage.pkgmerge(mytbz2,portage.settings["ROOT"])
-               digraph.delnode(mykey)
-               
diff --git a/bin/pkgmerge.new b/bin/pkgmerge.new
deleted file mode 100755 (executable)
index cfab4f9..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-#!@PYTHON@
-# Copyright 1999-2006 Gentoo Foundation
-# Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/pkgmerge.new,v 1.7 2004/10/04 13:56:50 vapier Exp $
-
-import os,string,sys
-sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
-
-import portage,xpak
-
-#beautiful directed graph functions
-
-def dig_addnode(digraph,mykey,myprovides):
-       if not digraph.has_key(mykey):
-               if myprovides==None:
-                       digraph[mykey]=[0,[]]
-               else:
-                       digraph[mykey]=[0,[myprovides]]
-                       digraph[myprovides][0]=digraph[myprovides][0]+1
-               return
-       digraph[mykey]=[digraph[mykey][0],digraph[mykey][1].append(myprovides)]
-
-def dig_delnode(digraph,mykey):
-       if not digraph.has_key(mykey):
-               return
-       for x in digraph[mykey][1]:
-               digraph[x][0]=digraph[x][0]-1
-       del digraph[mykey]
-
-def dig_firstzero(digraph):
-       for x in digraph.keys():
-               if digraph[x][0]==0:
-                       return x
-       return None 
-
-#build our package digraph
-
-def digraph_create(digraph,mykey,myprovides=None):
-       mytbz2=xpak.tbz2(bintree.getname(mykey))
-       mydep=mytbz2.getelements("RDEPEND")
-       dig_addnode(digraph,mykey,myprovides)
-       mycheck=roottree.depcheck(string.join(mydep," "))
-       if mycheck[0]==0:
-               print "!!! Error: RDEPEND string formatted incorrectly:",mydep
-               return None 
-       for x in mycheck[1]:
-               mymatch=bintree.dep_bestmatch(x)
-               if mymatch=="":
-                       print "!!! Error: can't resolve dependency --",x
-                       return None
-               if not digraph_create(digraph,mymatch,mykey):
-                       return None
-       return 1
-
-#main program loop
-myvirtuals=portage.getvirtual(portage.root)
-roottree=portage.vartree(portage.root,myvirtuals)
-bintree=portage.binarytree("/",myvirtuals)
-pretend=0
-if len(sys.argv)>=2:
-       if sys.argv[1]=="--pretend":
-               print "These are the packages that I would merge, in order:"
-               pretend=1
-               del sys.argv[1]
-       elif sys.argv[1]=="--help":
-               print "Usage: pkgmerge [--pretend] pkg1.tbz2 [pkg2.tbz2]..."
-               sys.exit(1)
-for mypkg in sys.argv[1:]:
-       digraph={}      
-       mytbz2=xpak.tbz2(mypkg)
-       mykey=mytbz2.getelements("CATEGORY")[0]+"/"+mypkg[:-5]
-       digraph_create(digraph,mykey)   
-       while (len(digraph)):
-               mykey=dig_firstzero(digraph)
-               if not mykey:
-                       print "!!! Error: circular dependencies"
-                       sys.exit(1)
-               mytbz2=bintree.getname(mykey)
-               if pretend:
-                       print mytbz2
-               else:
-                       portage.pkgmerge(mytbz2)
-               dig_delnode(digraph,mykey)
-               
index 70e5d55b94cbd79eda20375e47077bca0ba99689..7bb21d32198b5ab03b4f919aa4d3505b1eb6dcbc 100755 (executable)
@@ -3,8 +3,23 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id: /var/cvsroot/gentoo-src/portage/bin/portageq,v 1.13.2.1 2005/04/12 12:23:41 jstubbs Exp $
 
-import sys, os
-os.environ["PORTAGE_CALLER"] = "portageq"
+import sys
+# This block ensures that ^C interrupts are handled quietly.
+try:
+       import signal
+
+       def exithandler(signum, frame):
+               signal.signal(signal.SIGINT, signal.SIG_IGN)
+               signal.signal(signal.SIGTERM, signal.SIG_IGN)
+               sys.exit(1)
+
+       signal.signal(signal.SIGINT, exithandler)
+       signal.signal(signal.SIGTERM, exithandler)
+
+except KeyboardInterrupt:
+       sys.exit(1)
+
+import os
 sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
 
 import types,string
@@ -80,6 +95,36 @@ def mass_best_version(argv):
                sys.exit(1)
 mass_best_version.uses_root = True
 
+def metadata(argv):
+       """<root> <pkgtype> <category/package> [<key>]+
+       Returns metadata values for the specified package.
+       """
+       if (len(argv) < 4):
+               print >> sys.stderr, "ERROR: insufficient parameters!"
+               sys.exit(2)
+
+       root, pkgtype, pkgspec = argv[0:3]
+       metakeys = argv[3:]
+       type_map = {
+               "ebuild":"porttree",
+               "binary":"bintree",
+               "installed":"vartree"}
+       if pkgtype not in type_map:
+               print >> sys.stderr, "Unrecognized package type: '%s'" % pkgtype
+               sys.exit(1)
+       trees = portage.db
+       if os.path.realpath(root) == os.path.realpath(portage.settings["ROOT"]):
+               root = portage.settings["ROOT"] # contains the normalized $ROOT
+       try:
+                       values = trees[root][type_map[pkgtype]].dbapi.aux_get(
+                               pkgspec, metakeys)
+                       for value in values:
+                               print value
+       except KeyError:
+               print >> sys.stderr, "Package not found: '%s'" % pkgspec
+               sys.exit(1)
+
+metadata.uses_root = True
 
 def best_visible(argv):
        """<root> [<category/package>]+
@@ -263,9 +308,12 @@ def usage(argv):
                print "\nRun portageq with --help for info"
 
 def main():
-       if (len(sys.argv) < 2) or ("-h" in sys.argv or "--help" in sys.argv):
+       if "-h" in sys.argv or "--help" in sys.argv:
+               usage(sys.argv)
+               sys.exit(os.EX_OK)
+       elif len(sys.argv) < 2:
                usage(sys.argv)
-               sys.exit()
+               sys.exit(os.EX_USAGE)
 
        cmd = sys.argv[1]
        try:
@@ -280,7 +328,7 @@ def main():
                function(sys.argv[2:])
        except KeyError:
                usage(sys.argv)
-               sys.exit()
+               sys.exit(os.EX_USAGE)
 
 main()
 
index 03327aeb5c4fb97a1407070ee4702a2752569ede..6197b2211be3e3833b562b0b0a10dc6c95feafc4 100755 (executable)
@@ -15,7 +15,7 @@ if [[ ! -d ${z} ]] ; then
 fi
 
 for x in $(find "${z}"/ -type d 2>/dev/null) ; do
-       for y in $(find "${x}"/ -mindepth 1 -maxdepth 1 \( -type f -or -type l \) ! -name '.keep' 2>/dev/null) ; do
+       for y in $(find "${x}"/ -mindepth 1 -maxdepth 1 \( -type f -or -type l \) ! -name '.keep_*' 2>/dev/null) ; do
                if [[ -L ${y} ]] ; then
                        # Symlink ...
                        mylink=${y}
index b45cd56435631e1526869c6e14516853dbb846aa..d5cf0bc827e4851e47622d0944333aad6758d0d2 100755 (executable)
@@ -1,13 +1,16 @@
 #!@BASH@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/prepstrip,v 1.23.2.3 2005/08/15 02:58:20 vapier Exp $
+# $Id$
 
-if [[ " ${FEATURES} " == *" nostrip "* ]] || \
-   [[ " ${RESTRICT} " == *" nostrip "* ]] || \
-   [[ " ${RESTRICT} " == *" strip "* ]]
+source "${PORTAGE_BIN_PATH:-${EPREFIX}/usr/lib/portage/bin}"/isolated-functions.sh
+
+unset NOSTRIP
+if hasq nostrip ${FEATURES} ${RESTRICT} || \
+   hasq strip ${RESTRICT}
 then
-       exit 0
+       NOSTRIP=1
+       hasq installsources ${FEATURES} || exit 0
 fi
 
 STRIP=${STRIP:-${CHOST}-strip}
@@ -15,15 +18,27 @@ type -p -- ${STRIP} > /dev/null || STRIP=strip
 OBJCOPY=${OBJCOPY:-${CHOST}-objcopy}
 type -p -- ${OBJCOPY} > /dev/null || OBJCOPY=objcopy
 
-PORTAGE_STRIP_FLAGS=${PORTAGE_STRIP_FLAGS:---strip-unneeded}
+export PORTAGE_STRIP_FLAGS=${PORTAGE_STRIP_FLAGS:---strip-unneeded}
 
 banner=1
 
 save_elf_debug() {
        local x=$1
-       local y="${D}/usr/lib/debug/${x:${#D}:${#x}}.debug"
+       local y="${D}usr/lib/debug/${x:${#D}}.debug"
+
+       if hasq installsources ${FEATURES} && [ -x "${EPREFIX}"/usr/bin/debugedit ] ; then
+               local sources_dir=/usr/src/debug/${CATEGORY}/${PF}
+               debugedit -b "${WORKDIR}" -d "${EPREFIX}/${sources_dir}" \
+                       -l "${T}"/debug.sources "${x}"
+               if [[ -s ${T}/debug.sources ]] ; then 
+                       [[ -d ${D}${sources_dir} ]] || mkdir -p "${D}${sources_dir}"
+                       cat "${T}"/debug.sources | (cd "${WORKDIR}"; LANG=C sort -z -u | \
+                               rsync -aL0 --files-from=- "${WORKDIR}/" "${D}${sources_dir}/" )
+               fi
+       fi
 
-       [[ " ${FEATURES} " != *" splitdebug "* ]] && return 0
+       hasq splitdebug ${FEATURES} || return 0
+       [[ -z "${NOSTRIP}" ]] || return 0
 
        # dont save debug info twice.
        [[ ${x:7} == ".debug" ]] && return 0
@@ -31,49 +46,49 @@ save_elf_debug() {
        mkdir -p $(dirname "${y}")
        ${OBJCOPY} --only-keep-debug "${x}" "${y}"
        ${OBJCOPY} --add-gnu-debuglink="${y}" "${x}"
-       chmod a-x "${y}"
+       chmod a-x,o-w "${y}"
 
-       [[ " ${FEATURES} " != *" installsources "* ]] && return 0
+}
 
-       if [[ -x "${EPREFIX}/usr/bin/debugedit" ]] ; then
-               debugedit -b "${WORKDIR}" -d "${EPREFIX}"/usr/src/debug/${PF} -l "${T}"/debug.sources "${x}"
-               if [[ -s ${T}/debug.sources ]] ; then 
-                       [[ -d ${D}/usr/src/debug/${PF} ]] || mkdir -p "${D}/usr/src/debug/${PF}"
-                       cat "${T}"/debug.sources | (cd "${WORKDIR}"; LANG=C sort -z -u | xargs -0 -- cp --parents -p --target-directory="${D}/usr/src/debug/${PF}" )
-               fi
+# The existance of the section .symtab tells us that a binary is stripped.
+# We want to log already stripped binaries, as this may be a QA violation.
+# They prevent us from getting the splitdebug data.
+f="$(scanelf -yqRBF '#k%F' -k '!.symtab' "$@")"
+if [[ -n "${f}" ]] ; then
+       vecho -e "\n\aQA Notice: pre-stripped files found:\a"
+       vecho "${f}"
+       echo "${f}" > "${T}"/scanelf-already-stripped.log
+fi
+
+# Now we look for unstripped binaries.
+for x in $(scanelf -yqRBF '#k%F' -k '.symtab' "$@") $(for y in "$@"; do find "${y}" -type f -name '*.a' -print ; done); do
+       if [[ ${banner} -eq 1 ]] ; then
+               [[ -z ${NOSTRIP} ]] && vecho "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
+               banner=0
        fi
-}
-if [[ `type -p scanelf` ]]; then
-       for x in $(scanelf -yRBF%F "$@") $(for y in "$@"; do find "${y}" -type f -name '*.a' -print0 ; done); do
-               if [[ ${banner} -eq 1 ]] ; then
-                       echo "strip: ${STRIP} ${PORTAGE_STRIP_FLAGS}"
-                       banner=0
-               fi
 
-               f=$(file "${x}") || continue
-               [[ -z ${f} ]] && continue
-
-               # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
-               #  the for loop from expanding the globs.
-               # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
-               set -o noglob
-               stripitbaby=1
-               for m in $(eval echo ${STRIP_MASK}) ; do
-                       [[ ${x} == ${m} ]] && stripitbaby=1 && break
-               done
-               set +o noglob
-
-               if [[ ${f} == *"current ar archive"* ]] ; then
-                       echo "   ${x:${#D}:${#x}}"
-                       [[ ${stripitbaby} -eq 1 ]] && ${STRIP} -g "${x}"
-               fi
-               if [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
-                       echo "   ${x:${#D}:${#x}}"
-                       save_elf_debug "${x}"
-                       [[ ${stripitbaby} -eq 1 ]] && ${STRIP} ${PORTAGE_STRIP_FLAGS} "${x}"
-               fi
+       f=$(file "${x}") || continue
+       [[ -z ${f} ]] && continue
+
+       # The noglob funk is to support STRIP_MASK="/*/booga" and to keep
+       #  the for loop from expanding the globs.
+       # The eval echo is to support STRIP_MASK="/*/{booga,bar}" sex.
+       set -o noglob
+       stripitbaby=1
+       for m in $(eval echo ${STRIP_MASK}) ; do
+               [[ ${x} == ${m} ]] && stripitbaby=0 && break
        done
-else
-       echo "scanelf(1) not found, skipping..."
-fi
-       
+       set +o noglob
+
+       if [[ ${f} == *"current ar archive"* ]] ; then
+               vecho "   ${x:${#D}}"
+               [[ -n ${NOSTRIP} ]] && continue
+               [[ ${stripitbaby} -eq 1 ]] && ${STRIP} -g "${x}"
+       fi
+       if [[ ${f} == *"SB executable"* || ${f} == *"SB shared object"* ]] ; then
+               vecho "   ${x:${#D}}"
+               save_elf_debug "${x}"
+               [[ -n ${NOSTRIP} ]] && continue
+               [[ ${stripitbaby} -eq 1 ]] && ${STRIP} ${PORTAGE_STRIP_FLAGS} "${x}"
+       fi
+done
index 09f48d21c749dbfb650da6ad2cea20b796344e3e..ab1589fb644b9f8a4173394fc22b4b01d37008cf 100755 (executable)
@@ -1,7 +1,7 @@
 #!@BASH@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/quickpkg,v 1.13.2.6 2005/08/10 22:08:48 vapier Exp $
+# $Id$
 
 # This script tries to quickly create a Gentoo binary package using the
 # VDB_PATH/category/pkg/*  files
@@ -9,14 +9,23 @@
 # Resulting tbz2 file will be created in ${PKGDIR} ...
 # default is /usr/portage/packages/All/
 
-if [ "`whoami`" != "root" ] ; then
+if [ "${UID}" != "0" ] ; then
        echo "You must run this as root"
        exit 1
 fi
 
+# We need to ensure a sane umask for the packages that will be created.
+umask 022
+
+eval $(portageq envvar -v NOCOLOR PKGDIR PORTAGE_BIN_PATH PORTAGE_NICENESS \
+       PORTAGE_PYM_PATH PORTAGE_TMPDIR ROOT)
+export PKGDIR PORTAGE_TMPDIR ROOT
+
+[ -n "${PORTAGE_NICENESS}" ] && renice $PORTAGE_NICENESS $$ > /dev/null
+
+# Make sure the xpak module is in PYTHONPATH
+export PYTHONPATH=${PORTAGE_PYM_PATH}
 export PORTAGE_DB=$(portageq vdb_path)
-export ROOT=$(portageq envvar ROOT)
-export ROOT=${ROOT%/}/
 
 if [ -z "$1" ] || [ $1 == "-h" ] || [ $1 == "--help" ] ; then
        echo "QUICKPKG ver 1.2"
@@ -37,10 +46,15 @@ if [ -z "$1" ] || [ $1 == "-h" ] || [ $1 == "--help" ] ; then
        exit 1
 fi
 
-export PKGDIR=$(portageq envvar PKGDIR)
-export PORTAGE_TMPDIR=$(portageq envvar PORTAGE_TMPDIR)
-
-source @PORTAGE_BASE@/sbin/functions.sh
+source "${PORTAGE_BIN_PATH}/isolated-functions.sh"
+case "${NOCOLOR:-false}" in
+       yes|true)
+               unset_colors
+               ;;
+       no|false)
+               set_colors
+               ;;
+esac
 
 # here we make a package given a little info
 # $1 = package-name w/version
@@ -60,6 +74,9 @@ do_pkg() {
                # get pkg info files
                mkdir -p "${MYDIR}"/temp
                cp "${SRCDIR}"/* "${MYDIR}"/temp/
+               [ -d "${PKGDIR}"/All ] ||  mkdir -p "${PKGDIR}"/All
+               local pkg_dest="${PKGDIR}/All/${1}.tbz2"
+               local pkg_tmp="${PKGDIR}/All/${1}.tbz2.$$"
 
                # create filelist and a basic tbz2
                gawk '{
@@ -68,19 +85,21 @@ do_pkg() {
                                        NF=NF-2
                                else if ($1 == "sym")
                                        NF=NF-3
-                               print
                        }
-               }' "${SRCDIR}"/CONTENTS | cut -f2- -d" " - | sed -e 's:^/:./:' > "${MYDIR}"/filelist
-               tar vjcf "${MYDIR}"/bin.tar.bz2 -C "${ROOT}" --files-from="${MYDIR}"/filelist --no-recursion
+                       print
+               }' "${SRCDIR}"/CONTENTS | cut -f2- -d" " - | sed -e 's:^/:./:' | \
+               while read f; do
+                       [ -d "${ROOT}/${f}" ] && [ -h "${ROOT}/${f}" ] && continue
+                       echo "$f"
+               done > "${MYDIR}"/filelist
+               tar vjcf "${pkg_tmp}" -C "${ROOT}" --files-from="${MYDIR}"/filelist --no-recursion
 
                # join together the basic tbz2 and the pkg info files
-               xpak "${MYDIR}"/temp "${MYDIR}"/inf.xpak
-               tbz2tool join "${MYDIR}"/bin.tar.bz2 "${MYDIR}"/inf.xpak "${MYDIR}"/$1.tbz2
+               python -c "import xpak; t=xpak.tbz2('${pkg_tmp}'); t.recompose('${MYDIR}/temp')"
 
                # move the final binary package to PKGDIR
-               [ -d "${PKGDIR}"/All ] ||  mkdir -p "${PKGDIR}"/All
+               mv -f "${pkg_tmp}" "${pkg_dest}"
                [ -d "${PKGDIR}/$2" ] || mkdir -p "${PKGDIR}/$2"
-               mv "${MYDIR}"/$1.tbz2 "${PKGDIR}"/All
                ( cd "${PKGDIR}/$2" && ln -s ../All/$1.tbz2 )
 
                # cleanup again
index f75efe16df93f7e37003d31d2bd1772cbb9cf2c3..803de9171e0ac9b47b718b92edca28b46b9f10d0 100755 (executable)
@@ -9,7 +9,7 @@ import os
 import portage, string, re
 
 __candidatematcher__ = re.compile("^[0-9]+: \\*\\*\\* emerge ")
-__noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot| unmerge( |$)")
+__noncandidatematcher__ = re.compile(" sync( |$)| clean( |$)| search( |$)|--oneshot|--fetchonly| unmerge( |$)")
 
 def issyspkg(pkgline):
        return (pkgline[0] == "*")
index c54ffbd42e5bdeb23e69a1202a17a24b2f5b4f22..5a8a8aa0b43e03772a0f318dcb80786f5dedf680 100755 (executable)
@@ -1,15 +1,16 @@
 #!@PYTHON@ -O
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: /var/cvsroot/gentoo-src/portage/bin/repoman,v 1.98.2.23 2005/06/18 01:00:43 vapier Exp $
+# $Id$
 
 # Next to do: dep syntax checking in mask files
 # Then, check to make sure deps are satisfiable (to avoid "can't find match for" problems)
 # that last one is tricky because multiple profiles need to be checked.
 
-import os,sys,shutil
+import errno, os, shutil, sys
+if not hasattr(__builtins__, "set"):
+       from sets import Set as set
 exename=os.path.basename(sys.argv[0])  
-os.environ["PORTAGE_CALLER"]="repoman"
 sys.path = ["@PORTAGE_BASE@/pym"]+sys.path
 version="1.2"  
 
@@ -22,7 +23,10 @@ map(allowed_filename_chars_set.setdefault, map(chr, map(ord, [".", "-", "_", "+"
 
 import string,signal,re,pickle,tempfile
 
+os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
 import portage
+del os.environ["PORTAGE_LEGACY_GLOBALS"]
+
 import portage_checksum
 import portage_const
 import portage_dep
@@ -32,16 +36,23 @@ import time
 import codecs
 
 from portage_manifest import Manifest
+from portage_exception import ParseError
 
-from output import *
-#bold, darkgreen, darkred, green, red, turquoise, yellow
+from output import bold, darkgreen, darkred, green, nocolor, red, turquoise, yellow
 
 from commands import getstatusoutput
 from fileinput import input
 from grp import getgrnam
-from stat import *
+from stat import S_ISDIR, ST_CTIME, ST_GID, ST_MTIME
+
+# A sane umask is needed for files that portage creates.
+os.umask(022)
+repoman_settings = portage.config(local_config=False,
+       config_incrementals=portage_const.INCREMENTALS)
+repoman_settings.lock()
 
-if portage.settings["NOCOLOR"] in ("yes","true") or not sys.stdout.isatty():
+if repoman_settings.get("NOCOLOR", "").lower() in ("yes", "true") or \
+       not sys.stdout.isatty():
        nocolor()
 
 def warn(txt):
@@ -61,7 +72,6 @@ def exithandler(signum=None,frame=None):
        os.kill(0,signal.SIGKILL)
 signal.signal(signal.SIGINT,exithandler)
 
-REPOROOTS=["gentoo-x86","gentoo-alt/trunk/prefix"]
 shortmodes={"ci":"commit"}
 modeshelp={
 "scan"   : "Scan directory tree for QA issues (default)",
@@ -78,7 +88,7 @@ repoman_options={
 "--commitmsgfile"  : "Adds a commit message from the specified file",
 "--help"           : "Show this screen",
 "--ignore-arches"  : "Ignore arch-specific failures (where arch != host)",
-"--include-masked" : "Include masked packages in scans at category or tree level",
+"--ignore-masked"  : "Ignore masked packages (not allowed with commit mode)",
 "--pretend"        : "Don't commit or fix anything; just show what would be done",
 "--quiet"          : "Be less verbose about extraneous info",
 "--verbose"        : "Displays every package name while checking",
@@ -87,7 +97,7 @@ repoman_options={
 }
 repoman_shortoptions={
 "-h" : "--help",
-"-i" : "--include-masked",
+"-i" : "--ignore-masked",
 "-I" : "--ignore-arches",
 "-m" : "--commitmsg",
 "-M" : "--commitmsgfile",
@@ -149,7 +159,8 @@ qahelp={
        "ebuild.output":"A simple sourcing of the ebuild produces output; this breaks ebuild policy.",
        "ebuild.nesteddie":"Placing 'die' inside ( ) prints an error, but doesn't stop the ebuild.",
        "variable.readonly":"Assigning a readonly variable",
-       "IUSE.invalid":"This build has a variable in IUSE that is not in the use.desc or use.local.desc file",
+       "LIVEVCS.stable":"This ebuild is a live checkout from a VCS but has stable keywords.",
+       "IUSE.invalid":"This ebuild has a variable in IUSE that is not in the use.desc or use.local.desc file",
        "LICENSE.invalid":"This ebuild is listing a license that doesnt exist in portages license/ dir.",
        "KEYWORDS.invalid":"This ebuild contains KEYWORDS that are not listed in profiles/arch.list or for which no valid profile was found",
        "ebuild.nostable":"There are no ebuilds that are marked as stable for your ARCH",
@@ -192,7 +203,9 @@ qawarnings=[
 "metadata.bad",
 "virtual.versioned",
 "virtual.exists",
-"virtual.unavailable"
+"virtual.unavailable",
+"usage.obsolete",
+"LIVEVCS.stable"
 ]
 
 missingvars=["KEYWORDS","LICENSE","DESCRIPTION","HOMEPAGE","SLOT"]
@@ -217,7 +230,6 @@ ven_string=ven_cat+'/'+ven_nam+'-'+ven_ver+ven_suf+ven_rev
 valid_ebuild_name_re=re.compile(ven_string+'$', re.I)
 valid_ebuild_filename_re=re.compile(ven_string+'\.ebuild$', re.I)
 
-repoman_settings = portage.config(clone=portage.settings)
 verbose=0
 quiet=0
 
@@ -349,7 +361,7 @@ if len(sys.argv)>1:
                elif sys.argv[x] in repoman_shortoptions.keys():
                        sys.argv[x] = repoman_shortoptions[sys.argv[x]]
                if sys.argv[x] in modes:
-                       if mymode==None:
+                       if mymode is None:
                                mymode=sys.argv[x]
                        else:
                                err("Please specify either \""+mymode+"\" or \""+sys.argv[x]+"\", but not both.")
@@ -370,7 +382,7 @@ if len(sys.argv)>1:
                else:
                        err_help("\""+sys.argv[x]+"\" is not a valid mode or option.")
                x=x+1
-if mymode==None:
+if mymode is None:
        mymode="scan"
 if mymode=="help" or ("--help" in myoptions):
        help(exitstatus=0)
@@ -378,20 +390,21 @@ if ("--version" in myoptions):
        show_version()
 if mymode=="last" or (mymode=="lfull"):
        last()
-if mymode=="commit" and "--include-masked" not in myoptions:
-       myoptions.append("--include-masked")
+if mymode == "commit":
+       while "--ignore-masked" in myoptions:
+               myoptions.remove("--ignore-masked")
 
 isCvs=False
 myreporoot=None
 if os.path.isdir("CVS"):
-       repoman_settings["PORTDIR_OVERLAY"]=""
-       if "cvs" not in portage.features:
+       if "cvs" not in repoman_settings.features:
                print
                print
                print red('!!! You do not have ')+bold('FEATURES="cvs" ')+red("enabled...")
                print red("!!! ")+bold("Adding \"cvs\" to FEATURES")
                print
                os.environ["FEATURES"]=repoman_settings["FEATURES"]+" cvs"
+       isCvs = True
 
        try:
                isCvs=True
@@ -476,13 +489,20 @@ def have_profile_dir(path, maxdepth=3):
 portdir=None
 portdir_overlay=None
 mydir=os.getcwd()
+if "PWD" in os.environ and os.environ["PWD"] != mydir and \
+       os.path.realpath(os.environ["PWD"]) == mydir:
+       # getcwd() returns the canonical path but that makes it hard for repoman to
+       # orient itself if the user has symlinks in their portage tree structure.
+       # We use os.environ["PWD"], if available, to get the non-canonical path of
+       # the current working directory (from the shell).
+       mydir = os.path.normpath(os.environ["PWD"])
 if mydir[-1] != "/":
        mydir += "/"
 
 for overlay in repoman_settings["PORTDIR_OVERLAY"].split():
        if overlay[-1] != "/":
                overlay += "/"
-       if mydir[:len(overlay)] == overlay:
+       if mydir.startswith(overlay):
                portdir_overlay = overlay
                subdir = mydir[len(overlay):]
                if subdir and subdir[-1] != "/":
@@ -492,14 +512,15 @@ for overlay in repoman_settings["PORTDIR_OVERLAY"].split():
                break
 
 if not portdir_overlay:
-       if (repoman_settings["PORTDIR"]+"/")[:len(mydir)] == mydir:
+       if (repoman_settings["PORTDIR"] + os.path.sep).startswith(mydir):
                portdir_overlay = repoman_settings["PORTDIR"]
        else:
                portdir_overlay = have_profile_dir(mydir)
        portdir = portdir_overlay
 
 if not portdir_overlay:
-       print darkred("Unable to determine PORTDIR.")
+       sys.stderr.write("Repoman is unable to determine PORTDIR or PORTDIR_OVERLAY from" + \
+               " the current\nworking directory.\n")
        sys.exit(1)
 
 if not portdir:
@@ -521,9 +542,15 @@ if quiet < 2:
        print "PORTDIR = \""+os.environ["PORTDIR"]+"\""
        print "PORTDIR_OVERLAY = \""+os.environ["PORTDIR_OVERLAY"]+"\""
 
-
-reload(portage)
-repoman_settings = portage.config(clone=portage.settings)
+# Now that PORTDIR_OVERLAY is properly overridden, create the portdb.
+repoman_settings = portage.config(local_config=False,
+       config_incrementals=portage_const.INCREMENTALS)
+trees = portage.create_trees()
+trees["/"]["porttree"].settings = repoman_settings
+portdb = trees["/"]["porttree"].dbapi
+portdb.mysettings = repoman_settings
+# dep_zapdeps looks at the vardbapi, but it shouldn't for repoman.
+trees["/"]["vartree"].dbapi = portage.fakedbapi(settings=repoman_settings)
 
 if not myreporoot:
        myreporoot = os.path.basename(portdir_overlay)
@@ -553,9 +580,6 @@ if mymode == "commit" and repolevel not in [1,2,3]:
        print red("***")
        err("Unable to identify level we're commiting from for %s" % string.join(reposplit,'/'))
 
-if repolevel == 3 and "--include-masked" not in myoptions:
-       myoptions.append("--include-masked")
-
 startdir=os.getcwd()
 
 for x in range(0,repolevel-1):
@@ -570,47 +594,78 @@ if "--pretend" in myoptions:
 elif quiet < 1:
        print green("\nRepoMan scours the neighborhood...")
 
+def parse_use_local_desc(mylines, usedict=None):
+       """returns a dict of the form {cpv:set(flags)}"""
+       if usedict is None:
+               usedict = {}
+       lineno = 0
+       for l in mylines:
+               lineno += 1
+               if not l or l.startswith("#"):
+                       continue
+               mysplit = l.split(None, 1)
+               if not mysplit:
+                       continue
+               mysplit = mysplit[0].split(":")
+               if len(mysplit) != 2:
+                       raise ParseError("line %d: Malformed input: '%s'" % \
+                               (lineno, l.rstrip("\n")))
+               usedict.setdefault(mysplit[0], set())
+               usedict[mysplit[0]].add(mysplit[1])
+       return usedict
+
 # retreive local USE list
 luselist={}
 try:
-       mylist=portage.grabfile(portdir+"/profiles/use.local.desc")
-       for mypos in range(0,len(mylist)):
-               mysplit=mylist[mypos].split()[0]
-               myuse=string.split(mysplit,":")
-               if len(myuse)==2:
-                       if not luselist.has_key(myuse[0]):
-                               luselist[myuse[0]] = []
-                       luselist[myuse[0]].append(myuse[1])
-except SystemExit, e:
-       raise  # Need to propogate this
-except:
+       f = open(os.path.join(portdir, "profiles", "use.local.desc"))
+       parse_use_local_desc(f, luselist)
+       f.close()
+except (IOError, OSError, ParseError), e:
+       print >> sys.stderr, str(e)
        err("Couldn't read from use.local.desc")
 
+if portdir_overlay != portdir:
+       filename = os.path.join(portdir_overlay, "profiles", "use.local.desc")
+       if os.path.exists(filename):
+               try:
+                       f = open(filename)
+                       parse_use_local_desc(f, luselist)
+                       f.close()
+               except (IOError, OSError, ParseError), e:
+                       print >> sys.stderr, str(e)
+                       err("Couldn't read from '%s'" % filename)
+       del filename
+
 # setup a uselist from portage
 uselist=[]
 try:
        uselist=portage.grabfile(portdir+"/profiles/use.desc")
        for l in range(0,len(uselist)):
                uselist[l]=string.split(uselist[l])[0]
+       for var in string.split(repoman_settings["USE_EXPAND"]):
+               vardescs = portage.grabfile(portdir+"/profiles/desc/"+var.lower()+".desc")
+               for l in range(0, len(vardescs)):
+                       uselist.append(var.lower() + "_" + string.split(vardescs[l])[0])
 except SystemExit, e:
        raise  # Need to propogate this
 except:
        err("Couldn't read USE flags from use.desc")
 
 # retrieve a list of current licenses in portage
-liclist=portage.listdir(portdir+"/licenses")
+liclist = set(portage.listdir(os.path.join(portdir, "licenses")))
 if not liclist:
        err("Couldn't find licenses?")
+if portdir_overlay != portdir:
+       liclist.update(portage.listdir(os.path.join(portdir_overlay, "licenses")))
 
 # retrieve list of offical keywords
-try:
-       kwlist=portage.grabfile(portdir+"/profiles/arch.list")
-except SystemExit, e:
-       raise  # Need to propogate this
-except:
-       err("Couldn't read KEYWORDS from arch.list")
+kwlist = set(portage.grabfile(os.path.join(portdir, "profiles", "arch.list")))
 if not kwlist:
-       kwlist=["alpha","arm","hppa","mips","ppc","ppc-macos","sparc","x86"]
+       err("Couldn't read KEYWORDS from arch.list")
+
+if portdir_overlay != portdir:
+       kwlist.update(portage.grabfile(
+               os.path.join(portdir_overlay, "profiles", "arch.list")))
 
 scanlist=[]
 if repolevel==2:
@@ -620,7 +675,7 @@ if repolevel==2:
                caterror(catdir)
        mydirlist=os.listdir(startdir)
        for x in mydirlist:
-               if x=="CVS" or x==".svn":
+               if x == "CVS" or x.startswith("."):
                        continue
                if os.path.isdir(startdir+"/"+x):
                        scanlist.append(catdir+"/"+x)
@@ -629,7 +684,7 @@ elif repolevel==1:
                if not os.path.isdir(startdir+"/"+x):
                        continue
                for y in os.listdir(startdir+"/"+x):
-                       if y=="CVS" or y==".svn":
+                       if y == "CVS" or y.startswith("."):
                                continue
                        if os.path.isdir(startdir+"/"+x+"/"+y):
                                scanlist.append(x+"/"+y)
@@ -657,7 +712,7 @@ if os.path.exists(descfile):
                else:
                        profiles[arch[0]] = [[arch[1], arch[2]]]
 
-       for x in portage.archlist:
+       for x in repoman_settings.archlist():
                if x[0] == "~":
                        continue
                if not profiles.has_key(x):
@@ -674,8 +729,7 @@ else:
 
 stats={}
 fails={}
-#objsadded records all object being added to cvs
-objsadded=[]
+
 for x in qacats:
        stats[x]=0
        fails[x]=[]
@@ -763,7 +817,6 @@ for x in scanlist:
                print "checking package " + x
        eadded=[]
        dadded=[]
-       cladded=0
        catdir,pkgdir=x.split("/")
        checkdir=repodir+"/"+x
        checkdirlist=os.listdir(checkdir)
@@ -819,16 +872,12 @@ for x in scanlist:
                        myf.close()
                        for l in myl:
                                if l[0]!="/":
-                                       lname=l.split()
-                               else:
-                                       lname=l[1:].split("/")
-                               if not len(lname):
                                        continue
-                               objsadded.append(lname[0])
-                               if lname[0][-7:]==".ebuild":
-                                       eadded.append(lname[0][:-7])
-                               if lname[0]=="ChangeLog":
-                                       cladded=1
+                               splitl=l[1:].split("/")
+                               if not len(splitl):
+                                       continue
+                               if splitl[0][-7:]==".ebuild":
+                                       eadded.append(splitl[0][:-7])
                except IOError:
                        if mymode=="commit" and isCvs:
                                stats["CVS/Entries.IO_error"] += 1
@@ -847,14 +896,12 @@ for x in scanlist:
                        myf.close()
                        for l in myl:
                                if l[0]!="/":
-                                       lname=l.split()
-                               else:
-                                       lname=l[1:].split("/")
-                               if not len(lname):
                                        continue
-                               objsadded.append(lname[0])
-                               if lname[0][:7]=="digest-":
-                                       dadded.append(lname[0][7:])
+                               splitl=l[1:].split("/")
+                               if not len(splitl):
+                                       continue
+                               if splitl[0][:7]=="digest-":
+                                       dadded.append(splitl[0][7:])
                except IOError:
                        if mymode=="commit" and isCvs:
                                stats["CVS/Entries.IO_error"] += 1
@@ -864,7 +911,12 @@ for x in scanlist:
                                fails["svn.IO_error"].append(checkdir+"/files svn info")
                        continue
 
-       mf=Manifest(checkdir, db=portage.db["/"]["porttree"].dbapi, mysettings=repoman_settings)
+       if mymode == "commit":
+               repoman_settings["O"] = checkdir
+               portage.digestgen(
+                       [], repoman_settings, manifestonly=1, myportdb=portdb)
+
+       mf = Manifest(checkdir, repoman_settings["DISTDIR"])
        mydigests=mf.getTypeDigests("DIST")
        myfiles_all = []
 
@@ -894,7 +946,6 @@ for x in scanlist:
                                                        vcsrm="svn rm"
                                                if "--pretend" in myoptions:
                                                                print "(cd "+repodir+"/"+x+"/files; "+vcsrm+" "+y+")"
-                                                       
                                                else:
                                                        os.system("(cd "+repodir+"/"+x+"/files; "+vcsrm+" "+y+")")
                                        else:
@@ -902,7 +953,7 @@ for x in scanlist:
                                                fails["digest.stray"].append(x+"/files/"+y)
                                else:
                                        # We have an ebuild
-                                       myuris,myfiles = portage.db["/"]["porttree"].dbapi.getfetchlist(mykey,all=True)
+                                       myuris, myfiles = portdb.getfetchlist(mykey, all=True)
                                        myfiles_all.extend(myfiles)
 
                                        uri_dict = {}
@@ -922,12 +973,14 @@ for x in scanlist:
                                                                        stats["digest.unmatch"] += 1
                                                                        fails["digest.unmatch"].append(y+"::"+myf)
                                                                else:
-                                                                       eb_name,eb_location = portage.db["/"]["porttree"].dbapi.findname2(mykey)
-                                                                       portage.doebuild(eb_name, "digest", "/", uri_settings, tree="porttree")
+                                                                       eb_name = portdb.findname2(mykey)[0]
+                                                                       portage.doebuild(eb_name, "digest", "/",
+                                                                               uri_settings, tree="porttree",
+                                                                               mydbapi=portdb)
                                                        else:
                                                                stats["digest.partial"] += 1
                                                                fails["digest.partial"].append(y+"::"+myf)
-                                               elif "assume-digests" not in portage.features:
+                                               elif "assume-digests" not in repoman_settings.features:
                                                        if os.path.exists(myff):
                                                                if not portage_checksum.verify_all(myff, mydigests[myf]):
                                                                        stats["digest.fail"] += 1
@@ -952,6 +1005,8 @@ for x in scanlist:
                                if y == "CVS" or y == ".svn":
                                        continue
                                for z in os.listdir(checkdir+"/files/"+y):
+                                       if z == "CVS" or z == ".svn":
+                                               continue
                                        filesdirlist.append(y+"/"+z)
                        # current policy is no files over 20k, this is the check.
                        elif mystat.st_size > 20480:
@@ -1016,7 +1071,7 @@ for x in scanlist:
                                stats["digest.missing"]=stats["digest.missing"]+1
                                fails["digest.missing"].append(x+"/files/digest-"+y)
                myesplit=portage.pkgsplit(y)
-               if myesplit==None or not valid_ebuild_name(x.split("/")[0]+"/"+y):
+               if myesplit is None or not valid_ebuild_name(x.split("/")[0]+"/"+y):
                        stats["ebuild.invalidname"]=stats["ebuild.invalidname"]+1
                        fails["ebuild.invalidname"].append(x+"/"+y+".ebuild")
                        continue
@@ -1026,7 +1081,8 @@ for x in scanlist:
                        fails["ebuild.namenomatch"].append(x+"/"+y+".ebuild")
                        continue
                try:
-                       myaux = dict( zip(allvars, portage.db["/"]["porttree"].dbapi.aux_get(catdir+"/"+y, allvars ) ) )
+                       myaux = dict(
+                               zip(allvars, portdb.aux_get(os.path.join(catdir, y), allvars)))
                except KeyError:
                        stats["ebuild.syntax"]=stats["ebuild.syntax"]+1
                        fails["ebuild.syntax"].append(x+"/"+y+".ebuild")
@@ -1048,7 +1104,8 @@ for x in scanlist:
                        if prov_cp != myprovide:
                                stats["virtual.versioned"]+=1
                                fails["virtual.versioned"].append(x+"/"+y+".ebuild: "+myprovide)
-                       prov_pkg = portage.dep_getkey(portage.best(portage.db["/"]["porttree"].dbapi.xmatch("match-all", prov_cp)))
+                       prov_pkg = portage.dep_getkey(
+                               portage.best(portdb.xmatch("match-all", prov_cp)))
                        if prov_cp == prov_pkg:
                                stats["virtual.exists"]+=1
                                fails["virtual.exists"].append(x+"/"+y+".ebuild: "+prov_cp)
@@ -1070,9 +1127,21 @@ for x in scanlist:
                        if not haskeyword:
                                stats["KEYWORDS.stupid"] += 1
                                fails["KEYWORDS.stupid"].append(x+"/"+y+".ebuild")
-               
+
+               """
+               Ebuilds that inherit a "Live" eclasss (darcs,subversion,git,cvs,etc..) should
+               not be allowed to be marked stable
+               """
+               if set(["darcs","cvs","subversion","git"]).intersection(myaux["INHERITED"].split()):
+                       bad_stable_keywords = [keyword for keyword in myaux["KEYWORDS"].split() if not keyword.startswith("~") and not keyword.startswith("-")]
+                       if bad_stable_keywords:
+                               stats["LIVEVCS.stable"] += 1
+                               fails["LIVEVCS.stable"].append(x+"/"+y+".ebuild with stable keywords:%s " % bad_stable_keywords)
+                       del keyword, bad_stable_keywords                
+
                if "--ignore-arches" in myoptions:
-                       arches=[[repoman_settings["ARCH"], repoman_settings["ARCH"], portage.groups]]
+                       arches = [[repoman_settings["ARCH"], repoman_settings["ARCH"],
+                               repoman_settings["ACCEPT_KEYWORDS"].split()]]
                else:
                        arches=[]
                        for keyword in myaux["KEYWORDS"].split():
@@ -1088,7 +1157,7 @@ for x in scanlist:
                badlicsyntax = False
                badprovsyntax = False
                catpkg = catdir+"/"+y
-               myiuse = myaux["IUSE"].split() + portage.archlist
+               myiuse = myaux["IUSE"].split() + repoman_settings.archlist()
                type_list, badsyntax = [], []
                for mytype in ("DEPEND", "RDEPEND", "PDEPEND", "LICENSE", "PROVIDE"):
                        mydepstr = myaux[mytype]
@@ -1126,7 +1195,8 @@ for x in scanlist:
 
                        if mytype in ("DEPEND", "RDEPEND", "PDEPEND"):
                                for token in filter(lambda x: not (x.endswith("?") or x.strip() in ("||", "&&", "(", ")")), mydepstr.split()):
-                                       if not "/" in token:
+                                       if not "/" in token or \
+                                               ":" in token and myaux["EAPI"] == "0":
                                                badsyntax.append("'%s' not a valid atom" % token)
 
                        type_list.extend([mytype] * (len(badsyntax) - len(type_list)))
@@ -1147,7 +1217,6 @@ for x in scanlist:
                                fails["usage.obsolete"].append("%s/%s.ebuild: not migrated to modular X" % (x, y))
 
                for keyword,arch,groups in arches:
-                       portage.groups=groups
 
                        if not profiles.has_key(arch):
                                # A missing profile will create an error further down
@@ -1158,17 +1227,30 @@ for x in scanlist:
 
                                profdir = portdir+"/profiles/"+prof[0]
        
-                               portage.profiledir=profdir
-       
-                               if arch_caches.has_key(prof[0]):
-                                       dep_settings, portage.portdb, portage.db["/"]["porttree"] = arch_caches[prof[0]]
+                               if prof[0] in arch_caches:
+                                       dep_settings = arch_caches[prof[0]]
                                else:
-                                       os.environ["ACCEPT_KEYWORDS"]="-~"+arch
-                                       dep_settings=portage.config(config_profile_path=profdir, config_incrementals=portage_const.INCREMENTALS)
-                                       portage.portdb=portage.portdbapi(portdir, dep_settings)
-                                       portage.db["/"]["porttree"]=portage.portagetree("/",dep_settings.getvirtuals("/"))
-                                       arch_caches[prof[0]]=[dep_settings, portage.portdb, portage.db["/"]["porttree"]]
-       
+                                       dep_settings = portage.config(
+                                               config_profile_path=profdir,
+                                               config_incrementals=portage_const.INCREMENTALS,
+                                               local_config=False)
+                                       arch_caches[prof[0]] = dep_settings
+                                       while True:
+                                               try:
+                                                       # Protect ACCEPT_KEYWORDS from config.regenerate()
+                                                       # (just in case)
+                                                       dep_settings.incrementals.remove("ACCEPT_KEYWORDS")
+                                               except ValueError:
+                                                       break
+
+                               trees["/"]["porttree"].settings = dep_settings
+                               portdb.mysettings = dep_settings
+                               # for package.use.mask support inside dep_check
+                               dep_settings.setcpv("/".join((catdir, y)))
+                               dep_settings["ACCEPT_KEYWORDS"] = " ".join(groups)
+                               # just in case, prevent config.reset() from nuking these.
+                               dep_settings.backup_changes("ACCEPT_KEYWORDS")
+
                                for myprovide in myaux["PROVIDE"].split():
                                        prov_cp = portage.dep_getkey(myprovide)
                                        if prov_cp not in dep_settings.getvirtuals():
@@ -1176,9 +1258,10 @@ for x in scanlist:
                                                fails["virtual.unavailable"].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+prov_cp)
 
                                if not baddepsyntax:
-                                       ismasked = (catdir+"/"+y not in portage.db["/"]["porttree"].dbapi.xmatch("list-visible",x))
+                                       ismasked = os.path.join(catdir, y) not in \
+                                               portdb.xmatch("list-visible", x)
                                        if ismasked:
-                                               if "--include-masked" not in myoptions:
+                                               if "--ignore-masked" in myoptions:
                                                        continue
                                                #we are testing deps for a masked package; give it some lee-way
                                                suffix="masked"
@@ -1189,7 +1272,7 @@ for x in scanlist:
        
                                        if prof[1] == "dev":
                                                suffix=suffix+"indev"
-                                       
+
                                        for mytype,mypos in [["DEPEND",len(missingvars)],["RDEPEND",len(missingvars)+1],["PDEPEND",len(missingvars)+2]]:
                                                
                                                mykey=mytype+".bad"+suffix
@@ -1197,7 +1280,9 @@ for x in scanlist:
                                                if not myvalue:
                                                        continue
                                                try:
-                                                       mydep=portage.dep_check(myvalue,portage.db["/"]["porttree"].dbapi,dep_settings,use="all",mode=matchmode)
+                                                       mydep = portage.dep_check(myvalue, portdb,
+                                                               dep_settings, use="all", mode=matchmode,
+                                                               trees=trees)
                                                except KeyError, e:
                                                        stats[mykey]=stats[mykey]+1
                                                        fails[mykey].append(x+"/"+y+".ebuild: "+keyword+"("+prof[0]+") "+repr(e[0]))
@@ -1281,11 +1366,12 @@ for x in scanlist:
                ignore_line = re.compile(r'(^$)|(^(\t)*#)')
                leading_spaces = re.compile(r'^[\S\t]')
                trailing_whitespace = re.compile(r'.*([\S]$)')
-               readonly_assignment = re.compile(r'^\s*(export\s+)?(A|P|PV|PN|PR|PVR|PF|D|WORKDIR|FILESDIR|FEATURES|USE)=')
+               readonly_assignment = re.compile(r'^\s*(export\s+)?(A|CATEGORY|P|PV|PN|PR|PVR|PF|D|WORKDIR|FILESDIR|FEATURES|USE)=')
                continuation_symbol = re.compile(r'(.*[ ]+[\\][ ].*)')
                line_continuation_quoted = re.compile(r'(\"|\')(([\w ,:;#\[\]\.`=/|\$\^\*{}()\'-])|(\\.))*\1')
                line_continuation = re.compile(r'([^#]*\S)(\s+|\t)\\$')
                linenum=0
+               previous_line = None
                for line in input(checkdir+"/"+y+".ebuild"):
                        linenum += 1
                        # Gentoo copyright check
@@ -1329,7 +1415,9 @@ for x in scanlist:
                                                fails["ebuild.minorsyn"].append(x+"/"+y+".ebuild: %s" % myerrormsg)
                                        # Readonly variable assignment check
                                        match = readonly_assignment.match(line)
-                                       if match:
+                                       # The regex can give a false positive for continued lines,
+                                       # so we check the previous line to see if it was continued.
+                                       if match and (not previous_line or not line_continuation.match(previous_line)):
                                                # invalid assignment, very bad!
                                                myerrormsg = "Readonly variable assignment to %s on line %d" % (match.group(2), linenum)
                                                stats["variable.readonly"] += 1
@@ -1350,6 +1438,8 @@ for x in scanlist:
                                                                myerrormsg = "Line continuation (\"\\\") Syntax Error. Line %d" % linenum
                                                                stats["ebuild.majorsyn"] +=1
                                                                fails["ebuild.majorsyn"].append(x+"/"+y+".ebuild: %s" % myerrormsg)
+                       previous_line = line
+               del previous_line
 
        # Check for 'all unstable' or 'all masked' -- ACCEPT_KEYWORDS is stripped
        # XXX -- Needs to be implemented in dep code. Can't determine ~arch nicely.
@@ -1375,7 +1465,8 @@ if not (os.stat(statsfile)[ST_GID] == getgrnam('portage')[2]):
 if not (os.stat(failsfile)[ST_GID] == getgrnam('portage')[2]):
        os.chown(failsfile,os.geteuid(),getgrnam('portage')[2])
        os.chmod(failsfile,0664)
-print
+if quiet < 2:
+       print
 #dofail will be set to 1 if we have failed in at least one non-warning category
 dofail=0
 #dowarn will be set to 1 if we tripped any warnings
@@ -1525,48 +1616,41 @@ else:
                print
                sys.exit(1)
 
-       
-       myheaders=[]
-       mychanged=[]
-       mydirty=[]
-       mynew=[]
-       myupdates=[]
-       myremoved=[]
-       mymissing=None
+       retval=["",""]
        if isCvs:
-               if mymissing:
-                       print "The following files are obviously missing from your cvs tree"
-                       print "and are being fetched so we can continue:"
-                       for x in mymissing:
-                               print "   ",x
-                       if "--pretend" in myoptions:
-                               print "(cvs -q up "+string.join(mymissing)+")"
-                               retval=0
-                       else:
-                               retval=os.system("cvs -q up "+string.join(mymissing))
-                       if retval:
-                               print "!!! Exiting on cvs (shell) error code:",retval
-                               sys.exit(retval)
-                       del mymissing
-               retval=["",""]
                print "Performing a "+green("cvs -n up")+" with a little magic grep to check for updates."
                retval=getstatusoutput("cvs -n up 2>&1 | "+portage_const.EPREFIX+"/bin/grep -E '^[^\?] .*' | "+portage_const.EPREFIX+"/bin/grep -E -v '^. .*/digest-[^/]+|^cvs server: .* -- ignored$'")
-               mylines=string.split(retval[1], "\n")
-
-               for x in mylines:
-                       if not x:
-                               continue
-                       if x[0] not in "UPMAR": # Updates,Patches,Modified,Added,Removed
-                               print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R are ok)")
-                               print red("!!! Note: This is a pretend/no-modify pass...")
-                               print retval[1]
-                               print
-                               sys.exit(1)
-                       elif x[0] in ["U","P"]:
-                               myupdates+=[x[2:]]
+               
+       mylines=string.split(retval[1], "\n")
+       myupdates=[]
+       for x in mylines:
+               if not x:
+                       continue
+               if x[0] not in "UPMAR": # Updates,Patches,Modified,Added,Removed
+                       print red("!!! Please fix the following issues reported from cvs: ")+green("(U,P,M,A,R are ok)")
+                       print red("!!! Note: This is a pretend/no-modify pass...")
+                       print retval[1]
+                       print
+                       sys.exit(1)
+               elif x[0] in ["U","P"]:
+                       myupdates+=[x[2:]]
+       
+       if myupdates:
+               print green("Fetching trivial updates...")
+               if "--pretend" in myoptions:
+                       print "(cvs up "+string.join(myupdates)+")"
+                       retval=0
+               else:
+                       retval=os.system("cvs up "+string.join(myupdates))
+               if retval!=0:
+                       print "!!! cvs exited with an error. Terminating."
+                       sys.exit(retval)
        
+       if isCvs:
                mycvstree=cvstree.getentries("./",recursive=1)
                mychanged=cvstree.findchanged(mycvstree,recursive=1,basedir="./")
+               for manifest in [file for file in mychanged if '/Manifest' in file]:
+                       mychanged.remove(manifest)
                mynew=cvstree.findnew(mycvstree,recursive=1,basedir="./")
                myremoved=cvstree.findremoved(mycvstree,recursive=1,basedir="./")
                if not (mychanged or mynew or myremoved):
@@ -1576,34 +1660,42 @@ else:
                        print "(Didn't find any changed files...)"
                        print
                        sys.exit(0)
-               if myupdates:
-                       print green("Fetching trivial updates...")
-                       if "--pretend" in myoptions:
-                               print "(cvs up "+string.join(myupdates)+")"
-                               retval=0
-                       else:
-                               retval=os.system("cvs up "+string.join(myupdates))
-                       if retval!=0:
-                               print "!!! cvs exited with an error. Terminating."
-                               sys.exit(retval)
-               myupdates=mychanged+mynew
-               headerstring="'\$(Header|Id)"
-               headerstring+=".*\$'"
-               for myfile in myupdates:
-                       myout=getstatusoutput(portage_const.EPREFIX+"/bin/grep -E -q "+headerstring+" "+myfile)
-                       if myout[0]==0:
-                               myheaders.append(myfile)
-
-               print "*",green(str(len(myupdates))),"files being committed...",green(str(len(myheaders))),"have headers that will change."
-               print "*","Files with headers will cause the manifests to be made and recommited."
+
+       myupdates=mychanged+mynew
+       myheaders=[]
+       mydirty=[]
+       headerstring="'\$(Header|Id)"
+       headerstring+=".*\$'"
+       for myfile in myupdates:
+               myout=getstatusoutput("egrep -q "+headerstring+" "+myfile)
+               if myout[0]==0:
+                       myheaders.append(myfile)
+
+       print "*",green(str(len(myupdates))),"files being committed...",green(str(len(myheaders))),"have headers that will change."
+       print "*","Files with headers will cause the manifests to be made and recommited."
+       if quiet == 0:
                print "myupdates:",myupdates
                print "myheaders:",myheaders
                print
-               unlinkfile=0
+       unlinkfile=0
+       if commitmessagefile:
+               try:
+                       f = open(commitmessagefile)
+                       commitmessage = f.read()
+                       f.close()
+                       del f
+               except (IOError, OSError), e:
+                       if e.errno == errno.ENOENT:
+                               portage.writemsg("!!! File Not Found: --commitmsgfile='%s'\n" % commitmessagefile)
+                       else:
+                               raise
+               # We've read the content so the file is no longer needed.
+               commitmessagefile = None
+       if not commitmessage:
+               print "Please enter a CVS commit message at the prompt:"
        
        # TODO svn check for UPMAR
        if isSvn:
-
                myconflicts=[]
                print "Checking "+green("svn -u status")+" to check for updates."
                mylines=[ elem.strip().split() for elem in getstatusoutput("svn -u status")[1].split("\n") ][:-1]
@@ -1660,7 +1752,7 @@ else:
                                exithandler()
        try:
                commitmessage+="\n(Portage version: "+str(portage.VERSION)+"-prefix)"
-       except:
+       except AttributeError:
                print "Failed to insert portage version in message!"
                commitmessage+="\n(Portage version: Unknown)"
        if not commitmessagefile:
@@ -1679,6 +1771,7 @@ else:
                print green("------------------------------------------------------------------------------")
                print
 
+               retval = None
                if "--pretend" in myoptions:
                        if isCvs:
                                print "(cvs -q commit -F "+commitmessagefile+")"
@@ -1696,17 +1789,37 @@ else:
 
        # Setup the GPG commands
        def gpgsign(filename):
+               if "PORTAGE_GPG_KEY" not in repoman_settings:
+                       raise portage_exception.MissingParameter("PORTAGE_GPG_KEY is unset!")
+               if "PORTAGE_GPG_DIR" not in repoman_settings:
+                       if os.environ.has_key("HOME"):
+                               repoman_settings["PORTAGE_GPG_DIR"] = os.path.join(os.environ["HOME"], ".gnupg")
+                               if quiet < 1:
+                                       print "Automatically setting PORTAGE_GPG_DIR to",repoman_settings["PORTAGE_GPG_DIR"]
+                       else:
+                               raise portage_exception.MissingParameter("PORTAGE_GPG_DIR is unset!")
+               gpg_dir = repoman_settings["PORTAGE_GPG_DIR"]
+               if gpg_dir.startswith("~") and "HOME" in os.environ:
+                       repoman_settings["PORTAGE_GPG_DIR"] = os.path.join(
+                               os.environ["HOME"], gpg_dir[1:].lstrip(os.path.sep))
+               if not os.access(repoman_settings["PORTAGE_GPG_DIR"], os.X_OK):
+                       raise portage_exception.InvalidLocation(
+                               "Unable to access directory: PORTAGE_GPG_DIR='%s'" % \
+                               repoman_settings["PORTAGE_GPG_DIR"])
                gpgcmd = "gpg --sign --clearsign --yes "
                gpgcmd+= "--default-key "+repoman_settings["PORTAGE_GPG_KEY"]
                if repoman_settings.has_key("PORTAGE_GPG_DIR"):
                        gpgcmd += " --homedir "+repoman_settings["PORTAGE_GPG_DIR"]
-               rValue = os.system(gpgcmd+" "+filename)
-               if rValue == 0:
-                       os.rename(filename+".asc", filename)
+               if "--pretend" in myoptions:
+                       print "("+gpgcmd+" "+filename+")"
                else:
-                       print "!!! gpg exited with '" + str(rValue) + "' status"
-               return rValue
+                       rValue = os.system(gpgcmd+" "+filename)
+                       if rValue == os.EX_OK:
+                               os.rename(filename+".asc", filename)
+                       else:
+                               raise portage_exception.PortageException("!!! gpg exited with '" + str(rValue) + "' status")
 
+       need_commit = False
        if myheaders or myupdates or myremoved or mynew:
                myfiles=myheaders+myupdates+myremoved+mynew
                for x in range(len(myfiles)-1, -1, -1):
@@ -1715,7 +1828,8 @@ else:
                mydone=[]
                if repolevel==3:   # In a package dir
                        repoman_settings["O"]=os.getcwd()
-                       portage.digestgen([],repoman_settings,manifestonly=1)
+                       portage.digestgen([], repoman_settings, manifestonly=1,
+                               myportdb=portdb)
                elif repolevel==2: # In a category dir
                        for x in myfiles:
                                xs=string.split(x,"/")
@@ -1725,7 +1839,8 @@ else:
                                        continue
                                mydone.append(xs[0])
                                repoman_settings["O"]=os.path.join(os.getcwd(), xs[0])
-                               portage.digestgen([],repoman_settings,manifestonly=1)
+                               portage.digestgen([], repoman_settings, manifestonly=1,
+                                       myportdb=portdb)
                elif repolevel==1: # repo-cvsroot
                        print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n"
                        for x in myfiles:
@@ -1736,65 +1851,64 @@ else:
                                        continue
                                mydone.append(string.join(xs[:2],"/"))
                                repoman_settings["O"]=os.path.join(os.getcwd(), x[0], x[1])
-                               portage.digestgen([],repoman_settings,manifestonly=1)
+                               portage.digestgen([], repoman_settings, manifestonly=1,
+                                       myportdb=portdb)
                else:
                        print red("I'm confused... I don't know where I am!")
                        sys.exit(1)
 
-               if "--pretend" in myoptions:
-                       if isCvs:
+               # Force an unsigned commit when more than one Manifest needs to be signed.
+               if repolevel < 3 and "sign" in repoman_settings.features:
+                       if "--pretend" in myoptions:
                                print "(cvs -q commit -F "+commitmessagefile+")"
-                       if isSvn:
-                               print "(svn -q commit -F "+commitmessagefile+")"
-               else:
-                       mymsg=open(commitmessagefile,"w")
-                       mymsg.write(commitmessage)
-                       mymsg.write(" (Unsigned Manifest commit)")
-                       mymsg.close()
-                       if isCvs:
+                       else:
+                               mymsg=open(commitmessagefile,"w")
+                               mymsg.write(commitmessage)
+                               mymsg.write("\n (Unsigned Manifest commit)")
+                               mymsg.close()
                                retval=os.system("cvs -q commit -F "+commitmessagefile)
-                       if isSvn:
-                               retval=os.system("svn -q commit -F "+commitmessagefile)
-                       if retval:
-                               print "!!! Exiting on cvs (shell) error code:",retval
-                               sys.exit(retval)
-       
-       if "sign" in portage.features:
-               mydone=[]
-               if repolevel==3:   # In a package dir
-                       repoman_settings["O"]="./"
-                       while(gpgsign(repoman_settings["O"]+"/Manifest")):
-                               portage.writemsg("!!! YOU MUST sign the Manifest.\n")
-                               portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'")
-                               time.sleep(3)
-               elif repolevel==2: # In a category dir
-                       for x in myfiles:
-                               xs=string.split(x,"/")
-                               if xs[0]==".":
-                                       xs=xs[1:]
-                               if xs[0] in mydone:
-                                       continue
-                               mydone.append(xs[0])
-                               repoman_settings["O"]="./"+xs[0]
-                               while(gpgsign(repoman_settings["O"]+"/Manifest")):
-                                       portage.writemsg("!!! YOU MUST sign the Manifest.\n")
-                                       portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'")
-                                       time.sleep(3)
-               elif repolevel==1: # repo-cvsroot
-                       print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n"
-                       for x in myfiles:
-                               xs=string.split(x,"/")
-                               if xs[0]==".":
-                                       xs=xs[1:]
-                               if string.join(xs[:2],"/") in mydone:
-                                       continue
-                               mydone.append(string.join(xs[:2],"/"))
-                               repoman_settings["O"]="./"+string.join(xs[:2],"/")
-                               while(gpgsign(repoman_settings["O"]+"/Manifest")):
-                                       portage.writemsg("!!! YOU MUST sign the Manifest.\n")
-                                       portage.writemsg("!!! You can also disable this for the time being by removing FEATURES='sign'")
-                                       time.sleep(3)
+                               if retval:
+                                       print "!!! Exiting on cvs (shell) error code:",retval
+                                       sys.exit(retval)
+               else:
+                       need_commit = True
 
+       signed = False
+       if "sign" in repoman_settings.features:
+               signed = True
+               try:
+                       if repolevel==3:   # In a package dir
+                               repoman_settings["O"] = "."
+                               gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+                       elif repolevel==2: # In a category dir
+                               mydone=[]
+                               for x in myfiles:
+                                       xs=string.split(x,"/")
+                                       if xs[0]==".":
+                                               xs=xs[1:]
+                                       if xs[0] in mydone:
+                                               continue
+                                       mydone.append(xs[0])
+                                       repoman_settings["O"] = os.path.join(".", xs[0])
+                                       gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+                       elif repolevel==1: # repo-cvsroot
+                               print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n"
+                               mydone=[]
+                               for x in myfiles:
+                                       xs=string.split(x,"/")
+                                       if xs[0]==".":
+                                               xs=xs[1:]
+                                       if string.join(xs[:2],"/") in mydone:
+                                               continue
+                                       mydone.append(string.join(xs[:2],"/"))
+                                       repoman_settings["O"] = os.path.join(".", xs[0], xs[1])
+                                       gpgsign(os.path.join(repoman_settings["O"], "Manifest"))
+               except portage_exception.PortageException, e:
+                       portage.writemsg("!!! %s\n" % str(e))
+                       portage.writemsg("!!! Disabled FEATURES='sign'\n")
+                       signed = False
+
+       if need_commit or signed:
                if "--pretend" in myoptions:
                        if isCvs:
                                print "(cvs -q commit -F "+commitmessagefile+")"
@@ -1803,16 +1917,19 @@ else:
                else:
                        mymsg=open(commitmessagefile,"w")
                        mymsg.write(commitmessage)
-                       mymsg.write("\n (Signed Manifest commit)")
+                       if signed:
+                               mymsg.write("\n (Signed Manifest commit)")
+                       else:
+                               mymsg.write("\n (Unsigned Manifest commit)")
                        mymsg.close()
                        if isCvs:
                                retval=os.system("cvs -q commit -F "+commitmessagefile)
                        if isSvn:
                                retval=os.system("svn -q commit -F "+commitmessagefile)
                        if retval:
-                               print "!!! Exiting on vcs (shell) error code:",retval
+                               print "!!! Exiting on cvs (shell) error code:",retval
                                sys.exit(retval)
-       
+
        if unlinkfile:
                os.unlink(commitmessagefile)
        print