public inbox for gentoo-portage-dev@lists.gentoo.org
 help / color / mirror / Atom feed
From: Zac Medico <zmedico@gmail.com>
To: gentoo-portage-dev@lists.gentoo.org
Subject: Re: [gentoo-portage-dev] the refactoring of emerge, continued... (was PATCH: refactor emerge spinner (#102073))
Date: Sat, 13 Aug 2005 15:25:17 -0700	[thread overview]
Message-ID: <42FE734D.5020808@gmail.com> (raw)
In-Reply-To: <42FE2F3F.7000806@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 501 bytes --]

Hi,

In #gentoo-portage Jason requested for me to split out some parts of the the emerge_cmd.perform() method.  Actually, I should have done that before I posted to the list earlier but I was anxious to show people what I had done.  Sorry for the extra post. :-)

I have split out 4 new methods called action_sync(), action_info(), action_depclean(), and action_merge().  This time I am posting a patch against portage-2.1.0_alpha20050718.  As always, I would appreciate feedback.

Thanks again,

Zac

[-- Attachment #2: emerge-2.1.0_alpha20050718-refactored-r1.patch --]
[-- Type: text/x-patch, Size: 121392 bytes --]

Index: portage-2.1.0_alpha20050718/bin/emerge
===================================================================
--- portage-2.1.0_alpha20050718.orig/bin/emerge
+++ portage-2.1.0_alpha20050718/bin/emerge
@@ -21,64 +21,95 @@ import portage_exec, sync
 from portage_dep import DependencyGraph
 import portage_dep, portage_versions
 
+def emergeexitsig(signum, frame):
+	signal.signal(signal.SIGINT, signal.SIG_IGN)
+	portage.portageexit()
+	portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
+	sys.exit(100+signum)
+signal.signal(signal.SIGINT, emergeexitsig)
 
-spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")",
-                "Thank you for using Gentoo. :)",
-                "Are you actually trying to read this?",
-                "How many times have you stared at this?",
-                "We are generating the cache right now",
-                "You are paying too much attention.",
-                "A theory is better than its explanation.",
-                "Phasers locked on target, Captain.",
-                "Thrashing is just virtual crashing.",
-                "To be is to program.",
-                "Real Users hate Real Programmers.",
-                "When all else fails, read the instructions.",
-                "Functionality breeds Contempt.",
-                "The future lies ahead.",
-                "3.1415926535897932384626433832795028841971694",
-                "Sometimes insanity is the only alternative.",
-                "Inaccuracy saves a world of explanation.",
-               ]
-
-
-def update_basic_spinner():
-	global spinner, spinpos
-	spinpos = (spinpos+1) % 500
-	if (spinpos % 100) == 0:
-		if spinpos == 0:
-			sys.stdout.write(". ")
-		else:
-			sys.stdout.write(".")
-	sys.stdout.flush()
-
-def update_scroll_spinner():
-	global spinner, spinpos
-	if(spinpos >= len(spinner)):
-		sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))]))
-	else:
-		sys.stdout.write(green("\b "+spinner[spinpos]))
-	sys.stdout.flush()
-	spinpos = (spinpos+1) % (2*len(spinner))
-
-def update_twirl_spinner():
-	global spinner, spinpos
-	spinpos = (spinpos+1) % len(spinner)
-	sys.stdout.write("\b\b "+spinner[spinpos])
-	sys.stdout.flush()
-
-spinpos = 0
-spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
-update_spinner = update_twirl_spinner
-if "candy" in portage.settings.features:
-	spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)]
-	update_spinner = update_scroll_spinner
-if not sys.stdout.isatty() or ("--nospinner" in sys.argv):
-	update_spinner = update_basic_spinner
+def emergelog(edebug,mystr,short_msg=None):
+	if "notitles" not in portage.features:
+		if short_msg:
+			xtermTitle(short_msg)
+		else:
+			xtermTitle(mystr)
+	try:
+		#seems odd opening a file each write...
+		if not os.path.exists("/var/log/emerge.log"):
+			mylogfile=open("/var/log/emerge.log", "w")
+			os.chmod("/var/log/emerge.log", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
+			os.chown("/var/log/emerge.log", portage.portage_uid, portage.portage_gid)
+		else:
+			mylogfile=open("/var/log/emerge.log", "a")
+
+		l=portage_locks.lockfile(mylogfile)
+		# seek because we may have gotten held up by the lock.
+		# if so, we may not be positioned at the end of the file.
+		mylogfile.seek(0,2)
+		mylogfile.write(str(time.time())[:10]+": "+mystr+"\n")
+		mylogfile.flush()
+		portage_locks.unlockfile(l)
+		mylogfile.close()
+	except SystemExit, e:
+		raise # Needed else can't exit
+	except Exception, e:
+		if edebug:
+			print "emergelog():",e
+		pass
 
 
-if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]):
-	nocolor()
+class stdout_spinner:
+	
+	def __init__(self):
+		spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")",
+		                "Thank you for using Gentoo. :)",
+		                "Are you actually trying to read this?",
+		                "How many times have you stared at this?",
+		                "We are generating the cache right now",
+		                "You are paying too much attention.",
+		                "A theory is better than its explanation.",
+		                "Phasers locked on target, Captain.",
+		                "Thrashing is just virtual crashing.",
+		                "To be is to program.",
+		                "Real Users hate Real Programmers.",
+		                "When all else fails, read the instructions.",
+		                "Functionality breeds Contempt.",
+		                "The future lies ahead.",
+		                "3.1415926535897932384626433832795028841971694",
+		                "Sometimes insanity is the only alternative.",
+		                "Inaccuracy saves a world of explanation.",
+		               ]
+		
+		self.spinpos = 0
+		self.spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
+		self.update_spinner = self.update_twirl_spinner
+		
+		if "candy" in portage.settings.features:
+			self.spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)]
+			self.update_spinner = self.update_scroll_spinner
+
+	def update_basic_spinner(self):
+		self.spinpos = (self.spinpos+1) % 500
+		if (self.spinpos % 100) == 0:
+			if self.spinpos == 0:
+				sys.stdout.write(". ")
+			else:
+				sys.stdout.write(".")
+		sys.stdout.flush()
+	
+	def update_scroll_spinner(self):
+			if(self.spinpos >= len(self.spinner)):
+				sys.stdout.write(darkgreen(" \b\b\b"+self.spinner[len(self.spinner)-1-(self.spinpos%len(self.spinner))]))
+			else:
+				sys.stdout.write(green("\b "+self.spinner[self.spinpos]))
+			sys.stdout.flush()
+			self.spinpos = (self.spinpos+1) % (2*len(self.spinner))
+	
+	def update_twirl_spinner(self):
+		self.spinpos = (self.spinpos+1) % len(self.spinner)
+		sys.stdout.write("\b\b "+self.spinner[self.spinpos])
+		sys.stdout.flush()
 
 def normpath(mystr):
 	if mystr and (mystr[0]=='/'):
@@ -120,307 +151,6 @@ def userquery(prompt, responses=None, co
 		print "Interrupted."
 		sys.exit(1)
 
-if portage.settings.has_key("PORTAGE_NICENESS"):
-	try:
-		os.nice(int(portage.settings["PORTAGE_NICENESS"]))
-	except SystemExit, e:
-		raise # Needed else can't exit
-	except Exception,e:
-		print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'"
-		print "!!!",e
-
-#Freeze the portdbapi for enhanced performance:
-portage.portdb.freeze()
-
-# Kill noauto as it will break merges otherwise.
-while 'noauto' in portage.features:
-	portage.features.remove('noauto')
-
-#number of ebuilds merged
-merged=0
-params=["selective", "deep", "self", "recurse", "empty"]
-actions=[
-"clean", "config", "depclean",
-"info",   "inject",   "metadata",
-"prune", "regen",  "rsync", "search",
-"sync",  "system", "unmerge",  "world",
-]
-options=[
-"--ask",
-"--buildpkg",     "--buildpkgonly",
-"--changelog",    "--columns",
-"--debug",        "--deep",
-"--digest",
-"--emptytree",
-"--fetchonly",    "--fetch-all-uri",
-"--getbinpkg",    "--getbinpkgonly",
-"--help",         "--noconfmem",
-"--newuse",
-"--nodeps",       "--noreplace",
-"--nospinner",    "--oneshot",
-"--onlydeps",     "--pretend",
-"--quiet",        "--resume",
-"--searchdesc",   "--selective",
-"--skipfirst",
-"--tree",
-"--update",
-"--usepkg",       "--usepkgonly",
-"--verbose",      "--version"
-]
-
-shortmapping={
-"1":"--oneshot",
-"a":"--ask",
-"b":"--buildpkg",  "B":"--buildpkgonly",
-"c":"--clean",     "C":"--unmerge",
-"d":"--debug",     "D":"--deep",
-"e":"--emptytree",
-"f":"--fetchonly", "F":"--fetch-all-uri",
-"g":"--getbinpkg", "G":"--getbinpkgonly",
-"h":"--help",
-"k":"--usepkg",    "K":"--usepkgonly",
-"l":"--changelog",
-"n":"--noreplace", "N":"--newuse",
-"o":"--onlydeps",  "O":"--nodeps",
-"p":"--pretend",   "P":"--prune",
-"q":"--quiet",
-"s":"--search",    "S":"--searchdesc",
-'t':"--tree",
-"u":"--update",
-"v":"--verbose",   "V":"--version"
-}
-
-myaction=None
-myopts=[]
-myfiles=[]
-edebug=0
-verbosity=0
-
-# process short actions
-tmpcmdline=sys.argv[1:]
-#tmpcmdline.extend(portage.settings["EMERGE_OPTS"].split())
-cmdline=[]
-for x in tmpcmdline:
-	if x[0:1]=="-" and x[1:2]!="-":
-		for y in x[1:]:
-			if shortmapping.has_key(y):
-				if shortmapping[y]=="--verbose":
-					verbosity += 1
-				elif shortmapping[y] in cmdline:
-					print
-					print "*** Warning: Redundant use of",shortmapping[y]
-				else:
-					cmdline.append(shortmapping[y])
-			else:
-				print "!!! Error: -"+y+" is an invalid short action or option."
-				sys.exit(1)
-	else:
-		cmdline.append(x)
-
-# process the options and command arguments
-for x in cmdline:
-	if not x:
-		continue
-	if len(x)>=2 and x[0:2]=="--":
-		if x in options:
-			myopts.append(x)
-		elif x[2:] in actions:
-			if x[2:]=="rsync" or x=="rsync":
-				# "emerge --rsync"
-				print
-				print red("*** '--rsync' has been deprecated.")
-				print red("*** Please use '--sync' instead.")
-				print
-				x="--sync"
-			if myaction:
-				if myaction not in ["system", "world"]:
-					myaction="--"+myaction
-				print
-				print red("!!!")+green(" Multiple actions requested... Please choose one only.")
-				print red("!!!")+" '"+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
-				print
-				sys.exit(1)
-			myaction=x[2:]
-		else:
-			print "!!! Error:",x,"is an invalid option."
-			sys.exit(1)
-	elif (not myaction) and (x in actions):
-		if x not in ["system", "world"]:
-			#print red("*** Deprecated use of action '"+x+"'")
-			if x=="rsync":
-				# "emerge rsync"
-				print
-				print red("*** 'rsync' will now install the package rsync.")
-				print red("*** To sync the tree, please use '--sync' instead.")
-				print
-				myfiles.append(x)
-				continue
-		if myaction:
-			print
-			print red("!!!")+green(" Multiple actions requested... Please choose one only.")
-			print red("!!! '")+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
-			print
-			sys.exit(1)
-		myaction=x
-	elif x[-1]=="/":
-		# this little conditional helps tab completion
-		myfiles.append(x[:-1])
-	else:
-		myfiles.append(x)
-
-if verbosity:
-	import portage_metadata
-
-if "moo" in myfiles:
-	print """
-
-  Gentoo (""" + os.uname()[0] + """)
-
- _______________________
-< Have you mooed today? >
- -----------------------
-        \   ^__^
-         \  (oo)\_______
-            (__)\       )\/\  
-                ||----w |
-                ||     ||
-
-"""
-
-if (myaction in ["world", "system"]) and myfiles:
-	print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
-	sys.exit(1)
-
-for x in myfiles:
-	if (x.endswith(".ebuild") or x.endswith(".tbz2")) and os.path.exists(os.path.abspath(x)):
-		print "emerging by path implies --oneshot... adding --oneshot to options."
-		print red("\n*** emerging by path is broken and may not always work!!!\n")
-		break
-
-if ("--tree" in myopts) and ("--columns" in myopts):
-	print "emerge: can't specify both of \"--tree\" and \"--columns\"."
-	sys.exit(1)
-
-# Always create packages if FEATURES=buildpkg
-# Imply --buildpkg if --buildpkgonly
-if ("buildpkg" in portage.features) or ("--buildpkgonly" in myopts):
-	if "--buildpkg" not in myopts:
-		myopts.append("--buildpkg")
-
-# --tree only makes sense with --pretend
-if "--tree" in myopts and not (("--pretend" in myopts) or ("--ask" in myopts)):
-	print ">>> --tree implies --pretend... adding --pretend to options."
-	myopts.append("--pretend")
-
-# Also allow -S to invoke search action (-sS)
-if ("--searchdesc" in myopts):
-	if myaction and myaction != "search":
-		myfiles.append(myaction)
-	if "--search" not in myopts:
-		myopts.append("--search")
-	myaction = "search"
-
-# Always try and fetch binary packages if FEATURES=getbinpkg
-if ("getbinpkg" in portage.features):
-	myopts.append("--getbinpkg")
-
-if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts):
-	myopts.append("--usepkgonly")
-
-if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts):
-	myopts.append("--getbinpkg")
-
-if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts):
-	myopts.append("--usepkg")
-
-# Also allow -K to apply --usepkg/-k
-if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts):
-	myopts.append("--usepkg")
-
-# Also allow -l to apply --pretend/-p, but if already in --ask mode
-if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)):
-	print ">>> --changelog implies --pretend... adding --pretend to options."
-	myopts.append("--pretend")
-
-# Allow -p to remove --ask
-if ("--pretend" in myopts) and ("--ask" in myopts):
-	print ">>> --pretend disables --ask... removing --ask from options."
-	myopts.remove("--ask")
-
-# forbid --ask when not in a terminal
-# note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
-if ("--ask" in myopts) and (not sys.stdout.isatty()):
-	portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n")
-	sys.exit(1)
-
-# Set so that configs will be merged regardless of remembered status
-if ("--noconfmem" in myopts):
-	portage.settings.unlock()
-	portage.settings["NOCONFMEM"]="1"
-	portage.settings.backup_changes("NOCONFMEM")
-	portage.settings.lock()
-
-# Set various debug markers... They should be merged somehow.
-if ("--debug" in myopts):
-	portage.settings.unlock()
-	portage.settings["PORTAGE_DEBUG"]="1"
-	portage.settings.backup_changes("PORTAGE_DEBUG")
-	portage.debug=1
-	portage.settings.lock()
-
-CLEAN_DELAY = 5
-EMERGE_WARNING_DELAY = 10
-if portage.settings["CLEAN_DELAY"]:
-	CLEAN_DELAY = int("0"+portage.settings["CLEAN_DELAY"])
-if portage.settings["EMERGE_WARNING_DELAY"]:
-	EMERGE_WARNING_DELAY = int("0"+portage.settings["EMERGE_WARNING_DELAY"])
-
-
-def emergelog(mystr,short_msg=None):
-	if "notitles" not in portage.features:
-		if short_msg:
-			xtermTitle(short_msg)
-		else:
-			xtermTitle(mystr)
-	try:
-		#seems odd opening a file each write...
-		if not os.path.exists("/var/log/emerge.log"):
-			mylogfile=open("/var/log/emerge.log", "w")
-			os.chmod("/var/log/emerge.log", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP)
-			os.chown("/var/log/emerge.log", portage.portage_uid, portage.portage_gid)
-		else:
-			mylogfile=open("/var/log/emerge.log", "a")
-
-		l=portage_locks.lockfile(mylogfile)
-		# seek because we may have gotten held up by the lock.
-		# if so, we may not be positioned at the end of the file.
-		mylogfile.seek(0,2)
-		mylogfile.write(str(time.time())[:10]+": "+mystr+"\n")
-		mylogfile.flush()
-		portage_locks.unlockfile(l)
-		mylogfile.close()
-	except SystemExit, e:
-		raise # Needed else can't exit
-	except Exception, e:
-		if edebug:
-			print "emergelog():",e
-		pass
-
-def emergeexit():
-	"""This gets out final log message in before we quit."""
-	if "--pretend" not in myopts:
-		emergelog(" *** terminating.")
-	if "notitles" not in portage.features:
-		xtermTitleReset()
-atexit.register(emergeexit)
-
-def emergeexitsig(signum, frame):
-	signal.signal(signal.SIGINT, signal.SIG_IGN)
-	portage.portageexit()
-	portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
-	sys.exit(100+signum)
-signal.signal(signal.SIGINT, emergeexitsig)
-
 def countdown(secs=5, doing="Starting"):
 	if secs:
 		print ">>> Waiting",secs,"seconds before starting..."
