Merged from trunk 8873:8896
authorFabian Groffen <grobian@gentoo.org>
Mon, 17 Dec 2007 18:02:15 +0000 (18:02 -0000)
committerFabian Groffen <grobian@gentoo.org>
Mon, 17 Dec 2007 18:02:15 +0000 (18:02 -0000)
   | 8874    | Do an EBUILD_EXIT_STATUS_FILE sanity check in spawnebuild()  |
   | zmedico | where it spawns misc-functions.sh after the install phase.   |

   | 8876    | Add some documentation for ebuild phases and pre/post phase  |
   | zmedico | hooks that can be defined via bashrc.                        |

   | 8877    | Add a "Quality Assurance" tag so that all chapters are       |
   | zmedico | consistently nested inside tags.                             |

   | 8878    | * When installing a binary package, export the file name of  |
   | zmedico | the package as PORTAGE_BINPKG_FILE in order to give bashrc   |
   |         | users an opportunity to do various things such as remove     |
   |         | binary packages after they're installed. * Add a note in     |
   |         | ebuild.sh explaining why hardcoded bash lists are needed for |
   |         | backward compatibility with <portage-2.1.4 since they assume |
   |         | that a newly installed version of ebuild.sh will work for    |
   |         | pkg_postinst, pkg_prerm, and pkg_postrm when portage is      |
   |         | upgrading itself.                                            |

   | 8882    | First import the main portage module without legacy globals  |
   | zmedico | since it is almost certain to succeed in that case. This     |
   |         | provides access to the portage.exception namespace which is  |
   |         | needed for later exception handling, like if                 |
   |         | portage.exception.PermissionDenied is raised when            |
   |         | constructing the legacy global config instance.              |

   | 8883    | * Raise PermissionDenied from getconfig() when appropriate.  |
   | zmedico | * When available, make getconfig() include an invalid token  |
   |         | in a ParseError message.                                     |

   | 8884    | Instead of calling sys.exit when a ParseError occurs in the  |
   | zmedico | config constructor, raise a ParseError and make emerge and   |
   |         | portageq handle the error. This way consumers of the portage |
   |         | api can handle the ParseError rather than have their         |
   |         | application exit. Thanks to lxnay for reporting.             |

   | 8887    | Bug #198398 - Make repoman bail out if support for RMD160    |
   | zmedico | hash creation appears to be missing.                         |

   | 8888    | Fix the check for bug #198398 so that it works even when     |
   | zmedico | running repoman from the root of the repo.                   |

   | 8889    | Bug #202036 - In case of blockers, bail out earlier so that  |
   | zmedico | later code can assume there are no blockers.                 |

   | 8891    | In filter_readonly_variables(), replace 'declare -r ' with   |
   | zmedico | 'declare ' instead of removing it completely.                |

   | 8892    | Bug #202068 - In order to filter unwanted variable           |
   | zmedico | assignments out of the bash environment, use a               |
   |         | filter-bash-environment.py script that behaves similar to    |
   |         | egrep -v except that it leaves bash here- documents intact.  |

   | 8893    | Use the sed -r option to enable extended regular expressions |
   | zmedico | so that commonly used characters like (, ), and + don't have |
   |         | to be escaped.                                               |

   | 8894    | Bug #201848 - Mask ebuilds that do not define SLOT.          |
   | zmedico |                                                              |

   | 8895    | Bug #201848 - Make the ebuild command reject ebuilds that do |
   | zmedico | not define SLOT.                                             |

   | 8896    | Bug #201771 - Make unpack() detect common errors such as     |
   | zmedico | absolute paths that start with ${DISTDIR} and die an         |
   |         | appropriate error message. Thanks to grobian for this patch. |

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

15 files changed:
bin/ebuild.sh
bin/emerge
bin/filter-bash-environment.py [new file with mode: 0755]
bin/portageq
bin/repoman
doc/config.docbook
doc/config/bashrc.docbook [new file with mode: 0644]
doc/package.docbook [new file with mode: 0644]
doc/package/ebuild.docbook [new file with mode: 0644]
doc/package/ebuild/phases.docbook [new file with mode: 0644]
doc/portage.docbook
doc/qa.docbook
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/util.py

