Merged from trunk -r12200:12248
authorFabian Groffen <grobian@gentoo.org>
Tue, 16 Dec 2008 18:29:15 +0000 (18:29 -0000)
committerFabian Groffen <grobian@gentoo.org>
Tue, 16 Dec 2008 18:29:15 +0000 (18:29 -0000)
   | 12201   | Make BinpkgFetcher synchronize the local timestamp of the    |
   | zmedico | downloaded file with the remote file, if the fetcher hasn't  |
   |         | done it automatically.                                       |

   | 12202   | Fix exit code to return non-zero when an error occurs.       |
   | zmedico | Thanks to Christoph Mende <angelos@g.o> for reporting.       |

   | 12204   | Remove stray part about 'link level dependency awareness' in |
   | zmedico | the 2.1.6 section and remove extraneous line 8. Thanks to    |
   |         | Arun Raghavan <ford_prefect@g.g> for reporting.              |

   | 12205   | Add --sync support for `git pull`, and also add a failsafe   |
   | zmedico | to prevent rsync from being called if $PORTDIR appears to be |
   |         | under revision control. Thanks to Daniel Robbins for the     |
   |         | initial patch.                                               |

   | 12206   | Don't warn about missing repo_name for $PORTDIR when it      |
   | zmedico | happens to be empty.                                         |

   | 12207   | Fix --getbinpkgonly behavior so that binaries from the       |
   | zmedico | remote server are preferred over local packages if they are  |
   |         | not identical. Thanks to Lance Albertson <ramereth@g.o> for  |
   |         | reporting.                                                   |

   | 12208   | Fix old-style binhost code binarytree.digestCheck() will use |
   | zmedico | local digests when a local package overrides a remote one.   |

   | 12209   | When using the old binhost protocol, comparison with the     |
   | zmedico | remote package isn't supported, so the local package is      |
   |         | always preferred even if --getbinpkgonly is enabled.         |
   |         | Simplify bintree.isremote() so it works the same way         |
   |         | regardless of which protocol is used.                        |

   | 12210   | Fix incorrect usage of trap (only remove on signal at a      |
   | zmedico | time).                                                       |

   | 12211   | Fix breakage in stale metadata logic inside                  |
   | zmedico | binarytree._poplulate().                                     |

   | 12212   | Fix --getbinpkg to behave as expected with --pretend and     |
   | zmedico | --fetchonly.                                                 |

   | 12213   | Fix --pretend logic in Binpkg some more.                     |
   | zmedico |                                                              |

   | 12214   | Add a new FEATURES=test-fail-continue value which causes     |
   | zmedico | ebuild execution to continue after the test phase has        |
   |         | failed. Thanks to Diego Pettenò <flameeyes@g.o> for the     |
   |         | suggestion.                                                  |

   | 12246   | Update comment about resume opts stored as dict starting     |
   | zmedico | with 2.1.6_rc1.                                              |

   | 12248   | Detect problems with arguments and return non-zero when      |
   | zmedico | appropriate.                                                 |

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

NEWS
bin/dosed
bin/etc-update
man/emerge.1
man/make.conf.5
pym/_emerge/__init__.py
pym/portage/__init__.py
pym/portage/dbapi/bintree.py

diff --git a/NEWS b/NEWS
index 2affc7f49052f3bdeaa53cf3256a4cb6188cbc3e..2e8942a377a9a2710e351510d7e2e44b1c500c51 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -5,7 +5,6 @@ portage-2.2
 
 * Add link level dependency awareness to emerge --depclean and --prune actions
   in order to protect against uninstallation of required libraries.
-  packages in the same way, and also drops any masked packages.
 * Add license visibility filtering (GLEP 23)
 * Add support for generic package sets (also see RELEASE-NOTES)
 
@@ -17,8 +16,6 @@ portage-2.1.6
   installed with portage.
 * Add PORTAGE_IONICE_COMMAND setting for make.conf which is called to adjust
   IO priority on portage and it's subprocesses.
-* Add link level dependency awareness to emerge --depclean and --prune actions
-  in order to protect against uninstallation of required libraries.
 * Add emerge --jobs and --load-average options which specify behavior
   for building packages in parallel or for generating metadata in parallel
   with emerge --regen.
index 951f581d7756d51284ae1e3ea6af0e1df8ebf5b0..e7686f97bf86087a1c44f2e63ddf5dd9c0b03586 100755 (executable)
--- a/bin/dosed
+++ b/bin/dosed
@@ -3,18 +3,34 @@
 # Distributed under the terms of the GNU General Public License v2
 # $Id$
 
