Index: ChangeLog
===================================================================
--- a/ChangeLog	(revision 15731)
+++ b/ChangeLog	(revision 15814)
@@ -1,3 +1,178 @@
+2010-03-10 00:31  zmedico
+
+	* [r15814] pym/_emerge/depgraph.py: Only try to merge portage asap
+	  when the new version is different. (trunk r15813)
+
+2010-03-09 21:27  zmedico
+
+	* [r15812] pym/_emerge/Scheduler.py, pym/_emerge/depgraph.py: Only
+	  create implicit libc deps when the version changes. (trunk
+	  r15810)
+
+2010-03-09 21:25  zmedico
+
+	* [r15811] pym/_emerge/Scheduler.py, pym/_emerge/depgraph.py:
+	  Disable implicit libc deps for ROOT != "/" since it's probably
+	  not needed. (trunk r15809)
+
+2010-03-09 20:21  zmedico
+
+	* [r15808] pym/_emerge/depgraph.py: Merge libc asap for all roots
+	  instead of just ROOT="/". (trunk r15804)
+
+2010-03-09 20:21  zmedico
+
+	* [r15807] pym/_emerge/sync/old_tree_timestamp.py: Add periods.
+	  (trunk r15803)
+
+2010-03-09 20:20  zmedico
+
+	* [r15806] pym/_emerge/sync/old_tree_timestamp.py: Use ewarn output
+	  style to add some color. (trunk r15802)
+
+2010-03-09 20:20  zmedico
+
+	* [r15805] man/portage.5: * Remove outdated profiles.desc sentence
+	  about "1 profile allowed per stable/dev/KEYWORD". Thanks to
+	  Torsten Veller <tove@g.o> for reporting.
+	  
+	  * Add 'exp' to valid profiles.desc status values, and update the
+	  example. (trunk r15795)
+
+2010-03-09 08:11  zmedico
+
+	* [r15794] pym/portage/mail.py: Import 'email' and 'smtlib' locally
+	  since python ebuilds remove the 'email' module when built with
+	  USE=build. (trunk r15793)
+
+2010-03-09 05:04  zmedico
+
+	* [r15792] pym/_emerge/Scheduler.py: Add --debug output for the
+	  scheduler digraph. (trunk r15790)
+
+2010-03-09 05:04  zmedico
+
+	* [r15791] pym/_emerge/Scheduler.py: If _implicit_libc_deps() finds
+	  both a new-style virtual and an old-style PROVIDE virtual, use
+	  the new-style virtual. (trunk r15789)
+
+2010-03-09 04:31  zmedico
+
+	* [r15788] pym/_emerge/actions.py: Add support for displaying
+	  profile listed in make.profile/parent when make.profile is not a
+	  symlink. The first parent with a path inside $PORTDIR is
+	  displayed. (trunk r15787)
+
+2010-03-09 03:59  zmedico
+
+	* [r15786] pym/_emerge/Scheduler.py: Fix typo in parenthesis from
+	  previous commit. (trunk r15784)
+
+2010-03-09 03:58  zmedico
+
+	* [r15785] pym/_emerge/Scheduler.py: Bug #303567 - Create implicit
+	  dependencies on libc, in order to ensure that libc is installed
+	  as early as possible. (trunk r15783)
+
+2010-03-09 02:42  zmedico
+
+	* [r15782] pym/portage/dbapi/vartree.py,
+	  pym/portage/proxy/lazyimport.py: When portage upgrades or
+	  downgrades itself, preload lazily referenced portage submodules
+	  into memory so that imports won't fail later. (trunk r15778)
+
+2010-03-09 02:42  zmedico
+
+	* [r15781] man/emerge.1, pym/_emerge/help.py: Move --update from
+	  the actions to the options section. (trunk r15777)
+
+2010-03-09 02:42  zmedico
+
+	* [r15780] man/emerge.1, pym/_emerge/help.py: Clean up/sync docs
+	  for emerge --sync, and add a note about PORTAGE_SYNC_STALE.
+	  (trunk r15776)
+
+2010-03-09 02:42  zmedico
+
+	* [r15779] man/emerge.1: Escape hyphens. (trunk r15775)
+
+2010-03-08 09:40  zmedico
+
+	* [r15772] pym/_emerge/sync/__init__.py: Add copyright header.
+	  (trunk r15771)
+
+2010-03-08 09:10  zmedico
+
+	* [r15770] pym/_emerge/actions.py: Disable PORTAGE_SYNC_STALE
+	  warnings when --usepkgonly is enabled. (trunk r15769)
+
+2010-03-08 09:05  zmedico
+
+	* [r15768] pym/portage/package/ebuild/config.py: Exclude
+	  PORTAGE_SYNC_STALE from the ebuild environment. (trunk r15767)
+
+2010-03-08 08:57  zmedico
+
+	* [r15766] pym/_emerge/depgraph.py: Bug #307409 - Force --verbose
+	  mode when displaying circular deps. (trunk r15765)
+
+2010-03-08 08:47  zmedico
+
+	* [r15764] pym/portage/mail.py: Bug #291331 - Force ascii encoding
+	  in send_mail() in order to avoid UnicodeEncodeError from
+	  smtplib.sendmail with python3. (trunk r15759)
+
+2010-03-08 08:47  zmedico
+
+	* [r15763] pym/_emerge/sync/old_tree_timestamp.py: Show --sync in
+	  messages, to help avoid confusion. (trunk r15758)
+
+2010-03-08 08:47  zmedico
+
+	* [r15762] man/make.conf.5: Note that PORTAGE_SYNC_STALE=0 will
+	  disable warnings. (trunk r15757)
+
+2010-03-08 08:47  zmedico
+
+	* [r15761] cnf/make.globals, man/make.conf.5,
+	  pym/_emerge/actions.py, pym/_emerge/sync: Produce a warning
+	  message if the timestamp of the portage tree is more than 30 days
+	  old, and make it adjustable via the PORTAGE_SYNC_STALE variable.
+	  Thanks to Ned Ludd <solar@g.o> for the most of this code. (trunk
+	  r15756)
+
+2010-03-08 08:46  zmedico
+
+	* [r15760] pym/portage/package/ebuild/doebuild.py: Bug #308415 -
+	  Fix broken uri parameter passed to fetch () for some cases when
+	  using ebuild(1). (trunk r15755)
+
+2010-03-04 11:23  zmedico
+
+	* [r15749] pym/portage/package/ebuild/getmaskingstatus.py: Bug
+	  #307723 - Define basestring for python3. (trunk r15745)
+
+2010-03-04 11:23  zmedico
+
+	* [r15748] pym/portage/package/ebuild/doebuild.py,
+	  pym/portage/package/ebuild/fetch.py: Fix imports
+	  doebuild_environment and prepare_build_dirs imports to import
+	  from the real location instead of importing proxies. (trunk
+	  r15744)
+
+2010-03-04 11:22  zmedico
+
+	* [r15747] pym/portage/package/ebuild/fetch.py: Bug #307707 - Fix
+	  fetch() to use the correct spawn function when calling nofetch.
+	  (trunk r15743)
+
+2010-03-04 11:22  zmedico
+
+	* [r15746] man/color.map.5, pym/_emerge/depgraph.py,
+	  pym/portage/output.py: Add new colors for binary packages in the
+	  merge list. Thanks to Sebastian Luther (few) for this patch.
+	  (trunk r15739)
+
 2010-03-03 06:27  zmedico
 
 	* [r15731] NEWS: Add news about splitting the top-level