index 6638740d6fa3326c2ddc7b7ec9c52d07a15b2659..ffd497192196cc8427aae5aa60e829544bb97289 100755 (executable)
@@ -314,15 +314,16 @@ unpack() {
                y=${x%.*}
                y=${y##*.}
 
-               myfail="${x} does not exist"
-               if [ "${x:0:2}" = "./" ] ; then
+               if [[ ${x} == "./"* ]] ; then
                        srcdir=""
+               elif [[ ${x} == ${DISTDIR%/}/* ]] ; then
+                       die "Arguments to unpack() cannot begin with \${DISTDIR}."
+               elif [[ ${x} == "/"* ]] ; then
+                       die "Arguments to unpack() cannot be absolute"
                else
                        srcdir="${DISTDIR}/"
                fi
-               [[ ${x} == ${DISTDIR}* ]] && \
-                       die "Arguments to unpack() should not begin with \${DISTDIR}."
-               [ ! -s "${srcdir}${x}" ] && die "$myfail"
+               [[ ! -s ${srcdir}${x} ]] && die "${x} does not exist"
 
                myfail="failure unpacking ${x}"
                case "${x##*.}" in
@@ -1376,12 +1377,17 @@ source_all_bashrcs() {
        [ ! -z "${OCXX}" ] && export CXX="${OCXX}"
 }
 
+# Hardcoded bash lists are needed for backward compatibility with
+# <portage-2.1.4 since they assume that a newly installed version
+# of ebuild.sh will work for pkg_postinst, pkg_prerm, and pkg_postrm
+# when portage is upgrading itself.
+
 READONLY_EBUILD_METADATA="DEPEND DESCRIPTION
        EAPI HOMEPAGE INHERITED IUSE KEYWORDS LICENSE
        PDEPEND PROVIDE RDEPEND RESTRICT SLOT SRC_URI"
 
 READONLY_PORTAGE_VARS="D EBUILD EBUILD_PHASE \
-       EBUILD_SH_ARGS EMERGE_FROM FILESDIR \
+       EBUILD_SH_ARGS EMERGE_FROM FILESDIR PORTAGE_BINPKG_FILE \
        PORTAGE_BIN_PATH PORTAGE_PYM_PATH PORTAGE_MUTABLE_FILTERED_VARS \
        PORTAGE_SAVED_READONLY_VARS PORTAGE_TMPDIR T WORKDIR ED"
 
@@ -1441,9 +1447,9 @@ filter_readonly_variables() {
        # listed in READONLY_EBUILD_METADATA, since having any readonly attributes
        # persisting in the saved environment can be inconvenient when it
        # eventually needs to be reloaded.
-       egrep -v -e "${var_grep}" | sed \
-               -e 's:^declare[[:space:]]\+-r[[:space:]]\+::' \
-               -e 's:^declare[[:space:]]\+-\([[:alnum:]]*\)r\([[:alnum:]]*\)[[:space:]]\+:declare -\1\2 :'
+       "${PORTAGE_BIN_PATH}"/filter-bash-environment.py "${var_grep}" | sed -r \
+               -e 's:^declare[[:space:]]+-r[[:space:]]+:declare :' \
+               -e 's:^declare[[:space:]]+-([[:alnum:]]*)r([[:alnum:]]*)[[:space:]]+:declare -\1\2 :'
 }
 
 # @FUNCTION: preprocess_ebuild_env
index b1c9e748ae673ddbc916f5aa450cee454badedfe..f97d7b5e36d31d65cc76f7448aefad94eb13d3a6 100755 (executable)
@@ -13,10 +13,13 @@ except ImportError:
 
 if __name__ == "__main__":
        import sys
-       from portage.exception import PermissionDenied
+       from portage.exception import ParseError, PermissionDenied
        try:
                retval = _emerge.emerge_main()
        except PermissionDenied, e:
                sys.stderr.write("Permission denied: '%s'\n" % str(e))
                sys.exit(e.errno)
+       except ParseError, e:
+               sys.stderr.write("%s\n" % str(e))
+               sys.exit(1)
        sys.exit(retval)
diff --git a/bin/filter-bash-environment.py b/bin/filter-bash-environment.py
new file mode 100755 (executable)
index 0000000..83b250b
--- /dev/null
@@ -0,0 +1,52 @@
+#!/usr/bin/env python
+# Copyright 1999-2007 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id$
+
+import os, re, sys
+
+egrep_compat_map = {
+       "[:alnum:]" : r'\w',
+       "[:space:]" : r'\s',
+}
+
+here_doc_re = re.compile(r'.*\s<<[-]?(\w+)$')
+
+def compile_egrep_pattern(s):
+       for k, v in egrep_compat_map.iteritems():
+               s = s.replace(k, v)
+       return re.compile(s)
+
+def filter_bash_environment(pattern, file_in, file_out):
+       here_doc_delim = None
+       for line in file_in:
+               if here_doc_delim is not None:
+                       if here_doc_delim.match(line):
+                               here_doc_delim = None
+                       file_out.write(line)
+                       continue
+               here_doc = here_doc_re.match(line)
+               if here_doc is not None:
+                       here_doc_delim = re.compile("^%s$" % here_doc.group(1))
+                       file_out.write(line)
+                       continue
+               if pattern.match(line) is None:
+                       file_out.write(line)
+
+if __name__ == "__main__":
+       description = "Filter out any lines that match a given PATTERN " + \
+               "while leaving bash here-documents intact. The PATTERN should " + \
+               "use python regular expression syntax but [:space:] and " + \
+               "[:alnum:] character classes will be automatically translated " + \
+               "for compatibility with egrep syntax."
+       usage = "usage: %s PATTERN" % os.path.basename(sys.argv[0])
+       from optparse import OptionParser
+       parser = OptionParser(description=description, usage=usage)
+       options, args = parser.parse_args(sys.argv[1:])
+       if len(args) != 1:
+               parser.error("Missing required PATTERN argument.")
+       file_in = sys.stdin
+       file_out = sys.stdout
+       filter_bash_environment(
+               compile_egrep_pattern(args[0]), file_in, file_out)
+       file_out.flush()
index 8a25afa3c242ee0331d68b0273a3f3d8b154e3c4..756b1b2fdc6922e018e0c2461c6f568135792b3a 100755 (executable)
@@ -434,10 +434,19 @@ def main():
                        sys.stderr.flush()
                        sys.exit(os.EX_USAGE)
                os.environ["ROOT"] = sys.argv[2]
+
+       # First import the main portage module without legacy globals since it
+       # is almost certain to succeed in that case. This provides access to
+       # the portage.exception namespace which is needed for later exception
+       # handling, like if portage.exception.PermissionDenied is raised when
+       # constructing the legacy global config instance.
+       os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
+       import portage
+       del os.environ["PORTAGE_LEGACY_GLOBALS"]
        try:
                global portage
                try:
-                       import portage
+                       reload(portage)
                except ImportError:
                        from os import path as osp
                        sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
@@ -450,6 +459,9 @@ def main():
        except portage.exception.PermissionDenied, e:
                sys.stderr.write("Permission denied: '%s'\n" % str(e))
                sys.exit(e.errno)
+       except portage.exception.ParseError, e:
+               sys.stderr.write("%s\n" % str(e))
+               sys.exit(1)
        except ValueError, e:
                if not e.args or \
                        not hasattr(e.args[0], "__len__") or \
index a95491362d94aca497edea77111e38643aaf97b5..885baeab3615dbb8e667b8aef28af6d255f3b869 100755 (executable)
@@ -824,6 +824,21 @@ if isCvs:
        mynew = cvstree.findnew(mycvstree, recursive=1, basedir="./")
        new_ebuilds.update(x for x in mynew if x.endswith(".ebuild"))
        del mycvstree, mynew
+       if "commit" == options.mode and \
+               "RMD160" not in portage.checksum.hashorigin_map:
+               from portage.util import grablines
+               repo_lines = grablines("./CVS/Repository")
+               if repo_lines and \
+                       "gentoo-x86" == repo_lines[0].strip().split(os.path.sep)[0]:
+                       msg = "Please install " \
+                       "pycrypto or enable python's ssl USE flag in order " \
+                       "to enable RMD160 hash support. See bug #198398 for " \
+                       "more information."
+                       prefix = red(" * ")
+                       from textwrap import wrap
+                       for line in wrap(msg, 70):
+                               print prefix + line
+                       sys.exit(1)
 
 dofail = 0
 arch_caches={}
index 39c560080c4e9f5950bd2c4a41912d37ed8fd2c5..88009dfc6f65c8a3c73906231ccbec3442e98e3a 100644 (file)
@@ -1,4 +1,5 @@
 <part id='config'>
 <title>Configuration</title>
+&config_bashrc;
 &config_set;
 </part>
diff --git a/doc/config/bashrc.docbook b/doc/config/bashrc.docbook
new file mode 100644 (file)
index 0000000..2f06262
--- /dev/null
@@ -0,0 +1,22 @@
+<chapter id='config-bashrc'>
+       <title>Bashrc Configuration</title>
+       <sect1 id='config-bashrc-locations'>
+               <title>bashrc locations</title>
+               <para>
+               If a bashrc file is located at <filename>/etc/portage/bashrc</filename>
+               then it will be sourced before an ebuild is executed.
+               </para>
+       </sect1>
+       <sect1 id='config-bashrc-ebuild-phase-hooks'>
+               <title>Ebuild Phase Hooks</title>
+               <para>
+               A phase hook function name begins with a pre_ or post_
+               prefix to indicate that it will be called before or after
+               one of the <link linkend='package-ebuild-phases'>ebuild phases</link>.
+               The prefix is followed by the name of the ebuild function that the hook
+               will be associated with. For example, a hook named pre_src_compile
+               will be called before src_compile, and a hook named post_src_compile
+               will be called after src_compile.
+               </para>
+       </sect1>
+</chapter>
diff --git a/doc/package.docbook b/doc/package.docbook
new file mode 100644 (file)
index 0000000..d37e6d5
--- /dev/null
@@ -0,0 +1,4 @@
+<part id='package'>
+<title>Package Formats</title>
+&package_ebuild;
+</part>
diff --git a/doc/package/ebuild.docbook b/doc/package/ebuild.docbook
new file mode 100644 (file)
index 0000000..5466f99
--- /dev/null
@@ -0,0 +1,4 @@
+<chapter id='package-ebuild'>
+<title>Ebuild</title>
+&package_ebuild_phases;
+</chapter>
diff --git a/doc/package/ebuild/phases.docbook b/doc/package/ebuild/phases.docbook
new file mode 100644 (file)
index 0000000..5c7f049
--- /dev/null
@@ -0,0 +1,43 @@
+<sect1 id='package-ebuild-phases'>
+       <title>Ebuild Phases</title>
+       <para>
+       Ebuild execution is divided into a series of phases. In order
+       to implement a phase, an ebuild defines a function to serve as
+       an entry point for execution of that phase.
+       This design is similar to the template method pattern that
+       is commonly used in object oriented programming languages. An ebuild
+       can inherit or override a template method from an eclass.
+       </para>
+       <para>
+       The function names for the ebuild phases, listed in order of execution:
+       <itemizedlist>
+       <listitem>
+               pkg_setup
+       </listitem>
+       <listitem>
+               src_unpack
+       </listitem>
+       <listitem>
+               src_compile
+       </listitem>
+       <listitem>
+               src_test
+       </listitem>
+       <listitem>
+               src_install
+       </listitem>
+       <listitem>
+               pkg_preinst
+       </listitem>
+       <listitem>
+               pkg_postinst
+       </listitem>
+       <listitem>
+               pkg_prerm
+       </listitem>
+       <listitem>
+               pkg_postrm
+       </listitem>
+       </itemizedlist>
+       </para>
+</sect1>
index ac1061310131bc0947a49347a2b6b9a27f51f9aa..5417bb73e7ee5cb22f18d58a835e352e247b6af0 100644 (file)
@@ -7,8 +7,12 @@
 
        <!ENTITY project "portage">
 
+       <!ENTITY package SYSTEM "package.docbook">
+       <!ENTITY package_ebuild SYSTEM "package/ebuild.docbook">
+       <!ENTITY package_ebuild_phases SYSTEM "package/ebuild/phases.docbook">
        <!ENTITY qa SYSTEM "qa.docbook">
        <!ENTITY config SYSTEM "config.docbook">
+       <!ENTITY config_bashrc SYSTEM "config/bashrc.docbook">
        <!ENTITY config_set SYSTEM "config/sets.docbook">
 ]>
 
@@ -30,6 +34,7 @@
 </bookinfo>
 
 &config;
+&package;
 &qa;
 
 </book>
index a8178d5b72842adfcb41f9f1d5da161363526432..cb9b242d647bf1f6420f0f800e5bbf0db97bcd97 100644 (file)
@@ -1,3 +1,5 @@
+<part id='qa'>
+<title>Quality Assurance</title>
 <chapter id='qa-notices'>
  <title>QA Notices</title>
  <para>
   </para>
  </sect1>
 </chapter>
+</part>
index 57b5f429b565631473e5b2ec85d5609c98e34aba..87514ab5157cbce5a09d4be734b56ee0c120047e 100644 (file)
@@ -869,6 +869,8 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False):
        @rtype: Boolean
        @returns: True if the package is visible, False otherwise.
        """
+       if not metadata["SLOT"]:
+               return False
        if built and not installed and \
                metadata["CHOST"] != pkgsettings["CHOST"]:
                return False
@@ -2216,6 +2218,8 @@ class depgraph(object):
                                                mreasons.append("EPREFIX: '%s' too small" % metadata["EPREFIX"])
                                missing_licenses = []
                                if metadata:
+                                       if not metadata["SLOT"]:
+                                               mreasons.append("invalid: SLOT is undefined")
                                        if not portage.eapi_is_supported(metadata["EAPI"]):
                                                have_eapi_mask = True
                                        try:
@@ -4124,19 +4128,6 @@ class MergeTask(object):
                ldpath_mtimes = mtimedb["ldpath"]
                xterm_titles = "notitles" not in self.settings.features
 
-               #check for blocking dependencies
-               if "--fetchonly" not in self.myopts and \
-                       "--fetch-all-uri" 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."
-                                       if "--quiet" not in self.myopts:
-                                               show_blocker_docs_link()
-                                       return 1
-
                if "--resume" in self.myopts:
                        # We're resuming.
                        print colorize("GOOD", "*** Resuming merge...")
@@ -6609,13 +6600,27 @@ def action_build(settings, trees, mtimedb,
                                                        ("--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():
-                                       if pkg[0] != "blocks":
-                                               pkglist.append(pkg)
+
+                       pkglist = mydepgraph.altlist()
+
+                       if fetchonly or "--buildpkgonly"  in myopts:
+                               pkglist = [pkg for pkg in pkglist if pkg[0] != "blocks"]
                        else:
-                               pkglist = mydepgraph.altlist()
+                               for x in pkglist:
+                                       if x[0] != "blocks":
+                                               continue
+                                       msg = "Error: the " + x[2] + " package conflicts " + \
+                                       "with another package; the two packages cannot " + \
+                                       "be installed on the same system together. " + \
+                                       "Please use 'emerge --pretend' to determine blockers."
+                                       prefix = red(" * ")
+                                       from textwrap import wrap
+                                       for line in wrap(msg, 70):
+                                               print prefix + line
+                                       if "--quiet" not in myopts:
+                                               show_blocker_docs_link()
+                                       return 1
+
                        mydepgraph.saveNomergeFavorites()
                        del mydepgraph
                        mergetask = MergeTask(settings, trees, myopts)
@@ -7263,7 +7268,3 @@ def emerge_main():
                if "--pretend" in myopts:
                        display_news_notification(trees)
                return retval
-
-if __name__ == "__main__":
-       retval = emerge_main()
-       sys.exit(retval)
index baf7403cbc0ec6ecdc0f4121fc2675fa0e61d418..9c776f1a0bce8289bd64241e13edd1c8a7734da7 100644 (file)
@@ -880,7 +880,9 @@ class config(object):
                "FEATURES", "FILESDIR", "HOME", "PATH",
                "PKGUSE", "PKG_LOGDIR", "PKG_TMPDIR",
                "PORTAGE_ACTUAL_DISTDIR", "PORTAGE_ARCHLIST",
-               "PORTAGE_BASHRC", "PORTAGE_BINPKG_TMPFILE", "PORTAGE_BIN_PATH",
+               "PORTAGE_BASHRC",
+               "PORTAGE_BINPKG_FILE", "PORTAGE_BINPKG_TMPFILE",
+               "PORTAGE_BIN_PATH",
                "PORTAGE_BUILDDIR", "PORTAGE_COLORMAP",
                "PORTAGE_CONFIGROOT", "PORTAGE_DEBUG", "PORTAGE_DEPCACHEDIR",
                "PORTAGE_GID", "PORTAGE_INST_GID", "PORTAGE_INST_UID",
@@ -1222,74 +1224,36 @@ class config(object):
 
                        # make.globals should not be relative to config_root
                        # because it only contains constants.
-                       try:
-                               self.mygcfg   = getconfig(os.path.join(BPREFIX, "etc", "make.globals"))
+                       self.mygcfg   = getconfig(os.path.join(BPREFIX, "etc", "make.globals"))
+
+                       if self.mygcfg is None:
+                               self.mygcfg = {}
 
-                               if self.mygcfg is None:
-                                       self.mygcfg = {}
-                       except SystemExit, e:
-                               raise
-                       except Exception, e:
-                               if debug:
-                                       raise
-                               writemsg("!!! %s\n" % (e), noiselevel=-1)
-                               if not isinstance(e, EnvironmentError):
-                                       writemsg("!!! Incorrect multiline literals can cause " + \
-                                               "this. Do not use them.\n", noiselevel=-1)
-                               sys.exit(1)
                        self.configlist.append(self.mygcfg)
                        self.configdict["globals"]=self.configlist[-1]
 
                        self.make_defaults_use = []
                        self.mygcfg = {}
                        if self.profiles:
-                               try:
-                                       mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults")) for x in self.profiles]
-                                       for cfg in mygcfg_dlists:
-                                               if cfg:
-                                                       self.make_defaults_use.append(cfg.get("USE", ""))
-                                               else:
-                                                       self.make_defaults_use.append("")
-                                       self.mygcfg   = stack_dicts(mygcfg_dlists, incrementals=portage.const.INCREMENTALS, ignore_none=1)
-                                       #self.mygcfg = grab_stacked("make.defaults", self.profiles, getconfig)
-                                       if self.mygcfg is None:
-                                               self.mygcfg = {}
-                               except SystemExit, e:
-                                       raise
-                               except Exception, e:
-                                       if debug:
-                                               raise
-                                       writemsg("!!! %s\n" % (e), noiselevel=-1)
-                                       if not isinstance(e, EnvironmentError):
-                                               writemsg("!!! 'rm -Rf %s/usr/portage/profiles; " + \
-                                                       "emerge sync' may fix this. If it does\n" % EPREFIX,
-                                                       noiselevel=-1)
-                                               writemsg("!!! not then please report this to " + \
-                                                       "bugs.gentoo.org and, if possible, a dev\n",
-                                                               noiselevel=-1)
-                                               writemsg("!!! on #gentoo (irc.freenode.org)\n",
-                                                       noiselevel=-1)
-                                       sys.exit(1)
-                       self.configlist.append(self.mygcfg)
-                       self.configdict["defaults"]=self.configlist[-1]
-
-                       try:
-                               self.mygcfg = getconfig(
-                                       os.path.join(config_root, MAKE_CONF_FILE.lstrip(os.path.sep)),
-                                       allow_sourcing=True)
+                               mygcfg_dlists = [getconfig(os.path.join(x, "make.defaults")) \
+                                       for x in self.profiles]
+                               for cfg in mygcfg_dlists:
+                                       if cfg:
+                                               self.make_defaults_use.append(cfg.get("USE", ""))
+                                       else:
+                                               self.make_defaults_use.append("")
+                               self.mygcfg = stack_dicts(mygcfg_dlists,
+                                       incrementals=portage.const.INCREMENTALS, ignore_none=1)
                                if self.mygcfg is None:
                                        self.mygcfg = {}
-                       except SystemExit, e:
-                               raise
-                       except Exception, e:
-                               if debug:
-                                       raise
-                               writemsg("!!! %s\n" % (e), noiselevel=-1)
-                               if not isinstance(e, EnvironmentError):
-                                       writemsg("!!! Incorrect multiline literals can cause " + \
-                                               "this. Do not use them.\n", noiselevel=-1)
-                               sys.exit(1)
+                       self.configlist.append(self.mygcfg)
+                       self.configdict["defaults"]=self.configlist[-1]
 
+                       self.mygcfg = getconfig(
+                               os.path.join(config_root, MAKE_CONF_FILE.lstrip(os.path.sep)),
+                               allow_sourcing=True)
+                       if self.mygcfg is None:
+                               self.mygcfg = {}
 
                        # Don't allow the user to override certain variables in make.conf
                        profile_only_variables = self.configdict["defaults"].get(
@@ -3754,6 +3718,8 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None):
                                os.path.basename(MISC_SH_BINARY))
                        mycommand = " ".join([_shell_quote(misc_sh_binary),
                                "install_qa_check", "install_symlink_html_docs"])
+                       _doebuild_exit_status_unlink(
+                               mysettings.get("EBUILD_EXIT_STATUS_FILE"))
                        filter_calling_env_state = mysettings._filter_calling_env
                        if os.path.exists(os.path.join(mysettings["T"], "environment")):
                                mysettings._filter_calling_env = True
@@ -3762,7 +3728,14 @@ def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None):
                                        logfile=logfile, **kwargs)
                        finally:
                                mysettings._filter_calling_env = filter_calling_env_state
-                       if qa_retval:
+                       msg = _doebuild_exit_status_check(mydo, mysettings)
+                       if msg:
+                               qa_retval = 1
+                               from textwrap import wrap
+                               from portage.elog.messages import eerror
+                               for l in wrap(msg, 72):
+                                       eerror(l, phase=mydo, key=mysettings.mycpv)
+                       if qa_retval != os.EX_OK:
                                writemsg("!!! install_qa_check failed; exiting.\n",
                                        noiselevel=-1)
                        return qa_retval
@@ -4414,7 +4387,8 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                mycpv = mysettings["CATEGORY"] + "/" + mysettings["PF"]
                dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
                misc_keys = ["LICENSE", "PROVIDE", "RESTRICT", "SRC_URI"]
-               all_keys = dep_keys + misc_keys
+               other_keys = ["SLOT"]
+               all_keys = dep_keys + misc_keys + other_keys
                metadata = dict(izip(all_keys, mydbapi.aux_get(mycpv, all_keys)))
                class FakeTree(object):
                        def __init__(self, mydb):
@@ -4442,6 +4416,10 @@ def doebuild(myebuild, mydo, myroot, mysettings, debug=0, listonly=0,
                                if mydo not in invalid_dep_exempt_phases:
                                        return 1
                        del k
+               if not metadata["SLOT"]:
+                       writemsg("SLOT is undefined\n", noiselevel=-1)
+                       if mydo not in invalid_dep_exempt_phases:
+                               return 1
                del mycpv, dep_keys, metadata, misc_keys, FakeTree, dep_check_trees
 
                if "PORTAGE_TMPDIR" not in mysettings or \
@@ -5865,6 +5843,10 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
                fp.write(str(portage.checksum.perform_md5(mytbz2))+"\n")
                fp.close()
 
+               # This gives bashrc users an opportunity to do various things
+               # such as remove binary packages after they're installed.
+               mysettings["PORTAGE_BINPKG_FILE"] = mytbz2
+               mysettings.backup_changes("PORTAGE_BINPKG_FILE")
                debug = mysettings.get("PORTAGE_DEBUG", "") == "1"
 
                # We want to install in "our" prefix, not the binary one
@@ -5913,6 +5895,7 @@ def pkgmerge(mytbz2, myroot, mysettings, mydbapi=None, vartree=None, prev_mtimes
                did_merge_phase = True
                return retval
        finally:
+               mysettings.pop("PORTAGE_BINPKG_FILE", None)
                if tbz2_lock:
                        portage.locks.unlockfile(tbz2_lock)
                if builddir_lock:
index 1f83cdbdfa268cb5ffc6ec939ece05b29995c9a1..9cf7fff7d7a63a821313bca20125a8ab37ba929d 100644 (file)
@@ -309,6 +309,8 @@ def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True):
        try:
                f=open(mycfg,'r')
        except IOError, e:
+               if e.errno == PermissionDenied.errno:
+                       raise PermissionDenied(mycfg)
                if e.errno != errno.ENOENT:
                        raise
                return None
@@ -339,9 +341,9 @@ def getconfig(mycfg, tolerant=0, allow_sourcing=False, expand=True):
                                #invalid token
                                #lex.error_leader(self.filename,lex.lineno)
                                if not tolerant:
-                                       writemsg("!!! Invalid token (not \"=\") "+str(equ)+"\n",
-                                               noiselevel=-1)
-                                       raise Exception("ParseError: Invalid token (not '='): "+str(mycfg)+": line "+str(lex.lineno))
+                                       raise Exception("ParseError: Invalid token " + \
+                                               "'%s' (not '='): %s: line %s" % \
+                                               (equ, mycfg, lex.lineno))
                                else:
                                        return mykeys
                        val=lex.get_token()