@@ -541,85 +271,6 @@ def getportageversion():
 
 	return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")"
 
-def help():
-	# Move all the help stuff out of this file.
-	emergehelp.help(myaction,myopts,havecolor)
-
-# check if root user is the current user for the actions where emerge needs this
-if ("--pretend" in myopts) or ("--fetchonly" in myopts or "--fetch-all-uri" in myopts) or (myaction=="search"):
-	if not portage.secpass:
-		if portage.wheelgid==portage.portage_gid:
-			print "emerge: wheel group membership required for \"--pretend\" and search."
-			print "emerge: wheel group use is being deprecated. Please update group and passwd to"
-			print "        include the portage user as noted above, and then use group portage."
-		else:
-			print "emerge: portage group membership required for \"--pretend\" and search."
-		sys.exit(1)
-elif "--version" in myopts:
-	print getportageversion()
-	sys.exit(0)
-elif "--help" in myopts:
-	help()
-	sys.exit(0)
-elif portage.secpass!=2:
-	if myaction in ["search", "info", "regen", "metadata"]:
-		pass
-	elif (not myaction) and (not myfiles):
-		pass
-	elif ("--pretend" in myopts) and (myaction in ["world","system","clean","prune","unmerge"]):
-		pass
-	else:
-		if "--debug" in myopts:
-			print "myaction",myaction
-			print "myopts",myopts
-		print "emerge: root access required."
-		sys.exit(1)
-
-if not "--pretend" in myopts:
-	emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
-	myelogstr=""
-	if myopts:
-		myelogstr=" ".join(myopts)
-	if myaction:
-		myelogstr+=" "+myaction
-	if myfiles:
-		myelogstr+=" "+" ".join(myfiles)
-	emergelog(" *** emerge "+myelogstr)
-
-#configure emerge engine parameters
-#
-# self:      include _this_ package regardless of if it is merged.
-# selective: exclude the package if it is merged
-# recurse:   go into the dependencies
-# empty:     pretend nothing is merged
-myparams=["self","recurse"]
-add=[]
-sub=[]
-if "--update" in myopts:
-	add.extend(["selective","empty"])
-if "--emptytree" in myopts:
-	add.extend(["empty"])
-	sub.extend(["selective"])
-if "--nodeps" in myopts:
-	sub.extend(["recurse"])
-if "--noreplace" in myopts:
-	add.extend(["selective"])
-if "--deep" in myopts:
-	add.extend(["deep"])
-if "--selective" in myopts:
-	add.extend(["selective"])
-if myaction in ["world","system"]:
-	add.extend(["selective"])
-elif myaction in ["depclean"]:
-	add.extend(["empty"])
-	sub.extend(["selective"])
-for x in add:
-	if (x not in myparams) and (x not in sub):
-		myparams.append(x)
-for x in sub:
-	if x in myparams:
-		myparams.remove(x)
-
 # search functionality
 class search:
 	
@@ -632,19 +283,22 @@ class search:
 	#
 	# public interface
 	#
-	def __init__(self):
+	def __init__(self,myopts,edebug,verbosity,spinner):
 		"""Searches the available and installed packages for the supplied search key.
 		The list of available and installed packages is created at object instantiation.
 		This makes successive searches faster."""
 		self.installcache = portage.db["/"]["vartree"]
+		self.myopts=myopts
+		self.edebug=edebug
+		self.verbosity=verbosity
+		self.spinner=spinner
 		
 	def execute(self,searchkey):
 		"""Performs the search for the supplied search key"""
-		global myopts
 		match_category = 0
 		self.searchkey=searchkey
 		self.packagematches = []
-		if "--searchdesc" in myopts:
+		if "--searchdesc" in self.myopts:
 			self.searchdesc=1
 			self.matches = {"pkg":[], "desc":[]}
 		else:
@@ -663,7 +317,7 @@ class search:
 			self.searchkey=re.sub("\+\+","\+\+",self.searchkey)
 		self.searchre=re.compile(self.searchkey.lower(),re.I)
 		for package in portage.portdb.cp_all():
-			update_spinner()
+			self.spinner.update_spinner()
 			
 			if match_category:
 				match_string  = package[:]
@@ -746,18 +400,18 @@ class search:
 					except SystemExit, e:
 						raise # Needed else can't exit
 					except Exception, e:
-						if edebug:
+						if self.edebug:
 							print "!!! Exception:",e
 						mysum[0]=" [no/bad digest]"
 						
-					if "--quiet" not in myopts:
+					if "--quiet" not in self.myopts:
 						print "     ", darkgreen("Latest version available:"),myversion
 						print "     ", self.getInstallationStatus(mycat+'/'+mypkg)
 						print "     ", darkgreen("Size of downloaded files:"),mysum[0]
 						print "     ", darkgreen("Homepage:")+"   ",homepage
 						print "     ", darkgreen("Description:"),desc
 						print "     ", darkgreen("License:")+"    ",license
-						if (verbosity):
+						if (self.verbosity):
 							# show herd/maintainers if verbosity>=1 (ie: -vv)
 							metadata_file=portage.settings["PORTDIR"] + "/" + match + "/metadata.xml"
 							if not os.path.exists(metadata_file):
@@ -835,11 +489,15 @@ def genericdict(mylist):
 		mynewdict[portage.portage_dep.dep_getkey(x)]=x
 	return mynewdict
 
-olddbapi=None
 class depgraph:
 
-	def __init__(self,myaction,myopts):
-		global olddbapi
+	def __init__(self,myaction,myopts,myparams,edebug,verbosity,EMERGE_WARNING_DELAY,spinner):
+		self.myparams=myparams
+		self.myopts=myopts
+		self.edebug=edebug
+		self.verbosity=verbosity
+		self.EMERGE_WARNING_DELAY=EMERGE_WARNING_DELAY
+		self.spinner=spinner
 		self.pkgsettings = portage.config(clone=portage.settings)
 		if not self.pkgsettings["ARCH"]:
 			portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n"))
@@ -854,17 +512,17 @@ class depgraph:
 		self.outdatedpackages=[]
 		self.mydbapi={}
 		self.mydbapi["/"] = portage.fakedbapi()
-		if "empty" not in myparams:
+		if "empty" not in self.myparams:
 			for pkg in portage.db["/"]["vartree"].getallcpv():
 				self.mydbapi["/"].cpv_inject(pkg)
 		if portage.root != "/":
 			self.mydbapi[portage.root] = portage.fakedbapi()
-			if "empty" not in myparams:
+			if "empty" not in self.myparams:
 				for pkg in portage.db[portage.root]["vartree"].getallcpv():
 					self.mydbapi[portage.root].cpv_inject(pkg)
 		