Index: cnf/make.globals
===================================================================
--- a/cnf/make.globals	(revision 15731)
+++ b/cnf/make.globals	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1999-2006 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: make.globals 15254 2010-01-29 18:49:10Z zmedico $
+# $Id: make.globals 15761 2010-03-08 08:47:02Z zmedico $
 # System-wide defaults for the Portage system
 
 #            *****************************
@@ -80,6 +80,10 @@
 
 PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --compress --force --whole-file --delete --stats --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages"
 
+# The number of days after the last `emerge --sync` that a warning
+# message should be produced.
+PORTAGE_SYNC_STALE="30"
+
 # Minimal CONFIG_PROTECT
 CONFIG_PROTECT="/etc"
 CONFIG_PROTECT_MASK="/etc/env.d"
Index: man/color.map.5
===================================================================
--- a/man/color.map.5	(revision 15731)
+++ b/man/color.map.5	(revision 15814)
@@ -50,6 +50,15 @@
 \fBPKG_MERGE_WORLD\fR = \fI"green"\fR
 Defines color used for world packages planned to be merged.
 .TP
+\fBPKG_BINARY_MERGE\fR = \fI"darkgreen"\fR
+Defines color used for packages planned to be merged using a binary package.
+.TP
+\fBPKG_BINARY_MERGE_SYSTEM\fR = \fI"darkgreen"\fR
+Defines color used for system packages planned to be merged using a binary package.
+.TP
+\fBPKG_BINARY_MERGE_WORLD\fR = \fI"green"\fR
+Defines color used for world packages planned to be merged using a binary package.
+.TP
 \fBPKG_NOMERGE\fR = \fI"darkblue"\fR
 Defines color used for packages not planned to be merged.
 .TP
Index: man/emerge.1
===================================================================
--- a/man/emerge.1	(revision 15731)
+++ b/man/emerge.1	(revision 15814)
@@ -195,7 +195,7 @@
 name starts with "kde"; \fBemerge \-\-search "%gcc$"\fR searches for any 
 package that ends with "gcc"; \fBemerge \-\-search "office"\fR searches for 
 any package that contains the word "office".  If you want to include the 
-category into the search string, prepend an @: \fBemerge --search 
+category into the search string, prepend an @: \fBemerge \-\-search 
 "%@^dev-java.*jdk"\fR. If you want to search the package descriptions as well, 
 use the \fB\-\-searchdesc\fR action.
 .TP
@@ -205,11 +205,26 @@
 matched as regular expressions.
 .TP
 .BR \-\-sync
-Initiates a portage tree update with one of the rsync.gentoo.org
-mirrors.  \fBNote that any changes you have made to the portage
-tree will be erased\fR.  Except for special circumstances, 
-this uses \fBrsync\fR to do the update.  See \fBmake.conf\fR(5)'s 
-description of PORTDIR_OVERLAY for a method to avoid deletions.
+This updates the portage tree that is located in the
+directory that the PORTDIR variable refers to (default
+location is /usr/portage). The SYNC variable specifies
+the remote URI from which files will be synchronized.
+The \fBPORTAGE_SYNC_STALE\fR variable configures
+warnings that are shown when emerge \-\-sync has not
+been executed recently.
+
+\fBWARNING:\fR
+The emerge \-\-sync action will modify and/or delete
+files located inside the directory that the PORTDIR
+variable refers to (default location is /usr/portage).
+For more information, see the PORTDIR documentation in
+the make.conf(5) man page.
+
+\fBNOTE:\fR
+The \fBemerge\-webrsync\fR program will download the entire
+portage tree as a tarball, which is much faster than emerge
+\-\-sync for first time syncs.
+
 .TP
 .BR "\-\-unmerge " (\fB\-C\fR)
 \fBWARNING: This action can remove important packages!\fR Removes
@@ -219,13 +234,6 @@
 \fIebuilds\fR. For a dependency aware version of \fB\-\-unmerge\fR,
 use \fB\-\-depclean\fR or \fB\-\-prune\fR.
 .TP
