summaryrefslogtreecommitdiffstats
path: root/spec/emerge.syntax
diff options
context:
space:
mode:
Diffstat (limited to 'spec/emerge.syntax')
-rwxr-xr-xspec/emerge.syntax1149
1 files changed, 1149 insertions, 0 deletions
diff --git a/spec/emerge.syntax b/spec/emerge.syntax
new file mode 100755
index 000000000..17b8131a2
--- /dev/null
+++ b/spec/emerge.syntax
@@ -0,0 +1,1149 @@
+#!/usr/bin/env python
+import os
+from os.path import walk, splitext, exists, basename, dirname
+import sys
+
+import output
+from output import *
+import portage
+import xpak
+import string
+from string import strip, find, replace, split
+import commands
+import shutil
+import re
+import time
+
+#number of ebuilds merged
+merged=0
+# there can only be one action specified; the default action is to merge
+# specified packages, not update.
+actions=["help",
+ "rebuild",
+ "search",
+ "update",
+ "clean",
+ "zap",
+ "rsync"]
+# emerge (prints help)
+# emerge help (prints help)
+# emerge help config (prints config file management help)
+
+# emerge rsync
+
+# the default behavior of emerge is to satisfy dependencies specified by merging packages.
+# emerge system (satisfy deps for "system" package class)
+# emerge world (equivalent to emerge system since "world" doesn't offer any new deps)
+# emerge <depstring> (satisfy dep by merging most recent version of app available that satisfies dep)
+# NOTE: this will cause something to be merged again if the dep happens to be already satisfied
+# "unslotted" is invalid for a package class here because it only applies to already-installed ebuilds.
+# pkgclass support: "system", "world", <depstring>, <pkgname>, <ebuild>, <tbz2>
+
+# no changes here except we use "update" rather than "--update"
+# emerge update <pkgclass/depstring/pkgname>
+# emerge update (defaults to "world")
+# "emerge update <ebuild/tbz2> doesn't make too much sense.
+# But it should do the same thing are "emerge <ebuild/tbz2>".
+
+# rebuild is like "update" except that all packages will be rebuilt even if they currently are installed.
+# emerge rebuild (defaults to "world")
+# emerge rebuild <pkgclass/depstring/pkgname/ebuild>
+# "emerge rebuild <ebuild/tbz2> doesn't make too much sense.
+# But it should do the same thing are "emerge <ebuild/tbz2>".
+
+# emerge search (invalid)
+# emerge search <regex>
+
+# clean does "cleaning" only; it does not do anything that would generally be considered dangerous
+# emerge clean (defaults to "world"; apply default AUTOCLEAN behavior defined in make.conf)
+# emerge --rev clean (defaults to "world", cleans out old revisions)
+# emerge --slot clean (defaults to "world", cleans out old stuff from slots)
+# emerge [--rev/--slot] clean <pkgclass>
+# AUTOCLEAN var can be set to "slot", "rev", or "none/off/etc".
+
+# zap flat out removes stuff. No holds barred. Can be dangerous.
+# emerge zap <pkgclass> (only "unslotted" is valid, which is still dangerous. Or a dep "=foo/bar")
+# NOTE: of course, "emerge zap" alone is invalid and will *not* default to a "world" package class
+
+pkgclass=["world","system","unslotted"]
+helpclass=["config"]
+
+# These next options are the only long options for Portage 1.8.9 except for "--help" (equiv. to "help")
+
+options=["--autoclean",
+ "--buildpkg",
+ "--debug",
+ "--fetchonly",
+ "--noreplace",
+ "--onlydeps",
+ "--pretend",
+ "--usepkg",
+ "--verbose",
+ "--emptytree",
+ "--rev",
+ "--slot",
+ "--help"]
+
+# Here are the currently supported short mappings.
+
+shortmapping={"a":"--autoclean",
+ "b":"--buildpkg",
+ "d":"--debug",
+ "f":"--fetchonly",
+ "h":"--help",
+ "k":"--usepkg",
+ "n":"--noreplace",
+ "o":"--onlydeps",
+ "p":"--pretend",
+ "v":"--verbose" }
+
+# end of spec
+
+myaction=None
+myopts=[]
+mymode=[]
+myfiles=[]
+edebug=0
+
+# process short actions and options
+for x in sys.argv[1:]:
+ if x[0:1]=="-"and not x[1:2]=="-":
+ for y in x[1:]:
+ if shortmapping.has_key(y):
+ sys.argv.append(shortmapping[y])
+ else:
+ print y
+ print "!!! Error: -"+y+" is an invalid short action or option."
+ sys.argv.remove(x)
+
+# process the command arguments
+for x in sys.argv[1:]:
+ if x=="update" or x=="--unmerge" or x=="--world":
+ print
+ if x=="update":
+ print " "+red("* WARNING:"),green("emerge update"),"has been deprecated, use",green("emerge --update"),"instead."
+ elif x=="--unmerge":
+ print " "+red("* WARNING:"),green("emerge --unmerge"),"has been deprecated, use",green("emerge --zap"),"instead."
+ elif x=="--world":
+ print " "+red("* WARNING:"),green("emerge --world"),"has been deprecated, use",green("emerge world"),"instead."
+ print " "+red("*"),"Read",green("emerge --help"),"to get a complete overview of the interface changes."
+ print
+ sys.exit(1)
+
+ if len(x)>=2:
+ if x[0:1]=="-":
+ if x[1:2]=="-":
+ if x in actions:
+ if myaction:
+ print "!!! Error: more than one action specified on command-line."
+ print "!!! Available actions:",actions
+ sys.exit(1)
+ else:
+ myaction=x
+ elif x in options:
+ myopts.append(x)
+ else:
+ print "!!! Error:",x,"is an invalid action or option."
+ sys.exit(1)
+ else:
+ for y in x[1:]:
+ if shortmapping.has_key(y):
+ myopts.append(shortmapping[y])
+ else:
+ print y
+ print "!!! Error: -"+y+" is an invalid short action or option."
+ elif x in modes:
+ if len(mymode)>=1:
+ print "!!! Error: more than one mode specified on command-line."
+ print "!!! Available modes:",modes
+ sys.exit(1)
+ else:
+ mymode.append(x)
+ else:
+ # this little conditional helps tab completion
+ if x[-1]=="/":
+ myfiles.append(x[:-1])
+ else:
+ myfiles.append(x)
+
+# check if root user is the current user for the actions where emerge needs this
+if os.getuid()!=0 and "--help"!=myaction and "--search"!=myaction:
+ print "!!! to be able to perform the requested action, emerge must be run by root."
+ sys.exit(1)
+
+# search functionality
+class search:
+
+ #
+ # class constants
+ #
+ VERSION_SHORT=1
+ VERSION_RELEASE=2
+
+ #
+ # public interface
+ #
+ def __init__(self,searchkey=""):
+ """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.searchkey = searchkey
+ self.treecache = portage.portagetree()
+ self.treecache.populate()
+ self.installcache = portage.vartree()
+ self.installcache.populate()
+ self.re_portagedir = re.compile('/usr/portage/')
+ self.re_description = re.compile('DESCRIPTION="')
+ self.initResults()
+
+ def setKey(self,searchkey):
+ """changes the search key"""
+ self.searchkey = searchkey
+ self.initResults()
+
+ def execute(self):
+ """Performs the saerch for the supplied search key"""
+ if self.searchkey:
+ self.initResults()
+ for package in self.treecache.getallnodes():
+ package_parts=package.split("/")
+ if package_parts:
+ if self.searchkey != "*":
+ if re.search(self.searchkey.lower(), package_parts[1].lower()):
+ self.packagematches.append(package)
+ else:
+ self.packagematches.append(package)
+
+ def output(self):
+ """Outputs the results of the search."""
+ print "[ Results for search key : "+white(self.searchkey)+" ]"
+ print "[ Applications found : "+white(str(len(self.packagematches)))+" ]"
+ print " "
+ for match in self.packagematches:
+ full_package = strip(self.treecache.dep_bestmatch(match))
+ if len(full_package) > 1:
+ print green("*")+" "+white(match)
+ print " ", "Latest version Available:",self.getVersion(full_package, search.VERSION_RELEASE)
+ print " ", self.getInstallationStatus(match)
+ print " ", "Description:",self.getDescription(self.getFullPath(match, full_package),self.getVersion(full_package, search.VERSION_SHORT))
+ print " "
+ else:
+ print green("*")+" "+white(match)+" "+red("[ Masked ]")
+ print " "
+
+ #
+ # private interface
+ #
+ def initResults(self):
+ self.packagematches = []
+
+ def getInstallationStatus(self,package):
+ installed_package = self.installcache.dep_bestmatch(package)
+ result = ""
+ version = self.getVersion(installed_package,search.VERSION_RELEASE)
+ if len(version) > 1:
+ result = "Latest version Installed: "+version
+ else:
+ result = "Latest version Installed: [ Not Installed ]"
+ return result
+
+ def getDescription(self,ebuildPath,packageVersion): ## Gets description from latest ebuild ##
+ file = open(ebuildPath)
+ result = "";
+ indescription=0
+ while 1:
+ data = file.readline()
+ if data:
+ if self.re_description.match(data.upper()):
+ indescription=1
+ p = self.re_description.split(data)
+ p = p[1].split('"')
+ result = p[0].strip()
+ if len(p)>1:
+ break
+ elif indescription==1:
+ if '"' in data:
+ p = data.split('"')
+ result = result+" "+p[0].strip()
+ indescription = 0
+ else:
+ result = result+" "+data.strip()
+ else:
+ break;
+ result = replace(result, "${PV}", packageVersion)
+ result = replace(result, "${pv}", packageVersion)
+ result = replace(result, "${description}", "KDE " + packageVersion + " ")
+ result = replace(result, "\n", "")
+ file.close()
+ # format and wrap the description text nicely
+ wraplength=60
+ formatted_result=""
+ while len(result)>wraplength:
+ lineposition=0
+ position=wraplength
+ while result[lineposition+position]!=' ' and position != 0:
+ position = position-1
+ if position==0:
+ position=wraplength
+ if len(formatted_result)==0:
+ formatted_result=result[:position]
+ else:
+ formatted_result=formatted_result+"\n "+result[:position]
+ result=result[position+1:]
+ if wraplength==60:
+ wraplength=73
+ formatted_result=formatted_result+"\n "+result
+ return formatted_result
+
+ def getFullPath(self,packageShortName,packageFullName): ## Returns the full path of the ebuild ##
+ absolute_path = '/usr/portage/' + strip(packageShortName)
+ package_parts = packageFullName.split("/")
+ result = absolute_path + "/" + package_parts[1] + ".ebuild"
+ return result
+
+ def getVersion(self,full_package,detail):
+ if len(full_package) > 1:
+ package_parts = portage.catpkgsplit(full_package)
+ if detail == search.VERSION_RELEASE and package_parts[3] != 'r0':
+ result = package_parts[2]+ "-" + package_parts[3]
+ else:
+ result = package_parts[2]
+ else:
+ result = ""
+ return result
+
+#build our package digraph
+def getsyslist():
+ if os.path.exists(portage.profiledir+"/packages"):
+ pfile=portage.profiledir+"/packages"
+ else:
+ print "!!! Couldn't find",portage.profiledir+"/packages;"
+ print "\"system\" mode unavailable."
+ sys.exit(1)
+ myfile=open(pfile,"r")
+ mylines=myfile.readlines()
+ myfile.close()
+
+ mynewlines=[]
+ for x in mylines:
+ myline=string.join(string.split(x))
+ if not len(myline):
+ continue
+ elif myline[0]=="#":
+ continue
+ elif myline[0]!="*":
+ continue
+ myline=myline[1:]
+ mynewlines.append(myline.strip())
+
+ return mynewlines
+
+class depgraph:
+
+ def __init__(self,mymode,myaction,myopts):
+ self.mymode=mymode
+ self.myaction=myaction
+ self.myopts=myopts
+ virts=portage.getvirtuals("/")
+ self.db={}
+ self.db["/"]={"virtuals":virts,"vartree":portage.vartree("/",virts),"porttree":portage.portagetree("/",virts),"bintree":portage.binarytree("/",virts)}
+ if portage.root!="/":
+ pr=portage.root
+ virts=portage.getvirtuals(pr)
+ self.db[pr]={"virtuals":virts,"vartree":portage.vartree(pr,virts),"porttree":portage.portagetree(pr,virts),"bintree":portage.binarytree(pr,virts)}
+ self.digraph=portage.digraph()
+ self.orderedkeys=[]
+ #the following is so we have an empty vartree (used in emerge update calculations)
+ self.emptytree=portage.vartree("/",virts,self.db["/"]["vartree"])
+ self.emptytree.tree={}
+ if "--emptytree" in myopts:
+ print "Running in empty tree mode"
+ self.db["/"]["vartree"].tree=self.emptytree.tree
+ self.db["/"]["vartree"].populated=1
+ self.db["/"]["vartree"].inject("virtual/glibc-1.0")
+ self.outdatedpackages=[]
+ def create(self,mybigkey,myparent=None,addme=1):
+ """creates the actual digraph of packages to merge. return 1 on success, 0 on failure
+ mybigkey = specification of package to merge; myparent = parent package (one depending on me);
+ addme = should I be added to the tree? (for the --onlydeps mode)"""
+ if mybigkey==None:
+ return
+ sys.stdout.write(".")
+ sys.stdout.flush()
+ if self.digraph.hasnode(mybigkey):
+ #if we've already hit this node before, we're already recursing on the dependencies.
+ #no need to recurse again.
+ if addme:
+ if myparent:
+ self.digraph.addnode(mybigkey,myparent)
+ return 1
+ mytype,myroot,mykey=string.split(mybigkey)
+ if "--noreplace" in self.myopts:
+ if self.db[myroot]["vartree"].exists_specific(mykey):
+ print "\n>>>",mykey,"already merged in",myroot+", skipping...\n"
+ return 1
+ if mytype=="binary":
+ if not self.db[portage.root]["bintree"].exists_specific(mykey):
+ print "\n\n!!!",mytype,mykey,"not found (possibly blocked by package.mask)\n"
+ sys.exit(1)
+ mypkgparts=portage.catpkgsplit(mykey)
+ mytbz2=xpak.tbz2(self.db[portage.root]["bintree"].getname(mykey))
+ edepend=["",string.join(mytbz2.getelements("RDEPEND")," "),mytbz2.getfile("SLOT",mypkgparts[2])]
+ elif mytype=="ebuild":
+ if not self.db[myroot]["porttree"].exists_specific(mykey):
+ print "\n\n!!!",mytype,mykey,"not found (possibly blocked by package.mask)\n"
+ sys.exit(1)
+ mydep={}
+ myebuild=self.db[myroot]["porttree"].getname(mykey)
+ edepend=portage.doebuild(myebuild,"depend",myroot,1,edebug)
+ if edepend==1:
+ print "!!! emerge aborting."
+ sys.exit(1)
+ elif mytype=="blocks":
+ edepend=None
+ parenttype,parentroot,parentkey=string.split(myparent)
+ mykeyparts=portage.catpkgsplit(mykey)
+ parentkeyparts=portage.catpkgsplit(parentkey)
+ # only add blocking deps that aren't from the same package that is installing
+ if mykeyparts[0]!=parentkeyparts[0] or mykeyparts[1]!=parentkeyparts[1]:
+ self.digraph.addnode(mybigkey,myparent)
+
+ if edepend:
+ mydep={}
+ if myroot=="/":
+ mydep["/"]=edepend[0]+" "+edepend[1]
+ else:
+ mydep["/"],mydep[myroot]=edepend
+ if addme:
+ self.digraph.addnode(mybigkey,myparent)
+ for dep in mydep.keys():
+ if "--update"==self.myaction:
+ mycheck=self.emptytree.depcheck(mydep[dep])
+ else:
+ mycheck=self.db[dep]["vartree"].depcheck(mydep[dep])
+ if mycheck[0]==0:
+ print "!!! depgraph.create() error: string format:",mydep
+ return 0
+ for x in mycheck[1]:
+ mynew=self.match(x,dep,mykey)
+ if not self.digraph.hasnode(mynew):
+ if addme:
+ if not self.create(mynew,mybigkey):
+ return 0
+ else:
+ if not self.create(mynew,None):
+ return 0
+ else:
+ self.digraph.addnode(mynew,mybigkey)
+
+ return 1
+
+ def altlist(self):
+ mygraph=self.digraph.copy()
+ dolist=["/"]
+ retlist=[]
+ for x in self.db.keys():
+ self.db[x]["merge"]=[]
+ if x not in dolist:
+ dolist.append(x)
+ while (not mygraph.empty()):
+ mycurkey=mygraph.firstzero()
+ if not mycurkey:
+ print "!!! Error: circular dependencies"
+ sys.exit(1)
+ splitski=string.split(mycurkey)
+ if "--update"==self.myaction:
+ if not self.db["/"]["vartree"].exists_specific(splitski[2]):
+ self.db["/"]["merge"].append(splitski)
+ else:
+ self.db[splitski[1]]["merge"].append(splitski)
+ mygraph.delnode(mycurkey)
+ for x in dolist:
+ for y in self.db[x]["merge"]:
+ retlist.append(y)
+ return retlist
+
+ def syscreate(self,mylines=[]):
+ for myline in mylines:
+ if "--update"==self.myaction or "--rebuild"==self.myaction:
+ self.create(self.match(myline,mykey="update (likely old /var/db/pkg entry)"))
+ else:
+ mycheck=self.db[portage.root]["vartree"].depcheck(myline)
+ if mycheck[0]==0:
+ print "\n!!! Warning:",myline,"has an invalid depstring\n"
+ continue
+ if mycheck[1]==None:
+ continue
+ for x in mycheck[1]:
+ self.create(self.match(myline,mykey="syscreate1"))
+
+ def match(self,mydep,myroot=portage.root,mykey=None):
+ # support mutual exclusive deps
+ mydep2=mydep
+ if mydep2[0]=="!":
+ mydep2=mydep[1:]
+
+ if self.myaction=="--rebuild":
+ myeb=self.db[portage.root]["vartree"].dep_bestmatch(mydep2)
+ if not self.db[portage.root]["porttree"].exists_specific(myeb):
+ self.outdatedpackages.append(myeb)
+ return None
+ else:
+ myeb=self.db[portage.root]["porttree"].dep_bestmatch(mydep2)
+ if not myeb:
+ if not mykey:
+ print "\n!!! Warning: couldn't find match for",mydep
+ else:
+ print "\n!!! Warning: couldn't find match for",mydep,"in",mykey
+ return None
+
+ # handle filtering of virtual deps for the rebuild action
+ if self.myaction=="--rebuild" and myeb[0:len("virtual")]=="virtual":
+ return None
+
+ # handle filtering of non slot packages
+ if "noslot" in mymode and self.db[portage.root]["vartree"].slotted(myeb)==1:
+ return None
+
+ if mydep[0]=="!":
+ myk="blocks "+myroot+" "+myeb
+ else:
+ if "--usepkg" in self.myopts:
+ mypk=self.db[portage.root]["bintree"].dep_bestmatch(mydep)
+ if myeb==mypk:
+ myk="binary "+portage.root+" "+mypk
+ else:
+ myk="ebuild "+myroot+" "+myeb
+ else:
+ myk="ebuild "+myroot+" "+myeb
+
+ return myk
+
+ def display(self,mylist):
+ for x in mylist:
+ if x[0]=="blocks":
+ addl=""+red("B")+" "
+ print "["+x[0]+" "+addl+"]",red(x[2])
+ else:
+ if self.db[x[1]]["vartree"].exists_specific(x[2]):
+ addl=" "+yellow("R")+" "
+ elif self.db[x[1]]["vartree"].exists_specific_cat(x[2]):
+ addl=" "+turquoise("U")+" "
+ else:
+ addl=" "+green("N")+" "
+ print "["+x[0]+" "+addl+"]",x[2],"to",x[1]
+
+ def outdated(self):
+ return self.outdatedpackages
+
+ def merge(self,mylist):
+ returnme=0
+ #check for blocking dependencies
+ for x in mylist:
+ if x[0]=="blocks":
+ print "\n!!! Error: the "+x[2]+" package conflicts with this package and both can't be installed on the same system together."
+ sys.exit(1)
+
+ #above line used by --fetchonly
+ for x in mylist:
+ myroot=x[1]
+ print ">>> emerge",x[2],"to",x[1]
+ #the last argument in the portage.doebuild() tells doebuild to *not* do dep checking
+ #(emerge is already handling that)
+ y=self.db[myroot]["porttree"].getname(x[2])
+ if x[0]=="ebuild":
+ if "--fetchonly" in self.myopts:
+ retval=portage.doebuild(y,"fetch",myroot,0,edebug)
+ if retval:
+ print
+ print "!!! Fetch for",y,"failed, continuing..."
+ print
+ returnme=1
+ elif "--buildpkg" in self.myopts:
+ #create pkg, then merge pkg
+ retval=portage.doebuild(y,"clean",myroot,0,edebug)
+ if retval:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ retval=portage.doebuild(y,"package",myroot,0,edebug)
+ if retval:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ #dynamically update our database
+ self.db[portage.root]["bintree"].inject(x[2])
+ mytbz2=self.db[portage.root]["bintree"].getname(x[2])
+ retval=portage.pkgmerge(mytbz2,myroot)
+ if retval==None:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ else:
+ retval=portage.doebuild(y,"clean",myroot,0,edebug)
+ if retval:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ retval=portage.doebuild(y,"merge",myroot,0,edebug)
+ if retval:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ #dynamically update our database
+ elif x[0]=="binary":
+ #merge the tbz2
+ mytbz2=self.db[portage.root]["bintree"].getname(x[2])
+ retval=portage.pkgmerge(mytbz2,x[1])
+ if retval==None:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ #need to check for errors
+ self.db[x[1]]["vartree"].inject(x[2])
+ if "--autoclean" in self.myopts:
+ retval=portage.doebuild(y,"clean",myroot,0,edebug)
+ if retval:
+ print "!!! emerge aborting on ",y,"."
+ sys.exit(1)
+ #my doing an exit this way, --fetchonly can continue to try to
+ #fetch everything even if a particular download fails.
+ if "--fetchonly" 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 post_emerge(retval=0):
+ auxpat=re.compile('^([^-]*)(-\d+)?\.info(-\d+)?(\.gz)?')
+ global myopts
+ print
+ if "--pretend" in myopts:
+ sys.exit(retval)
+ root=portage.root
+ if not os.path.isdir(root+"usr/share/info"):
+ print " "+root+"usr/share/info doesn't exist, skipping info regeneration."
+ elif not os.path.exists("/usr/bin/install-info"):
+ print " /usr/bin/install-info doesn't exist; skipping info regeneration."
+ else:
+ print " "+green("*")+" Regenerating GNU info directory index..."
+ if os.path.exists(root+"usr/share/info/dir"):
+ os.rename(root+"usr/share/info/dir",root+"usr/share/info/dir.old")
+ icount=0
+ badcount=0
+ for x in os.listdir(root+"usr/share/info"):
+ aux=auxpat.search(x)
+ if not aux:
+ continue
+ auxgroups=aux.groups()
+ if not (auxgroups[1] or auxgroups[2]):
+ myso=commands.getstatusoutput("/usr/bin/install-info --dir-file="+root+"usr/share/info/dir "+root+"usr/share/info/"+x)[1]
+ if myso!="":
+ print auxgroups
+ badcount=badcount+1
+ if "--verbose" in myopts:
+ print myso
+ icount=icount+1
+ if badcount:
+ if "--verbose" not in myopts:
+ print " "+yellow("*")+" Processed",icount,"info files:",badcount,"errors; type "+green("emerge --verbose")+" to view errors."
+ else:
+ print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors."
+
+ else:
+ print " "+green("*")+" Processed",icount,"info files."
+ if portage.settings["CONFIG_PROTECT"]:
+ #number of directories with some protect files in them
+ procount=0
+ for x in string.split(portage.settings["CONFIG_PROTECT"]):
+ if os.path.isdir(x):
+ a=commands.getstatusoutput("cd "+x+"; find -iname '._cfg????_*'")
+ if a[0]!=0:
+ print " "+red("*")+" error scanning",x
+ else:
+ files=string.split(a[1])
+ if files:
+ procount=procount+1
+ print " "+yellow("* IMPORTANT:")+"",len(files),"config files in",x,"need updating."
+ if procount:
+ print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
+ print
+ sys.exit(retval)
+
+# general options that should be taken into account before any action
+if not portage.settings.has_key("MAINTAINER_noclean"):
+ if not "--autoclean" in myopts:
+ myopts.append("--autoclean")
+if "--debug" in myopts:
+ edebug=1
+
+# process modes that aren't in the universal emerge interface format first
+# this format is 'emerge --action --option --option [packageset]'
+if "rsync" in mymode and not myaction:
+ if not os.path.exists("/usr/bin/rsync"):
+ print "!!! /usr/bin/rsync does not exist, so rsync support is disabled."
+ sys.exit(1)
+ rclean=0
+ 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)
+ if "--clean" in myopts:
+ #we'll --delete files when we rsync
+ rclean=1
+ mycommand="/usr/bin/rsync -rlptDv --stats --progress "
+ if rclean:
+ mycommand=mycommand+"--delete --exclude='distfiles/*' --exclude='packages/*' "
+ mycommand=mycommand+"rsync://cvs.gentoo.org/gentoo-x86-portage/* "+myportdir
+ print ">>> starting rsync with cvs.gentoo.org..."
+ #protect users that did not set a default umask
+ os.umask(022)
+ sys.exit(os.system(mycommand))
+
+# HELP action
+elif "--help"==myaction:
+ if len(mymode)==0:
+ print
+ print bold("Usage: ")+turquoise("emerge")+" [ "+green("action")+" ] [ "+green("options")+" ] [ "+turquoise("ebuildfile")+" | "+turquoise("tbz2file")+" | "+turquoise("dependency")+" ] ..."
+ print " "+turquoise("emerge")+" [ "+green("action")+" ] [ "+green("options")+" ] [ "+turquoise("system")+" | "+turquoise("world")+" | "+turquoise("noslot")+" ]"
+ print " "+turquoise("emerge")+" [ "+green("--clean")+" "+green("-c")+" ] "+turquoise("rsync")
+ print " "+turquoise("emerge")+" "+green("--help")+" "" "+green("-h")+" [ "+turquoise("rsync")+" | "+turquoise("system")+" | "+turquoise("world")+" | "+turquoise("noslot")+" | "+turquoise("config")+" ] "
+ print
+ print turquoise("Actions:")
+ print " "+green("--help")+" "+green("-h")
+ print " displays this help, an additional mode specifier provides"
+ print " detailed help about that mode instead"
+ print
+ print " "+green("--update")+" "+green("-u")
+ print " updates installed packages, this is typically used with",bold("world")
+ print " and",bold("system")
+ print
+ print " "+green("--zap")+" "+green("-z")
+ print " removes an installed package. the arguments can be in two"
+ print " different formats : /var/db/pkg/category/package-version"
+ print " or category/package."
+ print
+ print " "+green("--rebuild")+" "+green("-r")
+ print " forcably rebuild installed packages, this is typically used with"
+ print " "+bold("world"),"and",bold("system")
+ print
+ print " "+green("--search")+" "+green("-s")
+ print " searches for matches of the supplied string in the current local"
+ print " portage tree. The search string is a regular expression."
+ print " A few examples: "
+ print " "+bold("emerge --search \"^kde\"")
+ print " list all packages starting with kde"
+ print " "+bold("emerge --search \"gcc$\"")
+ print " list all packages ending with gcc"
+ print " "+bold("emerge --search \"\"")+" or"
+ print " "+bold("emerge --search \"*\"")
+ print " list all available packages "
+ print
+ print turquoise("Options:")
+ print " "+green("--autoclean")+" "+green("-a")
+ print " emerge normally cleans out the package-specific temporary"
+ print " build directory before it starts the building a package. With"
+ print " --autoclean, it will also clean the directory *after* the"
+ print " build completes. This option is automatically enabled for"
+ print " normal users, but maintainers can use this option to enable"
+ print " autocleaning."
+ print
+ print " "+green("--buildpkg")+" "+green("-b")
+ print " tell emerge to build binary packages for all ebuilds processed"
+ print " (in addition to actually merging the packages. Useful for"
+ print " maintainers or if you administrate multiple Gentoo Linux"
+ print " systems (build once, emerge tbz2s everywhere)."
+ print
+ print " "+green("--debug")+" "+green("-d")
+ print " Tell emerge to run the ebuild command in --debug mode. In this"
+ print " mode, the bash build environment will run with the -x option,"
+ print " causing it to output verbose debug information print to stdout."
+ print " --debug is great for finding bash syntax errors."
+ print
+ print " "+green("--fetchonly")+" "+green("-f")
+ print " Instead of doing any package building, just perform fetches for"
+ print " all packages (main package as well as all dependencies.)"
+ print
+ print " "+green("--onlydeps")+" "+green("-o")
+ print " Only merge (or pretend to merge) the dependencies of the"
+ print " specified packages, not the packages themselves."
+ print
+ print " "+green("--pretend")+" "+green("-p")
+ print " instead of actually performing the merge, simply display what"
+ print " ebuilds and tbz2s *would* have been installed if --pretend"
+ print " weren't used. Using --pretend is strongly recommended before"
+ print " installing an unfamiliar package. In the printout, N = new,"
+ print " U = upgrading, R = replacing"
+ print
+ print " "+green("--noreplace")+" "+green("-n")
+ print " Skip the packages specified on the command-line that have"
+ print " already been installed. Without this option, any packages,"
+ print " ebuilds, or deps you specify on on the command-line *will* cause"
+ print " Portage to remerge the package, even if it is already installed."
+ print " Note that Portage will never remerge dependencies automatically."
+ print
+ print " "+green("--usepkg")+" "+green("-k")
+ print " tell emerge to use binary packages (from $PKGDIR) if they are"
+ print " available, thus possibly avoiding some time-consuming compiles."
+ print " This option is useful for CD installs; you can export"
+ print " PKGDIR=/mnt/cdrom/packages and then use this option to have"
+ print " emerge \"pull\" binary packages from the CD in order to satisfy"
+ print " dependencies."
+ print
+ print " "+green("--verbose")+" "+green("-v")
+ print " Tell emerge to run in verbose mode. Currently, this causes"
+ print " emerge to print out GNU info errors, if any."
+ print
+ elif "rsync" in mymode:
+ print
+ print bold("Usage: ")+turquoise("emerge")+" [ "+green("--clean")+" "+green("-c")+" ] "+turquoise("rsync")
+ print
+ print " \"emerge rsync\" initiates an rsync update with cvs.gentoo.org,"
+ print " updating your Portage tree (typically in /usr/portage). This option"
+ print " will erase any changes that you have made to existing Portage files"
+ print " so be careful. \"emerge --clean rsync\" does the same thing as \"emerge"
+ print " rsync\", but files that no longer exist on our server are removed."
+ print
+ elif "system" in mymode:
+ print
+ print bold("Usage: ")+turquoise("emerge")+" [ "+green("action")+" ] "+" [ "+green("options")+" ] "+turquoise("system")
+ print
+ print " \"emerge system\" is the Portage system update command. When run, it"
+ print " will scan the etc/make.profile/packages file and determine what"
+ print " packages need to be installed so that your system meets the minimum"
+ print " requirements of your current system profile. Note that this doesn't"
+ print " necessarily bring your system up-to-date at all; instead, it just"
+ print " ensures that you have no missing parts. For example, if your system"
+ print " profile specifies that you should have sys-apps/iptables installed"
+ print " and you don't, then \"emerge system\" will install it (the most"
+ print " recent version that matches the profile spec) for you. It's always a"
+ print " good idea to do an \"emerge --pretend system\" before an \"emerge"
+ print " system\", just so you know what emerge is planning to do."
+ print
+ elif "world" in mymode:
+ print
+ print bold("Usage: ")+turquoise("emerge")+" [ "+green("action")+" ] "+" [ "+green("options")+" ] "+turquoise("world")
+ print
+ elif "noslot" in mymode:
+ print
+ print bold("Usage: ")+turquoise("emerge")+" [ "+green("action")+" ] "+" [ "+green("options")+" ] "+turquoise("noslot")
+ print
+ elif "config" in mymode:
+ outstuff=green("Config file management support (preliminary)")+"""
+
+Portage has a special feature called "config file protection". The purpose of
+this feature is to prevent new package installs from clobbering existig
+configuration files. By default, config file protection is turned on for /etc
+and the KDE configuration dirs; more may be added in the future.
+
+When Portage installs a file into a protected directory tree like /etc, any
+existing files will not be overwritten. If a file of the same name already
+exists, Portage will change the name of the to-be- installed file from 'foo' to
+'._cfg0000_foo'. If '._cfg0000_foo' already exists, this name becomes
+'._cfg0001_foo', etc. In this way, existing files are not overwritten,
+allowing the administrator to manually merge the new config files and avoid any
+unexpected changes.
+
+In addition to protecting overwritten files, Portage will not delete any files
+from a protected directory when a package is unmerged. While this may be a
+little bit untidy, it does prevent potentially valuable config files from being
+deleted, which is of paramount importance.
+
+Protected directories are set using the CONFIG_PROTECT variable, normally
+defined in /etc/make.globals. Directory exceptions to the CONFIG_PROTECTed
+directories can be specified using the CONFIG_PROTECT_MASK variable. To find
+files that need to be updated in /etc, type:
+
+# find /etc -iname '._cfg????_*'
+
+You can disable this feature by setting CONFIG_PROTECT="" in /etc/make.conf.
+Then, Portage will mercilessly auto-update your config files. Alternatively,
+you can leave Config File Protection on but tell Portage that it can overwrite
+files in certain specific /etc subdirectories. For example, if you wanted
+Portage to automatically update your rc scripts and your wget configuration,
+but didn't want any other changes made without your explicit approval, you'd
+add this to /etc/make.conf:
+
+CONFIG_PROTECT_MASK="/etc/wget /etc/rc.d"
+
+"""
+ print outstuff
+
+# SEARCH action
+elif "--search"==myaction:
+ if not myfiles:
+ print
+ print "No search terms provided."
+ print
+ else:
+ searchinstance = search()
+ for mysearch in myfiles:
+ searchinstance.setKey(mysearch)
+ searchinstance.execute()
+ searchinstance.output()
+
+# ZAP action
+elif "--zap"==myaction:
+ if not myfiles and not "noslot" in mymode:
+ print
+ print "No packages to unmerge have been provided."
+ print
+ else:
+ full_paths={}
+ full_ebuild_paths={}
+ full_package_paths={}
+ non_slot_packages=[]
+
+ var_path=portage.root+"var/db/pkg"
+ if "noslot" in mymode:
+ localtree=portage.vartree(portage.root)
+ for x in localtree.getallnodes():
+ if localtree.slotted(x)==0:
+ mymatches=localtree.dep_match(x)
+ for package in mymatches:
+ myfullpaths=localtree.getebuildpaths(package)
+ for full_path in myfullpaths :
+ if not os.path.exists(full_path):
+ print "The ebuild '"+full_path+"' couldn't be found."
+ print "Your portage installation tree seems to be corrupted."
+ else:
+ full_package_paths[full_path]=package
+ else:
+ # process all arguments, verify if they can be resolved to an installed
+ # ebuild file and add the absolute paths of these ebuild to a list
+ for x in myfiles:
+
+ # an absolute path has been given
+ if (x[0]=='/'):
+ path_parts=split(x, '/')
+ if len(path_parts) != 6:
+ print "When providing an absolute path it should be"
+ print "in the following format : "+var_path+"/category/package"
+ print "The path '"+x+"' doesn't respect this."
+ sys.exit(1)
+ elif not os.path.exists(x):
+ print "The path '"+x+"' doesn't exist."
+ sys.exit(1)
+ elif -1 == find(x, var_path):
+ print "The path '"+x+"' didn't commence with '"+var_path+"'."
+ sys.exit(1)
+ else:
+ # check if the SLOT file is present, and get the package version
+ # from the PF file in that case
+ package_slot_path=strip(x)+"/SLOT"
+ package_pf_path=strip(x)+"/PF"
+ if os.path.exists(package_pf_path):
+ package_pf_file=open(package_pf_path)
+ package_pf=package_pf_file.readline().strip()
+ package_pf_file.close()
+ else:
+ package_pf=path_parts[5]
+ full_path=strip(x)+"/"+package_pf+".ebuild"
+ if not os.path.exists(full_path):
+ print "The ebuild '"+full_path+"' couldn't be found."
+ print "Your portage installation tree seems to be corrupted."
+ else:
+ path_parts=split(full_path, "/")
+ full_ebuild_paths[full_path]=path_parts[4]+"/"+package_pf
+
+ # a category and package name have been given
+ else:
+ localtree=portage.vartree(portage.root)
+ mymatches=localtree.dep_match(x)
+ # if no matches were found, try again by adding a '=' dep symbol if no
+ # dep symbols are already present
+ if not mymatches and x[0] not in ('<','>','=','~'):
+ mymatches=localtree.dep_match("="+x)
+
+ # only loops over the matches if they were found
+ if mymatches:
+ for package in mymatches:
+ myfullpaths=localtree.getebuildpaths(package)
+ for full_path in myfullpaths :
+ if not os.path.exists(full_path):
+ print "The ebuild '"+full_path+"' couldn't be found."
+ print "Your portage installation tree seems to be corrupted."
+ else:
+ full_package_paths[full_path]=package
+
+ # determine what the non slot packages are
+ if len(full_package_paths) > 0:
+ # determine the latest installed packages of each cat/pkg key
+ full_paths_keys=full_package_paths.keys()
+ # sort the ebuild paths
+ full_paths_keys.sort()
+ previous_package_set=None
+ for full_path in full_paths_keys:
+ # construct the key that will be used to determine when a new package set
+ # is being processed, the package slot is taken into account for this
+ package_parts=portage.pkgsplit(full_package_paths[full_path])
+ slot_path=dirname(full_path)+"/SLOT"
+ if not os.path.exists(slot_path):
+ package_slot=package_parts[1]
+ non_slot_packages.append(package_parts[0]+"-"+package_parts[1])
+
+ full_paths=full_ebuild_paths.keys()
+ full_paths.extend(full_package_paths.keys())
+
+ if len(full_paths)==0:
+ print "Couldn't find any matching installed packages."
+ sys.exit(1)
+ else:
+ if "--pretend" in myopts:
+ print
+ print "The are the packages that I would unmerge :"
+ print
+ else:
+ print
+ print "The following packages are going to be unmerged :"
+ print
+ # this makes revisions come before slot versions
+ # and therefor unmerges the older packages first
+ full_paths.sort()
+ for full_path in full_paths:
+ path_parts=split(full_path, "/")
+ print " "+path_parts[4]+"/"+path_parts[5]
+
+ if len(non_slot_packages)>0:
+ print
+ if "--verbose" not in myopts:
+ print " "+yellow("* IMPORTANT:"),len(non_slot_packages),"non slot packages; use "+green("--verbose")+" to view details."
+ else:
+ print " "+yellow("* IMPORTANT:"),len(non_slot_packages),"non slot packages"
+ print " "+yellow("*")+" These packages have been merged with an old version of portage that didn't"
+ print " "+yellow("*")+" support binary compatibility slots. This means that each package with a"
+ print " "+yellow("*")+" different version number will be considered different and only older versions"
+ print " "+yellow("*")+" of different releases will be unmerged automatically."
+ print " "+yellow("*")+" To get rid of all non slot packages, you can rebuild your system with"
+ print " "+yellow("*")+" "+green("emerge --noslot rebuild")+"."
+ print
+ for non_slot_package in non_slot_packages:
+ print " "+non_slot_package
+
+ if "--pretend" in myopts:
+ print
+ else:
+ secs=string.atoi(portage.settings["UNMERGE_DELAY"])
+ if secs > 0:
+ print
+ print "Waiting",secs,"seconds to make sure that you want these"
+ print "packages to be removed ..."
+ while secs > 0:
+ sys.stdout.write(str(secs)+" ")
+ sys.stdout.flush()
+ time.sleep(1)
+ secs = secs-1
+ print secs
+ for full_path in full_paths:
+ print "Unmerging "+os.path.basename(full_path)+" ..."
+ retval=portage.doebuild(full_path,"unmerge",portage.root,0,edebug)
+ post_emerge()
+
+# REBUILD action
+elif "--rebuild"==myaction:
+ if not "system" in mymode and not "world" in mymode and not "noslot" in mymode:
+ print
+ print " "+red("* WARNING:"),green("emerge --rebuild"),"shouldn't be used for regular packages"
+ print " "+red("*"),"it's only intended to be used with",green("system")+", "+green("world")+", and",green("noroot")
+ print
+ else:
+ if "--pretend" in myopts:
+ print
+ print "These are the packages that I would rebuild, in order."
+ print
+
+ if "system" in mymode:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ print "Calculating system dependencies",
+ mydepgraph.syscreate(getsyslist())
+ print " done!"
+ elif "world" in mymode or "noslot" in mymode:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ print "Calculating world dependencies",
+ mydepgraph.syscreate(mydepgraph.db["/"]["vartree"].getallnodes())
+ print " done!"
+
+ if "--pretend" in myopts:
+ mydepgraph.display(mydepgraph.altlist())
+
+ myoutdated=mydepgraph.outdated()
+ if len(myoutdated):
+ if "--verbose" not in myopts:
+ print
+ print " "+yellow("* IMPORTANT:"),len(myoutdated),"packages aren't available anymore; use "+green("--verbose")+" for details."
+ else:
+ print
+ print " "+yellow("* IMPORTANT:"),len(myoutdated),"packages aren't available anymore"
+ print " "+yellow("*")+" Your portage tree doesn't contain the ebuilds anymore that correspond to the"
+ print " "+yellow("*")+" following packages. This means that portage is unable to rebuild them."
+ print " "+yellow("*")+" Instead you should upgrade to the latest versions or install possible"
+ print " "+yellow("*")+" alternative packages that provide the same functionalities."
+ myoutdated.sort()
+ for mypackage in myoutdated:
+ print " "+mypackage
+ else:
+ mydepgraph.merge(mydepgraph.altlist())
+ post_emerge()
+
+# INSTALL and UPDATE action
+elif "--update"==myaction or not myaction:
+ if not myaction and "world" in mymode:
+ print
+ print " "+red("* WARNING:"),green("emerge world"),"can't be used without an action"
+ print " "+red("*"),green("world"),"is only intended to be used with",green("emerge --update")
+ print
+ else:
+ if "--pretend" in myopts:
+ print
+ print "These are the packages that I would merge, in order."
+ print
+
+ if "system" in mymode:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ print "Calculating system dependencies",
+ mydepgraph.syscreate(getsyslist())
+ print " done!"
+ elif "world" in mymode:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ print "Calculating world dependencies",
+ mydepgraph.syscreate(mydepgraph.db["/"]["vartree"].getallnodes())
+ print " done!"
+ elif "noslot" in mymode:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ print "Calculating noslot dependencies",
+ mydepgraph.syscreate(mydepgraph.db["/"]["vartree"].getallnodes())
+ print " done!"
+ else:
+ mydepgraph=depgraph(mymode,myaction,myopts)
+ if not myfiles:
+ post_emerge()
+ #we don't have any files to process; skip this step and exit
+ print "Calculating dependencies",
+ for mypkg in myfiles:
+ if mypkg[-5:]==".tbz2":
+ mytype="binary"
+ mytbz2=xpak.tbz2(mypkg)
+ mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(mypkg)[:-5]
+ elif mypkg[-7:]==".ebuild":
+ mytype="ebuild"
+ mykey=os.path.basename(os.path.abspath(mypkg+"/../.."))+"/"+os.path.basename(mypkg)[:-7]
+ else:
+ mykey=""
+ if "--usepkg" in myopts:
+ mykey=mydepgraph.db[portage.root]["bintree"].dep_bestmatch(mypkg)
+ mytype="binary"
+ if not mykey:
+ mykey=mydepgraph.db[portage.root]["porttree"].dep_bestmatch(mypkg)
+ mytype="ebuild"
+ if not mykey:
+ print "!!! Couldn't find match for",mypkg+"; aborting."
+ sys.exit(1)
+ # else:
+ # print "!!! Error:",x,"is neither an ebuild nor a .tbz2 package."
+ # sys.exit(1)
+ mydepgraph.create(mytype+" "+portage.root+" "+mykey,None,"--onlydeps" not in myopts)
+ print " done!"
+
+ if "--pretend" in myopts:
+ mydepgraph.display(mydepgraph.altlist())
+ else:
+ mydepgraph.merge(mydepgraph.altlist())
+ post_emerge()
+