Merged from trunk 9300:9333
authorFabian Groffen <grobian@gentoo.org>
Sat, 23 Feb 2008 23:33:46 +0000 (23:33 -0000)
committerFabian Groffen <grobian@gentoo.org>
Sat, 23 Feb 2008 23:33:46 +0000 (23:33 -0000)
   | 9301      | Bug #208708 - Show informative warning messages for        |
   | zmedico   | installed packages that are masked.                        |

   | 9307      | removing obsolete cruft                                    |
   | genone    |                                                            |

   | 9308      | new script for creating release tarballs                   |
   | genone    | (Deleted in Prefix as we have a working tarball.sh)        |

   | 9309      | minor documentation updates                                |
   | genone    |                                                            |

   | 9310      | more minor doc updates regarding package sets              |
   | genone    |                                                            |

   | 9311      | add preserve-libs info to make.conf.example                |
   | genone    |                                                            |

   | 9312      | add tagging capabilities and cli options                   |
   | genone    |                                                            |

   | 9313      | Bug #208743 - Update dosed docs to indicate that           |
   | zmedico   | "s:${D}::g" is used as the default expression if none      |
   |           | other is given.                                            |

   | 9316      | fix nasty typo                                             |
   | genone    | (Prefix already had most of this fix)                      |

   | 9318      | Fix get_mask_info() to properly pass the "installed"       |
   | zmedico   | attribute into the Package constructor.                    |

   | 9320      | Fix the exitcode logic for bug #209144 so that when the    |
   | zmedico   | server is out of date it's not interpreted like an actual  |
   |           | rsync exitcode (to avoid a misleading exitcode             |
   |           | interpretation message).                                   |

   | 9321      | Bug #209144 - For emerge --sync, show an informative error |
   | zmedico   | and don't return 1 when PORTAGE_RSYNC_RETRIES is exceeded. |

   | 9324      | Fix CHOST masking logic wrt installed packages so that     |
   | zmedico   | it's consistent between visible() and                      |
   |           | get_masking_status().                                      |

   | 9326      | Fix rejects.                                               |
   | zmedico   |                                                            |

   | 9327      | Remove the killparent() function and associated SIGINT     |
   | zmedico   | trap since this should already be handled on the python    |
   |           | side and it won't work with dropped privileges anyway.     |

   | 9328      | fix more trivial issues breaking repoman                   |
   | genone    |                                                            |

   | 9330      | Bug #209538 - Disable annoying "masked by keyword"         |
   | zmedico   | warnings for installed packages. We can assume that if the |
   |           | user accepted the keywords at merge time then they never   |
   |           | want to be bothered again.                                 |

   | 9332      | Add bits about namespace pollution, add whitespacing       |
   | WarnerBro | comments after looking at some new code I wrote and        |
   |           | realizing I was not following the current style. Fix typos |

   | 9333      | Bug #209768 - Fix --search "Size of files:" handling so    |
   | zmedico   | that it properly shows the "Unknown (missing digest)"      |
   |           | message instead of a traceback.                            |

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

16 files changed:
DEVELOPING
NEWS
RELEASE-NOTES
bin/ebuild.sh
bin/isolated-functions.sh
bin/repoman
cnf/make.conf
cnf/make.conf.sparc-fbsd.diff
cnf/make.conf.x86-fbsd.diff
make-man-tarball.sh [deleted file]
man/ebuild.5
man/emerge.1
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/repoman/utilities.py
tarball.sh

index 725f1ae1eabbe5d3e28f8f4268ce77bb1cbc9cd2..cd9f78f9460d95b5291c1ccfd20486ca41b125a7 100644 (file)
@@ -1,11 +1,39 @@
 Code Guidelines
 ---------------
-A few code guidelines to try to stick to, please comment of none of these make
+A few code guidelines to try to stick to, please comment if none of these make
 sense, they are pretty basic and mostly apply to old code.  However for people
 who are looking at current code, they make take up bad habits that exist in the
 current codebase.
 