-.BR "\-\-update " (\fB\-u\fR)
-Updates packages to the best version available, which may not always be the 
-highest version number due to masking for testing and development.
-Package atoms
-specified on the command line are greedy, meaning that unspecific atoms may
-match multiple installed versions of slotted packages.
-.TP
 .BR "\-\-version " (\fB\-V\fR)
 Displays the version number of \fBemerge\fR.
 .SH "OPTIONS"
@@ -536,6 +544,13 @@
 constraint is removed, hopefully leading to a more
 readable dependency tree.
 .TP
+.BR "\-\-update " (\fB\-u\fR)
+Updates packages to the best version available, which may
+not always be the  highest version number due to masking
+for testing and development. Package atoms specified on
+the command line are greedy, meaning that unspecific
+atoms may match multiple versions of slotted packages.
+.TP
 .BR "\-\-use\-ebuild\-visibility[=n]"
 Use unbuilt ebuild metadata for visibility
 checks on built packages.
Index: man/make.conf.5
===================================================================
--- a/man/make.conf.5	(revision 15731)
+++ b/man/make.conf.5	(revision 15814)
@@ -639,6 +639,12 @@
 .br
 Defaults to 3.
 .TP
+\fBPORTAGE_SYNC_STALE\fR = \fI[NUMBER]\fR
+Defines the number of days after the last `emerge \-\-sync` that a warning
+message should be produced. A value of 0 will disable warnings.
+.br
+Defaults to 30.
+.TP
 \fBPORTAGE_TMPDIR\fR = \fI[path]\fR
 Defines the location of the temporary build directories.
 .br
Index: man/portage.5
===================================================================
--- a/man/portage.5	(revision 15731)
+++ b/man/portage.5	(revision 15814)
@@ -751,23 +751,22 @@
 .TP
 .BR profiles.desc
 List all the current stable and development profiles.  If a profile is listed 
-here, then it will be checked by repoman.  At the moment, only 1 profile is 
-allowed per stable/dev/KEYWORD; the last one found is the last one used.
-
+here, then it will be checked by repoman.
 .I Format:
 .nf
 \- comments begin with # (no inline comments)
 \- one profile list per line in format: arch dir status
 \- arch must be listed in arch.list
 \- dir is relative to profiles.desc
-\- status must be 'stable' or 'dev'
+\- status must be 'stable', 'dev', or 'exp'
 .fi
 
 .I Example:
 .nf
-alpha default-linux/alpha/2004.3 stable
-m68k  default-linux/m68k         dev
-x86   default-linux/x86/2004.3   stable
+alpha        default/linux/alpha/10.0    stable
+m68k         default/linux/m68k/10.0     dev
+x86          default/linux/x86/10.0      stable
+x86-linux    prefix/linux/x86            exp
 .fi
 .TP
 .BR repo_name
Index: pym/_emerge/actions.py
===================================================================
--- a/pym/_emerge/actions.py	(revision 15731)
+++ b/pym/_emerge/actions.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1999-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: actions.py 15687 2010-03-02 21:07:53Z zmedico $
+# $Id: actions.py 15788 2010-03-09 04:31:13Z zmedico $
 
 from __future__ import print_function
 
@@ -53,6 +53,7 @@
 from _emerge.search import search
 from _emerge.SetArg import SetArg
 from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+from _emerge.sync.old_tree_timestamp import old_tree_timestamp_warn
 from _emerge.unmerge import unmerge
 from _emerge.UnmergeDepPriority import UnmergeDepPriority
 from _emerge.UseFlagDisplay import UseFlagDisplay
@@ -64,6 +65,9 @@
 def action_build(settings, trees, mtimedb,
 	myopts, myaction, myfiles, spinner):
 
+	if '--usepkgonly' not in myopts:
+		old_tree_timestamp_warn(settings['PORTDIR'], settings)
+
 	# validate the state of the resume data
 	# so that we can make assumptions later.
 	for k in ("resume", "resume_backup"):
@@ -2249,19 +2253,38 @@
 	writemsg_level("".join("%s\n" % l for l in msg),
 		level=logging.ERROR, noiselevel=-1)
 
+def relative_profile_path(portdir, abs_profile):
+	realpath = os.path.realpath(abs_profile)
+	basepath   = os.path.realpath(os.path.join(portdir, "profiles"))
+	if realpath.startswith(basepath):
+		profilever = realpath[1 + len(basepath):]
+	else:
+		profilever = None
+	return profilever
+
 def getportageversion(portdir, target_root, profile, chost, vardb):
-	profilever = "unavailable"
+	profilever = None
 	if profile:
-		realpath = os.path.realpath(profile)
-		basepath   = os.path.realpath(os.path.join(portdir, "profiles"))
-		if realpath.startswith(basepath):
-			profilever = realpath[1 + len(basepath):]
-		else:
+		profilever = relative_profile_path(portdir, profile)
+		if profilever is None:
 			try:
-				profilever = "!" + os.readlink(profile)
-			except (OSError):
+				for parent in portage.grabfile(
+					os.path.join(profile, 'parent')):
+					profilever = relative_profile_path(portdir,
+						os.path.join(profile, parent))
+					if profilever is not None:
+						break
+			except portage.exception.PortageException:
 				pass
-		del realpath, basepath
+
+			if profilever is None:
+				try:
+					profilever = "!" + os.readlink(profile)
+				except (OSError):
+					pass
+
+	if profilever is None:
+		profilever = "unavailable"
 
 	libcver=[]
 	libclist  = vardb.match("virtual/libc")
Index: pym/_emerge/depgraph.py
===================================================================
--- a/pym/_emerge/depgraph.py	(revision 15731)
+++ b/pym/_emerge/depgraph.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1999-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: depgraph.py 15711 2010-03-02 21:14:20Z zmedico $
+# $Id: depgraph.py 15814 2010-03-10 00:31:43Z zmedico $
 
 from __future__ import print_function
 