-		if "--usepkg" in myopts:
-			portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts))
+		if "--usepkg" in self.myopts:
+			portage.db["/"]["bintree"].populate(("--getbinpkg" in self.myopts), ("--getbinpkgonly" in self.myopts))
 
 	def create(self,mybigkey,myparent=None,addme=1,myuse=None):
 		"""creates the actual digraph of packages to merge.  return 1 on success, 0 on failure
@@ -887,7 +545,7 @@ class depgraph:
 			#this conditional is needed to prevent infinite recursion on already-processed deps
 			return 1
 
-		update_spinner()
+		self.spinner.update_spinner()
 
 		mytype,myroot,mykey=mybigkey
 		# select the correct /var database that we'll be checking against
@@ -914,13 +572,13 @@ class depgraph:
 		# this is where we add the node to the list of packages to merge
 			if not myparent:
 				# command-line specified or part of a world list...
-				if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)):
+				if ("self" not in self.myparams) or (("selective" in self.myparams) and vardbapi.cpv_exists(mykey)):
 					# the package is on the system, so don't merge it.
 					merging=0
-			elif ("selective" in myparams) and vardbapi.cpv_exists(mykey):
+			elif ("selective" in self.myparams) and vardbapi.cpv_exists(mykey):
 				merging=0
 
-			if (merging==0 and "--newuse" in myopts and vardbapi.cpv_exists(mykey)):
+			if (merging==0 and "--newuse" in self.myopts and vardbapi.cpv_exists(mykey)):
 				iuses=portage.portdb.aux_get(mykey, ["IUSE"])[0].split()
 				old_use=vardbapi.aux_get(mykey, ["USE"])[0].split()
 				now_use=self.pkgsettings["USE"].split()
@@ -944,9 +602,9 @@ class depgraph:
 		self.mynewgraph.add_node(" ".join(mybigkey))
 		if myparent:
 			self.mynewgraph.add_relationship(myparent, " ".join(mybigkey))
-		if ("deep" not in myparams) and (not merging):
+		if ("deep" not in self.myparams) and (not merging):
 			return 1
-		elif "recurse" not in myparams:
+		elif "recurse" not in self.myparams:
 			return 1
 
 		edepend={}
@@ -1022,9 +680,9 @@ class depgraph:
 				if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x):
 					print red("\n*** You need to adjust PKGDIR to emerge this package.\n")
 					sys.exit(1)
-				if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts):
+				if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in self.myopts):
 					return (0,myfavorites)
-				elif not "--oneshot" in myopts:
+				elif not "--oneshot" in self.myopts:
 					myfavorites.append(mykey)
 			elif x[-7:]==".ebuild":
 				x = os.path.realpath(x)
@@ -1038,13 +696,13 @@ class depgraph:
 				                print red("\n*** You are emerging a masked package. It is MUCH better to use")
 				                print red("*** /etc/portage/package.* to accomplish this. See portage(5) man")
 				                print red("*** page for details.")
-				                countdown(EMERGE_WARNING_DELAY, "Continuing...")
+				                countdown(self.EMERGE_WARNING_DELAY, "Continuing...")
 				else:
 				        print red("\n*** "+x+" does not exist")
 				        sys.exit(1)
-				if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts):
+				if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in self.myopts):
 					return (0,myfavorites)
-				elif not "--oneshot" in myopts:
+				elif not "--oneshot" in self.myopts:
 					myfavorites.append(mykey)
 			else:
 				try:
@@ -1081,7 +739,7 @@ class depgraph:
 				except SystemExit, e:
 					raise # Needed else can't exit
 				except Exception, e:
-					if "--debug" in myopts:
+					if "--debug" in self.myopts:
 						raise
 					print "\n\n!!! Problem in",mykey,"dependencies."
 					print "!!!",str(e),e.__module__
@@ -1089,11 +747,11 @@ class depgraph:
 
 				if not self.mysd:
 					return (0,myfavorites)
-				elif not "--oneshot" in myopts:
+				elif not "--oneshot" in self.myopts:
 					myfavorites.append(mykey)
 
 		missing=0
-		if "--usepkgonly" in myopts:
+		if "--usepkgonly" in self.myopts:
 			for x in self.mynewgraph.get_all_nodes():
 				xs=x.split(" ")
 				if (xs[0] != "binary") and (xs[3]=="merge"):
@@ -1107,13 +765,13 @@ class depgraph:
 
 	def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None):
 		"given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure"
-		if "--debug" in myopts:
+		if "--debug" in self.myopts:
 			print
 			print "Parent:   ",myparent
 			print "Depstring:",depstring
 		if not arg:
 			#processing dependencies
-			mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkg" in myopts))
+			mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkg" in self.myopts))
 			#mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse)
 
 			if not mycheck[0]:
@@ -1141,14 +799,14 @@ class depgraph:
 		if not mymerge:
 			return 1
 
-		if "--debug" in myopts:
+		if "--debug" in self.myopts:
 			print "Candidates:",mymerge
 		for x in mymerge:
 			myk=None
 			binpkguseflags=None
 			if x[0]=="!":
 				# if this package is myself, don't append it to block list.
-				if "--debug" in myopts:
+				if "--debug" in self.myopts:
 					print "Myparent",myparent
 				if (myparent):
 					if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]):
@@ -1160,15 +818,15 @@ class depgraph:
 				#We are not processing a blocker but a normal dependency
 				myeb=None
 				myeb_matches = portage.portdb.xmatch("match-visible",x)
-				if ("--usepkgonly" not in myopts):
+				if ("--usepkgonly" not in self.myopts):
 					myeb=portage.best(myeb_matches)
 				
 				myeb_pkg=None
-				if ("--usepkg" in myopts):
+				if ("--usepkg" in self.myopts):
 					# The next line assumes the binarytree has been populated.
 					# XXX: Need to work out how we use the binary tree with roots.
 					myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x)
-					if ("--usepkgonly" not in myopts):
+					if ("--usepkgonly" not in self.myopts):
 						# Remove any binary package entries that are masked in the portage tree (#55871)
 						for idx in range(len(myeb_pkg_matches)-1,-1,-1):
 							if myeb_pkg_matches[idx] not in myeb_matches:
@@ -1186,7 +844,7 @@ class depgraph:
 						xfrom = '(dependency required by '+green('"'+myparent.split()[2]+'"')+red(' ['+myparent.split()[0]+"])")
 					alleb=portage.portdb.xmatch("match-all",x)
 					if alleb:
-						if "--usepkgonly" not in myopts:
+						if "--usepkgonly" not in self.myopts:
 							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:"
 							oldcomment = ""
@@ -1211,7 +869,7 @@ class depgraph:
 						print
 					return 0
 
-				if "--debug" in myopts:
+				if "--debug" in self.myopts:
 					print "ebuild:",myeb
 					print "binpkg:",myeb_pkg
 
@@ -1253,10 +911,10 @@ class depgraph:
 			else:
 				#if mysource is not set, then we are a command-line dependency and should not be added
 				#if --onlydeps is specified.
-				if not self.create(myk,myparent,"--onlydeps" not in myopts,myuse=binpkguseflags):
+				if not self.create(myk,myparent,"--onlydeps" not in self.myopts,myuse=binpkguseflags):
 					return 0
 
-		if "--debug" in myopts:
+		if "--debug" in self.myopts:
 			print "Exiting...",myparent
 		return 1
 		
@@ -1280,20 +938,19 @@ class depgraph:
 		return retlist
 
 	def xcreate(self,mode="system"):
-		global syslist
 		if mode=="system":
-			mylist=syslist
+			mylist=getlist("system")
 		else:
 			#world mode
 			worldlist=getlist("world")
-			sysdict=genericdict(syslist)
+			sysdict=genericdict(getlist("system"))
 			worlddict=genericdict(worldlist)
 			#we're effectively upgrading sysdict to contain all new deps from worlddict
 			for x in worlddict.keys():
 				#only add the world node if the package is:
 				#actually installed -- this prevents the remerging of already unmerged packages when we do a world --update;
 				#actually available -- this prevents emerge from bombing out due to no match being found (we want a silent ignore)
-				if "empty" in myparams:
+				if "empty" in self.myparams:
 					if portage.db["/"]["vartree"].dbapi.match(x):
 						sysdict[x]=worlddict[x]
 				elif portage.db[portage.root]["vartree"].dbapi.match(x):
@@ -1312,12 +969,12 @@ class depgraph:
 			#THIS NEXT BUNCH OF CODE NEEDS TO BE REPLACED TO SUPPORT WORLD ANTI-DEPS
 			#if mydep2[0]=="!":, etc.
 			binpkguseflags = None
-			if "--usepkg" in myopts:
+			if "--usepkg" in self.myopts:
 				mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep)
 				if myeb==mypk:
 					myk=["binary",portage.root,mypk]
 					binpkguseflags=portage.db[portage.root]["bintree"].get_use(mypk)
-				elif "--usepkgonly" in myopts:
+				elif "--usepkgonly" in self.myopts:
 					if not mypk:
 						self.missingbins += [myeb]
 						myk=["binary",portage.root,myeb]
@@ -1351,7 +1008,7 @@ class depgraph:
 				print
 				sys.exit(1)
 
-			if "--usepkg" in myopts:
+			if "--usepkg" in self.myopts:
 				mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep)
 				if myeb==mypk:
 					myk="binary "+portage.root+" "+mypk
@@ -1367,7 +1024,7 @@ class depgraph:
 		p=[]
 		totalsize=0
 
-		if verbosity:
+		if self.verbosity:
 			overlays = portage.settings['PORTDIR_OVERLAY'].split()
 		
 		i = 0
@@ -1410,9 +1067,9 @@ class depgraph:
 				#we need to use "--emptrytree" testing here rather than "empty" param testing because "empty"
 				#param is used for -u, where you still *do* want to see when something is being upgraded.
 				myoldbest=""
-				if (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]):
+				if (not "--emptytree" in self.myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]):
 					addl="  "+yellow("R")+fetch+"  "
-				elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]):
+				elif (not "--emptytree" in self.myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]):
 					if x[0] == "binary":
 						mynewslot=portage.db["/"]["bintree"].getslot(x[2])
 					elif x[0] == "ebuild":
@@ -1432,7 +1089,7 @@ class depgraph:
 						# New slot, mark it new.
 						addl=" "+green("NS")+fetch+"  "
 
-					if "--changelog" in myopts:
+					if "--changelog" in self.myopts:
 						changelogs.extend(self.calc_changelog(
 							portage.portdb.findname(x[2]),
 							portage.db["/"]["vartree"].dep_bestmatch('/'.join(portage_versions.catpkgsplit(x[2])[:2])),
@@ -1442,7 +1099,7 @@ class depgraph:
 					addl=" "+green("N")+" "+fetch+"  "
 
 				verboseadd=""
-				if verbosity > 0:
+				if self.verbosity > 0:
 					# iuse verbose
 					try:
 						if x[0] == "binary":
@@ -1488,8 +1145,8 @@ class depgraph:
 						else:
 							iuse=blue("-"+ebuild_iuse)
 						verboseadd+=iuse+usechange+" "
-					if (verbosity and "--pretend" not in myopts) or \
-						(verbosity > 1 and "--pretend" in myopts):
+					if (self.verbosity and "--pretend" not in self.myopts) or \
+						(self.verbosity > 1 and "--pretend" in self.myopts):
 						# show herd/maintainers.
 						metadata_file=portage.settings["PORTDIR"] + "/" + portage.portage_versions.pkgsplit(x[2])[0] + "/metadata.xml"
 	        				if not os.path.exists(metadata_file):
@@ -1513,7 +1170,7 @@ class depgraph:
 					# size verbose
 					mysize=0
 					if x[0] == "ebuild" and x[-1]!="nomerge":
-						myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug)
+						myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=self.edebug)
 						if myfilesdict==None:
 							myfilesdict="[empty/missing/bad digest]"
 						else:
@@ -1558,7 +1215,7 @@ class depgraph:
 					myoldbest=blue("["+myoldbest+"]")
 
 				if x[1]!="/":
-					if "--columns" in myopts:
+					if "--columns" in self.myopts:
 						myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
 						if (newlp-nc_len(myprint)) > 0:
 							myprint=myprint+(" "*(newlp-nc_len(myprint)))
@@ -1570,7 +1227,7 @@ class depgraph:
 					else:
 						myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd
 				else:
-					if "--columns" in myopts:
+					if "--columns" in self.myopts:
 						myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
 						if (newlp-nc_len(myprint)) > 0:
 							myprint=myprint+(" "*(newlp-nc_len(myprint)))
@@ -1585,23 +1242,23 @@ class depgraph:
 							myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd
 				p.append(myprint)
 
-			if ("--tree" not in myopts):
+			if ("--tree" not in self.myopts):
 				mysplit=portage_versions.pkgsplit(x[2])
 	
 				# XXX mysplit _can_ be None.... Why?
 				if mysplit and (len(mysplit)==3):
-					if "--emptytree" not in myopts:
+					if "--emptytree" not in self.myopts:
 						if mysplit[0]=="sys-apps/portage":
 							if (mysplit[1]+mysplit[2]!=portage.VERSION and
 								"livecvsportage" not in portage.settings.features):
 								if mylist.index(x)<len(mylist)-1:
 									p.append(red("*** Portage will stop merging at this point and reload itself,"))
 									p.append(red("    recalculate dependencies, and complete the merge."))
-									if "--update" not in myopts:
+									if "--update" not in self.myopts:
 										p.append(darkgreen("    You may avoid the remerging of packages by updating portage on its own."))
 									print
 					else:
-						if mysplit[0]=="sys-apps/portage" and ("--emptytree" in myopts):
+						if mysplit[0]=="sys-apps/portage" and ("--emptytree" in self.myopts):
 							if mysplit[1]+mysplit[2]!=portage.VERSION:
 								p.append(red("***")+" Please update portage to the above version before proceeding.")
 								p.append("    Failure to do so may result in failed or improper merges.")
@@ -1612,7 +1269,7 @@ class depgraph:
 		for x in p:
 			print x
 
-		if verbosity:
+		if self.verbosity:
 			print
 			print "Total size of downloads: "+format_size(totalsize)
 			if overlays and display_overlays:
@@ -1622,7 +1279,7 @@ class depgraph:
 					y=y+1
 					print " "+teal("["+str(y)+"]"),x
 		
-		if "--changelog" in myopts:
+		if "--changelog" in self.myopts:
 			print
 			for revision,text in changelogs:
 				print bold('*'+revision)
@@ -1697,29 +1354,29 @@ class depgraph:
 			if ret:
 				return False
 
-	def merge(self,mylist):
+	def merge(self,mylist,favorites):
 		returnme=0
 		mymergelist=[]
 
 		#check for blocking dependencies
-		if ("--fetchonly" not in myopts) and ("--buildpkgonly" not in myopts):
+		if ("--fetchonly" not in self.myopts) and ("--buildpkgonly" not in self.myopts):
 			for x in mylist:
 				if x[0]=="blocks":
 					print "\n!!! Error: the "+x[2]+" package conflicts with another package."
 					print   "!!!        both can't be installed on the same system together."
 					print   "!!!        Please use 'emerge --pretend' to determine blockers."
 					print
-					if ("--pretend" not in myopts):
+					if ("--pretend" not in self.myopts):
 						sys.exit(1)
 
 		#buildsyspkg: I need mysysdict also on resume (moved from the else block)
-		mysysdict=genericdict(syslist)
-		if ("--resume" in myopts):
+		mysysdict=genericdict(getlist("system"))
+		if ("--resume" in self.myopts):
 			# We're resuming.
 			print green("*** Resuming merge...")
-			emergelog(" *** Resuming merge...")
+			self.emergelog(" *** Resuming merge...")
 			mymergelist=portage.mtimedb["resume"]["mergelist"][:]
-			if ("--skipfirst" in myopts) and mymergelist:
+			if ("--skipfirst" in self.myopts) and mymergelist:
 				del portage.mtimedb["resume"]["mergelist"][0]
 				del mymergelist[0]
 		else:
@@ -1731,16 +1388,16 @@ class depgraph:
 					mymergelist.append(mylist[x])
 				else:
 					myfavkey=portage.cpv_getkey(mylist[x][2])
-					if "--onlydeps" in myopts:
+					if "--onlydeps" in self.myopts:
 						continue
 					# Add to the world file. Since we won't be able to later.
-					if (not "--fetchonly" in myopts) and (myfavkey in favorites):
+					if (not "--fetchonly" in self.myopts) and (myfavkey in favorites):
 						#don't record if already in system profile or already recorded
 						if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
 							#we don't have a favorites entry for this package yet; add one
 							myfavdict[myfavkey]=myfavkey
 							print ">>> Recording",myfavkey,"in \"world\" favorites file..."
-			if not "--fetchonly" in myopts:
+			if not "--fetchonly" in self.myopts:
 				portage.writedict(myfavdict,portage.root+portage.WORLD_FILE,writekey=0)
 
 			portage.mtimedb["resume"]["mergelist"]=mymergelist[:]
@@ -1759,7 +1416,7 @@ class depgraph:
 		# parallel-fetch should only kick in when not pretending, emerge isn't just fetching, 
 		# and there is more then one node being processed.
 		if "parallel-fetch" in self.pkgsettings["FEATURES"] and not \
-			("--ask" in myopts or "--pretend" in myopts or "--fetchonly" in myopts) and \
+			("--ask" in self.myopts or "--pretend" in self.myopts or "--fetchonly" in self.myopts) and \
 			len(mymergelist) > 1:
 			if "distlocks" not in self.pkgsettings["FEATURES"]:
 				print red("!!!")
@@ -1780,7 +1437,7 @@ class depgraph:
 				print ">>> parallel fetching is in the house, hizzay"
 				print ">>> represent."
 				portage_exec.spawn_func(self.__fetch,[mymergelist],{"verbosity":1,\
-					"fetchall":("--fetchalluri" in myopts)},returnpid=True,fd_pipes={1:1,2:2})
+					"fetchall":("--fetchalluri" in self.myopts)},returnpid=True,fd_pipes={1:1,2:2})
 #				time.sleep(2)
 
 		mergecount=0
@@ -1791,9 +1448,9 @@ class depgraph:
 			if x[0]=="blocks":
 				pkgindex=3
 			y=portage.portdb.findname(x[pkgindex])
-			if not "--pretend" in myopts:
+			if not "--pretend" in self.myopts:
 				print ">>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+")",x[pkgindex],"to",x[1]
-				emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1])
+				self.emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1])
 
 			self.pkgsettings["EMERGE_FROM"] = x[0][:]
 			self.pkgsettings.backup_changes("EMERGE_FROM")
@@ -1802,43 +1459,43 @@ class depgraph:
 			issyspkg = ("buildsyspkg" in myfeat) \
 					and x[0] != "blocks" \
 					and mysysdict.has_key(portage.cpv_getkey(x[2])) \
-					and not ("--buildpkg" in myopts)
+					and not ("--buildpkg" in self.myopts)
 			if x[0] in ["ebuild","blocks"]:
-				if (x[0]=="blocks") and ("--fetchonly" not in myopts):
+				if (x[0]=="blocks") and ("--fetchonly" not in self.myopts):
 					raise Exception, "Merging a blocker"
-				elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts):
-					if ("--fetch-all-uri" in myopts):
-						retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1)
+				elif ("--fetchonly" in self.myopts) or ("--fetch-all-uri" in self.myopts):
+					if ("--fetch-all-uri" in self.myopts):
+						retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,self.edebug,("--pretend" in self.myopts),fetchonly=1,fetchall=1)
 					else:
-						retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1)
+						retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,self.edebug,("--pretend" in self.myopts),fetchonly=1)
 					if retval:
 						print
 						print "!!! Fetch for",y,"failed, continuing..."
 						print	
 						returnme=1
 					continue
-				elif "--buildpkg" in myopts or issyspkg:
+				elif "--buildpkg" in self.myopts or issyspkg:
 					#buildsyspkg: Sounds useful to display something, but I don't know if we should also log it
 					if issyspkg:
 						print ">>> This is a system package, let's pack a rescue tarball."
 						#emergelog(">>> This is a system package, let's pack a rescue tarball.")
 					#create pkg, then merge pkg
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean"
-					emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1)
+					self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,self.edebug,cleanup=1)
 					if retval:
 						sys.exit(1)
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile"
-					emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-					retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug)
+					self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+					retval=portage.doebuild(y,"package",myroot,self.pkgsettings,self.edebug)
 					if retval:
 						sys.exit(1)
 					#dynamically update our database
-					if "--buildpkgonly" not in myopts:
+					if "--buildpkgonly" not in self.myopts:
 						portage.db[portage.root]["bintree"].inject(x[2])
 						mytbz2=portage.db[portage.root]["bintree"].getname(x[2])
 						short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge"
-						emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+						self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
 
 						self.pkgsettings["EMERGE_FROM"] = "binary"
 						self.pkgsettings.backup_changes("EMERGE_FROM")
@@ -1848,13 +1505,13 @@ class depgraph:
 							sys.exit(1)
 				else:
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean"
-					emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1)
+					self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,self.edebug,cleanup=1)
 					if retval:
 						sys.exit(1)
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile"
-					emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-					retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug)
+					self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+					retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,self.edebug)
 					if retval:
 						sys.exit(1)
 					#dynamically update our database	
@@ -1863,48 +1520,48 @@ class depgraph:
 				mytbz2=portage.db[portage.root]["bintree"].getname(x[2])
 				if portage.db[portage.root]["bintree"].isremote(x[2]):
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch"
-					emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
+					self.emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
 					portage.db[portage.root]["bintree"].gettbz2(x[2])
 
-				if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts):
+				if ("--fetchonly" in self.myopts) or ("--fetch-all-uri" in self.myopts):
 					continue
 				
 				short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary"
-				emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
+				self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
 				retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings)
 				if retval==None:
 					sys.exit(1)
 				#need to check for errors
-			if "--buildpkgonly" not in myopts:
+			if "--buildpkgonly" not in self.myopts:
 				portage.db[x[1]]["vartree"].inject(x[2])
 				myfavkey=portage.cpv_getkey(x[2])
-				if (not "--fetchonly" in myopts) and (not "--fetch-all-uri" in myopts) and (myfavkey in favorites):
+				if (not "--fetchonly" in self.myopts) and (not "--fetch-all-uri" in self.myopts) and (myfavkey in favorites):
 					myfavs=portage.grabfile(myroot+portage.WORLD_FILE)
 					myfavdict=genericdict(myfavs)
-					mysysdict=genericdict(syslist)
+					mysysdict=genericdict(getlist("system"))
 					#don't record if already in system profile or already recorded
-					if ("--update" not in myopts or not portage.db[portage.root]["vartree"].dbapi.match(myfavkey)) and \
+					if ("--update" not in self.myopts or not portage.db[portage.root]["vartree"].dbapi.match(myfavkey)) and \
 					    (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
 						#we don't have a favorites entry for this package yet; add one
 						myfavdict[myfavkey]=myfavkey
 						print ">>> Recording",myfavkey,"in \"world\" favorites file..."
-						emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")")
+						self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")")
 						portage.writedict(myfavdict,myroot+portage.WORLD_FILE,writekey=0)
 
 				if ("noclean" not in portage.features) and (x[0] != "binary"):
 					short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean Post"
-					emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
-					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1)
+					self.emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg)
+					retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,self.edebug,cleanup=1)
 					if retval:
 						sys.exit(1)
 			
-				if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
+				if ("--pretend" not in self.myopts) and ("--fetchonly" not in self.myopts) and ("--fetch-all-uri" not in self.myopts):
 					# Clean the old package that we have merged over top of it.
 					xsplit=portage.portage_versions.pkgsplit(x[2])
-					emergelog(" >>> AUTOCLEAN: "+xsplit[0])
-					retval=unmerge("clean", [xsplit[0]])
+					self.emergelog(" >>> AUTOCLEAN: "+xsplit[0])
+					retval=self.unmerge("clean", [xsplit[0]])
 					if not retval:
-						emergelog(" --- AUTOCLEAN: Nothing unmerged.")
+						self.emergelog(" --- AUTOCLEAN: Nothing unmerged.")
 
 					# Figure out if we need a restart.
 					mysplit=portage.portage_versions.pkgsplit(x[2])
@@ -1925,7 +1582,7 @@ class depgraph:
 										del myargv[myr]
 										myr-=1
 									myr+=1
-								emergelog(" *** RESTARTING emerge via exec() after change of portage version.")
+								self.emergelog(" *** RESTARTING emerge via exec() after change of portage version.")
 								portage.portageexit()
 								badlongopts = ["--ask","--tree","--changelog"]
 								badshortopts = ["a","t","l"]
@@ -1946,8 +1603,8 @@ class depgraph:
 										mynewargv += [arg]
 								os.execv("/usr/lib/portage/bin/emerge", mynewargv)
 
-			if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
-				emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1])
+			if ("--pretend" not in self.myopts) and ("--fetchonly" not in self.myopts) and ("--fetch-all-uri" not in self.myopts):
+				self.emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1])
 			
 			# Unsafe for parallel merges
 			del portage.mtimedb["resume"]["mergelist"][0]
@@ -1956,31 +1613,40 @@ class depgraph:
 			self.thread.join()
 			self.thread=None
 
-		emergelog(" *** Finished. Cleaning up...")
+		self.emergelog(" *** Finished. Cleaning up...")
 
 		# We're out of the loop... We're done. Delete the resume data.
 		if portage.mtimedb.has_key("resume"):
 			del portage.mtimedb["resume"]
 
-		if ("--pretend" not in myopts):
-			if ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts):
+		if ("--pretend" not in self.myopts):
+			if ("--fetchonly" not in self.myopts) and ("--fetch-all-uri" not in self.myopts):
 				if (mergecount>0):
 					if retval:
 						portage.env_update(portage.root)
 
 		#by doing an exit this way, --fetchonly can continue to try to
 		#fetch everything even if a particular download fails.
-		if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
+		if "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts:
 			if returnme:
 				print "\n\n!!! Some fetch errors were encountered.  Please see above for details.\n\n"
 				sys.exit(returnme)
 			else:
 				sys.exit(0)
 
+	def emergelog(self,mystr,short_msg=None):
+		emergelog(self.edebug,mystr,short_msg)
+
+	def unmerge(self,unmerge_action,unmerge_files):
+		return unmerge(self.myopts, self.edebug, self.EMERGE_WARNING_DELAY, unmerge_action, unmerge_files)
+
 class graph_display:
 	
-	def __init__(self, mygraph):
+	def __init__(self,mygraph,myopts,edebug,verbosity):
 		self.graph = mygraph.clone()
+		self.myopts=myopts
+		self.edebug=edebug
+		self.verbosity=verbosity
 		
 		merge_nodes = self.graph.get_all_nodes()
 		for x in range(len(merge_nodes)-1,-1,-1):
@@ -2208,7 +1874,7 @@ class graph_display:
 	def format_size(self, mydep):
 		mysize = 0
 		if mydep[0] == "ebuild" and mydep[3] != "nomerge":
-			myfilesdict=portage.portdb.getfetchsizes(mydep[2], useflags=self.use_flags(mydep), debug=edebug)
+			myfilesdict=portage.portdb.getfetchsizes(mydep[2], useflags=self.use_flags(mydep), debug=self.edebug)
 			if myfilesdict:
 				for myfetchfile in myfilesdict.keys():
 					mysize += myfilesdict[myfetchfile]
@@ -2308,13 +1974,13 @@ class graph_display:
 		
 		funclist = [self.format_summary, self.format_cpv, self.format_old_version]
 		postfuncs = []
-		if verbosity:
+		if self.verbosity:
 			funclist += [self.format_flags]
-			if verbosity >= 2:
+			if self.verbosity >= 2:
 				funclist += [self.format_metadata]
 			funclist += [self.format_size, self.format_overlay]
 			postfuncs += [self.post_size_msg, self.post_overlay_msg]
-		if "--changelog" in myopts:
+		if "--changelog" in self.myopts:
 			funclist += [self.format_changelog]
 			postfuncs += [self.post_changelog_msg]
 		
@@ -2344,13 +2010,13 @@ class graph_display:
 		funclist = [self.format_summary, self.format_name,
 		            self.format_new_version, self.format_old_version]
 		postfuncs = []
-		if verbosity:
+		if self.verbosity:
 			funclist += [self.format_flags]
-			if verbosity >= 2:
+			if self.verbosity >= 2:
 				funclist += [self.format_metadata]
 			funclist += [self.format_size, self.format_overlay]
 			postfuncs += [self.post_size_msg, self.post_overlay_msg]
-		if "--changelog" in myopts:
+		if "--changelog" in self.myopts:
 			funclist += [self.format_changelog]
 			postfuncs += [self.post_changelog_msg]
 		
@@ -2394,13 +2060,13 @@ class graph_display:
 		
 		funclist = [self.format_cpv, self.format_old_version]
 		postfuncs = []
-		if verbosity:
+		if self.verbosity:
 			funclist += [self.format_flags]
-			if verbosity >= 2:
+			if self.verbosity >= 2:
 				funclist += [self.format_metadata]
 			funclist += [self.format_size, self.format_overlay]
 			postfuncs += [self.post_size_msg, self.post_overlay_msg]
-		if "--changelog" in myopts:
+		if "--changelog" in self.myopts:
 			funclist += [self.format_changelog]
 			postfuncs += [self.post_changelog_msg]
 		
@@ -2446,10 +2112,7 @@ class graph_display:
 			if msg:
 				print msg
 
-
-
-
-def unmerge(unmerge_action, unmerge_files):
+def unmerge(myopts, edebug, EMERGE_WARNING_DELAY, unmerge_action, unmerge_files):
 	candidate_catpkgs=[]
 	global_unmerge=0
 	
@@ -2460,8 +2123,7 @@ def unmerge(unmerge_action, unmerge_file
 		if mycp in portage.settings.virtuals:
 			syslist.extend(portage.settings.virtuals[mycp])
 		syslist.append(mycp)
-	
-	global myopts	
+		
 	mysettings = portage.config(clone=portage.settings)
 	
 	if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files:
@@ -2570,11 +2232,10 @@ def unmerge(unmerge_action, unmerge_file
 						pkgmap[mykey]["selected"].append(y)
 						numselected=numselected+len(mymatch)
 				if not (pkgmap[mykey]["protected"] or pkgmap[mykey]["omitted"]) and \
-				   (mykey in syslist+["sys-apps/portage"]):
+				(mykey in syslist+["sys-apps/portage"]):
 					print red("\a\n\n!!! Trying to unmerge package(s) in system profile. '%s'" % (mykey))
 					print yellow("\a!!! This could be damaging to your system.\n")
 					if "--pretend" not in myopts:
-						global EMERGE_WARNING_DELAY
 						countdown(EMERGE_WARNING_DELAY,red("Press Ctrl-C to Stop"))
 
 		else:
@@ -2615,8 +2276,8 @@ def unmerge(unmerge_action, unmerge_file
 	for x in keys:
 		for y in localtree.dep_match(x):
 			if y not in pkgmap[x]["omitted"] and \
-			   y not in pkgmap[x]["selected"] and \
-			   y not in pkgmap[x]["protected"]:
+			y not in pkgmap[x]["selected"] and \
+			y not in pkgmap[x]["protected"]:
 				pkgmap[x]["omitted"].append(y)
 		if global_unmerge and not pkgmap[x]["selected"]:
 			#avoid cluttering the preview printout with stuff that isn't getting unmerged
@@ -2655,20 +2316,22 @@ def unmerge(unmerge_action, unmerge_file
 			return 0
 	#the real unmerging begins, after a short delay....
 	
-	global CLEAN_DELAY
+	CLEAN_DELAY = 5
+	if portage.settings["CLEAN_DELAY"]:
+		CLEAN_DELAY = int("0"+portage.settings["CLEAN_DELAY"])
 	countdown(CLEAN_DELAY, ">>> Unmerging")
 
 	for x in pkgmap.keys():
 		for y in pkgmap[x]["selected"]:
 			print ">>> Unmerging "+y+"..."
-			emergelog("=== Unmerging... ("+y+")")
+			emergelog(edebug,"=== Unmerging... ("+y+")")
 			mysplit=y.split("/")
 			#unmerge...
 			retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,mysettings,unmerge_action not in ["clean","prune"])
 			if retval:
-				emergelog(" !!! unmerge FAILURE: "+y)
+				emergelog(edebug," !!! unmerge FAILURE: "+y)
 			else:
-				emergelog(" >>> unmerge success: "+y)
+				emergelog(edebug," >>> unmerge success: "+y)
 	#run ldconfig, etc...
 	portage.env_update(portage.root)
 	if not numselected:
@@ -2676,7 +2339,6 @@ def unmerge(unmerge_action, unmerge_file
 	else:
 		return 1
 
-
 def chk_updated_info_files():
 	root=portage.root
 
@@ -2759,22 +2421,6 @@ def chk_updated_info_files():
 			else:
 				print " "+green("*")+" Processed",icount,"info files."
 
-
-def post_emerge(retval=0):
-	global myopts
-	os.chdir("/")
-	if "--pretend" in myopts:
-		sys.exit(retval)
-
-	emergelog(" *** exiting successfully.")
-
-	if "noinfo" not in portage.settings.features:
-		chk_updated_info_files()
-
-	chk_updated_cfg_files()
-
-	sys.exit(retval)
-
 def chk_updated_cfg_files():
 	if portage.settings["CONFIG_PROTECT"]:
 		#number of directories with some protect files in them
@@ -2794,719 +2440,1107 @@ def chk_updated_cfg_files():
 			print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
 		print
 
-# general options that should be taken into account before any action
-if "--debug" in myopts:
-	edebug=1
-
-if myaction in ["sync","rsync","metadata"] and (not "--help" in myopts):
-	if "--pretend" in myopts:
-		print "emerge: \"sync\" actions do not support \"--pretend.\""
-		sys.exit(1)
-
-	emergelog(" === "+str(myaction))
-	myportdir=portage.settings["PORTDIR"]
-	if myportdir[-1]=="/":
-		myportdir=myportdir[:-1]
-	if not os.path.exists(myportdir):
-		print ">>>",myportdir,"not found, creating it."
-		os.makedirs(myportdir,0755)	
-	syncuri=portage.settings["SYNC"].rstrip()
-	os.umask(0022)
-
-	sync_verbosity=0
-	if "--quiet" in myopts:
-		sync_verbosity = 1
-	elif "--verbose" in myopts:
-		sync_verbosity = 3
-	else:
-		sync_verbosity = 2
-
-	print "sync_verbosity=",sync_verbosity
-	tmpservertimestampfile = None
-
-	protocol,host_uri = sync.parseSyncUri(syncuri)
-	print "host_uri=",host_uri
-
-	if myaction == "metadata":
-		if "--ask" in myopts:
-			if userquery("Are you sure?") == "No":
-				#userquery("Are you sure you should be using *NIX?",["Definately Not"])
-				sys.exit(1)
-		print "skipping sync"
-		updatecache_flg = True
-		tmpservertimestampfile = None
-	elif protocol == "rsync":
-		mytimeout=180
-		if portage.settings.has_key("RSYNC_TIMEOUT"):
+class emerge_cmd:
+	
+	def __init__(self):
+		self.myaction=None
+		self.myopts=[]
+		self.myfiles=[]
+		self.myparams=None
+		self.edebug=0
+		self.verbosity=0
+		self.EMERGE_WARNING_DELAY = 10
+		if portage.settings["EMERGE_WARNING_DELAY"]:
+			self.EMERGE_WARNING_DELAY = int("0"+portage.settings["EMERGE_WARNING_DELAY"])
+		
+		spinner=stdout_spinner()
+		
+		if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]):
+			nocolor()
+		
+		if portage.settings.has_key("PORTAGE_NICENESS"):
 			try:
-				mytimeout=int(portage.settings["RSYNC_TIMEOUT"])
+				os.nice(int(portage.settings["PORTAGE_NICENESS"]))
 			except SystemExit, e:
 				raise # Needed else can't exit
-			except:
-				pass
-
-		syncer=sync.rsync.RsyncHost(host_uri)
-
-		servertimestampdir  = portage.settings.depcachedir+"/"
-		servertimestampfile = portage.settings.depcachedir+"/timestamp.chk"
-		tmpservertimestampdir  = portage.settings["PORTAGE_TMPDIR"]+"/"
-		tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk"
-
-		# We only use the backup if a timestamp exists in the portdir.
-
-		content=None
-		if os.path.exists(myportdir+"/metadata/timestamp.chk"):
-			content=portage.grabfile(servertimestampfile)
-		if (not content):
-			content=portage.grabfile(myportdir+"/metadata/timestamp.chk")
-
-		if (content):
-			try:
-				mytimestamp=time.mktime(time.strptime(content[0], "%a, %d %b %Y %H:%M:%S +0000"))
-			except ValueError:
-				mytimestamp=0
-		else:
-			mytimestamp=0
-
-		if not os.path.exists(servertimestampdir):
-			os.mkdir(servertimestampdir)
-			os.chown(servertimestampdir, os.getuid(), portage.portage_gid)
-			os.chmod(servertimestampdir, 0775)
-
-		#exitcode=0
-		try:
-			maxretries=int(portage.settings["RSYNC_RETRIES"])
-		except SystemExit, e:
-			raise # Needed else can't exit
-		except:
-			maxretries=3 #default number of retries
-
-		retries=0
-		updatecache_flg=True
-
-		ips=syncer.get_ips()
-		if ips == None:
-			ips=[None]
-		while (1):
-			if (retries==0):
-				if "--ask" in myopts:
-					if userquery("Do you want to sync your Portage tree with the mirror %s at %s\n" \
-						% (host_uri, blue(str(ips[0])))+bold("?"))=="No":
+			except Exception,e:
+				print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'"
+				print "!!!",e
+		
+		#Freeze the portdbapi for enhanced performance:
+		portage.portdb.freeze()
+		
+		# Kill noauto as it will break merges otherwise.
+		while 'noauto' in portage.features:
+			portage.features.remove('noauto')
+	
+	def emergelog(self,mystr,short_msg=None):
+		emergelog(self.edebug,mystr,short_msg)
+	
+	def help(self):
+		# Move all the help stuff out of this file.
+		emergehelp.help(self.myaction,self.myopts,havecolor)
+	
+	def parse_args(self,args):
+		
+		actions=[
+		"clean", "config", "depclean",
+		"info",   "inject",   "metadata",
+		"prune", "regen",  "rsync", "search",
+		"sync",  "system", "unmerge",  "world",
+		]
+		options=[
+		"--ask",
+		"--buildpkg",     "--buildpkgonly",
+		"--changelog",    "--columns",
+		"--debug",        "--deep",
+		"--digest",
+		"--emptytree",
+		"--fetchonly",    "--fetch-all-uri",
+		"--getbinpkg",    "--getbinpkgonly",
+		"--help",         "--noconfmem",
+		"--newuse",
+		"--nodeps",       "--noreplace",
+		"--nospinner",    "--oneshot",
+		"--onlydeps",     "--pretend",
+		"--quiet",        "--resume",
+		"--searchdesc",   "--selective",
+		"--skipfirst",
+		"--tree",
+		"--update",
+		"--usepkg",       "--usepkgonly",
+		"--verbose",      "--version"
+		]
+		
+		shortmapping={
+		"1":"--oneshot",
+		"a":"--ask",
+		"b":"--buildpkg",  "B":"--buildpkgonly",
+		"c":"--clean",     "C":"--unmerge",
+		"d":"--debug",     "D":"--deep",
+		"e":"--emptytree",
+		"f":"--fetchonly", "F":"--fetch-all-uri",
+		"g":"--getbinpkg", "G":"--getbinpkgonly",
+		"h":"--help",
+		"k":"--usepkg",    "K":"--usepkgonly",
+		"l":"--changelog",
+		"n":"--noreplace", "N":"--newuse",
+		"o":"--onlydeps",  "O":"--nodeps",
+		"p":"--pretend",   "P":"--prune",
+		"q":"--quiet",
+		"s":"--search",    "S":"--searchdesc",
+				't':"--tree",
+		"u":"--update",
+		"v":"--verbose",   "V":"--version"
+		}
+		
+		# process short actions
+		tmpcmdline=args[1:]
+		#tmpcmdline.extend(portage.settings["EMERGE_OPTS"].split())
+		cmdline=[]
+		for x in tmpcmdline:
+			if x[0:1]=="-" and x[1:2]!="-":
+				for y in x[1:]:
+					if shortmapping.has_key(y):
+						if shortmapping[y]=="--verbose":
+							self.verbosity += 1
+						elif shortmapping[y] in cmdline:
+							print
+							print "*** Warning: Redundant use of",shortmapping[y]
+						else:
+							cmdline.append(shortmapping[y])
+					else:
+						print "!!! Error: -"+y+" is an invalid short action or option."
+						sys.exit(1)
+			else:
+				cmdline.append(x)
+		
+		# process the options and command arguments
+		for x in cmdline:
+			if not x:
+				continue
+			if len(x)>=2 and x[0:2]=="--":
+				if x in options:
+					self.myopts.append(x)
+				elif x[2:] in actions:
+					if x[2:]=="rsync" or x=="rsync":
+						# "emerge --rsync"
 						print
-						print "Quitting."
+						print red("*** '--rsync' has been deprecated.")
+						print red("*** Please use '--sync' instead.")
 						print
-						sys.exit(0)
-				emergelog(">>> starting rsync with "+host_uri)
-				if "--quiet" not in myopts:
-					print ">>> starting rsync with %s, ip %s..." % (host_uri,ips[0])
-			else:
-				emergelog(">>> Starting retry %d of %d with %s ip %s" % \
-					(retries,maxretries,host_uri,ips[0]))
-				print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,host_uri)
-
-			try:
-				if "--quiet" not in myopts:
-					print ">>> syncing..."
-				exitcode=syncer.sync(portage.settings,tmpservertimestampdir, \
-					remote_path=syncer.get_remote_path()+"/metadata/timestamp.chk",
-					verbosity=0, cleanup=False, ip=ips[0])
-				if exitcode==True:
-					exitcode=0
-			except (sync.rsync.RSyncSyntaxError,IOError),e:
-				print e
-				exitcode=1
-
-			if exitcode==0:
-				try:
-					servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000"))
-				except SystemExit, e:
-					raise # Needed else can't exit
-				except:
-					servertimestamp = 0
-				
-				if (servertimestamp != 0) and (servertimestamp == mytimestamp):
-					emergelog(">>> Cancelling sync -- Already current.")
-					print
-					print ">>>"
-					print ">>> Timestamps on the server and in the local repository are the same."
-					print ">>> Cancelling all further sync action. You are already up to date."
-					print ">>>"
-					print
-					sys.exit(0)
-				elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
-					emergelog(">>> Server out of date: %s" % dosyncuri)
+						x="--sync"
+					if self.myaction:
+						if self.myaction not in ["system", "world"]:
+							self.myaction="--"+self.myaction
+						print
+						print red("!!!")+green(" Multiple actions requested... Please choose one only.")
+						print red("!!!")+" '"+darkgreen(self.myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
+						print
+						sys.exit(1)
+					self.myaction=x[2:]
+				else:
+					print "!!! Error:",x,"is an invalid option."
+					sys.exit(1)
+			elif (not self.myaction) and (x in actions):
+				if x not in ["system", "world"]:
+					#print red("*** Deprecated use of action '"+x+"'")
+					if x=="rsync":
+						# "emerge rsync"
+						print
+						print red("*** 'rsync' will now install the package rsync.")
+						print red("*** To sync the tree, please use '--sync' instead.")
+						print
+						self.myfiles.append(x)
+						continue
+				if self.myaction:
 					print
-					print ">>>"
-					print ">>> SERVER OUT OF DATE: %s" % dosyncuri
-					print ">>>"
+					print red("!!!")+green(" Multiple actions requested... Please choose one only.")
+					print red("!!! '")+darkgreen(self.myaction)+"' "+red("or")+" '"+darkgreen(x)+"'"
 					print
-				elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
-					# actual sync
-					try:
-						exitcode=syncer.sync(portage.settings,portage.settings["PORTDIR"],
-							verbosity=sync_verbosity,
-							excludes=('/distfiles','/local','/packages'),ip=ips[0])
-						if exitcode==True:
-							exitcode=0
-					except (sync.rsync.RSyncSyntaxError,IOError),e:
-						print e
-						exitcode=21
-					if exitcode in [0,1,2,3,4,11,14,20,21]:
-						break
-			elif exitcode in [0,1,2,3,4,11,14,20,21]:
-				break
-
-			retries=retries+1
-
-			if retries<=maxretries:
-				print ">>> retry ..."
-				time.sleep(11)
-			else:
-				# over retries
-				# exit loop
-				updatecache_flg=False
+					sys.exit(1)
+				self.myaction=x
+			elif x[-1]=="/":
+				# this little conditional helps tab completion
+				self.myfiles.append(x[:-1])
+			else:
+				self.myfiles.append(x)
+		
+		if self.verbosity:
+			import portage_metadata
+		
+		if "moo" in self.myfiles:
+			print """
+		
+		  Gentoo (""" + os.uname()[0] + """)
+		
+		 _______________________
+		< Have you mooed today? >
+		 -----------------------
+		        \   ^__^
+		         \  (oo)\_______
+		            (__)\       )\/\  
+		                ||----w |
+		                ||     ||
+		
+"""
+		
+		if (self.myaction in ["world", "system"]) and self.myfiles:
+			print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
+			sys.exit(1)
+		
+		for x in self.myfiles:
+			if (x.endswith(".ebuild") or x.endswith(".tbz2")) and os.path.exists(os.path.abspath(x)):
+				print "emerging by path implies --oneshot... adding --oneshot to options."
+				print red("\n*** emerging by path is broken and may not always work!!!\n")
 				break
-
-		if (exitcode==0):
-			emergelog("=== Sync completed with %s: %s" % (host_uri,ips[0]))
-		elif (exitcode>0):
-			print
-			try:
-				exitcode=syncer.sync(portage.settings,portage.settings["PORTDIR"],
-					excludes=("/distfiles","/local","/packages"),verbosity=sync_verbosity,ip=ips[0])
-				if exitcode == True:
-					exitcode=0
-			except sync.rsync.RSyncSyntaxError, rsse:
-				print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure")
-				print darkred("!!!")+green(" that your SYNC statement is proper.")
-				print darkred("!!!")+green(" SYNC="+rsse.value)
-			except IOError, ie:
-				print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally")
-				print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption")
-				print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate")
-				print darkred("!!!")+green(" and try again after the problem has been fixed.")
-				print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"])
-			if exitcode==20:
-				print darkred("!!!")+green(" Rsync was killed before it finished.")
-			elif exitcode > 0:
-				print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep")
-				print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable")
-				print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a")
-				print darkred("!!!")+green(" temporary problem unless complications exist with your network")
-				print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.")
-			if exitcode:
-				print "bailing",exitcode
-				sys.exit(exitcode)
-			else:
-				updatecache_flg=True
-	elif protocol == "cvs":
-		syncer=sync.cvs.CvsHost(host_uri)
-		try:
-			print ">>> starting cvs update with "+syncuri+"..."
-			syncer.sync(portage.settings["PORTDIR"],compress=False)
-			print ">>> finished"
-		except sync.cvs.CVSIOError, ce:
-			print red("!!!")+"cvs operation failed-"
-			print str(ce)
+		
+		if ("--tree" in self.myopts) and ("--columns" in self.myopts):
+			print "emerge: can't specify both of \"--tree\" and \"--columns\"."
 			sys.exit(1)
-	elif protocol == "snapshot":
-		fetcher=portage.get_preferred_fetcher()
-		print 'host_uri=',host_uri
-		if host_uri == None:
-			print ">>> choosing a random mirror from the mirror list"
-			host_uri = portage.thirdpartymirrors["gentoo"][:]
-			random.shuffle(host_uri)
-			host_uri=host_uri[0].replace("distfiles","snapshots")
-			print ">>> using %s" % host_uri
-		if not os.path.exists(portage.settings["PORTAGE_TMPDIR"]+"/snapshots"):
-			os.mkdir(portage.settings["PORTAGE_TMPDIR"]+"/snapshots")
-		syncer=sync.snapshot.SnapshotHost(host_uri,portage.settings["DISTDIR"], \
-			portage.settings["PORTAGE_TMPDIR"]+"/snapshots", fetcher=fetcher)
-		if not syncer.sync(portage.settings["PORTDIR"],verbosity=sync_verbosity):
-			print "!!! snapshot failed"
+		
+		# Always create packages if FEATURES=buildpkg
+		# Imply --buildpkg if --buildpkgonly
+		if ("buildpkg" in portage.features) or ("--buildpkgonly" in self.myopts):
+			if "--buildpkg" not in self.myopts:
+				self.myopts.append("--buildpkg")
+		
+		# --tree only makes sense with --pretend
+		if "--tree" in self.myopts and not (("--pretend" in self.myopts) or ("--ask" in self.myopts)):
+			print ">>> --tree implies --pretend... adding --pretend to options."
+			self.myopts.append("--pretend")
+		
+		# Also allow -S to invoke search action (-sS)
+		if ("--searchdesc" in self.myopts):
+			if self.myaction and self.myaction != "search":
+				self.myfiles.append(self.myaction)
+			if "--search" not in self.myopts:
+				self.myopts.append("--search")
+			self.myaction = "search"
+		
+		# Always try and fetch binary packages if FEATURES=getbinpkg
+		if ("getbinpkg" in portage.features):
+			self.myopts.append("--getbinpkg")
+		
+		if ("--getbinpkgonly" in self.myopts) and not ("--usepkgonly" in self.myopts):
+			self.myopts.append("--usepkgonly")
+		
+		if ("--getbinpkgonly" in self.myopts) and not ("--getbinpkg" in self.myopts):
+			self.myopts.append("--getbinpkg")
+		
+		if ("--getbinpkg" in self.myopts) and not ("--usepkg" in self.myopts):
+			self.myopts.append("--usepkg")
+		
+		# Also allow -K to apply --usepkg/-k
+		if ("--usepkgonly" in self.myopts) and not ("--usepkg" in self.myopts):
+			self.myopts.append("--usepkg")
+		
+		# Also allow -l to apply --pretend/-p, but if already in --ask mode
+		if ("--changelog" in self.myopts) and not (("--pretend" in self.myopts) or ("--ask" in self.myopts)):
+			print ">>> --changelog implies --pretend... adding --pretend to options."
+			self.myopts.append("--pretend")
+		
+		# Allow -p to remove --ask
+		if ("--pretend" in self.myopts) and ("--ask" in self.myopts):
+			print ">>> --pretend disables --ask... removing --ask from options."
+			self.myopts.remove("--ask")
+		
+		# forbid --ask when not in a terminal
+		# note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
+		if ("--ask" in self.myopts) and (not sys.stdout.isatty()):
+			portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n")
+			sys.exit(1)
+		
+		# Set so that configs will be merged regardless of remembered status
+		if ("--noconfmem" in self.myopts):
+			portage.settings.unlock()
+			portage.settings["NOCONFMEM"]="1"
+			portage.settings.backup_changes("NOCONFMEM")
+			portage.settings.lock()
+		
+		# Set various debug markers... They should be merged somehow.
+		if ("--debug" in self.myopts):
+			portage.settings.unlock()
+			portage.settings["PORTAGE_DEBUG"]="1"
+			portage.settings.backup_changes("PORTAGE_DEBUG")
+			portage.debug=1
+			portage.settings.lock()
+		
+		# check if root user is the current user for the actions where emerge needs this
+		if ("--pretend" in self.myopts) or ("--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts) or (self.myaction=="search"):
+			if not portage.secpass:
+				if portage.wheelgid==portage.portage_gid:
+					print "emerge: wheel group membership required for \"--pretend\" and search."
+					print "emerge: wheel group use is being deprecated. Please update group and passwd to"
+					print "        include the portage user as noted above, and then use group portage."
+				else:
+					print "emerge: portage group membership required for \"--pretend\" and search."
+				sys.exit(1)
+		elif "--version" in self.myopts:
+			print getportageversion()
+			sys.exit(0)
+		elif "--help" in self.myopts:
+			self.help()
+			sys.exit(0)
+		elif portage.secpass!=2:
+			if self.myaction in ["search", "info", "regen", "metadata"]:
+				pass
+			elif (not self.myaction) and (not self.myfiles):
+				pass
+			elif ("--pretend" in self.myopts) and (self.myaction in ["world","system","clean","prune","unmerge"]):
+				pass
+			else:
+				if "--debug" in self.myopts:
+					print "myaction",self.myaction
+					print "myopts",self.myopts
+				print "emerge: root access required."
+				sys.exit(1)
+		
+		if not "--pretend" in self.myopts:
+			self.emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
+			myelogstr=""
+			if self.myopts:
+				myelogstr=" ".join(self.myopts)
+			if self.myaction:
+				myelogstr+=" "+self.myaction
+			if self.myfiles:
+				myelogstr+=" "+" ".join(self.myfiles)
+			self.emergelog(" *** emerge "+myelogstr)
+		
+		#configure emerge engine parameters
+		#
+		# self:      include _this_ package regardless of if it is merged.
+		# selective: exclude the package if it is merged
+		# recurse:   go into the dependencies
+		# empty:     pretend nothing is merged
+		self.myparams=["self","recurse"]
+		add=[]
+		sub=[]
+		if "--update" in self.myopts:
+			add.extend(["selective","empty"])
+		if "--emptytree" in self.myopts:
+			add.extend(["empty"])
+			sub.extend(["selective"])
+		if "--nodeps" in self.myopts:
+			sub.extend(["recurse"])
+		if "--noreplace" in self.myopts:
+			add.extend(["selective"])
+		if "--deep" in self.myopts:
+			add.extend(["deep"])
+		if "--selective" in self.myopts:
+			add.extend(["selective"])
+		if self.myaction in ["world","system"]:
+			add.extend(["selective"])
+		elif self.myaction in ["depclean"]:
+			add.extend(["empty"])
+			sub.extend(["selective"])
+		for x in add:
+			if (x not in self.myparams) and (x not in sub):
+				self.myparams.append(x)
+		for x in sub:
+			if x in self.myparams:
+				self.myparams.remove(x)
+
+		# general options that should be taken into account before any action
+		if "--debug" in self.myopts:
+			self.edebug=1
+		
+		self.spinner=stdout_spinner()
+		if not sys.stdout.isatty() or ("--nospinner" in args):
+			self.spinner.update_spinner = self.spinner.update_basic_spinner
+
+	def perform(self):
+		if self.myaction in ["sync","rsync","metadata"] and (not "--help" in self.myopts):
+			self.action_sync()
+		elif self.myaction=="regen":
+			self.emergelog(" === regen")
+			#regenerate cache entries
+			print "Regenerating cache entries... "
+			portage.portdb.regen_keys()
+			print "done!"
+		# HELP action
+		elif "config"==self.myaction:
+			self.emergelog(" === config")
+			print
+			print "Currently, \'config\' is a help option only."
+			print
+		# INFO action
+		elif "info"==self.myaction:
+			self.action_info()		
+		# SEARCH action
+		elif "search"==self.myaction:
+			if not self.myfiles:
+				print "emerge: no search terms provided."
+			else:
+				searchinstance = search(self.myopts,self.edebug,self.verbosity,self.spinner)
+				for mysearch in self.myfiles:
+					try:
+						searchinstance.execute(mysearch)
+					except re.error, comment:
+						print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment )
+						sys.exit(1)
+					searchinstance.output()
+		elif "unmerge"==self.myaction or "prune"==self.myaction or "clean"==self.myaction:
+			if 1==self.unmerge(self.myaction, self.myfiles):
+				self.post_emerge()
+			
+		elif "depclean"==self.myaction:
+			self.action_depclean()
+		
+		# "update", "system", or just process files:
+		else:
+			self.action_merge()
+	
+	def action_sync(self):
+		if "--pretend" in self.myopts:
+			print "emerge: \"sync\" actions do not support \"--pretend.\""
 			sys.exit(1)
-		if os.path.exists("%s/metadata/timestamp.chk" % portage.settings["PORTAGE_PORTDIR"]):
-			tmpservertimestampfile = "%s/metadata.timestamp.chk" % portage.settings["PORTAGE_PORTDIR"]
-
-		updatecache_flg = True
-	else:
-		print "!!! rsync setting: ",syncuri,"not recognized; exiting."
-		sys.exit(1)
-
-
-	if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
-		if "--quiet" not in myopts:
-			print "\n>>> Updating Portage cache:      ",
-		os.umask(0002)
-		cachedir = os.path.normpath(portage.settings.depcachedir)
-		if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
-		                "/lib", "/opt", "/proc", "/root", "/sbin",
-		                "/sys", "/tmp", "/usr",  "/var"]:
-			print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM."
-			print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir)
-			sys.exit(73)
-		if not os.path.exists(cachedir):
-			os.mkdir(cachedir)
-
-		if (os.path.exists(cachedir) and os.path.exists(cachedir+"/app-portage")):
-			# removed old style cache.
-			# XXX: Compat Code, and Potentially bad.
-			portage.spawn("rm -Rf "+cachedir+"/*",portage.settings,free=1)
-
-		# save timestamp.chk for next timestamp check.
-		try:
-			if tmpservertimestampfile != None:
-				portage.movefile(tmpservertimestampfile, servertimestampfile)
-		except SystemExit, e:
-			raise # Needed else can't exit
-		except Exception, e:
-			print "!!! Failed to save current timestamp."
-			print "!!!",e
-
-		portage.portdb.flush_cache()
-
-		try:
-			os.umask(002)
-			os.chown(cachedir, os.getuid(), portage.portage_gid)
-			os.chmod(cachedir, 00775)
-		except SystemExit, e:
-			raise # Needed else can't exit
-		except:
-			pass
-		# we don't make overlay trees cache here.
-		#grab our own eclass_cache.
-		ec = portage.eclass_cache.cache(portage.portdb.porttree_root)
-		# kinda ugly.
-		cm = portage.settings.load_best_module("portdbapi.metadbmodule")
-		cmi = cm("metadata/cache", cm.auxdbkey_order, basepath=myportdir)
-		
-		def quicky_cpv_generator(dbapi):
-			for x in dbapi.cp_all():
-				for y in dbapi.cp_list(x):
-					yield y
-
-		import cache.util
-		# mangle the settings var.
-		config=portage.config(clone=portage.settings)
-		config["PORTDIR_OVERLAY"] = ''
-		config["PORTDIR"] = myportdir
-		pdb=portage.portdbapi(myportdir, config)
-		cache.util.mirror_cache(quicky_cpv_generator(pdb), cmi, 
-			pdb.auxdb[myportdir], eclass_cache=ec,
-			verbose_instance=cache.util.non_quiet_mirroring())
-		del ec
-		del cmi
-		del cm
-		del pdb
-#		mynodes=portage.portdb.cp_all()
-#		mynodes.sort()
-#		pcnt=0
-#		pcntstr=""
-#		pcntcount=len(mynodes)/100.0
-#		nextupdate=pcntcount
-#		current=0
-#		# need to add a callback option to regen_keys to take advantage of the happy spinny eye-candy stuff.
-#		portage.portdb.regen_keys(src_cache=myportdir+"/metadata/cache",debug=("cachedebug" in portage.features),
-#			verbose=False)
-#		portage.portdb.porttrees=backup_porttrees
-		sys.stdout.write("\n\n")
-		sys.stdout.flush()
-
-	portage.portageexit()
-	reload(portage)
-	mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage")
-	mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage"))
-
-	chk_updated_cfg_files()
-
-	if(mybestpv != mypvs):
-		print
-		print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
-		print red(" * ")+"that you update portage now, before any other packages are updated."
-		print red(" * ")+"Please do so and then update "+bold("ALL")+" of your configuration files."
-		print
-elif myaction=="regen":
-	emergelog(" === regen")
-	#regenerate cache entries
-	print "Regenerating cache entries... "
-	portage.portdb.regen_keys()
-	print "done!"
-# HELP action
-elif "config"==myaction:
-	emergelog(" === config")
-	print
-	print "Currently, \'config\' is a help option only."
-	print
-# INFO action
-elif "info"==myaction:
-	unameout=portage_exec.spawn_get_output("uname -mrp")[1]
-	print getportageversion()
-	print "================================================================="
-	print "System uname: "+unameout
-	if os.path.exists("/etc/gentoo-release"):
-		portage_exec.spawn("cat /etc/gentoo-release")
-	else:
-		print "Unknown Host Operating System"
 	
-	py_vers = string.join(portage.db["/"]["vartree"].dbapi.match("dev-lang/python"), ",")
-	py_this = string.strip(string.split(sys.version,"\n")[0])
-	print "%-20s %s [%s]" % ("Python:",py_vers,py_this)
-
-	output=portage_exec.spawn_get_output("distcc --version")
-	if not output[0]:
-		print output[1].split("\n",1)[0],
-		if "distcc" in portage.features:
-			print "[enabled]"
-		else:
-			print "[disabled]"
-
-	output=portage_exec.spawn_get_output("ccache -V")
-	if not output[0]:
-		print output[1].split("\n",1)[0],
-		if "ccache" in portage.features:
-			print "[enabled]"
-		else:
-			print "[disabled]"
-
-	myvars  = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
-	           "sys-devel/binutils", "sys-devel/libtool",  "dev-lang/python"]
-	myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs")
-	myvars  = portage_util.unique_array(myvars)		
-	myvars.sort()
-	
-	for x in myvars:
-		if portage.portage_dep.isvalidatom(x):
-			pkg_matches = portage.db["/"]["vartree"].dbapi.match(x)
-			pkgs = ""
-			for y in pkg_matches:
-				mycpv   = portage.catpkgsplit(y)
-				if pkgs:
-					pkgs += ", "
-				pkgs   += str(mycpv[2])
-				if(mycpv[3] != "r0"):
-					pkgs += "-" + str(mycpv[3])
-			if not pkgs:
-				pkgs = "[Not Present]"
-			print "%-20s %s" % (x+":", pkgs)
+		self.emergelog(" === "+str(self.myaction))
+		myportdir=portage.settings["PORTDIR"]
+		if myportdir[-1]=="/":
+			myportdir=myportdir[:-1]
+		if not os.path.exists(myportdir):
+			print ">>>",myportdir,"not found, creating it."
+			os.makedirs(myportdir,0755)	
+		syncuri=portage.settings["SYNC"].rstrip()
+		os.umask(0022)
+	
+		sync_verbosity=0
+		if "--quiet" in self.myopts:
+			sync_verbosity = 1
+		elif "--verbose" in self.myopts:
+			sync_verbosity = 3
 		else:
-			print "%-20s %s" % (x+":", "[NOT VALID]")
-
-	libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",")
+			sync_verbosity = 2
 	
-	if "--verbose" in myopts:
-		myvars=portage.settings.keys()
-	else:
-		myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
-		          'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
-		          'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
-		          'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES']
-
-		myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars"))
-
-	myvars = portage_util.unique_array(myvars)		
-	unset_vars = []
-	myvars.sort()
-	for x in myvars:
-		if portage.settings.has_key(x):
-			print x+'="'+portage.settings[x]+'"'
-		else:
-			unset_vars.append(x)
-	if unset_vars:
-		print "Unset:  "+", ".join(unset_vars)
-	print
-
-	config_files = [portage.MAKE_CONF_FILE,
-	                portage.MODULES_FILE_PATH,
-	                portage.USER_VIRTUALS_FILE,
-	                portage.EBUILD_SH_ENV_FILE,
-	                portage.CUSTOM_MIRRORS_FILE]
-	config_files += [portage.USER_CONFIG_PATH+"/package."+x for x in ["mask","unmask","keywords","env"]]
-	config_files += [portage.CUSTOM_PROFILE_PATH+"/"+x for x in ["make.defaults","packages","use.mask","virtuals","profile.bashrc","use.defaults"]]
-	print "Config files: "+(", ".join([x for x in config_files if os.path.exists(x)]))
-
-	if "--debug" in myopts:
-		for x in dir(portage):
-			module = getattr(portage, x)
-			if "cvs_id_string" in dir(module):
-				print "%s: %s" % (str(x), str(module.cvs_id_string))
-
-# SEARCH action
-elif "search"==myaction:
-	if not myfiles:
-		print "emerge: no search terms provided."
-	else:
-		searchinstance = search()
-		for mysearch in myfiles:
+		print "sync_verbosity=",sync_verbosity
+		tmpservertimestampfile = None
+	
+		protocol,host_uri = sync.parseSyncUri(syncuri)
+		print "host_uri=",host_uri
+	
+		if self.myaction == "metadata":
+			if "--ask" in self.myopts:
+				if userquery("Are you sure?") == "No":
+					#userquery("Are you sure you should be using *NIX?",["Definately Not"])
+					sys.exit(1)
+			print "skipping sync"
+			updatecache_flg = True
+			tmpservertimestampfile = None
+		elif protocol == "rsync":
+			mytimeout=180
+			if portage.settings.has_key("RSYNC_TIMEOUT"):
+				try:
+					mytimeout=int(portage.settings["RSYNC_TIMEOUT"])
+				except SystemExit, e:
+					raise # Needed else can't exit
+				except:
+					pass
+	
+			syncer=sync.rsync.RsyncHost(host_uri)
+	
+			servertimestampdir  = portage.settings.depcachedir+"/"
+			servertimestampfile = portage.settings.depcachedir+"/timestamp.chk"
+			tmpservertimestampdir  = portage.settings["PORTAGE_TMPDIR"]+"/"
+			tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk"
+	
+			# We only use the backup if a timestamp exists in the portdir.
+	
+			content=None
+			if os.path.exists(myportdir+"/metadata/timestamp.chk"):
+				content=portage.grabfile(servertimestampfile)
+			if (not content):
+				content=portage.grabfile(myportdir+"/metadata/timestamp.chk")
+	
+			if (content):
+				try:
+					mytimestamp=time.mktime(time.strptime(content[0], "%a, %d %b %Y %H:%M:%S +0000"))
+				except ValueError:
+					mytimestamp=0
+			else:
+				mytimestamp=0
+	
+			if not os.path.exists(servertimestampdir):
+				os.mkdir(servertimestampdir)
+				os.chown(servertimestampdir, os.getuid(), portage.portage_gid)
+				os.chmod(servertimestampdir, 0775)
+	
+			#exitcode=0
+			try:
+				maxretries=int(portage.settings["RSYNC_RETRIES"])
+			except SystemExit, e:
+				raise # Needed else can't exit
+			except:
+				maxretries=3 #default number of retries
+	
+			retries=0
+			updatecache_flg=True
+	
+			ips=syncer.get_ips()
+			if ips == None:
+				ips=[None]
+			while (1):
+				if (retries==0):
+					if "--ask" in self.myopts:
+						if userquery("Do you want to sync your Portage tree with the mirror %s at %s\n" \
+							% (host_uri, blue(str(ips[0])))+bold("?"))=="No":
+							print
+							print "Quitting."
+							print
+							sys.exit(0)
+					self.emergelog(">>> starting rsync with "+host_uri)
+					if "--quiet" not in self.myopts:
+						print ">>> starting rsync with %s, ip %s..." % (host_uri,ips[0])
+				else:
+					self.emergelog(">>> Starting retry %d of %d with %s ip %s" % \
+						(retries,maxretries,host_uri,ips[0]))
+					print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,host_uri)
+	
+				try:
+					if "--quiet" not in self.myopts:
+						print ">>> syncing..."
+					exitcode=syncer.sync(portage.settings,tmpservertimestampdir, \
+						remote_path=syncer.get_remote_path()+"/metadata/timestamp.chk",
+						verbosity=0, cleanup=False, ip=ips[0])
+					if exitcode==True:
+						exitcode=0
+				except (sync.rsync.RSyncSyntaxError,IOError),e:
+					print e
+					exitcode=1
+	
+				if exitcode==0:
+					try:
+						servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000"))
+					except SystemExit, e:
+						raise # Needed else can't exit
+					except:
+						servertimestamp = 0
+					
+					if (servertimestamp != 0) and (servertimestamp == mytimestamp):
+						self.emergelog(">>> Cancelling sync -- Already current.")
+						print
+						print ">>>"
+						print ">>> Timestamps on the server and in the local repository are the same."
+						print ">>> Cancelling all further sync action. You are already up to date."
+						print ">>>"
+						print
+						sys.exit(0)
+					elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
+						self.emergelog(">>> Server out of date: %s" % dosyncuri)
+						print
+						print ">>>"
+						print ">>> SERVER OUT OF DATE: %s" % dosyncuri
+						print ">>>"
+						print
+					elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
+						# actual sync
+						try:
+							exitcode=syncer.sync(portage.settings,portage.settings["PORTDIR"],
+								verbosity=sync_verbosity,
+								excludes=('/distfiles','/local','/packages'),ip=ips[0])
+							if exitcode==True:
+								exitcode=0
+						except (sync.rsync.RSyncSyntaxError,IOError),e:
+							print e
+							exitcode=21
+						if exitcode in [0,1,2,3,4,11,14,20,21]:
+							break
+				elif exitcode in [0,1,2,3,4,11,14,20,21]:
+					break
+	
+				retries=retries+1
+	
+				if retries<=maxretries:
+					print ">>> retry ..."
+					time.sleep(11)
+				else:
+					# over retries
+					# exit loop
+					updatecache_flg=False
+					break
+	
+			if (exitcode==0):
+				self.emergelog("=== Sync completed with %s: %s" % (host_uri,ips[0]))
+			elif (exitcode>0):
+				print
+				try:
+					exitcode=syncer.sync(portage.settings,portage.settings["PORTDIR"],
+						excludes=("/distfiles","/local","/packages"),verbosity=sync_verbosity,ip=ips[0])
+					if exitcode == True:
+						exitcode=0
+				except sync.rsync.RSyncSyntaxError, rsse:
+					print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure")
+					print darkred("!!!")+green(" that your SYNC statement is proper.")
+					print darkred("!!!")+green(" SYNC="+rsse.value)
+				except IOError, ie:
+					print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally")
+					print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption")
+					print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate")
+					print darkred("!!!")+green(" and try again after the problem has been fixed.")
+					print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"])
+				if exitcode==20:
+					print darkred("!!!")+green(" Rsync was killed before it finished.")
+				elif exitcode > 0:
+					print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep")
+					print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable")
+					print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a")
+					print darkred("!!!")+green(" temporary problem unless complications exist with your network")
+					print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.")
+				if exitcode:
+					print "bailing",exitcode
+					sys.exit(exitcode)
+				else:
+					updatecache_flg=True
+		elif protocol == "cvs":
+			syncer=sync.cvs.CvsHost(host_uri)
 			try:
-				searchinstance.execute(mysearch)
-			except re.error, comment:
-				print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment )
+				print ">>> starting cvs update with "+syncuri+"..."
+				syncer.sync(portage.settings["PORTDIR"],compress=False)
+				print ">>> finished"
+			except sync.cvs.CVSIOError, ce:
+				print red("!!!")+"cvs operation failed-"
+				print str(ce)
+				sys.exit(1)
+		elif protocol == "snapshot":
+			fetcher=portage.get_preferred_fetcher()
+			print 'host_uri=',host_uri
+			if host_uri == None:
+				print ">>> choosing a random mirror from the mirror list"
+				host_uri = portage.thirdpartymirrors["gentoo"][:]
+				random.shuffle(host_uri)
+				host_uri=host_uri[0].replace("distfiles","snapshots")
+				print ">>> using %s" % host_uri
+			if not os.path.exists(portage.settings["PORTAGE_TMPDIR"]+"/snapshots"):
+				os.mkdir(portage.settings["PORTAGE_TMPDIR"]+"/snapshots")
+			syncer=sync.snapshot.SnapshotHost(host_uri,portage.settings["DISTDIR"], \
+				portage.settings["PORTAGE_TMPDIR"]+"/snapshots", fetcher=fetcher)
+			if not syncer.sync(portage.settings["PORTDIR"],verbosity=sync_verbosity):
+				print "!!! snapshot failed"
 				sys.exit(1)
-			searchinstance.output()
-elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
-	if 1==unmerge(myaction, myfiles):
-		post_emerge()
-	
-elif "depclean"==myaction:
-	# Kill packages that aren't explicitly merged or are required as a
-	# dependency of another package. World file is explicit.
-
-	print
-	print red("*** WARNING ***")+" : DEPCLEAN CAN  SERIOUSLY  IMPAIR YOUR SYSTEM. USE CAUTION."
-	print red("*** WARNING ***")+" : (Cancel: CONTROL-C) -- ALWAYS VERIFY ALL PACKAGES IN THE"
-	print red("*** WARNING ***")+" : CANDIDATE LIST FOR  SANITY  BEFORE  ALLOWING DEPCLEAN TO"
-	print red("*** WARNING ***")+" : UNMERGE ANY PACKAGES."
-	print red("*** WARNING ***")+" :"
-	print red("*** WARNING ***")+" : USE FLAGS MAY HAVE AN EXTREME EFFECT ON THE OUTPUT."
-	print red("*** WARNING ***")+" : SOME LIBRARIES MAY BE USED BY PACKAGES BUT ARE NOT"
-	print red("*** WARNING ***")+" : CONSIDERED TO BE A DEPEND DUE TO USE FLAG SETTINGS."
-	print red("*** WARNING ***")+" : emerge --update --deep --newuse world TO VERIFY"
-	print red("*** WARNING ***")+" : SANITY IN THIS REGARD."
-	print red("*** WARNING ***")+" :"
-	print red("*** WARNING ***")+" : Packages  in the list  that are  desired  may be added"
-	print red("*** WARNING ***")+" : directly to the world file to cause them to be ignored"
-	print red("*** WARNING ***")+" : by depclean and maintained in the future. BREAKAGES DUE"
-	print red("*** WARNING ***")+" : TO UNMERGING AN  ==IN-USE LIBRARY==  MAY BE REPAIRED BY"
-	print red("*** WARNING ***")+" : MERGING  *** THE PACKAGE THAT COMPLAINS ***  ABOUT THE"
-	print red("*** WARNING ***")+" : MISSING LIBRARY."
-	print
-	if ("--pretend" not in myopts) and ("--ask" not in myopts):
-		countdown(EMERGE_WARNING_DELAY, ">>> Depclean")
-		emergelog(" >>> depclean")
-
-	mydepgraph=depgraph(myaction,myopts)
-	syslist=getlist("system")
-	worldlist=getlist("world")
-
-	print "Calculating",myaction,"dependencies  ",
-	if not mydepgraph.xcreate("world"):
-		print "\n!!! Failed to create deptree."
-		sys.exit(1)
-	print "\b\b ... done!"
-
-	if ("--usepkgonly" in myopts) and mydepgraph.missingbins:
-		sys.stderr.write(red("The following binaries are not available for merging...\n"))
-		for x in mydepgraph.missingbins:
-			sys.stderr.write("   "+str(x)+"\n")
-		sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
-		sys.exit(1)
-
-	alldeps=mydepgraph.mynewgraph.get_all_nodes()
-	myvarlist=portage.vardbapi(portage.root).cp_all()
-
-	if not syslist:
-		print "!!! You have no system list. Cannot determine system from world."
-	if not worldlist:
-		print "!!! You have no world file. Cannot determine explicit merges."
-	if not myvarlist:
-		print "!!! You have no installed package tree (%s). This is a problem." % portage.VDB_PATH
-	if not alldeps:
-		print "!!! You have no dependencies. Impossible. Bug."
-
-	if not (syslist and worldlist and myvarlist and alldeps):
-		print
-		sys.exit(1)
-
-	reallist=[]
-	for x in alldeps:
-		myparts=portage_versions.catpkgsplit(x.split()[2])
-		if not myparts:
-			sys.stderr.write(
-			  red("!!! There appears to be a problem with the following package:\n")+
-				red("!!! "+str(x.split()[2])+"\n\n")+
-				    "!!! Please ensure that blocking/conflicting packages are not merged."+
-						"!!! 'emerge -p "+str(x.split()[2])+"\n\n")
-			if ("--pretend" not in myopts) and ("--ask" not in myopts):
-				countdown(EMERGE_WARNING_DELAY, "*** Continuing")
-			continue
-			
-		catpack=myparts[0]+"/"+myparts[1]
-		if catpack not in reallist:
-			reallist.append(catpack)
-
-	cleanlist=[]
-	for x in myvarlist:
-		if x not in reallist:
-			if x not in cleanlist:
-				cleanlist.append(x)
-
-	for x in syslist+worldlist:
-		myparts = portage_versions.catpkgsplit(x)
-		if myparts:
-			mycat = ""
-			myparts = list(myparts)
-			if myparts[0][0] in ('<','>','='):
-				mycat = myparts[0][1:]
-			elif myparts[0][:2] in ('<=','>='):
-				mycat = myparts[0][2:]
-			catpack=mycat+"/"+myparts[1]
-		else:
-			catpack=x
-		if catpack in cleanlist:
-			cleanlist.remove(catpack)
-
-	#print "\n\n\nCleaning: "
-	#for x in cleanlist:
-	#	print x
-	#print
-
-	if len(cleanlist):
-		unmerge("unmerge", cleanlist)
-
-	print
-	print "Packages installed:   "+str(len(myvarlist))
-	print "Packages in world:    "+str(len(worldlist))
-	print "Packages in system:   "+str(len(syslist))
-	print "Unique package names: "+str(len(reallist))
-	print "Required packages:    "+str(len(alldeps))
-	if "--pretend" in myopts:
-		print "Number to remove:     "+str(len(cleanlist))
-	else:
-		print "Number removed:       "+str(len(cleanlist))
-		post_emerge()
 
-# "update", "system", or just process files:
-else:
-	favorites=[]
-	syslist=getlist("system")
-	if (("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts)) or ("--ask" in myopts):
-		if "--tree" in myopts:
-			print
-			print darkgreen("These are the packages that I would merge, in reverse order:")
-			print
+			if os.path.exists("%s/metadata/timestamp.chk" % portage.settings["PORTAGE_PORTDIR"]):
+				tmpservertimestampfile = "%s/metadata.timestamp.chk" % portage.settings["PORTAGE_PORTDIR"]
+	
+			updatecache_flg = True
 		else:
-			print
-			print darkgreen("These are the packages that I would merge, in order:")
-			print
-
-	if ("--resume" in myopts) and portage.mtimedb.has_key("resume"):
-		myresumeopts=portage.mtimedb["resume"]["myopts"][:]
-
-		while "--skipfirst" in myresumeopts:
-			myresumeopts.remove("--skipfirst")
-		while "--ask" in myresumeopts:
-			myresumeopts.remove("--ask")
+			print "!!! rsync setting: ",syncuri,"not recognized; exiting."
+			sys.exit(1)
+	
+	
+		if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
+			if "--quiet" not in self.myopts:
+				print "\n>>> Updating Portage cache:      ",
+			os.umask(0002)
+			cachedir = os.path.normpath(portage.settings.depcachedir)
+			if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
+					"/lib", "/opt", "/proc", "/root", "/sbin",
+					"/sys", "/tmp", "/usr",  "/var"]:
+				print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM."
+				print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir)
+				sys.exit(73)
+			if not os.path.exists(cachedir):
+				os.mkdir(cachedir)
+	
+			if (os.path.exists(cachedir) and os.path.exists(cachedir+"/app-portage")):
+				# removed old style cache.
+				# XXX: Compat Code, and Potentially bad.
+				portage.spawn("rm -Rf "+cachedir+"/*",portage.settings,free=1)
+	
+			# save timestamp.chk for next timestamp check.
+			try:
+				if tmpservertimestampfile != None:
+					portage.movefile(tmpservertimestampfile, servertimestampfile)
+			except SystemExit, e:
+				raise # Needed else can't exit
+			except Exception, e:
+				print "!!! Failed to save current timestamp."
+				print "!!!",e
+	
+			portage.portdb.flush_cache()
+	
+			try:
+				os.umask(002)
+				os.chown(cachedir, os.getuid(), portage.portage_gid)
+				os.chmod(cachedir, 00775)
+			except SystemExit, e:
+				raise # Needed else can't exit
+			except:
+				pass
+			# we don't make overlay trees cache here.
+			#grab our own eclass_cache.
+			ec = portage.eclass_cache.cache(portage.portdb.porttree_root)
+			# kinda ugly.
+			cm = portage.settings.load_best_module("portdbapi.metadbmodule")
+			cmi = cm("metadata/cache", cm.auxdbkey_order, basepath=myportdir)
 			
-		for myopt in myopts:
-			if myopt not in myresumeopts:
-				myresumeopts.append(myopt)
-		myopts=myresumeopts
-		mydepgraph=depgraph("resume",myopts)
-		if "--resume" not in myopts:
-			myopts+=["--resume"]
-	else:
-		if ("--resume" in myopts):
-			del myopts[myopts.index("--resume")]
-			print darkgreen("emerge: It seems we have nothing to resume...")
-			sys.exit(0)
-
-		mydepgraph=depgraph(myaction,myopts)
-		if myaction in ["system","world"]:
-			print "Calculating",myaction,"dependencies  ",
-			sys.stdout.flush()
-			if not mydepgraph.xcreate(myaction):
-				print "!!! Depgraph creation failed."
-				sys.exit(1)
-			print "\b\b ...done!"
-		else:
-			if not myfiles:
-				print "emerge: please tell me what to do."
-				help()
-				sys.exit(1)
-				#we don't have any files to process; skip this step and exit
-			print "Calculating dependencies  ",
+			def quicky_cpv_generator(dbapi):
+				for x in dbapi.cp_all():
+					for y in dbapi.cp_list(x):
+						yield y
+	
+			import cache.util
+			# mangle the settings var.
+			config=portage.config(clone=portage.settings)
+			config["PORTDIR_OVERLAY"] = ''
+			config["PORTDIR"] = myportdir
+			pdb=portage.portdbapi(myportdir, config)
+			cache.util.mirror_cache(quicky_cpv_generator(pdb), cmi, 
+				pdb.auxdb[myportdir], eclass_cache=ec,
+				verbose_instance=cache.util.non_quiet_mirroring())
+			del ec
+			del cmi
+			del cm
+			del pdb
+	#		mynodes=portage.portdb.cp_all()
+	#		mynodes.sort()
+	#		pcnt=0
+	#		pcntstr=""
+	#		pcntcount=len(mynodes)/100.0
+	#		nextupdate=pcntcount
+	#		current=0
+	#		# need to add a callback option to regen_keys to take advantage of the happy spinny eye-candy stuff.
+	#		portage.portdb.regen_keys(src_cache=myportdir+"/metadata/cache",debug=("cachedebug" in portage.features),
+	#			verbose=False)
+	#		portage.portdb.porttrees=backup_porttrees
+			sys.stdout.write("\n\n")
 			sys.stdout.flush()
-			retval,favorites=mydepgraph.select_files(myfiles)
-			if not retval:
-				sys.exit(1)
-			print "\b\b ...done!"
-
-			if ("--usepkgonly" in myopts) and mydepgraph.missingbins:
-				sys.stderr.write(red("The following binaries are not available for merging...\n"))
-
-		if mydepgraph.missingbins:
+	
+		portage.portageexit()
+		reload(portage)
+		mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage")
+		mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage"))
+	
+		chk_updated_cfg_files()
+	
+		if(mybestpv != mypvs):
+			print
+			print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
+			print red(" * ")+"that you update portage now, before any other packages are updated."
+			print red(" * ")+"Please do so and then update "+bold("ALL")+" of your configuration files."
+			print
+	
+	def action_info(self):
+		unameout=portage_exec.spawn_get_output("uname -mrp")[1]
+		print getportageversion()
+		print "================================================================="
+		print "System uname: "+unameout
+		if os.path.exists("/etc/gentoo-release"):
+			portage_exec.spawn("cat /etc/gentoo-release")
+		else:
+			print "Unknown Host Operating System"
+		
+		py_vers = string.join(portage.db["/"]["vartree"].dbapi.match("dev-lang/python"), ",")
+		py_this = string.strip(string.split(sys.version,"\n")[0])
+		print "%-20s %s [%s]" % ("Python:",py_vers,py_this)
+	
+		output=portage_exec.spawn_get_output("distcc --version")
+		if not output[0]:
+			print output[1].split("\n",1)[0],
+			if "distcc" in portage.features:
+				print "[enabled]"
+			else:
+				print "[disabled]"
+	
+		output=portage_exec.spawn_get_output("ccache -V")
+		if not output[0]:
+			print output[1].split("\n",1)[0],
+			if "ccache" in portage.features:
+				print "[enabled]"
+			else:
+				print "[disabled]"
+	
+		myvars  = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
+				"sys-devel/binutils", "sys-devel/libtool",  "dev-lang/python"]
+		myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs")
+		myvars  = portage_util.unique_array(myvars)		
+		myvars.sort()
+		
+		for x in myvars:
+			if portage.portage_dep.isvalidatom(x):
+				pkg_matches = portage.db["/"]["vartree"].dbapi.match(x)
+				pkgs = ""
+				for y in pkg_matches:
+					mycpv   = portage.catpkgsplit(y)
+					if pkgs:
+						pkgs += ", "
+					pkgs   += str(mycpv[2])
+					if(mycpv[3] != "r0"):
+						pkgs += "-" + str(mycpv[3])
+				if not pkgs:
+					pkgs = "[Not Present]"
+				print "%-20s %s" % (x+":", pkgs)
+			else:
+				print "%-20s %s" % (x+":", "[NOT VALID]")
+	
+		libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",")
+		
+		if "--verbose" in self.myopts:
+			myvars=portage.settings.keys()
+		else:
+			myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
+					'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
+					'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
+					'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES']
+	
+			myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars"))
+	
+		myvars = portage_util.unique_array(myvars)		
+		unset_vars = []
+		myvars.sort()
+		for x in myvars:
+			if portage.settings.has_key(x):
+				print x+'="'+portage.settings[x]+'"'
+			else:
+				unset_vars.append(x)
+		if unset_vars:
+			print "Unset:  "+", ".join(unset_vars)
+		print
+	
+		config_files = [portage.MAKE_CONF_FILE,
+				portage.MODULES_FILE_PATH,
+				portage.USER_VIRTUALS_FILE,
+				portage.EBUILD_SH_ENV_FILE,
+				portage.CUSTOM_MIRRORS_FILE]
+		config_files += [portage.USER_CONFIG_PATH+"/package."+x for x in ["mask","unmask","keywords","env"]]
+		config_files += [portage.CUSTOM_PROFILE_PATH+"/"+x for x in ["make.defaults","packages","use.mask","virtuals","profile.bashrc","use.defaults"]]
+		print "Config files: "+(", ".join([x for x in config_files if os.path.exists(x)]))
+	
+		if "--debug" in self.myopts:
+			for x in dir(portage):
+				module = getattr(portage, x)
+				if "cvs_id_string" in dir(module):
+					print "%s: %s" % (str(x), str(module.cvs_id_string))
+
+	def action_depclean(self):
+		# Kill packages that aren't explicitly merged or are required as a
+		# dependency of another package. World file is explicit.
+	
+		print
+		print red("*** WARNING ***")+" : DEPCLEAN CAN  SERIOUSLY  IMPAIR YOUR SYSTEM. USE CAUTION."
+		print red("*** WARNING ***")+" : (Cancel: CONTROL-C) -- ALWAYS VERIFY ALL PACKAGES IN THE"
+		print red("*** WARNING ***")+" : CANDIDATE LIST FOR  SANITY  BEFORE  ALLOWING DEPCLEAN TO"
+		print red("*** WARNING ***")+" : UNMERGE ANY PACKAGES."
+		print red("*** WARNING ***")+" :"
+		print red("*** WARNING ***")+" : USE FLAGS MAY HAVE AN EXTREME EFFECT ON THE OUTPUT."
+		print red("*** WARNING ***")+" : SOME LIBRARIES MAY BE USED BY PACKAGES BUT ARE NOT"
+		print red("*** WARNING ***")+" : CONSIDERED TO BE A DEPEND DUE TO USE FLAG SETTINGS."
+		print red("*** WARNING ***")+" : emerge --update --deep --newuse world TO VERIFY"
+		print red("*** WARNING ***")+" : SANITY IN THIS REGARD."
+		print red("*** WARNING ***")+" :"
+		print red("*** WARNING ***")+" : Packages  in the list  that are  desired  may be added"
+		print red("*** WARNING ***")+" : directly to the world file to cause them to be ignored"
+		print red("*** WARNING ***")+" : by depclean and maintained in the future. BREAKAGES DUE"
+		print red("*** WARNING ***")+" : TO UNMERGING AN  ==IN-USE LIBRARY==  MAY BE REPAIRED BY"
+		print red("*** WARNING ***")+" : MERGING  *** THE PACKAGE THAT COMPLAINS ***  ABOUT THE"
+		print red("*** WARNING ***")+" : MISSING LIBRARY."
+		print
+		if ("--pretend" not in self.myopts) and ("--ask" not in self.myopts):
+			countdown(self.EMERGE_WARNING_DELAY, ">>> Depclean")
+			self.emergelog(" >>> depclean")
+	
+		mydepgraph=depgraph(self.myaction,self.myopts,self.myparams,self.edebug,self.verbosity,self.EMERGE_WARNING_DELAY,self.spinner)
+		syslist=getlist("system")
+		worldlist=getlist("world")
+	
+		print "Calculating",self.myaction,"dependencies  ",
+		if not mydepgraph.xcreate("world"):
+			print "\n!!! Failed to create deptree."
+			sys.exit(1)
+		print "\b\b ... done!"
+	
+		if ("--usepkgonly" in self.myopts) and mydepgraph.missingbins:
+			sys.stderr.write(red("The following binaries are not available for merging...\n"))
 			for x in mydepgraph.missingbins:
 				sys.stderr.write("   "+str(x)+"\n")
 			sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
 			sys.exit(1)
-
-	if "--ask" in myopts:
-		if "--resume" in myopts:
-			mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
-			prompt="Do you want me to resume merging these packages?"
-		else:
-			graphdisp = graph_display(mydepgraph.mynewgraph)
-			if "--tree" in myopts:
-				graphdisp.display_tree()
-			elif "--columns" in myopts:
-				graphdisp.display_columns()
-			else:
-				graphdisp.display_flat()
-			mergecount=0
-			for x in mydepgraph.altlist():
-				if x[3]!="nomerge":
-					mergecount+=1
-				#check for blocking dependencies
-				if x[0]=="blocks":
-					print "\n!!! Error: The above package list contains packages which cannot be installed"
-					print   "!!!        on the same system."
-					print
+	
+		alldeps=mydepgraph.mynewgraph.get_all_nodes()
+		myvarlist=portage.vardbapi(portage.root).cp_all()
+	
+		if not syslist:
+			print "!!! You have no system list. Cannot determine system from world."
+		if not worldlist:
+			print "!!! You have no world file. Cannot determine explicit merges."
+		if not myvarlist:
+			print "!!! You have no installed package tree (%s). This is a problem." % portage.VDB_PATH
+		if not alldeps:
+			print "!!! You have no dependencies. Impossible. Bug."
+	
+		if not (syslist and worldlist and myvarlist and alldeps):
+			print
+			sys.exit(1)
+	
+		reallist=[]
+		for x in alldeps:
+			myparts=portage_versions.catpkgsplit(x.split()[2])
+			if not myparts:
+				sys.stderr.write(
+					red("!!! There appears to be a problem with the following package:\n")+
+					red("!!! "+str(x.split()[2])+"\n\n")+
+						"!!! Please ensure that blocking/conflicting packages are not merged."+
+							"!!! 'emerge -p "+str(x.split()[2])+"\n\n")
+				if ("--pretend" not in self.myopts) and ("--ask" not in self.myopts):
+					countdown(self.EMERGE_WARNING_DELAY, "*** Continuing")
+				continue
+				
+			catpack=myparts[0]+"/"+myparts[1]
+			if catpack not in reallist:
+				reallist.append(catpack)
+	
+		cleanlist=[]
+		for x in myvarlist:
+			if x not in reallist:
+				if x not in cleanlist:
+					cleanlist.append(x)
+	
+		for x in syslist+worldlist:
+			myparts = portage_versions.catpkgsplit(x)
+			if myparts:
+				mycat = ""
+				myparts = list(myparts)
+				if myparts[0][0] in ('<','>','='):
+					mycat = myparts[0][1:]
+				elif myparts[0][:2] in ('<=','>='):
+					mycat = myparts[0][2:]
+				catpack=mycat+"/"+myparts[1]
+			else:
+				catpack=x
+			if catpack in cleanlist:
+				cleanlist.remove(catpack)
+	
+		#print "\n\n\nCleaning: "
+		#for x in cleanlist:
+		#	print x
+		#print
+	
+		if len(cleanlist):
+			self.unmerge("unmerge", cleanlist)
+	
+		print
+		print "Packages installed:   "+str(len(myvarlist))
+		print "Packages in world:    "+str(len(worldlist))
+		print "Packages in system:   "+str(len(syslist))
+		print "Unique package names: "+str(len(reallist))
+		print "Required packages:    "+str(len(alldeps))
+		if "--pretend" in self.myopts:
+			print "Number to remove:     "+str(len(cleanlist))
+		else:
+			print "Number removed:       "+str(len(cleanlist))
+			self.post_emerge()
+
+	def action_merge(self):
+		favorites=[]
+		syslist=getlist("system")
+		if (("--pretend" in self.myopts) and not ("--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts)) or ("--ask" in self.myopts):
+			if "--tree" in self.myopts:
+				print
+				print darkgreen("These are the packages that I would merge, in reverse order:")
+				print
+			else:
+				print
+				print darkgreen("These are the packages that I would merge, in order:")
+				print
+	
+		if ("--resume" in self.myopts) and portage.mtimedb.has_key("resume"):
+			myresumeopts=portage.mtimedb["resume"]["myopts"][:]
+	
+			while "--skipfirst" in myresumeopts:
+				myresumeopts.remove("--skipfirst")
+			while "--ask" in myresumeopts:
+				myresumeopts.remove("--ask")
+				
+			for myopt in self.myopts:
+				if myopt not in myresumeopts:
+					myresumeopts.append(myopt)
+			self.myopts=myresumeopts
+			mydepgraph=depgraph("resume",self.myopts,self.myparams,self.edebug,self.verbosity,self.EMERGE_WARNING_DELAY,self.spinner)
+			if "--resume" not in self.myopts:
+				self.myopts+=["--resume"]
+		else:
+			if ("--resume" in self.myopts):
+				del self.myopts[self.myopts.index("--resume")]
+				print darkgreen("emerge: It seems we have nothing to resume...")
+				sys.exit(0)
+	
+			mydepgraph=depgraph(self.myaction,self.myopts,self.myparams,self.edebug,self.verbosity,self.EMERGE_WARNING_DELAY,self.spinner)
+			if self.myaction in ["system","world"]:
+				print "Calculating",self.myaction,"dependencies  ",
+				sys.stdout.flush()
+				if not mydepgraph.xcreate(self.myaction):
+					print "!!! Depgraph creation failed."
 					sys.exit(1)
-			if mergecount==0:
-				prompt="Nothing to merge; do you want me to auto-clean packages?"
-			elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
-				prompt="Do you want me to fetch the source files for these packages?"
+				print "\b\b ...done!"
 			else:
-				prompt="Do you want me to merge these packages?"
-		print
-		if userquery(prompt)=="No":
-			print
-			print "Quitting."
+				if not self.myfiles:
+					print "emerge: please tell me what to do."
+					self.help()
+					sys.exit(1)
+					#we don't have any files to process; skip this step and exit
+				print "Calculating dependencies  ",
+				sys.stdout.flush()
+				retval,favorites=mydepgraph.select_files(self.myfiles)
+				if not retval:
+					sys.exit(1)
+				print "\b\b ...done!"
+	
+				if ("--usepkgonly" in self.myopts) and mydepgraph.missingbins:
+					sys.stderr.write(red("The following binaries are not available for merging...\n"))
+	
+			if mydepgraph.missingbins:
+				for x in mydepgraph.missingbins:
+					sys.stderr.write("   "+str(x)+"\n")
+				sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
+				sys.exit(1)
+	
+		if "--ask" in self.myopts:
+			if "--resume" in self.myopts:
+				mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
+				prompt="Do you want me to resume merging these packages?"
+			else:
+				graphdisp = graph_display(mydepgraph.mynewgraph,self.myopts,self.edebug,self.verbosity)
+				if "--tree" in self.myopts:
+					graphdisp.display_tree()
+				elif "--columns" in self.myopts:
+					graphdisp.display_columns()
+				else:
+					graphdisp.display_flat()
+				mergecount=0
+				for x in mydepgraph.altlist():
+					if x[3]!="nomerge":
+						mergecount+=1
+					#check for blocking dependencies
+					if x[0]=="blocks":
+						print "\n!!! Error: The above package list contains packages which cannot be installed"
+						print   "!!!        on the same system."
+						print
+						sys.exit(1)
+				if mergecount==0:
+					prompt="Nothing to merge; do you want me to auto-clean packages?"
+				elif "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts:
+					prompt="Do you want me to fetch the source files for these packages?"
+				else:
+					prompt="Do you want me to merge these packages?"
 			print
-			sys.exit(0)
-		# Don't ask again (e.g. when auto-cleaning packages after merge)
-		myopts.remove("--ask")
-
-	if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
-		if ("--resume" in myopts):
-			mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
-		else:
-			graphdisp = graph_display(mydepgraph.mynewgraph)
-			if "--tree" in myopts:
-				graphdisp.display_tree()
-			elif "--columns" in myopts:
-				graphdisp.display_columns()
+			if userquery(prompt)=="No":
+				print
+				print "Quitting."
+				print
+				sys.exit(0)
+			# Don't ask again (e.g. when auto-cleaning packages after merge)
+			self.myopts.remove("--ask")
+	
+		if ("--pretend" in self.myopts) and not ("--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts):
+			if ("--resume" in self.myopts):
+				mydepgraph.display(portage.mtimedb["resume"]["mergelist"])
+			else:
+				graphdisp = graph_display(mydepgraph.mynewgraph,self.myopts,self.edebug,self.verbosity)
+				if "--tree" in self.myopts:
+					graphdisp.display_tree()
+				elif "--columns" in self.myopts:
+					graphdisp.display_columns()
+				else:
+					graphdisp.display_flat()
+		else:
+			if ("--buildpkgonly" in self.myopts):
+				has_deps = False
+				for node in mydepgraph.mynewgraph.get_all_nodes():
+					if mydepgraph.mynewgraph.get_relationships(node)[0]:
+						has_deps = True
+				if has_deps:
+					print "\n!!! --buildpkgonly requires all dependencies to be merged."
+					print "!!! Cannot merge requested packages. Merge deps and try again.\n"
+					sys.exit(1)
+	
+			if ("--resume" in self.myopts):
+				mydepgraph.merge(portage.mtimedb["resume"]["mergelist"],portage.mtimedb["resume"]["favorites"])
 			else:
-				graphdisp.display_flat()
-	else:
-		if ("--buildpkgonly" in myopts):
-			has_deps = False
-			for node in mydepgraph.mynewgraph.get_all_nodes():
-				if mydepgraph.mynewgraph.get_relationships(node)[0]:
-					has_deps = True
-			if has_deps:
-				print "\n!!! --buildpkgonly requires all dependencies to be merged."
-				print "!!! Cannot merge requested packages. Merge deps and try again.\n"
-				sys.exit(1)
-
-		if ("--resume" in myopts):
-			favorites=portage.mtimedb["resume"]["favorites"]
-			mydepgraph.merge(portage.mtimedb["resume"]["mergelist"])
-		else:
-			portage.mtimedb["resume"]={}
-			portage.mtimedb["resume"]["myopts"]=myopts
-			portage.mtimedb["resume"]["favorites"]=favorites
-			if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
-				for pkgline in mydepgraph.altlist():
-					if pkgline[0]=="ebuild" and pkgline[3]=="merge":
-						y=portage.portdb.findname(pkgline[2])
-						tmpsettings = portage.config(clone=portage.settings)
-						retval=portage.doebuild(y,"digest",portage.root,tmpsettings,edebug,("--pretend" in myopts))
-			mydepgraph.merge(mydepgraph.altlist())
+				portage.mtimedb["resume"]={}
+				portage.mtimedb["resume"]["myopts"]=self.myopts
+				portage.mtimedb["resume"]["favorites"]=favorites
+				if ("--digest" in self.myopts) and not ("--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts):
+					for pkgline in mydepgraph.altlist():
+						if pkgline[0]=="ebuild" and pkgline[3]=="merge":
+							y=portage.portdb.findname(pkgline[2])
+							tmpsettings = portage.config(clone=portage.settings)
+							retval=portage.doebuild(y,"digest",portage.root,tmpsettings,self.edebug,("--pretend" in self.myopts))
+				mydepgraph.merge(mydepgraph.altlist(),favorites)
+	
+			if portage.mtimedb.has_key("resume"):
+				del portage.mtimedb["resume"]
+			print ">>> Auto-cleaning packages ..."
+			self.unmerge("clean", ["world"])
+		self.post_emerge()
+		
+	def post_emerge(self,retval=0):
+		os.chdir("/")
+		if "--pretend" in self.myopts:
+			sys.exit(retval)
+	
+		self.emergelog(" *** exiting successfully.")
+	
+		if "noinfo" not in portage.settings.features:
+			chk_updated_info_files()
+	
+		chk_updated_cfg_files()
+	
+		sys.exit(retval)
 
-		if portage.mtimedb.has_key("resume"):
-			del portage.mtimedb["resume"]
-		print ">>> Auto-cleaning packages ..."
-		unmerge("clean", ["world"])
-	post_emerge()
+	def unmerge(self,unmerge_action,unmerge_files):
+		return unmerge(self.myopts, self.edebug, self.EMERGE_WARNING_DELAY, unmerge_action, unmerge_files)
 
+	def exit(self):
+		"""This gets out final log message in before we quit."""
+		if "--pretend" not in self.myopts:
+			self.emergelog(" *** terminating.")
+		if "notitles" not in portage.features:
+			xtermTitleReset()
+
+if __name__=="__main__":
+	cmd=emerge_cmd()
+	def emergeexit():
+		cmd.exit()
+	atexit.register(emergeexit)
+	cmd.parse_args(sys.argv)
+	cmd.perform()

      reply	other threads:[~2005-08-13 22:19 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-08-11  5:08 [gentoo-portage-dev] PATCH: refactor emerge spinner (#102073) Zac Medico
2005-08-11 12:14 ` Alec Warner
2005-08-11 14:06 ` Jason Stubbs
2005-08-12  5:19   ` [gentoo-portage-dev] the refactoring of emerge, continued... (was PATCH: refactor emerge spinner (#102073)) Zac Medico
2005-08-12 12:36     ` Alec Warner
2005-08-12 20:57       ` Zac Medico
2005-08-12 21:48         ` warnera6
2005-08-12 22:10           ` Marius Mauch
2005-08-12 22:12             ` warnera6
2005-08-12 22:49           ` Zac Medico
2005-08-13  1:06             ` Jason Stubbs
2005-08-13 17:34     ` Zac Medico
2005-08-13 22:25       ` Zac Medico [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=42FE734D.5020808@gmail.com \
    --to=zmedico@gmail.com \
    --cc=gentoo-portage-dev@lists.gentoo.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox