Merged from trunk 6108:6129
authorFabian Groffen <grobian@gentoo.org>
Fri, 2 Mar 2007 14:17:18 +0000 (14:17 -0000)
committerFabian Groffen <grobian@gentoo.org>
Fri, 2 Mar 2007 14:17:18 +0000 (14:17 -0000)
Use an alarm signal to implement a timeout when rsync is fetching the
server timestamp file, since rsync's --timeout option doesn't apply to
the initial connection attempt.

Make sure pids are appropriately removed from
portage.process.spawned_pids.

please be --quiet emerge. still need to hunt down one more newline
(Solar)

Add compatibility code to avoid the GNU specific --reference option of
chmod.  Thanks to Timothy Redaelli <drizzt@gentoo.org>.

For consistency, remove exit code 2 (protocol incompatibility) from the
other list of rsync exit codes.

Fix broken except statement syntax.

Fix the rest of the broken except statement syntax.

Fix broken rsync exitcode shift.

Remove unnecessary print statement reported by solar.

Even if there's no timestamp available locally, fetch the timestamp
anyway as an initial probe to verify that the server is responsive.
This protects us from hanging indefinitely on a connection attempt to an
unresponsive server which rsync's --timeout option does not prevent.

For bug #168646, remove --prune-empty-dirs from PORTAGE_RSYNC_OPTS since
it's only a small optimization and it's inconvenient to force
>=rsync-2.6.4 on server admins at this time.  If users desire, they can
still add it to PORTAGE_RSYNC_EXTRA_OPTS.

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

bin/etc-update
cnf/make.globals
pym/emerge/__init__.py
pym/portage/cache/fs_template.py

index e447a807f39d386e67326c45f92328364a3ac804..f3e2e101b729108b34590c94c3ad3a5380aa79da 100755 (executable)
@@ -386,7 +386,11 @@ Please select from the menu above (-1 to exit, losing this merge): "
                        my_input=$(read_int)
                        case ${my_input} in
                                1) echo "Replacing ${ofile} with ${mfile}"
-                                  chmod --reference=${ofile} ${mfile}
+                                  if [[ ${USERLAND} == GNU ]]; then
+                                      chmod --reference="${ofile}" "${mfile}"
+                                  else
+                                      chmod $(stat -f %Mp%Lp "${ofile}") "${mfile}"
+                                  fi
                                   mv ${mv_opts} ${mfile} ${ofile}
                                   rm ${rm_opts} ${file}
                                   return 255
@@ -438,7 +442,7 @@ trap die term
 
 eval $(@PORTAGE_BASE@/bin/portageq envvar -v CONFIG_PROTECT \
        CONFIG_PROTECT_MASK PORTAGE_CONFIGROOT PORTAGE_TMPDIR ROOT \
-       EPREFIX)
+       USERLAND EPREFIX)
 export PORTAGE_TMPDIR
 export EROOT=${ROOT%/}${EPREFIX}/
 
index b8aed34132eab8fbf485a04bc6c8941d1877e494..e88550de92de9d09a3663bf8a63cbb2fd8e12313 100644 (file)
@@ -54,7 +54,7 @@ PORTAGE_RSYNC_RETRIES="3"
 # Number of seconds rsync will wait before timing out.
 #RSYNC_TIMEOUT="180"
 
-PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --compress --force --whole-file --delete --delete-after --stats --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages --filter=H_**/files/digest-* --prune-empty-dirs"
+PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --compress --force --whole-file --delete --delete-after --stats --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages --filter=H_**/files/digest-*"
 
 # Minimal CONFIG_PROTECT
 CONFIG_PROTECT="/etc"
index 78350dfa98d3b867179890beca4000cb11c391a0..df930ea11180cdde6fe924d72de0263909e72b35 100644 (file)
@@ -3428,7 +3428,7 @@ def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files,
                                        # ok, now the last-merged package
                                        # is protected, and the rest are selected
                if global_unmerge and not numselected:
-                       print "\n>>> No outdated packages were found on your system.\n"
+                       portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n")
                        return 0
        
                if not numselected:
@@ -3535,7 +3535,6 @@ def show_unmerge_failure_message(pkg, ebuild, retval):
 
 def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
 
-       print
        if os.path.exists(EPREFIX+"/usr/bin/install-info"):
                regen_infodirs=[]
                for z in infodirs:
@@ -3549,9 +3548,9 @@ def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
                                                regen_infodirs.append(inforoot)
 
                if not regen_infodirs:
-                       print " "+green("*")+" GNU info directory index is up-to-date."
+                       portage.writemsg_stdout(" "+green("*")+" GNU info directory index is up-to-date.\n")
                else:
-                       print " "+green("*")+" Regenerating GNU info directory index..."
+                       portage.writemsg_stdout(" "+green("*")+" Regenerating GNU info directory index...\n")
 
                        icount=0
                        badcount=0
@@ -3801,7 +3800,6 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                                "--exclude=/local",       # Exclude local     from consideration
                                "--exclude=/packages",    # Exclude packages  from consideration
                                "--filter=H_**/files/digest-*", # Exclude manifest1 digests and delete on the receiving side
-                               "--prune-empty-dirs"      # Prune empty ${FILESDIR} when manifest1 digests are excluded
                        ])
 
                else:
@@ -3894,7 +3892,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                        try:
                                mytimestamp = time.mktime(time.strptime(content[0],
                                        "%a, %d %b %Y %H:%M:%S +0000"))
-                       except OverflowError, ValueError:
+                       except (OverflowError, ValueError):
                                pass
                del content
 
@@ -3985,28 +3983,61 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
 
                        exitcode = os.EX_OK
                        servertimestamp = 0
-                       if mytimestamp != 0:
+                       # Even if there's no timestamp available locally, fetch the
+                       # timestamp anyway as an initial probe to verify that the server is
+                       # responsive.  This protects us from hanging indefinitely on a
+                       # connection attempt to an unresponsive server which rsync's
+                       # --timeout option does not prevent.
+                       if True:
                                mycommand = rsynccommand.split()
                                mycommand.append(dosyncuri.rstrip("/") + \
                                        "/metadata/timestamp.chk")
                                mycommand.append(tmpservertimestampfile)
+                               content = None
+                               mypids = []
                                try:
-                                       exitcode = portage.process.spawn(
-                                               mycommand, env=settings.environ())
-                                       content = portage.grabfile(tmpservertimestampfile)
-                                       if content:
+                                       def timeout_handler(signum, frame):
+                                               raise portage.exception.PortageException("timed out")
+                                       signal.signal(signal.SIGALRM, timeout_handler)
+                                       # Timeout here in case the server is unresponsive.  The
+                                       # --timeout rsync option doesn't apply to the initial
+                                       # connection attempt.
+                                       signal.alarm(15)
+                                       try:
+                                               mypids.extend(portage.process.spawn(
+                                                       mycommand, env=settings.environ(), returnpid=True))
+                                               exitcode = os.waitpid(mypids[0], 0)[1]
+                                               content = portage.grabfile(tmpservertimestampfile)
+                                       finally:
+                                               signal.alarm(0)
                                                try:
-                                                       servertimestamp = time.mktime(time.strptime(
-                                                               content[0], "%a, %d %b %Y %H:%M:%S +0000"))
-                                               except OverflowError, ValueError:
+                                                       os.unlink(tmpservertimestampfile)
+                                               except OSError:
                                                        pass
-                                       del content
-                               finally:
+                               except portage.exception.PortageException, e:
+                                       # timed out
+                                       print e
+                                       del e
+                                       if mypids and os.waitpid(mypids[0], os.WNOHANG) == (0,0):
+                                               os.kill(mypids[0], signal.SIGTERM)
+                                               os.waitpid(mypids[0], 0)
+                                       # This is the same code rsync uses for timeout.
+                                       exitcode = 30
+                               else:
+                                       if exitcode != os.EX_OK:
+                                               if exitcode & 0xff:
+                                                       exitcode = (exitcode & 0xff) << 8
+                                               else:
+                                                       exitcode = exitcode >> 8
+                               if mypids:
+                                       portage.process.spawned_pids.remove(mypids[0])
+                               if content:
                                        try:
-                                               os.unlink(tmpservertimestampfile)
-                                       except OSError:
+                                               servertimestamp = time.mktime(time.strptime(
+                                                       content[0], "%a, %d %b %Y %H:%M:%S +0000"))
+                                       except (OverflowError, ValueError):
                                                pass
-                               del mycommand
+                               del mycommand, mypids, content
                        if exitcode == os.EX_OK:
                                if (servertimestamp != 0) and (servertimestamp == mytimestamp):
                                        emergelog(xterm_titles,
@@ -4036,7 +4067,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                                        mycommand = mycommand.split()
                                        exitcode = portage.process.spawn(mycommand,
                                                env=settings.environ())
-                                       if exitcode in [0,1,2,3,4,11,14,20,21]:
+                                       if exitcode in [0,1,3,4,11,14,20,21]:
                                                break
                        elif exitcode in [1,3,4,11,14,20,21]:
                                break
@@ -4044,7 +4075,7 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                                # Code 2 indicates protocol incompatibility, which is expected
                                # for servers with protocol < 29 that don't support
                                # --prune-empty-directories.  Retry for a server that supports
-                               # at least rsync protocol version 29 (>=rsync-2.6.7).
+                               # at least rsync protocol version 29 (>=rsync-2.6.4).
                                pass
 
                        retries=retries+1
@@ -4320,7 +4351,7 @@ def action_regen(settings, portdb):
                        for y in nodes:
                                try:
                                        del auxdb[y]
-                               except KeyError, CacheError:
+                               except (KeyError, CacheError):
                                        pass
        print "done!"
 
@@ -4953,7 +4984,7 @@ def action_build(settings, trees, mtimedb,
                if mtimedb.has_key("resume"):
                        del mtimedb["resume"]
                if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
-                       print ">>> Auto-cleaning packages..."
+                       portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
                        vartree = trees[settings["ROOT"]]["vartree"]
                        unmerge(settings, myopts, vartree, "clean", ["world"],
                                ldpath_mtimes, autoclean=1)
index 70a5fd349c64e48f05ad2c745a293ed5fb26d7a2..5e395f3527514b2c84692472b63e21f7a29de0b2 100644 (file)
@@ -39,7 +39,7 @@ class FsBased(template.database):
                        if mtime:
                                mtime=long(mtime)
                                os.utime(path, (mtime, mtime))
-               except OSError, IOError:
+               except (OSError, IOError):
                        return False
                return True