+if [[ $# -lt 1 ]] ; then
+       echo "!!! ${0##*/}: at least one argument needed" >&2
+       exit 1
+fi
+
+ret=0
+file_found=0
 mysed="s:${ED}::g"
 
 for x in "$@" ; do
-       y="${ED}${x}"
+       y=$ED${x#/}
        if [ -e "${y}" ] ; then
                if [ -f "${y}" ] ; then
+                       file_found=1
                        sed -i -e "${mysed}" "${y}"
                else
-                       echo "${y} is not a regular file!"
-                       exit 1
+                       echo "${y} is not a regular file!" >&2
+                       false
                fi
+               ((ret+=$?))
        else
                mysed="${x}"
        fi
 done
+
+if [ $file_found = 0 ] ; then
+       echo "!!! ${0##*/}: $y does not exist" 1>&2
+       ((ret+=1))
+fi
+
+exit $ret
index 0a0f829c3f6c458e8a3b617eda280ea99cf1338a..4a8166b98dfed9e8fe6aad4756b3daa469866724 100755 (executable)
@@ -446,7 +446,8 @@ Please select from the menu above (-1 to exit, losing this merge): "
 }
 
 die() {
-       trap SIGTERM SIGINT
+       trap SIGTERM
+       trap SIGINT
 
        if [ "$2" -eq 0 ]; then
                echo "Exiting: ${1}"
index 391ec0395da9f702e061c2e753e89d2276233d31..50c525f722d8d84499c45c11c7f98d77ab51cf5b 100644 (file)
@@ -320,10 +320,8 @@ list.  This option implies \fB\-k\fR.  (Use \fB\-gK\fR for binary\-only
 merging.)
 .TP
 .BR "\-\-getbinpkgonly " (\fB\-G\fR)
-This option is identical to \fB\-g\fR, as above, except it will not use ANY 
-information from the local machine.  All binaries will be downloaded from the 
-remote server without consulting packages existing in the local packages 
-directory.
+This option is identical to \fB\-g\fR, as above, except binaries from the
+remote server are preferred over local packages if they are not identical.
 .TP
 .BR "\-\-ignore-default-opts"
 Causes \fIEMERGE_DEFAULT_OPTS\fR (see \fBmake.conf\fR(5)) to be ignored.
index 159217f546bca379f4f8070c8b145f453dd8d4ec..2f71dac1a369d28b2857f695f884a8de6f8aed09 100644 (file)
@@ -338,6 +338,12 @@ the package compiled properly.  See \fItest\fR in \fBebuild\fR(1)
 and \fIsrc_test()\fR in \fBebuild\fR(5). This feature implies the "test"
 \fBUSE\fR flag.
 .TP
+.B test\-fail\-continue
+If "test" is enabled \fBFEATURES\fR and the test phase of an ebuild fails,
+continue to execute the remaining phases as if the failure had not occurred.
+Note that the test phase for a specific package may be disabled by masking
+the "test" \fBUSE\fR flag in \fBpackage.use.mask\fR (see \fBportage\fR(5)).
+.TP
 .B unmerge\-orphans
 If a file is not claimed by another package in the same slot and it is not
 protected by \fICONFIG_PROTECT\fR, unmerge it even if the modification time or
index ba82bbd9f297cc203c477d0413d1537ec693621f..815643d0a244a4847f5bf25eb30d9dcab0aa2aa8 100644 (file)
@@ -2954,6 +2954,10 @@ class EbuildProcess(SpawnProcess):
                        self.returncode = portage._doebuild_exit_status_check_and_log(
                                self.settings, self.phase, self.returncode)
 
+               if self.phase == "test" and self.returncode != os.EX_OK and \
+                       "test-fail-continue" in self.settings.features:
+                       self.returncode = os.EX_OK
+
                portage._post_phase_userpriv_perms(self.settings)
 
 class EbuildPhase(CompositeTask):
@@ -3211,7 +3215,7 @@ class Binpkg(CompositeTask):
 
                pkg = self.pkg
                pkg_count = self.pkg_count
-               if not self.opts.fetchonly:
+               if not (self.opts.pretend or self.opts.fetchonly):
                        self._build_dir.lock()
                        try:
                                shutil.rmtree(self._build_dir.dir_path)
@@ -3222,7 +3226,7 @@ class Binpkg(CompositeTask):
                        portage.prepare_build_dirs(self.settings["ROOT"], self.settings, 1)
                fetcher = BinpkgFetcher(background=self.background,
                        logfile=self.settings.get("PORTAGE_LOG_FILE"), pkg=self.pkg,
-                       scheduler=self.scheduler)
+                       pretend=self.opts.pretend, scheduler=self.scheduler)
                pkg_path = fetcher.pkg_path
                self._pkg_path = pkg_path
 
@@ -3249,6 +3253,12 @@ class Binpkg(CompositeTask):
                                self.wait()
                                return
 
+               if self.opts.pretend:
+                       self._current_task = None
+                       self.returncode = os.EX_OK
+                       self.wait()
+                       return
+
                verifier = None
                if self._verify:
                        logfile = None
@@ -3390,7 +3400,7 @@ class Binpkg(CompositeTask):
                self.wait()
 
        def _unlock_builddir(self):
-               if self.opts.fetchonly:
+               if self.opts.pretend or self.opts.fetchonly:
                        return
                portage.elog.elog_process(self.pkg.cpv, self.settings)
                self._build_dir.unlock()
@@ -3418,7 +3428,7 @@ class Binpkg(CompositeTask):
 
 class BinpkgFetcher(SpawnProcess):
 
-       __slots__ = ("pkg",
+       __slots__ = ("pkg", "pretend",
                "locked", "pkg_path", "_lock_obj")
 
        def __init__(self, **kwargs):
@@ -3432,11 +3442,24 @@ class BinpkgFetcher(SpawnProcess):
                        return
 
                pkg = self.pkg
+               pretend = self.pretend
                bintree = pkg.root_config.trees["bintree"]
                settings = bintree.settings
                use_locks = "distlocks" in settings.features
                pkg_path = self.pkg_path
-               resume = os.path.exists(pkg_path)
+
+               if not pretend:
+                       portage.util.ensure_dirs(os.path.dirname(pkg_path))
+                       if use_locks:
+                               self.lock()
+               exists = os.path.exists(pkg_path)
+               resume = exists and os.path.basename(pkg_path) in bintree.invalids
+               if not (pretend or resume):
+                       # Remove existing file or broken symlink.
+                       try:
+                               os.unlink(pkg_path)
+                       except OSError:
+                               pass
 
                # urljoin doesn't work correctly with
                # unrecognized protocols like sftp
@@ -3450,6 +3473,12 @@ class BinpkgFetcher(SpawnProcess):
                        uri = settings["PORTAGE_BINHOST"].rstrip("/") + \
                                "/" + pkg.pf + ".tbz2"
 
+               if pretend:
+                       portage.writemsg_stdout("\n%s\n" % uri, noiselevel=-1)
+                       self.returncode = os.EX_OK
+                       self.wait()
+                       return
+
                protocol = urlparse.urlparse(uri)[0]
                fcmd_prefix = "FETCHCOMMAND"
                if resume:
@@ -3468,10 +3497,6 @@ class BinpkgFetcher(SpawnProcess):
                fetch_args = [portage.util.varexpand(x, mydict=fcmd_vars) \
                        for x in shlex.split(fcmd)]
 
-               portage.util.ensure_dirs(os.path.dirname(pkg_path))
-               if use_locks:
-                       self.lock()
-
                if self.fd_pipes is None:
                        self.fd_pipes = {}
                fd_pipes = self.fd_pipes
@@ -3489,6 +3514,30 @@ class BinpkgFetcher(SpawnProcess):
 
        def _set_returncode(self, wait_retval):
                SpawnProcess._set_returncode(self, wait_retval)
+               if self.returncode == os.EX_OK:
+                       # If possible, update the mtime to match the remote package if
+                       # the fetcher didn't already do it automatically.
+                       bintree = self.pkg.root_config.trees["bintree"]
+                       if bintree._remote_has_index:
+                               remote_mtime = bintree._remotepkgs[self.pkg.cpv].get("MTIME")
+                               if remote_mtime is not None:
+                                       try:
+                                               remote_mtime = float(remote_mtime)
+                                       except ValueError:
+                                               pass
+                                       else:
+                                               try:
+                                                       local_mtime = os.stat(self.pkg_path).st_mtime
+                                               except OSError:
+                                                       pass
+                                               else:
+                                                       if remote_mtime != local_mtime:
+                                                               try:
+                                                                       os.utime(self.pkg_path,
+                                                                               (remote_mtime, remote_mtime))
+                                                               except OSError:
+                                                                       pass
+
                if self.locked:
                        self.unlock()
 
@@ -11754,14 +11803,41 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                        noiselevel=-1, level=logging.ERROR)
                return 1
 
+       vcs_dirs = frozenset([".git", ".svn", "CVS", ".hg"])
+       vcs_dirs = vcs_dirs.intersection(os.listdir(myportdir))
+
        os.umask(0022)
        updatecache_flg = False
        if myaction == "metadata":
                print "skipping sync"
                updatecache_flg = True
+       elif ".git" in vcs_dirs:
+               # Update existing git repository, and ignore the syncuri. We are
+               # going to trust the user and assume that the user is in the branch
+               # that he/she wants updated. We'll let the user manage branches with
+               # git directly.
+               msg = ">>> Starting git pull in %s..." % myportdir
+               emergelog(xterm_titles, msg )
+               writemsg_level(msg + "\n")
+               exitcode = portage.spawn("cd %s ; git pull" % \
+                       (portage._shell_quote(myportdir),), settings, free=1)
+               if exitcode != os.EX_OK:
+                       msg = "!!! git pull error in %s." % myportdir
+                       emergelog(xterm_titles, msg)
+                       writemsg_level(msg + "\n", level=logging.ERROR, noiselevel=-1)
+                       return exitcode
+               msg = ">>> Git pull in %s successful" % myportdir
+               emergelog(xterm_titles, msg)
+               writemsg_level(msg + "\n")
+               return exitcode
        elif syncuri[:8]=="rsync://":
+               for vcs_dir in vcs_dirs:
+                       writemsg_level(("!!! %s appears to be under revision " + \
+                               "control (contains %s).\n!!! Aborting rsync sync.\n") % \
+                               (myportdir, vcs_dir), level=logging.ERROR, noiselevel=-1)
+                       return 1
                if not os.path.exists(EPREFIX+"/usr/bin/rsync"):
-                       print "!!! rsync does not exist, so rsync support is disabled."
+                       print "!!! /usr/bin/rsync does not exist, so rsync support is disabled."
                        print "!!! Type \"emerge net-misc/rsync\" to enable rsync support."
                        sys.exit(1)
                mytimeout=180
@@ -13639,7 +13715,7 @@ def action_build(settings, trees, mtimedb,
                                del mtimedb["resume"]
                                mtimedb.commit()
                        mtimedb["resume"]={}
-                       # Stored as a dict starting with portage-2.2_rc7, and supported
+                       # Stored as a dict starting with portage-2.1.6_rc1, and supported
                        # by >=portage-2.1.3_rc8. Versions <portage-2.1.3_rc8 only support
                        # a list type for options.
                        mtimedb["resume"]["myopts"] = myopts.copy()
@@ -14222,6 +14298,12 @@ def repo_name_check(trees):
                        repos = portdb.getRepositories()
                        for r in repos:
                                missing_repo_names.discard(portdb.getRepositoryPath(r))
+                       if portdb.porttree_root in missing_repo_names and \
+                               not os.path.exists(os.path.join(
+                               portdb.porttree_root, "profiles")):
+                               # This is normal if $PORTDIR happens to be empty,
+                               # so don't warn about it.
+                               missing_repo_names.remove(portdb.porttree_root)
 
        if missing_repo_names:
                msg = []
index 00203cd5280fb3b7bb0b16b70cf105abfc8bf7ba..a796ecab45f6b47bffdb4592c44f7e823732fa60 100644 (file)
@@ -4523,6 +4523,11 @@ def spawnebuild(mydo, actionmap, mysettings, debug, alwaysdep=0,
                _check_build_log(mysettings)
                if phase_retval == os.EX_OK:
                        phase_retval = _post_src_install_checks(mysettings)
+
+       if mydo == "test" and phase_retval != os.EX_OK and \
+               "test-fail-continue" in mysettings.features:
+               phase_retval = os.EX_OK
+
        return phase_retval
 
 _post_phase_cmds = {
index 5a695161974e9c32efdf3b81bb50857d2a180d79..51012fb3eae657f77abc869f624d3a58335293f5 100644 (file)
@@ -414,7 +414,7 @@ class binarytree(object):
                if (not os.path.isdir(self.pkgdir) and not getbinpkgs):
                        return 0
 
-               if not getbinpkgsonly:
+               if True:
                        pkg_paths = {}
                        self._pkg_paths = pkg_paths
                        dirs = listdir(self.pkgdir, dirsonly=True, EmptyOnError=True)
@@ -605,13 +605,14 @@ class binarytree(object):
                                                        aux_cache[k] = d[k]
                                                self.dbapi._aux_cache[mycpv] = aux_cache
 
+                       for cpv in list(metadata):
+                               if cpv not in pkg_paths:
+                                       del metadata[cpv]
+
                        # Do not bother to write the Packages index if $PKGDIR/All/ exists
                        # since it will provide no benefit due to the need to read CATEGORY
                        # from xpak.
                        if update_pkgindex and os.access(self.pkgdir, os.W_OK):
-                               stale = [cpv for cpv in metadata if cpv not in self._pkg_paths]
-                               for cpv in stale:
-                                       del metadata[cpv]
                                del pkgindex.packages[:]
                                pkgindex.packages.extend(metadata.itervalues())
                                self._update_pkgindex_header(pkgindex.header)
@@ -699,6 +700,32 @@ class binarytree(object):
                                for cpv in self._remotepkgs:
                                        self.dbapi.cpv_inject(cpv)
                                self.populated = 1
+                               if getbinpkgsonly:
+                                       # Remote package instances override local package
+                                       # if they are not identical.
+                                       hash_names = ["SIZE"] + self._pkgindex_hashes
+                                       for cpv, local_metadata in metadata.iteritems():
+                                               remote_metadata = self._remotepkgs.get(cpv)
+                                               if remote_metadata is None:
+                                                       continue
+                                               # Use digests to compare identity.
+                                               identical = True
+                                               for hash_name in hash_names:
+                                                       local_value = local_metadata.get(hash_name)
+                                                       if local_value is None:
+                                                               continue
+                                                       remote_value = remote_metadata.get(hash_name)
+                                                       if remote_value is None:
+                                                               continue
+                                                       if local_value != remote_value:
+                                                               identical = False
+                                                               break
+                                               if identical:
+                                                       del self._remotepkgs[cpv]
+                               else:
+                                       # Local package instances override remote instances.
+                                       for cpv in metadata:
+                                               self._remotepkgs.pop(cpv, None)
                                return
                        self._remotepkgs = {}
                        try:
@@ -724,6 +751,13 @@ class binarytree(object):
                                        continue
                                mycat = self.remotepkgs[mypkg]["CATEGORY"].strip()
                                fullpkg = mycat+"/"+mypkg[:-5]
+
+                               if fullpkg in metadata:
+                                       # When using this old protocol, comparison with the remote
+                                       # package isn't supported, so the local package is always
+                                       # preferred even if getbinpkgsonly is enabled.
+                                       continue
+
                                if not self.dbapi._category_re.match(mycat):
                                        writemsg(("!!! Remote binary package has an " + \
                                                "unrecognized category: '%s'\n") % fullpkg,
@@ -738,10 +772,10 @@ class binarytree(object):
                                        # invalid tbz2's can hurt things.
                                        #print "cpv_inject("+str(fullpkg)+")"
                                        self.dbapi.cpv_inject(fullpkg)
-                                       metadata = self.remotepkgs[mypkg]
-                                       for k, v in metadata.items():
-                                               metadata[k] = v.strip()
-                                       self._remotepkgs[fullpkg] = metadata
+                                       remote_metadata = self.remotepkgs[mypkg]
+                                       for k, v in remote_metadata.items():
+                                               remote_metadata[k] = v.strip()
+                                       self._remotepkgs[fullpkg] = remote_metadata
                                        #print "  -- Injected"
                                except SystemExit, e:
                                        raise
@@ -845,6 +879,11 @@ class binarytree(object):
                        if pkgindex_lock:
                                unlockfile(pkgindex_lock)
 
+               if self._remotepkgs is not None:
+                       # When a remote package is downloaded and injected,
+                       # update state so self.isremote() returns False.
+                       self._remotepkgs.pop(cpv, None)
+
        def _pkgindex_entry(self, cpv):
                """
                Performs checksums and evaluates USE flag conditionals.
@@ -985,10 +1024,8 @@ class binarytree(object):
                downloaded (or it is only partially downloaded)."""
                if self._remotepkgs is None or pkgname not in self._remotepkgs:
                        return False
-               pkg_path = self.getname(pkgname)
-               if os.path.exists(pkg_path) and \
-                       os.path.basename(pkg_path) not in self.invalids:
-                       return False
+               # Presence in self._remotepkgs implies that it's remote. When a
+               # package is downloaded, state is updated by self.inject().
                return True
 
        def get_use(self, pkgname):