@@ -3341,7 +3341,9 @@
 		if replacement_portage == running_portage:
 			replacement_portage = None
 
-		if replacement_portage is not None:
+		if replacement_portage is not None and \
+			(running_portage is None or \
+			(running_portage.cpv != replacement_portage.cpv)):
 			# update from running_portage to replacement_portage asap
 			asap_nodes.append(replacement_portage)
 
@@ -3363,12 +3365,16 @@
 
 		# Merge libc asap, in order to account for implicit
 		# dependencies. See bug #303567.
-		libc_pkg = self._dynamic_config.mydbapi[running_root].match_pkgs(
-			portage.const.LIBC_PACKAGE_ATOM)
-		if libc_pkg:
-			libc_pkg = libc_pkg[0]
-			if libc_pkg.operation == 'merge':
-				asap_nodes.append(libc_pkg)
+		for root in (running_root,):
+			libc_pkg = self._dynamic_config.mydbapi[root].match_pkgs(
+				portage.const.LIBC_PACKAGE_ATOM)
+			if libc_pkg:
+				libc_pkg = libc_pkg[0]
+				if libc_pkg.operation == 'merge':
+					# Only add a dep when the version changes.
+					if not libc_pkg.root_config.trees[
+						'vartree'].dbapi.cpv_exists(libc_pkg.cpv):
+						asap_nodes.append(libc_pkg)
 
 		def gather_deps(ignore_priority, mergeable_nodes,
 			selected_nodes, node):
@@ -3904,7 +3910,7 @@
 			tempgraph.remove(node)
 		display_order.reverse()
 		self._frozen_config.myopts.pop("--quiet", None)
-		self._frozen_config.myopts.pop("--verbose", None)
+		self._frozen_config.myopts["--verbose"] = True
 		self._frozen_config.myopts["--tree"] = True
 		portage.writemsg("\n\n", noiselevel=-1)
 		self.display(display_order)
@@ -4500,12 +4506,20 @@
 
 				def pkgprint(pkg_str):
 					if pkg_merge:
-						if pkg_system:
-							return colorize("PKG_MERGE_SYSTEM", pkg_str)
-						elif pkg_world:
-							return colorize("PKG_MERGE_WORLD", pkg_str)
+						if built:
+							if pkg_system:
+								return colorize("PKG_BINARY_MERGE_SYSTEM", pkg_str)
+							elif pkg_world:
+								return colorize("PKG_BINARY_MERGE_WORLD", pkg_str)
+							else:
+								return colorize("PKG_BINARY_MERGE", pkg_str)
 						else:
-							return colorize("PKG_MERGE", pkg_str)
+							if pkg_system:
+								return colorize("PKG_MERGE_SYSTEM", pkg_str)
+							elif pkg_world:
+								return colorize("PKG_MERGE_WORLD", pkg_str)
+							else:
+								return colorize("PKG_MERGE", pkg_str)
 					elif pkg_status == "uninstall":
 						return colorize("PKG_UNINSTALL", pkg_str)
 					else:
Index: pym/_emerge/help.py
===================================================================
--- a/pym/_emerge/help.py	(revision 15731)
+++ b/pym/_emerge/help.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1999-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: help.py 15687 2010-03-02 21:07:53Z zmedico $
+# $Id: help.py 15781 2010-03-09 02:42:23Z zmedico $
 
 from __future__ import print_function
 
@@ -195,18 +195,31 @@
 		print("                emerge -S 'perl.*module'")
 		print()
 		print("       "+green("--sync"))
-		print("              Tells emerge to update the Portage tree as specified in")
-		print("              The SYNC variable found in /etc/make.conf.  By default, SYNC instructs")
-		print("              emerge to perform an rsync-style update with rsync.gentoo.org.")
+		desc = "This updates the portage tree that is located in the " + \
+			"directory that the PORTDIR variable refers to (default " + \
+			"location is /usr/portage). The SYNC variable specifies " + \
+			"the remote URI from which files will be synchronized. " + \
+			"The PORTAGE_SYNC_STALE variable configures " + \
+			"warnings that are shown when emerge --sync has not " + \
+			"been executed recently."
+		for line in wrap(desc, desc_width):
+			print(desc_indent + line)
 		print()
-		print("              'emerge-webrsync' exists as a helper app to emerge --sync, providing a")
-		print("              method to receive the entire portage tree as a tarball that can be")
-		print("              extracted and used. First time syncs would benefit greatly from this.")
+		print(desc_indent + turquoise("WARNING:"))
+		desc = "The emerge --sync action will modify and/or delete " + \
+			"files located inside the directory that the PORTDIR " + \
+			"variable refers to (default location is /usr/portage). " + \
+			"For more information, see the PORTDIR documentation in " + \
+			"the make.conf(5) man page."
+		for line in wrap(desc, desc_width):
+			print(desc_indent + line)
 		print()
-		print("              "+turquoise("WARNING:"))
-		print("              If using our rsync server, emerge will clean out all files that do not")
-		print("              exist on it, including ones that you may have created. The exceptions")
-		print("              to this are the distfiles, local and packages directories.")
+		print(desc_indent + green("NOTE:"))
+		desc = "The emerge-webrsync program will download the entire " + \
+			"portage tree as a tarball, which is much faster than emerge " + \
+			"--sync for first time syncs."
+		for line in wrap(desc, desc_width):
+			print(desc_indent + line)
 		print()
 		print("       "+green("--unmerge")+" ("+green("-C")+" short option)")
 		print("              "+turquoise("WARNING: This action can remove important packages!"))
@@ -216,13 +229,6 @@
 		print("              ebuilds. For a dependency aware version of --unmerge, use")
 		print("              --depclean or --prune.")
 		print()
