#!/usr/bin/env python2.2 # Copyright 1999-2003 Gentoo Technologies, Inc. # Distributed under the terms of the GNU General Public License v2 # $Header: /home/cvsroot/gentoo-src/portage/bin/emerge,v 1.215 2003/07/02 03:23:36 carpaski Exp $ import os os.environ["PORTAGE_CALLER"]="emerge" import sys,emergehelp,xpak,string,re,commands,time,shutil,traceback,atexit from stat import * from output import * import portage if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]): nocolor() if portage.settings.has_key("PORTAGE_NICENESS"): try: os.nice(int(portage.settings["PORTAGE_NICENESS"])) except Exception,e: print "!!! Failed to change nice value to '"+str(portage.settings["NICE"])+"'" print "!!!",e #Freeze the portdbapi for enhanced performance: portage.portdb.freeze() # Kill noauto as it will break merges otherwise. while 'noauto' in portage.features: del portage.features[portage.features.index('noauto')] spinner="\|/-\|/-" spinpos=0 #number of ebuilds merged merged=0 params=["selective", "deep", "self", "recurse", "empty"] actions=[ "clean", "config", "depclean", "help", "info", "inject", "prune", "regen", "rsync", "search", "sync", "system", "unmerge", "world" ] options=[ "--buildpkg", "--buildpkgonly", "--changelog", "--columns", "--debug", "--deep", "--digest", "--emptytree", "--fetchonly", "--help", "--noconfmem", "--nodeps", "--noreplace", "--nospinner", "--oneshot", "--onlydeps", "--pretend", "--quiet", "--resume", "--searchdesc", "--selective", "--skipfirst", "--update", "--upgradeonly", "--usepkg", "--usepkgonly", "--verbose", "--version" ] shortmapping={ "b":"--buildpkg", "B":"--buildpkgonly", "c":"--clean", "C":"--unmerge", "d":"--debug", "D":"--deep", "e":"--emptytree", "f":"--fetchonly", "h":"--help", "i":"--inject", "k":"--usepkg", "K":"--usepkgonly", "l":"--changelog", "n":"--noreplace", "o":"--onlydeps", "O":"--nodeps", "p":"--pretend", "P":"--prune", "q":"--quiet", "s":"--search", "S":"--searchdesc", "u":"--update", "U":"--upgradeonly", "v":"--verbose", "V":"--version" } myaction=None myopts=[] myfiles=[] edebug=0 # process short actions and options 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] 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 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": #print #print red("*** --rsync has been deprecated.") #print red("*** Please use '--sync' instead.") 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": #print red("*** Please use '--sync' instead.") x="sync" #else: #print red("*** Please use '--"+x+"' instead.") if myaction: print print red("!!!")+green(" Multiple actions requested... Please choose one only.") #print red("!!! '")+darkgreen("--"+myaction)+"' "+red("or")+" '"+darkgreen("--"+x)+"'" 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 (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) # 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") # Also allow -S to invoke search action (-sS) if ("--searchdesc" in myopts) and (not myaction): myaction = "search" # Also allow -K to apply --usepkg/-k if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): myopts.append("--usepkg") # Also allow -U to apply --update/-u if ("--upgradeonly" in myopts) and not ("--update" in myopts): print ">>> --upgradeonly implies --update... adding --update to options." myopts.append("--update") # Also allow -l to apply --pretend/-p if ("--changelog" in myopts) and not ("--pretend" in myopts): print ">>> --changelog implies --pretend... adding --pretend to options." myopts.append("--pretend") # Set so that configs will be merged regardless of remembered status if ("--noconfmem" in myopts): portage.settings["NOCONFMEM"]="1" # Set various debug markers... They should be merged somehow. if ("--debug" in myopts): portage.settings["PORTAGE_DEBUG"]="1" portage.debug=1 def emergelog(mystr): if "notitles" not in portage.features: xtermTitle(mystr) try: mylogfile=open("/var/log/emerge.log", "a") mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") mylogfile.flush() mylogfile.close() except Exception, e: if edebug: print "emergelog():",e pass def emergeexit(): """This gets out final log message in before we quit. As it overrides any other atexit's we have setup, we need to call them ourself.""" portage.portageexit() emergelog(" *** terminating.") if "notitles" not in portage.features: xtermTitleReset() atexit.register(emergeexit) def countdown(secs=5, doing="Starting"): if secs: print ">>> Waiting",secs,"seconds before starting..." print ">>> (Control-C to abort)...\n"+doing+" in: ", ticks=range(secs) ticks.reverse() for sec in ticks: sys.stdout.write(red(str(sec+1)+" ")) sys.stdout.flush() time.sleep(1) print def getportageversion(): try: profilestr=os.readlink("/etc/make.profile") if profilestr[-1]=="/": profilestr=profilestr[:-1] profilever=string.split(profilestr, "/")[-1] except: profilever="unavailable" glibcver=[] for x in portage.vardbapi(portage.root).match("glibc"): xs=portage.pkgsplit(x) if glibcver: glibcver+=","+xs[1]+"-"+xs[2] else: glibcver=xs[1]+"-"+xs[2] if glibcver==[]: glibcver="unavailable" gccout=commands.getstatusoutput("`which gcc` -dumpversion") if gccout[0]: print "!!! No gcc found. You probably need to 'source /etc/profile' to update" print "!!! the environment of this terminal and possibly other terminals also." print gccver="[unavailable]" else: gccver="gcc-"+gccout[1] return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", glibc-"+glibcver+")" 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 (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", "help", "info"]: pass elif (not myaction) and (not myfiles): pass elif ("--pretend" in myopts) and (myaction in ["world","system","clean","prune","unmerge"]): pass else: 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=string.join(myopts, " ") if myaction: myelogstr+=" "+myaction if myfiles: myelogstr+=" "+string.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) def update_spinner(): global spinner, spinpos if sys.stdout.isatty() and not ("--nospinner" in myopts): sys.stdout.write("\b"+spinner[spinpos]) spinpos=(spinpos+1)%8 sys.stdout.flush() # search functionality class search: # # class constants # VERSION_SHORT=1 VERSION_RELEASE=2 # # public interface # def __init__(self): """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"] def execute(self,searchkey): """Performs the search for the supplied search key""" global myopts self.searchkey=searchkey self.packagematches = [] if "--searchdesc" in myopts: self.searchdesc=1 self.matches = {"pkg":[], "desc":[]} else: self.searchdesc=0 self.matches = {"pkg":[]} print "Searching... ", if self.searchkey=="*": #hack for people who aren't regular expression gurus self.searchkey==".*" if re.search("\+\+", self.searchkey): #hack for people who aren't regular expression gurus self.searchkey=re.sub("\+\+","\+\+",self.searchkey) self.searchre=re.compile(self.searchkey.lower(),re.I) for package in portage.portdb.cp_all(): update_spinner() package_parts=package.split("/") masked=0 if self.searchre.search(package_parts[1]): if not portage.portdb.xmatch("match-visible",package): masked=1 self.matches["pkg"].append([package,masked]) elif self.searchdesc: # DESCRIPTION searching full_package = portage.portdb.xmatch("bestmatch-visible",package) if not full_package: #no match found; we don't want to query description full_package=portage.best(portage.portdb.xmatch("match-all",package)) if not full_package: continue else: masked=1 try: full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0] except KeyError: print "emerge: search: aux_get() failed, skipping" continue if self.searchre.search(full_desc): self.matches["desc"].append([full_package,masked]) self.mlen=0 for mtype in self.matches.keys(): self.matches[mtype].sort() self.mlen += len(self.matches[mtype]) def output(self): """Outputs the results of the search.""" print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]" print "[ Applications found : "+white(str(self.mlen))+" ]" print " " for mtype in self.matches.keys(): for match,masked in self.matches[mtype]: if mtype=="pkg": catpack=match full_package = portage.portdb.xmatch("bestmatch-visible",match) if not full_package: #no match found; we don't want to query description masked=1 full_package=portage.best(portage.portdb.xmatch("match-all",match)) else: full_package=match catpack=portage.pkgsplit(match)[0] if full_package: try: desc, homepage = portage.portdb.aux_get(full_package,["DESCRIPTION","HOMEPAGE"]) except KeyError: print "emerge: search: aux_get() failed, skipping" continue if masked: print green("*")+" "+white(match)+" "+red("[ Masked ]") else: print green("*")+" "+white(match) myversion = self.getVersion(full_package, search.VERSION_RELEASE) mysum = [0,0] mycat = match.split("/")[0] mypkg = match.split("/")[1] + "-" + myversion mydigest = portage.db["/"]["porttree"].dbapi.finddigest(mycat+"/"+mypkg) try: myfile = open(mydigest,"r") for line in myfile.readlines(): mysum[0] += int(line.split(" ")[3]) myfile.close() mystr = str(mysum[0]/1024) mycount=len(mystr) while (mycount > 3): mycount-=3 mystr=mystr[:mycount]+","+mystr[mycount:] mysum[0]=mystr+" kB" except Exception, e: if edebug: print "!!! Exception:",e mysum[0]=" [no/bad digest]" if "--quiet" not in myopts: print " ", darkgreen("Latest version available:"),myversion print " ", self.getInstallationStatus(catpack) print " ", darkgreen("Size of downloaded files:"),mysum[0] print " ", darkgreen("Homepage:")+" ",homepage print " ", darkgreen("Description:"),desc print print # # private interface # def getInstallationStatus(self,package): installed_package = self.installcache.dep_bestmatch(package) result = "" version = self.getVersion(installed_package,search.VERSION_RELEASE) if len(version) > 0: result = darkgreen("Latest version installed:")+" "+version else: result = darkgreen("Latest version installed:")+" [ Not Installed ]" 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 getlist(mode): if mode=="system": if portage.profiledir: pfile=portage.profiledir+"/packages" else: print "!!! No profile directory; system mode unavailable." sys.exit(1) elif mode=="world": pfile=portage.root+"var/cache/edb/world" try: myfile=open(pfile,"r") mylines=myfile.readlines() myfile.close() except OSError: print "!!! Couldn't open "+pfile+"; exiting." sys.exit(1) except IOError: #world file doesn't exist mylines=[] mynewlines=[] for x in mylines: myline=string.join(string.split(x)) if not len(myline): continue elif myline[0]=="#": continue elif mode=="system": if myline[0]!="*": continue myline=myline[1:] mynewlines.append(myline.strip()) return mynewlines def genericdict(mylist): mynewdict={} for x in mylist: mynewdict[portage.dep_getkey(x)]=x return mynewdict olddbapi=None class depgraph: def __init__(self,myaction,myopts): global olddbapi self.myaction=myaction self.virts=portage.getvirtuals("/") self.digraph=portage.digraph() self.orderedkeys=[] #the following is so we have an empty vartree (used in emerge update calculations) self.fakedbapi=portage.fakedbapi() #self.fakedbapi.cpv_inject("sys-libs/glibc-2.3") self.outdatedpackages=[] self.mydbapi={} if "empty" in myparams: #for --update, we want to rebuild an entire empty tree of dependencies, and then we won't merge was is already merged. self.mydbapi["/"]=self.fakedbapi else: self.mydbapi["/"]=portage.db["/"]["vartree"].dbapi if portage.root!="/": if "empty" in myparams: self.mydbapi[portage.root]=self.fakedbapi else: self.mydbapi[portage.root]=portage.db[portage.root]["vartree"].dbapi if "--usepkg" in myopts: portage.db["/"]["bintree"].populate() 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)""" #stuff to add: #SLOT-aware emerge #IUSE-aware emerge #"no downgrade" emerge #print "mybigkey:",mybigkey jbigkey=string.join(mybigkey) if self.digraph.hasnode(jbigkey+" merge") or self.digraph.hasnode(jbigkey+" nomerge"): #this conditional is needed to prevent infinite recursion on already-processed deps return 1 update_spinner() mytype,myroot,mykey=mybigkey # select the correct /var database that we'll be checking against vardbapi=portage.db[myroot]["vartree"].dbapi merging=1 # this is where we add the node to the list of packages to merge if addme: # if the package is already on the system, we add a "nomerge" # directive, otherwise we add a "merge" directive. if mytype=="blocks": # we've encountered a "blocks" node. We will totally ignore this # node and not add it to our digraph if it doesn't apply to us. if myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)): # otherwise, encode parent information where we would normally # write "(no)merge" and continue: parenttype,parentroot,parentkey,mergeme=string.split(myparent) mykexp=portage.dep_expand(mykey,self.mydbapi[myroot]) pakexp=portage.dep_expand(parentkey,self.mydbapi[myroot]) myrealkey=portage.dep_getkey(mykexp) parealkey=portage.dep_getkey(pakexp) if myrealkey!=parealkey: mybigkey.append(myparent.split()[2]) self.digraph.addnode(string.join(mybigkey),myparent) # since our blocks doesn't match any installed packages, # it doesn't apply to us and we can ignore it. return 1 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)): # the package is on the system, so don't merge it. merging=0 elif ("selective" in myparams) and vardbapi.cpv_exists(mykey): merging=0 else: #onlydeps mode; don't merge merging=2 if merging==1: mybigkey.append("merge") else: mybigkey.append("nomerge") # whatever the case, we need to add the node to our digraph so # that children can depend upon it. self.digraph.addnode(string.join(mybigkey),myparent) if ("deep" not in myparams) and (not merging): return 1 elif "recurse" not in myparams: return 1 edepend={} if mytype=="binary": mypkgparts=portage.catpkgsplit(mykey) mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey)) #edepend=["",string.join(mytbz2.getelements("RDEPEND")," "),mytbz2.getfile("SLOT",mypkgparts[2])] # We're doing this like this for clairity. edepend["DEPEND"] ="" edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ") edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ") edepend["CDEPEND"]=string.join(mytbz2.getelements("CDEPEND")," ") edepend["REBUILD"]=string.join(mytbz2.getelements("REBUILD")," ") edepend["SLOT"] =mytbz2.getfile("SLOT",mypkgparts[2]) elif mytype=="ebuild": try: #edepend=portage.portdb.aux_get(mykey,["DEPEND","RDEPEND"]) for x in ["DEPEND","RDEPEND","PDEPEND","REBUILD"]: edepend[x]=string.join(portage.portdb.aux_get(mykey,[x]), " ") except (KeyError,IOError): print "emerge: create(): aux_get() error on",mykey+"; aborting..." sys.exit(1) mydep={} mp=string.join(mybigkey) if myroot=="/": mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"] if not self.select_dep("/",mydep["/"],myparent=mp): return 0 else: mydep["/"]=edepend["DEPEND"] mydep[myroot]=edepend["RDEPEND"] if not self.select_dep("/",mydep["/"],myparent=mp): return 0 elif not self.select_dep(myroot,mydep[myroot],myparent=mp): return 0 if edepend.has_key("PDEPEND") and edepend["PDEPEND"]: # Post Depend -- Add to the list without a parent, as it depends # on a package being present AND must be built after that package. if not self.select_dep(myroot,edepend["PDEPEND"]): return 0 return 1 def select_files(self,myfiles): "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list" myfavorites=[] for x in myfiles: if x[-5:]==".tbz2": if not os.path.exists(x): if os.path.exists(portage.settings["PKGDIR"]+"/All/"+x): x=portage.settings["PKGDIR"]+"/All/"+x elif os.path.exists(portage.settings["PKGDIR"]+"/"+x): x=portage.settings["PKGDIR"]+"/"+x else: print "\n\n!!! Binary package '"+str(x)+"' does not exist." print "!!! Please ensure the tbz2 exists as specified.\n" sys.exit(1) mytbz2=xpak.tbz2(x) mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.basename(x)[:-5] if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts): return (0,myfavorites) elif not "--oneshot" in myopts: myfavorites.append(mykey) elif x[-7:]==".ebuild": mykey=os.path.basename(os.path.abspath(x+"/../.."))+"/"+os.path.basename(x)[:-7] if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts): return (0,myfavorites) elif not "--oneshot" in myopts: myfavorites.append(mykey) else: mykey=portage.dep_expand(x,portage.portdb) # select needs to return 0 on dep_check failure try: self.mysd=self.select_dep(portage.root,mykey,arg=x) except Exception, e: print "\n!!! Problem in",mykey,"dependencies." print "!!!",e sys.exit(1) if not self.mysd: return (0,myfavorites) elif not "--oneshot" in myopts: myfavorites.append(mykey) self.missingbins=0 if "--usepkgonly" in myopts: for x in self.digraph.dict.keys(): xs=string.split(x," ") if (xs[0] != "binary") and (xs[3]=="merge"): if self.missingbins == 0: print self.missingbins+=1 print "Missing binary for:",xs[2] # We're true here unless we are missing binaries. return (not self.missingbins,myfavorites) def is_newer_ver_installed(self,myroot,pkg,pkgver): "if there is a version of pkg installed newer than pkgver, return it" vardbapi=portage.db[myroot]["vartree"].dbapi myslot=portage.portdb.aux_get(pkgver,["SLOT"])[0] alleb=portage.portdb.xmatch("match-all",pkg) while alleb: cand=portage.portdb.xmatch("bestmatch-list",pkg,mylist=alleb) if not cand: break curslot=portage.portdb.aux_get(cand,["SLOT"])[0] if (curslot==myslot) and vardbapi.cpv_exists(cand): # installed, is this package newer? if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(cand)[1:]) < 0: return cand break alleb.remove(cand) def select_dep(self,myroot,depstring,myparent=None,arg=None): "given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure" if "--debug" in myopts: print print "Parent: ",myparent print "Depstring:",depstring if not arg: #processing dependencies mycheck=portage.dep_check(depstring,self.mydbapi[myroot]) if not mycheck[0]: return 0 mymerge=mycheck[1] else: #we're processing a command-line argument; unconditionally merge it even if it's already merged mymerge=[depstring] if "--debug" in myopts: print "Candidates:",mymerge for x in mymerge: if x[0]=="!": #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example) myk=["blocks",myroot,x[1:]] else: #We are not processing a blocker but a normal dependency if "--usepkgonly" in myopts: myeb=portage.db[portage.root]["bintree"].dep_bestmatch(x) else: myeb=portage.portdb.xmatch("bestmatch-visible",x) if not myeb: if not arg: xinfo='"'+x+'"' else: xinfo='"'+arg+'"' if myparent: 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: print "\n!!! "+red("all ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") if myparent: print "!!! "+red(xfrom) else: print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo) print "!!! Either add a suitable binary package or compile from an ebuild." else: print "\nemerge: there are no masked or unmasked ebuilds to satisfy "+xinfo+"." return 0 if "--debug" in myopts: print "ebuild:",myeb if "--upgradeonly" in myopts: # Check that there isn't a newer version of this package already installed cand=self.is_newer_ver_installed(myroot,x,myeb) if cand: myeb=cand if "--usepkg" in myopts: #If we want to use packages, see if we have a pre-built one... mypk=portage.db["/"]["bintree"].dbapi.match(x) if myeb in mypk: #Use it only if it's exactly the version we want. myk=["binary",myroot,myeb] else: myk=["ebuild",myroot,myeb] else: myk=["ebuild",myroot,myeb] if myparent: #we are a dependency, so we want to be unconditionally added if not self.create(myk,myparent): return 0 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): return 0 if "--debug" in myopts: print "Exiting...",myparent return 1 def altlist(self): mygraph=self.digraph.copy() dolist=["/"] retlist=[] for x in portage.db.keys(): portage.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:" print for x in mygraph.dict.keys(): for y in mygraph.dict[x][1]: print y,"depends on",x print sys.exit(1) splitski=string.split(mycurkey) #I'm not sure of the significance of the following lines (vestigal?) so I'm commenting 'em out. #These lines remove already-merged things from our alt-list #if "--update" in myopts: # if not portage.db["/"]["vartree"].exists_specific(splitski[2]): # portage.db["/"]["merge"].append(splitski) #else: portage.db[splitski[1]]["merge"].append(splitski) mygraph.delnode(mycurkey) for x in dolist: for y in portage.db[x]["merge"]: retlist.append(y) return retlist def xcreate(self,mode="system"): global syslist if mode=="system": mylist=syslist else: #world mode worldlist=getlist("world") sysdict=genericdict(syslist) 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 portage.db["/"]["vartree"].dbapi.match(x): sysdict[x]=worlddict[x] elif portage.db[portage.root]["vartree"].dbapi.match(x): #package is installed sysdict[x]=worlddict[x] else: print "\n*** Package in world file is not installed: "+x mylist=[] for x in sysdict.keys(): mylist.append(sysdict[x]) for mydep in mylist: myeb=portage.portdb.xmatch("bestmatch-visible",mydep) if not myeb: #this is an unavailable world entry; just continue continue if "--upgradeonly" in myopts: cand=self.is_newer_ver_installed(portage.root,mydep,myeb) if cand: myeb=cand #THIS NEXT BUNCH OF CODE NEEDS TO BE REPLACED TO SUPPORT WORLD ANTI-DEPS #if mydep2[0]=="!":, etc. if "--usepkg" in myopts: mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) if myeb==mypk: myk=["binary",portage.root,mypk] else: myk=["ebuild",portage.root,myeb] else: myk=["ebuild",portage.root,myeb] if not self.create(myk): print print "!!! Problem with",myk[0],myk[2] print "!!! Possibly a DEPEND/*DEPEND problem." print return 0 return 1 def match(self,mydep,myroot=portage.root,mykey=None): # support mutual exclusive deps mydep2=mydep if mydep2[0]=="!": mydep2=mydep[1:] if mydep[0]=="!": #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example) myk="blocks "+myroot+" "+mydep2 else: myeb=portage.db[portage.root]["porttree"].dep_bestmatch(mydep2) if not myeb: if not mykey: print "\n!!! Error: couldn't find match for",mydep else: print "\n!!! Error: couldn't find match for",mydep,"in",mykey print sys.exit(1) if "--usepkg" in myopts: mypk=portage.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): changelogs=[] for x in mylist: if x[0]=="blocks": addl=""+red("B")+" " resolved=portage.db[x[1]]["vartree"].resolve_key(x[2]) print "["+x[0]+" "+addl+"]",red(resolved), if resolved!=x[2]: if x[3]: print red("(\""+x[2]+"\" from pkg "+x[3]+")") else: print red("(\""+x[2]+"\")") else: if x[3]: print red("(from pkg "+x[3]+")") else: print else: if x[3]=="nomerge": continue #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]): addl=" "+yellow("R")+" " elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]): myoldbest=portage.best(portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0])) try: myoldslot=portage.db[portage.root]["vartree"].getslot(myoldbest) except: myoldslot=None mynewslot=portage.portdb.aux_get(x[2],["SLOT"])[0] if (myoldslot==mynewslot) and portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: addl=" "+turquoise("U")+blue("D") else: if myoldslot: addl=" "+turquoise("U")+" " else: addl=" "+turquoise("U")+blue("-") if "--changelog" in myopts: changelogs.extend(self.calc_changelog( portage.portdb.findname(x[2]), portage.db["/"]["vartree"].dep_bestmatch('/'.join(portage.catpkgsplit(x[2])[:2])), x[2] )) else: addl=" "+green("N")+" " if myoldbest: myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] if myoldbest[-3:]=="-r0": myoldbest=myoldbest[:-3] myoldbest=blue("["+myoldbest+"]") iuse="" if "--verbose" in myopts: for ebuild_iuse in string.split(portage.portdb.aux_get(x[2],["IUSE"])[0], " "): try: if (portage.usesplit.index(ebuild_iuse) >= 0) : iuse=iuse+red("+"+ebuild_iuse)+" " except ValueError: if ebuild_iuse != "": iuse=iuse+blue("-"+ebuild_iuse)+" " xs=portage.pkgsplit(x[2]) if xs[2]=="r0": xs[2]="" else: xs[2]="-"+xs[2] if portage.settings.has_key("COLUMNWIDTH"): mywidth=int(portage.settings["COLUMNWIDTH"]) else: mywidth=130 oldlp=mywidth-30 newlp=oldlp-30 if x[1]!="/": if "--columns" in myopts: myprint="["+x[0]+" "+addl+"] "+darkgreen(xs[0]) if (newlp-len(myprint)) > 0: myprint=myprint+(" "*(newlp-len(myprint))) myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " if (oldlp-len(myprint)) > 0: myprint=myprint+" "*(oldlp-len(myprint)) myprint=myprint+myoldbest myprint=myprint+darkgreen(" to "+x[1])+" "+iuse else: myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+iuse else: if "--columns" in myopts: myprint="["+x[0]+" "+addl+"] "+darkgreen(xs[0]) if (newlp-len(myprint)) > 0: myprint=myprint+(" "*(newlp-len(myprint))) myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") if (oldlp-len(myprint)) > 0: myprint=myprint+(" "*(oldlp-len(myprint))) myprint=myprint+myoldbest+" "+iuse else: myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+iuse print myprint mysplit=portage.pkgsplit(x[2]) # XXX mysplit _can_ be None.... Why? if mysplit and (len(mysplit)==3): if "--emptytree" not in myopts: if mysplit[0]=="sys-apps/portage": if mysplit[1]+mysplit[2]!=portage.VERSION: if mylist.index(x)>> Recording",myfavkey,"in \"world\" favorites file..." if not "--fetchonly" in myopts: portage.writedict(myfavdict,portage.root+"var/cache/edb/world",writekey=0) portage.mtimedb["resume"]["mergelist"]=mymergelist[:] # We need to yank the harmful-to-new-builds settings from features. myorigfeat=portage.settings["FEATURES"] myfeat=myorigfeat.split() while ("keeptemp" in myfeat): del myfeat[myfeat.index("keeptemp")] while ("keepwork" in myfeat): del myfeat[myfeat.index("keepwork")] portage.settings["FEATURES"]=string.join(myfeat) mergecount=0 for x in mymergelist: mergecount+=1 myroot=x[1] pkgindex=2 if x[0]=="blocks": pkgindex=3 y=portage.portdb.findname(x[pkgindex]) if not "--pretend" in 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]) if x[0] in ["ebuild","blocks"]: if ("--fetchonly" in myopts) or (x[0]=="blocks"): retval=portage.doebuild(y,"fetch",myroot,edebug,("--pretend" in myopts),fetchonly=1) if retval: print print "!!! Fetch for",y,"failed, continuing..." print returnme=1 if x[0]=="blocks": continue elif "--buildpkg" in myopts: #create pkg, then merge pkg emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+y+")") retval=portage.doebuild(y,"clean",myroot,edebug) if retval: sys.exit(1) portage.settings["FEATURES"]=myorigfeat # Put back flags. emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+y+")") retval=portage.doebuild(y,"package",myroot,edebug) if retval: sys.exit(1) #dynamically update our database if "--buildpkgonly" not in myopts: portage.db[portage.root]["bintree"].inject(x[2]) mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+y+")") retval=portage.pkgmerge(mytbz2,myroot) if retval==None: sys.exit(1) else: emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+y+")") retval=portage.doebuild(y,"clean",myroot,edebug) if retval: sys.exit(1) portage.settings["FEATURES"]=myorigfeat # Put back flags. emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+y+")") retval=portage.doebuild(y,"merge",myroot,edebug) if retval: sys.exit(1) #dynamically update our database elif x[0]=="binary": #merge the tbz2 mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+y+")") retval=portage.pkgmerge(mytbz2,x[1]) if retval==None: sys.exit(1) #need to check for errors if "--buildpkgonly" not in myopts: portage.db[x[1]]["vartree"].inject(x[2]) myfavkey=portage.cpv_getkey(x[2]) if (not "--fetchonly" in myopts) and (myfavkey in favorites): myfavs=portage.grabfile(myroot+"var/cache/edb/world") myfavdict=genericdict(myfavs) mysysdict=genericdict(syslist) #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..." emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+y+")") portage.writedict(myfavdict,myroot+"var/cache/edb/world",writekey=0) if ("noclean" not in portage.features) and (x[0] != "binary"): emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+y+")") retval=portage.doebuild(y,"clean",myroot,edebug) if retval: sys.exit(1) if ("--pretend" not in myopts) and ("--fetchonly" not in myopts): # Clean the old package that we have merged over top of it. if portage.settings.has_key("AUTOCLEAN") and (portage.settings["AUTOCLEAN"]=="yes"): xsplit=portage.pkgsplit(x[2]) emergelog(" >>> AUTOCLEAN: "+xsplit[0]) if not unmerge("clean", [xsplit[0]]): emergelog(" --- AUTOCLEAN: Nothing unmerged.") # Figure out if we need a restart. mysplit=portage.pkgsplit(x[2]) if mysplit[0]=="sys-apps/portage": myver=mysplit[1]+"-"+mysplit[2] if myver[-3:]=='-r0': myver=myver[:-3] if myver!=portage.VERSION: if len(mymergelist) > mergecount: myargv=sys.argv myr=0 for myra in range(len(myargv)): if myargv[myr][0:len("portage")]=="portage": del myargv[myr] myr-=1 if myargv[myr][0:len("sys-apps/portage")]=="sys-apps/portage": del myargv[myr] myr-=1 myr+=1 emergelog(" *** RESTARTING emerge via exec() after change of portage version.") portage.portageexit() os.execv("/usr/lib/portage/bin/emerge", myargv) if ("--pretend" not in myopts) and ("--fetchonly" not in myopts): emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1]) # Unsafe for parallel merges del portage.mtimedb["resume"]["mergelist"][0] 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): if (mergecount>0): portage.env_update() #by doing an exit this way, --fetchonly can continue to try to #fetch everything even if a particular download fails. if "--fetchonly" in 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 unmerge(unmerge_action, unmerge_files): candidate_catpkgs=[] global_unmerge=0 if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files: if "unmerge"==unmerge_action: print print bold("emerge unmerge")+" can only be used with specific package names, not with "+bold("world")+" or" print bold("system")+" targets." print return 0 else: global_unmerge=1 localtree=portage.db[portage.root]["vartree"] # process all arguments and add all valid db entries to candidate_catpkgs if global_unmerge: if not unmerge_files or "world" in unmerge_files: candidate_catpkgs.extend(localtree.getallnodes()) elif "system" in unmerge_files: candidate_catpkgs.extend(getlist("system")) else: #we've got command-line arguments if not unmerge_files: print "\nNo packages to unmerge have been provided.\n" return 0 for x in unmerge_files: arg_parts=x.split('/') if arg_parts[-1][-7:]!=".ebuild": #possible cat/pkg or dep; treat as such candidate_catpkgs.append(x) elif unmerge_action in ["prune","clean"]: print "\n!!! Prune and clean do not accept individual ebuilds as arguments;\n skipping.\n" continue else: # it appears that the user is specifying an installed ebuild and we're in "unmerge" mode, so it's # ok. if not os.path.exists(x): print "\n!!! The path '"+x+"' doesn't exist.\n" return 0 absx=os.path.abspath(x) spabsx=absx.split("/") if absx[:12]!="/var/db/pkg/" or len(spabsx)!=7: print spabsx print absx print "\n!!!",x,"is not inside /var/db/pkg; aborting.\n" return 0 candidate_catpkgs.append("="+spabsx[4]+"/"+spabsx[5]) if "--pretend" in myopts: print darkgreen("\n>>> These are the packages that I would unmerge:") pkgmap={} numselected=0 for x in candidate_catpkgs: #cycle through all our candidate deps and determine what will and will not get unmerged mymatch=localtree.dep_match(x) if not mymatch and x[0] not in "<>=~": #add a "=" if missing mydep="="+x mymatch=localtree.dep_match(mydep) else: mydep=x mykey=portage.key_expand(portage.dep_getkey(mydep),portage.db["/"]["vartree"].dbapi) if not mymatch: print "\n!!! Couldn't find match for",white(x) continue if not pkgmap.has_key(mykey): pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } if unmerge_action=="unmerge": for y in mymatch: if not y in pkgmap[mykey]["selected"]: pkgmap[mykey]["selected"].append(y) numselected=numselected+len(mymatch) else: #unmerge_action in ["prune", clean"] slotmap={} for mypkg in mymatch: if unmerge_action=="clean": myslot=localtree.getslot(mypkg) else: #since we're pruning, we don't care about slots and put all the pkgs in together myslot=0 if not slotmap.has_key(myslot): slotmap[myslot]={} slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg for myslot in slotmap.keys(): counterkeys=slotmap[myslot].keys() counterkeys.sort() if not counterkeys: continue counterkeys.sort() pkgmap[mykey]["protected"].append(slotmap[myslot][counterkeys[-1]]) del counterkeys[-1] #be pretty and get them in order of merge: for ckey in counterkeys: pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) numselected=numselected+1 #ok, now the last-merged package is protected, and the rest are selected for y in localtree.dep_nomatch(mydep): if not y in pkgmap[mykey]["omitted"]: pkgmap[mykey]["omitted"].append(y) if global_unmerge and not numselected: print "\n>>> No outdated packages were found on your system.\n" return 0 for x in pkgmap.keys(): if global_unmerge and not pkgmap[x]["selected"]: #avoid cluttering the preview printout with stuff that isn't getting unmerged continue print "\n "+white(x) for mytype in ["selected","protected","omitted"]: print string.rjust(mytype,12)+":", if pkgmap[x][mytype]: for mypkg in pkgmap[x][mytype]: mysplit=portage.catpkgsplit(mypkg) if mysplit[3]=="r0": myversion=mysplit[2] else: myversion=mysplit[2]+"-"+mysplit[3] if mytype=="selected": print red(myversion), else: print green(myversion), else: print "none", print if not numselected: print "\n>>>",unmerge_action+": No packages selected for removal.\n" return 0 print "\n>>> Packages in",red("red"),"are slated for removal." print ">>> Packages in",green("green"),"will not be removed.\n" if "--pretend" in myopts: #we're done... return return 0 #the real unmerging begins, after a short delay.... if portage.settings["CLEAN_DELAY"]: secs=string.atoi(portage.settings["CLEAN_DELAY"]) else: secs=5 countdown(secs, ">>> Unmerging") for x in pkgmap.keys(): for y in pkgmap[x]["selected"]: print ">>> Unmerging "+y+"..." emergelog("=== Unmerging... ("+y+")") mysplit=string.split(y,"/") #unmerge... retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,unmerge_action not in ["clean","prune"]) if retval: emergelog(" !!! unmerge FAILURE: "+y) else: emergelog(" >>> unmerge success: "+y) #run ldconfig, etc... portage.env_update() if not numselected: return 0 else: return 1 def post_emerge(retval=0): auxpat=re.compile('^([^-]*)(-\d+)?\.info(-\d+)?(\.gz)?') os.chdir("/") global myopts print if "--pretend" in myopts: sys.exit(retval) emergelog(" *** exiting successfully.") root=portage.root infodirs=[] infodirs.extend(string.split(portage.settings["INFOPATH"], ":")) infodirs.extend(string.split(portage.settings["INFODIR"], ":")) if os.path.exists("/usr/bin/install-info"): regen=0 for z in infodirs: if z=='': continue inforoot=root+z if os.path.isdir(inforoot): try: infomtime=os.stat(inforoot)[ST_MTIME] except: infomtime=0 if not portage.mtimedb.has_key("info"): portage.mtimedb["info"]={} if portage.mtimedb["info"].has_key(inforoot): if portage.mtimedb["info"][inforoot]==infomtime: pass else: portage.mtimedb["info"][inforoot]=0 regen+=1 else: regen+=1 if not regen: print " "+green("*")+" GNU info directory index is up-to-date." else: print " "+green("*")+" Regenerating GNU info directory index..." icount=0 badcount=0 for z in infodirs: if z=='': continue inforoot=root+z if portage.mtimedb["info"].has_key(inforoot): if portage.mtimedb["info"][inforoot]!=0: continue try: os.rename(inforoot+"/dir",inforoot+"/dir.old") except: pass if not os.path.isdir(inforoot): continue for x in os.listdir(inforoot): 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="+inforoot+"/dir "+inforoot+"/"+x)[1] if myso!="": badcount=badcount+1 if "--verbose" in myopts: print myso icount=icount+1 #update mtime so we can potentially avoid regenerating. portage.mtimedb["info"][inforoot]=os.stat(inforoot)[ST_MTIME] if badcount: if "--verbose" not in myopts: print " "+yellow("*")+" Processed",icount,"info files:",badcount,"errors; run with "+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 " "+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 "--debug" in myopts: edebug=1 if myaction in ["sync","rsync"] and (not "--help" in myopts): print darkgreen("Hello Sync") if "--pretend" in myopts: print "emerge: the \"sync\" action does not support \"--pretend.\"" sys.exit(1) emergelog(" === rsync") 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=string.rstrip(portage.settings["SYNC"]) os.umask(0022) print darkgreen("URI: ") + syncuri if syncuri[:7] == "http://" or syncuri[:6] == "ftp://": attempts = 0 downloaded = False minsize=1024*1024 while attempts < 2 and not downloaded: mytime = time.localtime( time.time() - (attempts*24*60*60)) mysnapshot = "portage-" + time.strftime("%Y%m%d", mytime)+".tar.bz2" syncdir=portage.settings["PORTAGE_TMPDIR"]+"/websync" print "Syncdir " + syncdir for m in syncuri.split(): if not os.path.exists(syncdir): os.mkdir(syncdir) os.chdir(syncdir) print "Changed" print os.getcwd() myfetchcmd=portage.settings["FETCHCOMMAND"]+" "+m+"/snapshots/"+mysnapshot print yellow("*"), "trying to download snapshot "+mysnapshot+" from "+m print "myfetchcmd: " + myfetchcmd if portage.spawn(myfetchcmd, free=1) == 0: print "Fetched " + mysnapshot print "Exist " print os.path.exists(mysnapshot) if os.path.exists(mysnapshot) and os.lstat(mysnapshot)[6] > minsize: print green("*"), mysnapshot+" successfully downloaded" downloaded = True attempts += 1 if not downloaded: print red("*"), "could not download a complete snapshot" sys.exit(1) portage.spawn("tar xjf "+mysnapshot, free=1) mycommand=mycommand+" "+syncdir+"/portage/* "+myportdir elif syncuri[:8]=="rsync://": if not os.path.exists("/usr/bin/rsync"): print "!!! /usr/bin/rsync does not exist, so rsync support is disabled." print "!!! Type \"emerge net-misc/rsync\" to enable rsync support." sys.exit(1) mytimeout=180 if portage.settings.has_key("RSYNC_TIMEOUT"): try: mytimeout=int(portage.settings["RSYNC_TIMEOUT"]) except: pass mycommand="/usr/bin/rsync -rlptDvz --progress --stats --delete --delete-after --timeout="+str(mytimeout)+" --exclude='distfiles/*' --exclude='local/*' --exclude='packages/*' " if portage.settings.has_key("RSYNC_EXCLUDEFROM"): if os.path.exists(portage.settings["RSYNC_EXCLUDEFROM"]): mycommand=mycommand+" --exclude-from "+portage.settings["RSYNC_EXCLUDEFROM"] else: print "!!! RSYNC_EXCLUDEFROM specified, but file does not exist." mycommand=mycommand+" "+syncuri+"/* "+myportdir print ">>> starting rsync with "+syncuri+"..." exitcode=portage.spawn(mycommand,free=1) try: maxretries=int(portage.settings["RSYNC_RETRIES"]) except: maxretries=3 #default number of retries retries=1 while (exitcode not in [0,1,2,3,4,11,14,20,21]) and (retries<=maxretries): print "\n\n>>> Starting retry %d of %d"% (retries,maxretries) time.sleep(11) retries=retries+1 exitcode=portage.spawn(mycommand,free=1) if (exitcode>0): print if exitcode==1: 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="+portage.settings["SYNC"]) elif exitcode==11: 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"]) elif exitcode==20: print darkred("!!!")+green(" Rsync was killed before it finished.") else: 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.") print sys.exit(exitcode) elif syncuri[:6]=="cvs://": if not os.path.exists("/usr/bin/cvs"): print "!!! /usr/bin/cvs does not exist, so rsync support is disabled." print "!!! Type \"emerge dev-util/cvs\" to enable CVS support." sys.exit(1) cvsroot=syncuri[6:] cvsdir=os.path.dirname(myportdir) if not os.path.exists(myportdir+"/CVS"): #initial checkout print ">>> starting initial cvs checkout with "+syncuri+"..." if not portage.spawn("cd "+cvsdir+"; cvs -d "+cvsroot+" login",free=1): print "!!! cvs login error; exiting." sys.exit(1) if os.path.exists(cvsdir+"/gentoo-x86"): print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." sys.exit(1) if not portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co gentoo-x86",free=1): print "!!! cvs checkout error; exiting." sys.exit(1) if cvsdir!=myportdir: portage.movefile(cvsdir,portage.settings["PORTDIR"]) sys.exit(0) else: #cvs update print ">>> starting cvs update with "+syncuri+"..." sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",free=1)) else: print "!!! rsync setting: ",syncuri,"not recognized; exiting." sys.exit(1) if os.path.exists(myportdir+"/metadata/cache"): print "\n>>> Updating Portage cache... ", os.umask(0002) if os.path.exists(portage.dbcachedir): portage.spawn("rm -Rf "+portage.dbcachedir,free=1) try: os.mkdir(portage.dbcachedir) os.chown(portage.dbcachedir, os.getuid(), portage.portage_gid) os.chmod(portage.dbcachedir, 06775) os.umask(002) except: pass mynodes=portage.portdb.cp_all() for x in mynodes: myxsplit=x.split("/") if not os.path.exists(portage.dbcachedir+"/"+myxsplit[0]): os.mkdir(portage.dbcachedir+"/"+myxsplit[0]) os.chown(portage.dbcachedir+"/"+myxsplit[0], os.getuid(), portage.portage_gid) os.chmod(portage.dbcachedir+"/"+myxsplit[0], 06775) mymatches=portage.portdb.xmatch("match-all",x) for y in mymatches: update_spinner() try: ignored=portage.portdb.aux_get(y,[],metacachedir=myportdir+"/metadata/cache") except: pass portage.spawn("chmod -R g+rw "+portage.dbcachedir, free=1) sys.stdout.write("\b\b ...done!\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")) 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... ", sys.stdout.flush() mynodes=portage.portdb.cp_all() for x in mynodes: mymatches=portage.portdb.xmatch("list-visible",x) if not "--quiet" in myopts: print "processing",x for y in mymatches: try: foo=portage.portdb.aux_get(y,["DEPEND"]) except: print "\nerror processing",y+", continuing..." 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=commands.getstatusoutput("/bin/uname -mrp")[1] print getportageversion() print "=================================================================" print "System uname: "+unameout 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', 'COMPILER', 'CHOST', 'CFLAGS', 'CXXFLAGS','ACCEPT_KEYWORDS', 'MAKEOPTS', 'AUTOCLEAN', 'SYNC', 'FEATURES'] for x in myvars: print x+'="'+portage.settings[x]+'"' #print portage.settings.keys() print # SEARCH action elif "search"==myaction: if not myfiles: print "emerge: no search terms provided." else: searchinstance = search() for mysearch in 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 "inject"==myaction: if not myfiles: print "emerge: please specify at least one cat/pkg-ver to inject." sys.exit(1) if "--pretend" in myopts: print "emerge: the \"inject\" action does not support \"--pretend.\"" sys.exit(1) for x in myfiles: if x[0] in [">","<","=","!"]: print "!!! '"+x+"' is an invalid specification." print "!!! Must be 'category/package-version' with no other symbols." print continue mycps=portage.catpkgsplit(x) if (not mycps) or (mycps[0]=="null"): print "!!!",x,"is not a specific cat/pkg-version, skipping..." continue if portage.db["/"]["vartree"].exists_specific(x): print "!!! Not injecting",x+"; Package already exists." else: portage.db["/"]["vartree"].dbapi.cpv_inject(x) print ">>> Injected",x+"." emergelog(" === inject: "+x) 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 ***")+" :" 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 declean and maintained in the future. BREAKAGES DUE" print red("*** WARNING ***")+" : TO UNMERGING AN IN-USE LIBRARIES MAY BE REPAIRED BY" print red("*** WARNING ***")+" : MERGING *** THE PACKAGE THAT COMPLAINS *** ABOUT THE" print red("*** WARNING ***")+" : MISSING LIBRARY." print if not "--pretend" in myopts: countdown(10, ">>> 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!" alldeps=mydepgraph.digraph.allnodes() 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 /var/db tree. This is a problem." 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.catpkgsplit(string.split(x)[2]) 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.catpkgsplit(x) if myparts: if myparts[0][0] in ('<','>','='): myparts[0] = myparts[0][1:] if myparts[0][0] in ('<','>','='): myparts[0] = myparts[0][1:] catpack=myparts[0]+"/"+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): 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"][:] 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 ", 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 ", retval,favorites=mydepgraph.select_files(myfiles) if not retval: print "\n!!! Error calculating dependencies. Please correct." sys.exit(1) print "\b\b ...done!" if ("--pretend" in myopts) and ("--fetchonly" not in myopts): if ("--resume" in myopts): mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) else: mydepgraph.display(mydepgraph.altlist()) else: if ("--buildpkgonly" in myopts): if not mydepgraph.digraph.hasallzeros(): 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): for pkgline in mydepgraph.altlist(): if pkgline[0]=="ebuild" and pkgline[3]=="merge": y=portage.portdb.findname(pkgline[2]) retval=portage.doebuild(y,"digest",portage.root,edebug,("--pretend" in myopts)) mydepgraph.merge(mydepgraph.altlist()) if portage.mtimedb.has_key("resume"): del portage.mtimedb["resume"] if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: print ">>> Auto-cleaning packages ..." unmerge("clean", ["world"]) post_emerge()