From: Fabian Groffen Date: Fri, 2 Mar 2007 14:17:18 +0000 (-0000) Subject: Merged from trunk 6108:6129 X-Git-Url: http://git.tremily.us/gitweb.cgi?a=commitdiff_plain;h=4e785260a71de07e2bfb4dfbc86a6a58f01c17df;p=portage.git Merged from trunk 6108:6129 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 . 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 --- diff --git a/bin/etc-update b/bin/etc-update index e447a807f..f3e2e101b 100755 --- a/bin/etc-update +++ b/bin/etc-update @@ -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}/ diff --git a/cnf/make.globals b/cnf/make.globals index b8aed3413..e88550de9 100644 --- a/cnf/make.globals +++ b/cnf/make.globals @@ -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" diff --git a/pym/emerge/__init__.py b/pym/emerge/__init__.py index 78350dfa9..df930ea11 100644 --- a/pym/emerge/__init__.py +++ b/pym/emerge/__init__.py @@ -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) diff --git a/pym/portage/cache/fs_template.py b/pym/portage/cache/fs_template.py index 70a5fd349..5e395f352 100644 --- a/pym/portage/cache/fs_template.py +++ b/pym/portage/cache/fs_template.py @@ -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