-		print("       "+green("--update")+" ("+green("-u")+" short option)")
-		print("              Updates packages to the best version available, which may not")
-		print("              always be the highest version number due to masking for testing")
-		print("              and development. Package atoms specified on the command")
-		print("              line are greedy, meaning that unspecific atoms may match multiple")
-		print("              installed versions of slotted packages.")
-		print()
 		print("       "+green("--version")+" ("+green("-V")+" short option)")
 		print("              Displays the currently installed version of portage along with")
 		print("              other information useful for quick reference on a system. See")
@@ -591,6 +597,15 @@
 		for line in wrap(desc, desc_width):
 			print(desc_indent + line)
 		print()
+		print("       "+green("--update")+" ("+green("-u")+" short option)")
+		desc = "Updates packages to the best version available, which may " + \
+			"not always be the  highest version number due to masking " + \
+			"for testing and development. Package atoms specified on " + \
+			"the command line are greedy, meaning that unspecific " + \
+			"atoms may match multiple versions of slotted packages."
+		for line in wrap(desc, desc_width):
+			print(desc_indent + line)
+		print()
 		print("       " + green("--use-ebuild-visibility") + "[=%s]" % turquoise("n"))
 		desc = "Use unbuilt ebuild metadata for visibility " + \
 			"checks on built packages."
Index: pym/_emerge/Scheduler.py
===================================================================
--- a/pym/_emerge/Scheduler.py	(revision 15731)
+++ b/pym/_emerge/Scheduler.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1999-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: Scheduler.py 15708 2010-03-02 21:13:39Z zmedico $
+# $Id: Scheduler.py 15812 2010-03-09 21:27:32Z zmedico $
 
 from __future__ import print_function
 
@@ -18,6 +18,7 @@
 from portage import _unicode_decode
 from portage import _unicode_encode
 from portage.cache.mappings import slot_dict_class
+from portage.const import LIBC_PACKAGE_ATOM
 from portage.elog.messages import eerror
 from portage.output import colorize, create_color_func, darkgreen, red
 bad = create_color_func("BAD")
@@ -351,6 +352,11 @@
 		self._find_system_deps()
 		self._prune_digraph()
 		self._prevent_builddir_collisions()