-Strings
+Tabs
+----
+
+The current code uses tabs, not spaces.  Keep whitespace usage consistent
+between files.  New files should use tabs.
+
+Line-Wrapping
+-------------
+
+Lines should typically not be longer than 80 characters; if they are an attempt
+should be made to wrap them.  Move code to the line below and indent once (\t).
+
+errors.append(MalformedMetadata(
+       errors.DESCRIPTION_TOO_LONG_ERROR % \
+       (length, max_desc_len),
+       attr='DESCRIPTION.toolong')
+
+Do not do this:
+
+errors.append(MalformedMetadata(
+              errors.DESCRIPTION_TOO_LONG_ERROR % \
+              (length, max_desc_len),
+              attr='DESCRIPTION.toolong')
+
+The mixing of tabs and spaces means other developers can't read what you did.
+This is why the python peps state spaces over tabs; because with spaces the line
+wrapping is always clear (but you cannot convert spaces as easily as tabwidth).
+
+String
 -------
 Try not to use the functions in the string module, they are deprecated.
 
@@ -21,7 +49,7 @@ string.split(string, delimeter)
 
 should be replaced with:
 
-string.split(delimeter)
+"somestring".split(delimeter)
 
 Nearly all other methods in string work on string objects and have similar calling
 conventions.
@@ -102,3 +130,36 @@ NO:
   import portage.util
   import time
   import sys
+
+Try not to import large numbers of things into the namespace of a module.
+I realize this is done all over the place in current code but it really makes it
+a pain to do code reflection when the namespace is cluttered with identifiers 
+from other modules.
+
+YES:
+
+from portage import output
+
+NO:
+
+from portage.output import bold, create_color_func, darkgreen, \
+  green, nocolor, red, turquoise, yellow
+
+The YES example imports the 'output' module into the current namespace.
+The negative here is having to use output.COLOR all over the place instead of
+just COLOR.  However it means during introspection of the current namespace
+'green','red', 'yellow', etc. will not show up.
+
+The NO example just imports a set of functions from the output module.  It is
+somewhat annoying because the import line needs to be modified when functions
+are needed and often unused functions are left in the import line until someone
+comes along with a linter to clean up (does not happen often).  The color is a
+bit clearer as
+
+  print red('blar')
+
+is shorter than:
+
+  print output.red('blar')
+
+Rationale: python -c 'import portage; dir(portage)' (circa 02/2008)
diff --git a/NEWS b/NEWS
index 86c9d5489af8e9328593bcbe553e0bc36b2976ae..243ef7ecc0286a8bb53502f3ee94504dd0da3c91 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,7 +10,7 @@ portage-2.2
 * Fix -* handling in package.keywords to work as intended (reset the accepted 
   keywords list), also see RELEASE-NOTES.
 * Experimental support for preserving old library files on package upgrades
-  based on FEATURES=preserve-libs, USE AT YOUR OWN RISK!!!
+  based on FEATURES=preserve-libs
 * Make elog functionality available to python code
 * Add support for news items (GLEP 42)
 * Add support for generic package sets (also see RELEASE-NOTES)
index e68670f77323a766d5f28f4ad5c8448d44c7afc0..49f316f96f6cbda32f75d3f758085213dcdf9afd 100644 (file)
@@ -24,9 +24,13 @@ portage-2.2
     conditionals or any-of constructs aren't possible yet
   - emerge makes no difference atm wether you pass a setname or all atoms contained
     in the set to it, this means that without options packages will be remerged if 
-       already installed and added to the worldfile, or in the case of --unmerge all
-       atoms in a set will be unmerged even if they are depended upon by other 
-       packages
+       already installed, or in the case of --unmerge all atoms in a set will be 
+       unmerged even if they are depended upon by other packages. This may change in 
+       future versions.
+  - sets can be referenced either in other file-based sets or as argument to emerge, but
+    not in ebuilds, config files or other tools at this time.
+* "world" does no longer include "system" unconditionally, but you can add
+  "@system" to the worldfile to restore the old state.
 
 portage-2.1.4.1
 ==================================
index 1704103dec7a7cdfb397e199de4c4a0550b79516..60f5d760b34e62063a74f44dd4b10610ea4fb3df 100755 (executable)
@@ -1586,14 +1586,6 @@ if [ -n "${EBUILD_SH_ARGS}" ] && \
 #              source ${X} || die "Failed to source ${X}"
 #      done
 
-else
-
-killparent() {
-       trap INT
-       kill ${PORTAGE_MASTER_PID}
-}
-trap "killparent" INT
-
 fi # "$*"!="depend" && "$*"!="clean" && "$*" != "setup"
 
 export SANDBOX_ON="1"
index 93774dc54e7987b00a92a0d3718ebb1643ebcdf6..239524ce5718c31051f24373562f6954acc0e83e 100755 (executable)
@@ -467,7 +467,7 @@ save_ebuild_env() {
                        abort_test abort_install dyn_compile dyn_test dyn_install \
                        dyn_preinst dyn_help debug-print debug-print-function \
                        debug-print-section inherit EXPORT_FUNCTIONS newdepend newrdepend \
-                       newpdepend do_newdepend remove_path_entry killparent \
+                       newpdepend do_newdepend remove_path_entry \
                        save_ebuild_env filter_readonly_variables preprocess_ebuild_env \
                        source_all_bashrcs ebuild_phase ebuild_phase_with_hooks \
                        ${QA_INTERCEPTORS}
index 6ea9f9684802bfaa3d116ff9cfa3b7781c2f2b2f..ba8f27b312871cdbb1510657778d0df6f78bd424 100755 (executable)
@@ -1680,10 +1680,10 @@ else:
                try:
                        editor = os.environ.get("EDITOR")
                        if editor and utilities.editor_is_executable(editor):
-                               commitmessage = utilties.get_commit_message_with_editor(
+                               commitmessage = utilities.get_commit_message_with_editor(
                                        editor, message=qa_output)
                        else:
-                               commitmessage = utilties.get_commit_message_with_stdin()
+                               commitmessage = utilities.get_commit_message_with_stdin()
                except KeyboardInterrupt:
                        exithandler()
                if not commitmessage or not commitmessage.strip():
index 1077d28ea31a423306e2493bd0f0097efc4aa9d6..d1adefbd2baea5e6b454feddd90abb386481988b 100644 (file)
 #  'notitles'    disables xterm titlebar updates (which contain status info). 
 #  'parallel-fetch'
 #                do fetching in parallel to compilation
+#  'preserve-libs'
+#                keep libraries around that would normally removed by an upgrade, 
+#                but are still needed by other packages
 #  'sandbox'     enables sandboxing when running emerge and ebuild.
 #  'splitdebug'  Prior to stripping ELF etdyn and etexec files, the debugging
 #                info is stored for later use by various debuggers.  This
index d71178abbaca6e9a8473dfb3319fbbc253ea7db9..4ca3a50cdeb8b2458da18788ed7b8cb2d8690700 100644 (file)
  
  # Portage Directories
  # ===================
-@@ -279,7 +286,8 @@
- #  'notitles'    disables xterm titlebar updates (which contain status info). 
- #  'parallel-fetch'
- #                do fetching in parallel to compilation
+@@ -272,7 +286,8 @@
+ #  'preserve-libs'
+ #                keep libraries around that would normally removed by an upgrade, 
+ #                but are still needed by other packages
 -#  'sandbox'     enables sandboxing when running emerge and ebuild.
 +#  'sandbox'     enables sandboxing when running emerge and ebuild. Doesn't
 +#                work on *BSD-based systems.
index c2cf7cb71945c89ec6ca4574c37912da1fee2256..a71e5403291d71c40ee1c3a599ec6316402b0df4 100644 (file)
  
  # Portage Directories
  # ===================
-@@ -279,7 +313,8 @@
- #  'notitles'    disables xterm titlebar updates (which contain status info). 
- #  'parallel-fetch'
- #                do fetching in parallel to compilation
+@@ -272,7 +313,8 @@
+ #  'preserve-libs'
+ #                keep libraries around that would normally removed by an upgrade, 
+ #                but are still needed by other packages
 -#  'sandbox'     enables sandboxing when running emerge and ebuild.
 +#  'sandbox'     enables sandboxing when running emerge and ebuild. Doesn't 
 +#                work on *BSD-based systems.
diff --git a/make-man-tarball.sh b/make-man-tarball.sh
deleted file mode 100755 (executable)
index 0f1f3ed..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-#!/bin/bash
-
-if [ -z "$1" ] ; then
-       echo "Usage: $0 <version>"
-       exit 1
-fi
-
-find man -name '*.eclass.5' > man-page-list
-tar -jcf portage-manpages-${1}.tar.bz2 --files-from man-page-list
-echo "Packed away $(wc -l man-page-list | cut -f1 -d' ') manpages"
-rm -f man-page-list
-
-ls -l portage-manpages-${1}.tar.bz2
index 6f6403738ae3c63780e7149e05444c020c80ffea..44bbc45aa7a752507bf242ff514f39099bc0d82f 100644 (file)
@@ -727,7 +727,8 @@ multiple directories.
 .PD 1
 .TP
 \fBdosed\fR \fI"s:orig:change:g" <filename>\fR
-Performs sed in place on \fIfilename\fR inside ${D}.
+Performs sed in place on \fIfilename\fR inside ${D}. If no expression is
+given then \fI"s:${D}::g"\fR is used as the default expression.
 .br
 .BR 'dosed\ "s:/usr/local:/usr:g"\ /usr/bin/some\-script'
 runs sed on ${D}/usr/bin/some\-script
index bf664e0c541dd538f2404a732c7d6dfd2439e486..d019eb54abdbecc71b0fab0f0677a9ed10588605 100644 (file)
@@ -4,7 +4,7 @@ emerge \- Command\-line interface to the Portage system
 .SH "SYNOPSIS"
 .TP
 .BR emerge
-[\fIoptions\fR] [\fIaction\fR] [\fIebuild\fR | \fItbz2file\fR | \fIset\fR | \fIatom\fR] ...
+[\fIoptions\fR] [\fIaction\fR] [\fIebuild\fR | \fItbz2file\fR | \fI@set\fR | \fIatom\fR] ...
 .TP
 .BR emerge
 \fB\-\-sync\fR | \fB\-\-version\fR
@@ -52,13 +52,15 @@ A \fItbz2file\fR must be a valid .tbz2 created with \fBebuild
 .TP
 .BR set
 A \fIset\fR is a convenient shorthand for a large group of
-packages.  Two sets are currently supported: \fBsystem\fR
+packages.  Two sets are currently always available: \fBsystem\fR
 and \fBworld\fR.  \fBsystem\fR refers to a set of packages
-deemed necessary for your system to run properly.  \fBworld\fR
-contains all the packages in \fBsystem\fR, plus any
-other packages listed in \fB/var/lib/portage/world\fR.  [See
-\fBFILES\fR below for more information.]  Note that a \fIset\fR
-is generally used in conjunction with \fB\-\-update\fR.
+deemed necessary for your system to run properly. \fBworld\fR
+contains all the packages listed in \fB/var/lib/portage/world\fR.  [See
+\fBFILES\fR below for more information.] Other sets can exist depending
+on the current configuration. Note that a \fIset\fR
+is generally used in conjunction with \fB\-\-update\fR. When used as 
+arguments to \fBemerge\fR sets have to be prefixed with \fB@\fR to be
+recognized.
 .TP
 .BR atom
 An \fIatom\fR describes bounds on a package that you wish to install.  
index 4e5dbb93efc8811660f33424ed7fb9f4f3c0e7a8..f6c57ec2f528b0e27a365934c3aae38c635b94a0 100644 (file)
@@ -665,6 +665,7 @@ class search(object):
                                        myversion = self.getVersion(full_package, search.VERSION_RELEASE)
 
                                        mysum = [0,0]
+                                       file_size_str = None
                                        mycat = match.split("/")[0]
                                        mypkg = match.split("/")[1]
                                        mycpv = match + "-" + myversion
@@ -679,7 +680,7 @@ class search(object):
                                                try:
                                                        mysum[0] = mf.getDistfilesSize(fetchlist)
                                                except KeyError, e:
-                                                       mysum[0] = "Unknown (missing digest for %s)" % \
+                                                       file_size_str = "Unknown (missing digest for %s)" % \
                                                                str(e)
 
                                        available = False
@@ -695,13 +696,13 @@ class search(object):
                                                                        myebuild = None
                                                        break
 
-                                       if myebuild:
+                                       if myebuild and file_size_str is None:
                                                mystr = str(mysum[0] / 1024)
                                                mycount = len(mystr)
                                                while (mycount > 3):
                                                        mycount -= 3
                                                        mystr = mystr[:mycount] + "," + mystr[mycount:]
-                                               mysum[0] = mystr + " kB"
+                                               file_size_str = mystr + " kB"
 
                                        if self.verbose:
                                                if available:
@@ -709,7 +710,7 @@ class search(object):
                                                print "     ", self.getInstallationStatus(mycat+'/'+mypkg)
                                                if myebuild:
                                                        print "      %s %s" % \
-                                                               (darkgreen("Size of files:"), mysum[0])
+                                                               (darkgreen("Size of files:"), file_size_str)
                                                print "     ", darkgreen("Homepage:")+"     ",homepage
                                                print "     ", darkgreen("Description:")+"  ",desc
                                                print "     ", darkgreen("License:")+"      ",license
@@ -1043,7 +1044,7 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False):
                        return False
        if not portage.eapi_is_supported(metadata["EAPI"]):
                return False
-       if pkgsettings.getMissingKeywords(cpv, metadata):
+       if not installed and pkgsettings.getMissingKeywords(cpv, metadata):
                return False
        if pkgsettings.getMaskAtom(cpv, metadata):
                return False
@@ -1053,6 +1054,97 @@ def visible(pkgsettings, cpv, metadata, built=False, installed=False):
                return False
        return True
 
+def get_masking_status(pkg, pkgsettings, root_config):
+
+       mreasons = portage.getmaskingstatus(
+               pkg, settings=pkgsettings,
+               portdb=root_config.trees["porttree"].dbapi)
+
+       if pkg.built and not pkg.installed and \
+               pkg.metadata["CHOST"] != root_config.settings["CHOST"]:
+               mreasons.append("CHOST: %s" % \
+                       pkg.metadata["CHOST"])
+
+       if pkg.built and not pkg.installed:
+               if not "EPREFIX" in metadata or not metadata["EPREFIX"]:
+                       mreasons.append("missing EPREFIX")
+               elif len(metadata["EPREFIX"].strip()) < len(pkgsettings["EPREFIX"]):
+                       mreasons.append("EPREFIX: '%s' too small" % metadata["EPREFIX"])
+
+       if not pkg.metadata["SLOT"]:
+               mreasons.append("invalid: SLOT is undefined")
+
+       return mreasons
+
+def get_mask_info(root_config, cpv, pkgsettings,
+       db, pkg_type, built, installed, db_keys):
+       eapi_masked = False
+       try:
+               metadata = dict(izip(db_keys,
+                       db.aux_get(cpv, db_keys)))
+       except KeyError:
+               metadata = None
+       if metadata and not built:
+               pkgsettings.setcpv(cpv, mydb=metadata)
+               metadata["USE"] = pkgsettings.get("USE", "")
+       if metadata is None:
+               mreasons = ["corruption"]
+       else:
+               pkg = Package(type_name=pkg_type, root=root_config.root,
+                       cpv=cpv, built=built, installed=installed, metadata=metadata)
+               mreasons = get_masking_status(pkg, pkgsettings, root_config)
+       return metadata, mreasons
+
+def show_masked_packages(masked_packages):
+       shown_licenses = set()
+       shown_comments = set()
+       # Maybe there is both an ebuild and a binary. Only
+       # show one of them to avoid redundant appearance.
+       shown_cpvs = set()
+       have_eapi_mask = False
+       for (root_config, pkgsettings, cpv,
+               metadata, mreasons) in masked_packages:
+               if cpv in shown_cpvs:
+                       continue
+               shown_cpvs.add(cpv)
+               comment, filename = None, None
+               if "package.mask" in mreasons:
+                       comment, filename = \
+                               portage.getmaskingreason(
+                               cpv, metadata=metadata,
+                               settings=pkgsettings,
+                               portdb=root_config.trees["porttree"].dbapi,
+                               return_location=True)
+               missing_licenses = []
+               if metadata:
+                       if not portage.eapi_is_supported(metadata["EAPI"]):
+                               have_eapi_mask = True
+                       try:
+                               missing_licenses = \
+                                       pkgsettings.getMissingLicenses(
+                                               cpv, metadata)
+                       except portage.exception.InvalidDependString:
+                               # This will have already been reported
+                               # above via mreasons.
+                               pass
+
+               print "- "+cpv+" (masked by: "+", ".join(mreasons)+")"
+               if comment and comment not in shown_comments:
+                       print filename+":"
+                       print comment
+                       shown_comments.add(comment)
+               portdb = root_config.trees["porttree"].dbapi
+               for l in missing_licenses:
+                       l_path = portdb.findLicensePath(l)
+                       if l in shown_licenses:
+                               continue
+                       msg = ("A copy of the '%s' license" + \
+                       " is located at '%s'.") % (l, l_path)
+                       print msg
+                       print
+                       shown_licenses.add(l)
+       return have_eapi_mask
+
 def iter_atoms(deps):
        """Take a dependency structure as returned by paren_reduce or use_reduce
        and iterate over all the atoms."""
@@ -1415,6 +1507,7 @@ class depgraph(object):
                self._altlist_cache = {}
                self._pprovided_args = []
                self._missing_args = []
+               self._masked_installed = []
                self._dep_stack = []
                self._unsatisfied_deps = []
                self._ignored_deps = []
@@ -1610,15 +1703,18 @@ class depgraph(object):
                pkgsettings = self.pkgsettings[pkg.root]
 
                args = None
+               arg_atoms = None
                if True:
                        try:
-                               args = list(self._iter_args_for_pkg(pkg))
+                               arg_atoms = list(self._iter_atoms_for_pkg(pkg))
                        except portage.exception.InvalidDependString, e:
                                if not pkg.installed:
                                        show_invalid_depstring_notice(
                                                pkg, pkg.metadata["PROVIDE"], str(e))
                                        return 0
                                del e
+                       else:
+                               args = [arg for arg, atom in arg_atoms]
 
                if not pkg.onlydeps:
                        if not pkg.installed and \
@@ -1698,6 +1794,32 @@ class depgraph(object):
                                        del e
                                        return 0
 
+               if pkg.installed:
+                       # Warn if all matching ebuilds are masked or
+                       # the installed package itself is masked. Do
+                       # not warn if there are simply no matching
+                       # ebuilds since that would be annoying in some
+                       # cases:
+                       #
+                       #  - binary packages installed from an overlay
+                       #    that is not listed in PORTDIR_OVERLAY
+                       #
+                       #  - multi-slot atoms listed in the world file
+                       #    to prevent depclean from removing them
+
+                       if arg_atoms:
+                               portdb = self.trees[pkg.root]["porttree"].dbapi
+                               for arg, atom in arg_atoms:
+                                       all_ebuilds_masked = bool(
+                                               portdb.xmatch("match-all", atom) and
+                                               not portdb.xmatch("bestmatch-visible", atom))
+                                       if all_ebuilds_masked:
+                                               self._missing_args.append((arg, atom))
+
+                       if not visible(pkgsettings, pkg.cpv, pkg.metadata,
+                               built=pkg.built, installed=pkg.installed):
+                               self._masked_installed.append((pkg, pkgsettings))
+
                if args:
                        self._set_nodes.add(pkg)
 
@@ -1874,6 +1996,18 @@ class depgraph(object):
                                        continue
                                yield arg
 
+       def _iter_atoms_for_pkg(self, pkg):
+               # TODO: add multiple $ROOT support
+               if pkg.root != self.target_root:
+                       return
+               atom_arg_map = self._atom_arg_map
+               for atom in self._set_atoms.iterAtomsForPackage(pkg):
+                       for arg in atom_arg_map[(atom, pkg.root)]:
+                               if isinstance(arg, PackageArg) and \
+                                       arg.package != pkg:
+                                       continue
+                               yield arg, atom
+
        def _get_arg_for_pkg(self, pkg):
                """
                Return a matching DependencyArg instance for the given Package if
@@ -2110,33 +2244,9 @@ class depgraph(object):
                                                        return 0, myfavorites
                                                self._missing_args.append((arg, atom))
                                                continue
-                                       if pkg.installed:
-                                               # Warn if all matching ebuilds are masked or
-                                               # the installed package itself is masked. Do
-                                               # not warn if there are simply no matching
-                                               # ebuilds since that would be annoying in some
-                                               # cases:
-                                               #
-                                               #  - binary packages installed from an overlay
-                                               #    that is not listed in PORTDIR_OVERLAY
-                                               #
-                                               #  - multi-slot atoms listed in the world file
-                                               #    to prevent depclean from removing them
-
-                                               installed_masked = not visible(
-                                                       pkgsettings, pkg.cpv, pkg.metadata,
-                                                       built=pkg.built, installed=pkg.installed)
-
-                                               all_ebuilds_masked = bool(
-                                                       portdb.xmatch("match-all", atom) and
-                                                       not portdb.xmatch("bestmatch-visible", atom))
-
-                                               if installed_masked or all_ebuilds_masked:
-                                                       self._missing_args.append((arg, atom))
-
-                                               if "selective" not in self.myparams:
-                                                       self._show_unsatisfied_dep(myroot, atom)
-                                                       return 0, myfavorites
+                                       if pkg.installed and "selective" not in self.myparams:
+                                               self._show_unsatisfied_dep(myroot, atom)
+                                               return 0, myfavorites
 
                                        self._dep_stack.append(
                                                Dependency(atom=atom, root=myroot, parent=arg))
@@ -2360,9 +2470,9 @@ class depgraph(object):
                                red(' [%s]' % myparent[0]) + ')'
                masked_packages = []
                missing_licenses = []
-               from textwrap import wrap
                have_eapi_mask = False
                pkgsettings = self.pkgsettings[root]
+               root_config = self.roots[root]
                portdb = self.roots[root].trees["porttree"].dbapi
                dbs = self._filtered_trees[root]["dbs"]
                for db, pkg_type, built, installed, db_keys in dbs:
@@ -2374,81 +2484,15 @@ class depgraph(object):
                        # descending order
                        cpv_list.reverse()
                        for cpv in cpv_list:
-                               try:
-                                       metadata = dict(izip(db_keys,
-                                               db.aux_get(cpv, db_keys)))
-                               except KeyError:
-                                       mreasons = ["corruption"]
-                                       metadata = None
-                               if metadata and not built:
-                                       if "?" in metadata["LICENSE"]:
-                                               pkgsettings.setcpv(cpv, mydb=portdb)
-                                               metadata["USE"] = pkgsettings.get("USE", "")
-                                       else:
-                                               metadata["USE"] = ""
-                               mreasons = portage.getmaskingstatus(
-                                       cpv, metadata=metadata,
-                                       settings=pkgsettings, portdb=portdb)
-                               comment, filename = None, None
-                               if "package.mask" in mreasons:
-                                       comment, filename = \
-                                               portage.getmaskingreason(
-                                               cpv, metadata=metadata,
-                                               settings=pkgsettings, portdb=portdb,
-                                               return_location=True)
-                               if built and \
-                                       metadata["CHOST"] != pkgsettings["CHOST"]:
-                                       mreasons.append("CHOST: %s" % \
-                                               metadata["CHOST"])
-                               if built:
-                                       if not "EPREFIX" in metadata or not metadata["EPREFIX"]:
-                                               mreasons.append("missing EPREFIX")
-                                       elif len(metadata["EPREFIX"].strip()) < len(pkgsettings["EPREFIX"]):
-                                               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:
-                                               missing_licenses = \
-                                                       pkgsettings.getMissingLicenses(
-                                                               cpv, metadata)
-                                       except portage.exception.InvalidDependString:
-                                               # This will have already been reported
-                                               # above via mreasons.
-                                               pass
-                               if not mreasons:
-                                       continue
-                               masked_packages.append((cpv, mreasons,
-                                       comment, filename, missing_licenses))
+                               metadata, mreasons  = get_mask_info(root_config, cpv,
+                                       pkgsettings, db, pkg_type, built, installed, db_keys)
+                               masked_packages.append(
+                                       (root_config, pkgsettings, cpv, metadata, mreasons))
+
                if masked_packages:
                        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:"
-                       shown_licenses = set()
-                       shown_comments = set()
-                       # Maybe there is both an ebuild and a binary. Only
-                       # show one of them to avoid redundant appearance.
-                       shown_cpvs = set()
-                       for cpv, mreasons, comment, filename, missing_licenses in masked_packages:
-                               if cpv in shown_cpvs:
-                                       continue
-                               shown_cpvs.add(cpv)
-                               print "- "+cpv+" (masked by: "+", ".join(mreasons)+")"
-                               if comment and comment not in shown_comments:
-                                       print filename+":"
-                                       print comment
-                                       shown_comments.add(comment)
-                               for l in missing_licenses:
-                                       l_path = portdb.findLicensePath(l)
-                                       if l in shown_licenses:
-                                               continue
-                                       msg = ("A copy of the '%s' license" + \
-                                       " is located at '%s'.") % (l, l_path)
-                                       print msg
-                                       print
-                                       shown_licenses.add(l)
+                       have_eapi_mask = show_masked_packages(masked_packages)
                        if have_eapi_mask:
                                if portage.const.EAPIPREFIX:
                                        p = portage.const.EAPIPREFIX + " "
@@ -2459,6 +2503,7 @@ class depgraph(object):
                                        "EAPI '%s%s'. You must upgrade to a newer version" + \
                                        " of portage before EAPI masked packages can" + \
                                        " be installed.") % (p, portage.const.EAPI)
+                               from textwrap import wrap
                                for line in wrap(msg, 75):
                                        print line
                        print
@@ -3947,6 +3992,18 @@ class depgraph(object):
 
                # TODO: Add generic support for "set problem" handlers so that
                # the below warnings aren't special cases for world only.
+
+               masked_packages = []
+               for pkg, pkgsettings in self._masked_installed:
+                       root_config = self.roots[pkg.root]
+                       mreasons = get_masking_status(pkg, pkgsettings, root_config)
+                       masked_packages.append((root_config, pkgsettings,
+                               pkg.cpv, pkg.metadata, mreasons))
+               if masked_packages:
+                       sys.stderr.write("\n" + colorize("BAD", "!!!") + \
+                               " The following installed packages are masked:\n")
+                       show_masked_packages(masked_packages)
+
                if self._missing_args:
                        world_problems = False
                        if "world" in self._sets:
@@ -3961,6 +4018,7 @@ class depgraph(object):
                                sys.stderr.write("!!! Please run " + \
                                        green("emaint --check world")+"\n\n")
 
+               if self._missing_args:
                        sys.stderr.write("\n" + colorize("BAD", "!!!") + \
                                " Ebuilds for the following packages are either all\n")
                        sys.stderr.write(colorize("BAD", "!!!") + \
@@ -5556,6 +5614,8 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                        ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
                        family = socket.AF_INET6
                ips=[]
+               SERVER_OUT_OF_DATE = -1
+               EXCEEDED_MAX_RETRIES = -2
                while (1):
                        if ips:
                                del ips[0]
@@ -5697,7 +5757,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                                        print ">>> In order to force sync, remove '%s'." % servertimestampfile
                                        print ">>>"
                                        print
-                                       exitcode = 1
+                                       exitcode = SERVER_OUT_OF_DATE
                                elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
                                        # actual sync
                                        mycommand = rsynccommand + [dosyncuri+"/", myportdir]
@@ -5723,10 +5783,17 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                                # over retries
                                # exit loop
                                updatecache_flg=False
+                               exitcode = EXCEEDED_MAX_RETRIES
                                break
 
                if (exitcode==0):
                        emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri)
+               elif exitcode == SERVER_OUT_OF_DATE:
+                       sys.exit(1)
+               elif exitcode == EXCEEDED_MAX_RETRIES:
+                       sys.stderr.write(
+                               ">>> Exceeded PORTAGE_RSYNC_RETRIES: %s\n" % maxretries)
+                       sys.exit(1)
                elif (exitcode>0):
                        print
                        if exitcode==1:
index 584ae40ae1ade3293603c71424c7ada770648526..c92adedb219bd6dd481cfe00efd1972c0e9362ff 100644 (file)
@@ -5741,11 +5741,21 @@ def getmaskingreason(mycpv, metadata=None, settings=None, portdb=None, return_lo
        else:
                return None
 
-def getmaskingstatus(mycpv, metadata=None, settings=None, portdb=None):
+def getmaskingstatus(mycpv, settings=None, portdb=None):
        if settings is None:
                settings = config(clone=globals()["settings"])
        if portdb is None:
                portdb = globals()["portdb"]
+
+       metadata = None
+       installed = False
+       if not isinstance(mycpv, basestring):
+               # emerge passed in a Package instance
+               pkg = mycpv
+               mycpv = pkg.cpv
+               metadata = pkg.metadata
+               installed = pkg.installed
+
        mysplit = catpkgsplit(mycpv)
        if not mysplit:
                raise ValueError("invalid CPV: %s" % mycpv)
@@ -5835,7 +5845,9 @@ def getmaskingstatus(mycpv, metadata=None, settings=None, portdb=None):
                                kmask="~"+myarch
                                break
 
-       if kmask:
+       # Assume that the user doesn't want to be bothered about
+       # KEYWORDS of packages that are already installed.
+       if kmask and not installed:
                rValue.append(kmask+" keyword")
 
        try:
index d22afb299ca1265b79f9726c49e075547d514dca..4282f2a9aa50cc7ca709f0b8594b017dbb6fa762 100644 (file)
@@ -13,13 +13,14 @@ import os
 import sys
 
 from portage import output
+from portage.output import red, green
 from portage import exception
 from portage import util
 normalize_path = util.normalize_path
 util.initialize_logger()
 
 
-def detect_vcs_conflicts(vcs, options):
+def detect_vcs_conflicts(options, vcs):
        """Determine if the checkout has problems like cvs conflicts.
        
        If you want more vcs support here just keep adding if blocks...
index 114bc56eb4d0df2672a979624c104eef7e2378df..c87d5e33ede9c6fb1fa47eb12059bdb53711b90e 100755 (executable)
@@ -1,5 +1,5 @@
 #!/usr/bin/env bash
-# $Id: $
+# $Id$
 
 if [ -z "$1" ]; then
        echo