+		self._implicit_libc_deps()
+		if '--debug' in self.myopts:
+			writemsg("\nscheduler digraph:\n\n", noiselevel=-1)
+			self._digraph.debug_print()
+			writemsg("\n", noiselevel=-1)
 
 	def _find_system_deps(self):
 		"""
@@ -412,6 +418,69 @@
 					priority=DepPriority(buildtime=True))
 			cpv_map[pkg.cpv].append(pkg)
 
+	def _implicit_libc_deps(self):
+		"""
+		Create implicit dependencies on libc, in order to ensure that libc
+		is installed as early as possible (see bug #303567). If the merge
+		list contains both a new-style virtual and an old-style PROVIDE
+		virtual, the new-style virtual is used.
+		"""
+		implicit_libc_roots = set([self._running_root.root])
+		libc_set = InternalPackageSet([LIBC_PACKAGE_ATOM])
+		norm_libc_pkgs = {}
+		virt_libc_pkgs = {}
+		for pkg in self._mergelist:
+			if not isinstance(pkg, Package):
+				# a satisfied blocker
+				continue
+			if pkg.installed:
+				continue
+			if pkg.root in implicit_libc_roots and \
+				pkg.operation == 'merge':
+				if libc_set.findAtomForPackage(pkg):
+					if pkg.category == 'virtual':
+						d = virt_libc_pkgs
+					else:
+						d = norm_libc_pkgs
+					if pkg.root in d:
+						raise AssertionError(
+							"found 2 libc matches: %s and %s" % \
+							(d[pkg.root], pkg))
+					d[pkg.root] = pkg
+
+		# Prefer new-style virtuals over old-style PROVIDE virtuals.
+		libc_pkg_map = norm_libc_pkgs.copy()
+		libc_pkg_map.update(virt_libc_pkgs)
+
+		# Only add a dep when the version changes.
+		for libc_pkg in list(libc_pkg_map.values()):
+			if libc_pkg.root_config.trees['vartree'].dbapi.cpv_exists(
+				libc_pkg.cpv):
+				del libc_pkg_map[pkg.root]
+
+		if not libc_pkg_map:
+			return
+
+		libc_pkgs = set(libc_pkg_map.values())
+		earlier_libc_pkgs = set()
+
+		for pkg in self._mergelist:
+			if not isinstance(pkg, Package):
+				# a satisfied blocker
+				continue
+			if pkg.installed:
+				continue
+			if pkg.root in implicit_libc_roots and \
+				pkg.operation == 'merge':
+				if pkg in libc_pkgs:
+					earlier_libc_pkgs.add(pkg)
+				else:
+					my_libc = libc_pkg_map.get(pkg.root)
+					if my_libc is not None and \
+						my_libc in earlier_libc_pkgs:
+						self._digraph.add(my_libc, pkg,
+							priority=DepPriority(buildtime=True))
+
 	class _pkg_failure(portage.exception.PortageException):
 		"""
 		An instance of this class is raised by unmerge() when
Index: pym/_emerge/sync/__init__.py
===================================================================
--- a/pym/_emerge/sync/__init__.py	(revision 15731)
+++ b/pym/_emerge/sync/__init__.py	(revision 15814)
@@ -0,0 +1,3 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id: __init__.py 15772 2010-03-08 09:40:46Z zmedico $
Index: pym/_emerge/sync/old_tree_timestamp.py
===================================================================
--- a/pym/_emerge/sync/old_tree_timestamp.py	(revision 15731)
+++ b/pym/_emerge/sync/old_tree_timestamp.py	(revision 15814)
@@ -0,0 +1,99 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+# $Id: old_tree_timestamp.py 15807 2010-03-09 20:21:05Z zmedico $
+
+import locale
+import logging
+import time
+
+from portage import os
+from portage.exception import PortageException
+from portage.localization import _
+from portage.output import EOutput
+from portage.util import grabfile, writemsg_level
+
+def have_english_locale():
+	lang, enc = locale.getdefaultlocale()
+	if lang is not None:
+		lang = lang.lower()
+		lang = lang.split('_', 1)[0]
+	return lang is None or lang in ('c', 'en')
+
+def whenago(seconds):
+	sec = int(seconds)
+	mins = 0
+	days = 0
+	hrs = 0
+	years = 0
+	out = []
+
+	if sec > 60:
+		mins = sec / 60
+		sec = sec % 60
+	if mins > 60:
+		hrs = mins / 60
+		mins = mins % 60
+	if hrs > 24:
+		days = hrs / 24
+		hrs = hrs % 24
+	if days > 365:
+		years = days / 365
+		days = days % 365
+
+	if years:
+		out.append(str(years)+"y ")
+	if days:
+		out.append(str(days)+"d ")
+	if hrs:
+		out.append(str(hrs)+"h ")
+	if mins:
+		out.append(str(mins)+"m ")
+	if sec:
+		out.append(str(sec)+"s ")
+
+	return "".join(out).strip()
+
+def old_tree_timestamp_warn(portdir, settings):
+	unixtime = time.time()
+	default_warnsync = 30
+
+	timestamp_file = os.path.join(portdir, "metadata/timestamp.x")
+	try:
+		lastsync = grabfile(timestamp_file)
+	except PortageException:
+		return False
+
+	if not lastsync:
+		return False
+
+	lastsync = lastsync[0].split()
+	if not lastsync:
+		return False
+
+	try:
+		lastsync = int(lastsync[0])
+	except ValueError:
+		return False
+
+	var_name = 'PORTAGE_SYNC_STALE'
+	try:
+		warnsync = float(settings.get(var_name, default_warnsync))
+	except ValueError:
+		writemsg_level("!!! %s contains non-numeric value: %s\n" % \
+			(var_name, settings[var_name]),
+			level=logging.ERROR, noiselevel=-1)
+		return False
+
+	if warnsync <= 0:
+		return False
+
+	if (unixtime - 86400 * warnsync) > lastsync:
+		out = EOutput()
+		if have_english_locale():
+			out.ewarn("Last emerge --sync was %s ago." % \
+				whenago(unixtime - lastsync))
+		else:
+			out.ewarn(_("Last emerge --sync was %s.") % \
+				time.strftime('%c', time.localtime(lastsync)))
+		return True
+	return False
Index: pym/portage/dbapi/vartree.py
===================================================================
--- a/pym/portage/dbapi/vartree.py	(revision 15731)
+++ b/pym/portage/dbapi/vartree.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1998-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: vartree.py 15727 2010-03-03 01:27:27Z zmedico $
+# $Id: vartree.py 15782 2010-03-09 02:42:40Z zmedico $
 
 __all__ = [
 	"vardbapi", "vartree", "dblink"] + \
@@ -3181,6 +3181,9 @@
 		if self.myroot == "/" and \
 			match_from_list(PORTAGE_PACKAGE_ATOM, [self.mycpv]) and \
 			not self.vartree.dbapi.cpv_exists(self.mycpv):
+			# Load lazily referenced portage submodules into memory,
+			# so imports won't fail during portage upgrade/downgrade.
+			portage.proxy.lazyimport._preload_portage_submodules()
 			settings = self.settings
 			base_path_orig = os.path.dirname(settings["PORTAGE_BIN_PATH"])
 			from tempfile import mkdtemp
Index: pym/portage/mail.py
===================================================================
--- a/pym/portage/mail.py	(revision 15731)
+++ b/pym/portage/mail.py	(revision 15814)
@@ -1,36 +1,43 @@
 # portage.py -- core Portage functionality
 # Copyright 1998-2004 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: mail.py 14860 2009-11-21 04:04:37Z zmedico $
+# $Id: mail.py 15794 2010-03-09 08:11:46Z zmedico $
+
+# Since python ebuilds remove the 'email' module when USE=build
+# is enabled, use a local import so that
+# portage.proxy.lazyimport._preload_portage_submodules()
+# can load this module even though the 'email' module is missing.
+# The elog mail modules won't work, but at least an ImportError
+# won't cause portage to crash during stage builds. Since the
+# 'smtlib' module imports the 'email' module, that's imported
+# locally as well.
 
-from email.mime.text import MIMEText
-from email.mime.multipart import MIMEMultipart as MultipartMessage
-from email.mime.base import MIMEBase as BaseMessage
-from email.header import Header
-import smtplib
 import socket
 import sys
 import time
 
 from portage import os
 from portage import _encodings
-from portage import _unicode_encode
+from portage import _unicode_decode, _unicode_encode
 from portage.localization import _
 import portage
 
 if sys.hexversion >= 0x3000000:
 	basestring = str
 
-if sys.hexversion >= 0x3000000:
-	def TextMessage(_text):
-		mimetext = MIMEText(_text)
+def TextMessage(_text):
+	from email.mime.text import MIMEText
+	mimetext = MIMEText(_text)
+	if sys.hexversion >= 0x3000000:
 		mimetext.set_charset("UTF-8")
-		return mimetext
-else:
-	TextMessage = MIMEText
+	return mimetext
 
 def create_message(sender, recipient, subject, body, attachments=None):
 
+	from email.header import Header
+	from email.mime.base import MIMEBase as BaseMessage
+	from email.mime.multipart import MIMEMultipart as MultipartMessage
+
 	if sys.hexversion < 0x3000000:
 		sender = _unicode_encode(sender,
 			encoding=_encodings['content'], errors='strict')
@@ -69,6 +76,9 @@
 	return mymessage
 
 def send_mail(mysettings, message):
+
+	import smtplib
+
 	mymailhost = "localhost"
 	mymailport = 25
 	mymailuser = ""
@@ -135,7 +145,17 @@
 				myconn = smtplib.SMTP(mymailhost, mymailport)
 			if mymailuser != "" and mymailpasswd != "":
 				myconn.login(mymailuser, mymailpasswd)
-			myconn.sendmail(myfrom, myrecipient, message.as_string())
+
+			message_str = message.as_string()
+			if sys.hexversion >= 0x3000000:
+				# Force ascii encoding in order to avoid UnicodeEncodeError
+				# from smtplib.sendmail with python3 (bug #291331).
+				message_str = _unicode_encode(message_str,
+					encoding='ascii', errors='backslashreplace')
+				message_str = _unicode_decode(message_str,
+					encoding='ascii', errors='replace')
+
+			myconn.sendmail(myfrom, myrecipient, message_str)
 			myconn.quit()
 		except smtplib.SMTPException as e:
 			raise portage.exception.PortageException(_("!!! An error occured while trying to send logmail:\n")+str(e))
Index: pym/portage/output.py
===================================================================
--- a/pym/portage/output.py	(revision 15731)
+++ b/pym/portage/output.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 1998-2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: output.py 15245 2010-01-29 18:47:30Z zmedico $
+# $Id: output.py 15746 2010-03-04 11:22:15Z zmedico $
 
 __docformat__ = "epytext"
 
@@ -139,6 +139,9 @@
 _styles["PKG_MERGE"]               = ( "darkgreen", )
 _styles["PKG_MERGE_SYSTEM"]        = ( "darkgreen", )
 _styles["PKG_MERGE_WORLD"]         = ( "green", )
+_styles["PKG_BINARY_MERGE"]        = ( "darkgreen", )
+_styles["PKG_BINARY_MERGE_SYSTEM"] = ( "darkgreen", )
+_styles["PKG_BINARY_MERGE_WORLD"]  = ( "green", )
 _styles["PKG_UNINSTALL"]           = ( "red", )
 _styles["PKG_NOMERGE"]             = ( "darkblue", )
 _styles["PKG_NOMERGE_SYSTEM"]      = ( "darkblue", )
Index: pym/portage/package/ebuild/config.py
===================================================================
--- a/pym/portage/package/ebuild/config.py	(revision 15731)
+++ b/pym/portage/package/ebuild/config.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: config.py 15705 2010-03-02 21:11:02Z zmedico $
+# $Id: config.py 15768 2010-03-08 09:05:13Z zmedico $
 
 __all__ = [
 	'autouse', 'best_from_dict', 'check_config_instance', 'config',
@@ -274,7 +274,8 @@
 		"PORTAGE_REPO_DUPLICATE_WARN",
 		"PORTAGE_RO_DISTDIRS",
 		"PORTAGE_RSYNC_EXTRA_OPTS", "PORTAGE_RSYNC_OPTS",
-		"PORTAGE_RSYNC_RETRIES", "PORTAGE_USE", "PORT_LOGDIR",
+		"PORTAGE_RSYNC_RETRIES", "PORTAGE_SYNC_STALE",
+		"PORTAGE_USE", "PORT_LOGDIR",
 		"QUICKPKG_DEFAULT_OPTS",
 		"RESUMECOMMAND", "RESUMECOMMAND_HTTP", "RESUMECOMMAND_HTTP",
 		"RESUMECOMMAND_SFTP", "SYNC", "USE_EXPAND_HIDDEN", "USE_ORDER",
Index: pym/portage/package/ebuild/doebuild.py
===================================================================
--- a/pym/portage/package/ebuild/doebuild.py	(revision 15731)
+++ b/pym/portage/package/ebuild/doebuild.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: doebuild.py 15713 2010-03-02 21:14:43Z zmedico $
+# $Id: doebuild.py 15760 2010-03-08 08:46:53Z zmedico $
 
 __all__ = ['doebuild', 'doebuild_environment', 'spawn', 'spawnebuild']
 
@@ -25,6 +25,7 @@
 	'portage.package.ebuild.config:check_config_instance',
 	'portage.package.ebuild.digestcheck:digestcheck',
 	'portage.package.ebuild.digestgen:digestgen',
+	'portage.package.ebuild.fetch:fetch',
 	'portage.util.ExtractKernelVersion:ExtractKernelVersion'
 )
 
@@ -47,7 +48,6 @@
 from portage.localization import _
 from portage.manifest import Manifest
 from portage.output import style_to_ansi_code
-from portage.package.ebuild.fetch import fetch
 from portage.package.ebuild.prepare_build_dirs import prepare_build_dirs
 from portage.util import apply_recursive_permissions, \
 	apply_secpass_permissions, noiselimit, normalize_path, \
@@ -810,7 +810,8 @@
 			mydo not in ("digest", "manifest") and "noauto" not in features)
 		alist = mysettings.configdict["pkg"].get("A")
 		aalist = mysettings.configdict["pkg"].get("AA")
-		if alist is None or aalist is None:
+		if alist is None or aalist is None or \
+			(not emerge_skip_distfiles and need_distfiles):
 			# Make sure we get the correct tree in case there are overlays.
 			mytree = os.path.realpath(
 				os.path.dirname(os.path.dirname(mysettings["O"])))
@@ -827,25 +828,26 @@
 				return 1
 			mysettings.configdict["pkg"]["A"] = " ".join(alist)
 			mysettings.configdict["pkg"]["AA"] = " ".join(aalist)
+
+			if not emerge_skip_distfiles and need_distfiles:
+				if "mirror" in features or fetchall:
+					fetchme = aalist
+				else:
+					fetchme = alist
+				if not fetch(fetchme, mysettings, listonly=listonly,
+					fetchonly=fetchonly):
+					return 1
+
 		else:
 			alist = set(alist.split())
 			aalist = set(aalist.split())
-		if ("mirror" in features) or fetchall:
-			fetchme = aalist
-			checkme = aalist
-		else:
-			fetchme = alist
-			checkme = alist
 
 		if mydo == "fetch":
 			# Files are already checked inside fetch(),
 			# so do not check them again.
 			checkme = []
-
-		if not emerge_skip_distfiles and \
-			need_distfiles and not fetch(
-			fetchme, mysettings, listonly=listonly, fetchonly=fetchonly):
-			return 1
+		else:
+			checkme = alist
 
 		if mydo == "fetch" and listonly:
 			return 0
Index: pym/portage/package/ebuild/fetch.py
===================================================================
--- a/pym/portage/package/ebuild/fetch.py	(revision 15731)
+++ b/pym/portage/package/ebuild/fetch.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: fetch.py 15718 2010-03-02 21:37:48Z zmedico $
+# $Id: fetch.py 15748 2010-03-04 11:23:00Z zmedico $
 
 from __future__ import print_function
 
@@ -20,18 +20,26 @@
 import portage
 portage.proxy.lazyimport.lazyimport(globals(),
 	'portage.package.ebuild.config:check_config_instance,config',
+	'portage.package.ebuild.doebuild:doebuild_environment,' + \
+		'spawn@doebuild_spawn',
+	'portage.package.ebuild.prepare_build_dirs:prepare_build_dirs',
 )
 
-from portage import doebuild_environment, OrderedDict, os, prepare_build_dirs, selinux, _encodings, _shell_quote, _unicode_encode
+from portage import OrderedDict, os, selinux, _encodings, \
+	_shell_quote, _unicode_encode
 from portage.checksum import perform_md5, verify_all
-from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, EBUILD_SH_BINARY, GLOBAL_CONFIG_PATH
+from portage.const import BASH_BINARY, CUSTOM_MIRRORS_FILE, \
+	EBUILD_SH_BINARY, GLOBAL_CONFIG_PATH
 from portage.data import portage_gid, portage_uid, secpass, userpriv_groups
-from portage.exception import FileNotFound, OperationNotPermitted, PermissionDenied, PortageException, TryAgain
+from portage.exception import FileNotFound, OperationNotPermitted, \
+	PermissionDenied, PortageException, TryAgain
 from portage.localization import _
 from portage.locks import lockfile, unlockfile
 from portage.manifest import Manifest
 from portage.output import colorize, EOutput
-from portage.util import apply_recursive_permissions, apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, varexpand, writemsg, writemsg_level, writemsg_stdout
+from portage.util import apply_recursive_permissions, \
+	apply_secpass_permissions, ensure_dirs, grabdict, shlex_split, \
+	varexpand, writemsg, writemsg_level, writemsg_stdout
 from portage.process import spawn
 
 _userpriv_spawn_kwargs = (
@@ -1096,7 +1104,7 @@
 					ebuild_phase = mysettings.get("EBUILD_PHASE")
 					try:
 						mysettings["EBUILD_PHASE"] = "nofetch"
-						spawn(_shell_quote(EBUILD_SH_BINARY) + \
+						doebuild_spawn(_shell_quote(EBUILD_SH_BINARY) + \
 							" nofetch", mysettings, fd_pipes=fd_pipes)
 					finally:
 						if ebuild_phase is None:
Index: pym/portage/package/ebuild/getmaskingstatus.py
===================================================================
--- a/pym/portage/package/ebuild/getmaskingstatus.py	(revision 15731)
+++ b/pym/portage/package/ebuild/getmaskingstatus.py	(revision 15814)
@@ -1,9 +1,11 @@
 # Copyright 2010 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: getmaskingstatus.py 15672 2010-03-02 21:01:19Z zmedico $
+# $Id: getmaskingstatus.py 15749 2010-03-04 11:23:09Z zmedico $
 
 __all__ = ['getmaskingstatus']
 
+import sys
+
 import portage
 from portage import eapi_is_supported, _eapi_is_deprecated
 from portage.dep import match_from_list
@@ -11,6 +13,9 @@
 from portage.package.ebuild.config import config
 from portage.versions import catpkgsplit, cpv_getkey
 
+if sys.hexversion >= 0x3000000:
+	basestring = str
+
 def getmaskingstatus(mycpv, settings=None, portdb=None):
 	if settings is None:
 		settings = config(clone=portage.settings)
Index: pym/portage/proxy/lazyimport.py
===================================================================
--- a/pym/portage/proxy/lazyimport.py	(revision 15731)
+++ b/pym/portage/proxy/lazyimport.py	(revision 15814)
@@ -1,6 +1,6 @@
 # Copyright 2009 Gentoo Foundation
 # Distributed under the terms of the GNU General Public License v2
-# $Id: lazyimport.py 14327 2009-09-21 16:07:07Z arfrever $
+# $Id: lazyimport.py 15782 2010-03-09 02:42:40Z zmedico $
 
 __all__ = ['lazyimport']
 
@@ -20,6 +20,24 @@
 _module_proxies = {}
 _module_proxies_lock = threading.RLock()
 
+def _preload_portage_submodules():
+	"""
+	Load lazily referenced portage submodules into memory,
+	so imports won't fail during portage upgrade/downgrade.
+	Note that this recursively loads only the modules that
+	are lazily referenced by currently imported modules,
+	so some portage submodules may still remain unimported
+	after this function is called.
+	"""
+	while True:
+		remaining = False
+		for name in list(_module_proxies):
+			if name.startswith('portage.'):
+				remaining = True
+				_unregister_module_proxy(name)
+		if not remaining:
+			break
+
 def _register_module_proxy(name, proxy):
 	_module_proxies_lock.acquire()
 	try:
