#!/usr/bin/python -O import sys import os import re import string import readline import getopt from output import * import portage import portage_exception # you might want to change this # items that directly depend on these are considered as valid (needing fixing) valid_marker = ['virtual/x11','x11-base/xorg-x11'] # we import portage later sys.path.insert(0, "/usr/lib/portage/pym") portdir = portage.settings["PORTDIR"] portdb = portage.portdbapi(portdir) def main(): os.environ["PORTAGE_CALLER"]="repoman" args = sys.argv[1:] # generate if len(args) == 0: print 'usage: find_broken_modular_package.py CP [CP...]' sys.exit(1) else: for cpv in sys.argv[1:]: check_package(cpv) return def check_package(cpv): #main() # line 267 myfiles = [cpv] # line 3236 mydepgraph=depgraph(myaction,myopts) # line 3255 retval,favorites=mydepgraph.select_files(myfiles) # line 3140 alldeps=mydepgraph.digraph.allnodes() # custom reason=[] for i in alldeps: iv = i.split(' ') if 'blocks'==iv[0]: for v in valid_marker: if v in iv[3]: reason.append(iv[3]) if len(reason) > 0: real = check_not_false_postive(cpv) if real == False: # print 'BAD-FALSE-POSITIVE',cpv pass else: # print 'BAD(DEP=(%s);MATCHES=(%s)) %s' % (string.join(real,','),string.join(reason,','),cpv) print '%s' % cpv else: # don't print fixed stuff #print 'GOOD',cpv pass # if this returns False, then you have a false positive # otherwise it returns items in valid_marker triggered it def check_not_false_postive(cp): cpv = portage.portdb.xmatch("bestmatch-visible", cp) aux = portdb.aux_get(cpv,['DEPEND','RDEPEND']) depend = aux[0] rdepend = aux[1] real = False for v in valid_marker: if v in depend or v in rdepend: if real == False: real = [v] else: real.append(v) return real #---------- the following is for depgraph def update_null_spinner(): return myaction = 'pretend' myopts = ['--pretend'] myparams=["self","recurse"] spinpos = 0 update_spinner = update_null_spinner #---------- end of stuff for depgraph # the following is lifted straight from emerge.py # it's the entire depgraph class # --------------------------------- class depgraph: def __init__(self,myaction,myopts): global olddbapi self.pkgsettings = portage.config(clone=portage.settings) if not self.pkgsettings["ARCH"]: portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n")) portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n")) sys.exit(9) self.applied_useflags = {} self.missingbins=[] self.myaction=myaction self.digraph=portage.digraph() self.orderedkeys=[] self.outdatedpackages=[] self.mydbapi={} self.mydbapi["/"] = portage.fakedbapi() if "empty" not in myparams or portage.root != "/": for pkg in portage.db["/"]["vartree"].getallcpv(): self.mydbapi["/"].cpv_inject(pkg) if portage.root != "/": self.mydbapi[portage.root] = portage.fakedbapi() if "empty" not in myparams: for pkg in portage.db[portage.root]["vartree"].getallcpv(): self.mydbapi[portage.root].cpv_inject(pkg) if "--usepkg" in myopts: portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts)) def create(self,mybigkey,myparent=None,addme=1,myuse=None): """creates the actual digraph of packages to merge. return 1 on success, 0 on failure 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 # 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 addme and "--buildpkgonly" not in myopts and myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)): mybigkey.append(myparent.split()[2]) self.digraph.addnode(string.join(mybigkey),myparent) return 1 if myuse == None: self.pkgsettings.setcpv(mykey) myuse = self.pkgsettings["USE"].split() self.applied_useflags[mykey] = myuse merging=1 if addme: # this is where we add the node to the list of packages to merge if not myparent: # command-line specified or part of a world list... if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)): # the package is on the system, so don't merge it. merging=0 elif ("selective" in myparams) and vardbapi.cpv_exists(mykey): merging=0 if (merging==0 and "--newuse" in myopts and vardbapi.cpv_exists(mykey)): old_use = vardbapi.aux_get(mykey, ["USE"])[0].split() if mytype == "binary": iuses = portage.db["/"]["bintree"].dbapi.aux_get(mykey, ["IUSE"])[0].split() else: iuses = portage.db["/"]["porttree"].dbapi.aux_get(mykey, ["IUSE"])[0].split() for x in iuses: if (old_use.count(x) and not myuse.count(x)) or (not old_use.count(x) and myuse.count(x)): merging=1 break 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) tbz2name = string.split(mykey, "/")[1]+".tbz2" if tbz2name in portage.db[portage.root]["bintree"].invalids: sys.stderr.write("\nINVALID PACKAGE (is required to continue): "+str(mykey)+"\n") sys.exit(1) if portage.db[portage.root]["bintree"].isremote(mykey): edepend = portage.db[portage.root]["bintree"].remotepkgs[tbz2name] edepend["DEPEND"] ="" edepend["RDEPEND"]=string.join(string.split(edepend["RDEPEND"])," ") edepend["PDEPEND"]=string.join(string.split(edepend["PDEPEND"])," ") edepend["SLOT"] =string.strip(edepend["SLOT"]) #portage.db[portage.root]["bintree"].gettbz2(mykey) else: # It's local. mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey)) edepend["DEPEND"] ="" edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ") edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ") edepend["SLOT"] =mytbz2.getfile("SLOT",mypkgparts[2]) elif mytype=="ebuild": try: mymeta = ["DEPEND","RDEPEND","PDEPEND"] myfoo = portage.portdb.aux_get(mykey, mymeta) for index in range(0,len(mymeta)): edepend[mymeta[index]] = myfoo[index] if "--buildpkgonly" in myopts: edepend["RDEPEND"] = "" edepend["PDEPEND"] = "" 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,myuse=myuse): return 0 else: mydep["/"]=edepend["DEPEND"] mydep[myroot]=edepend["RDEPEND"] if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): return 0 if not self.select_dep(myroot,mydep[myroot],myparent=mp,myuse=myuse): 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"],myuse=myuse): 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: ext = os.path.splitext(x)[1] if ext==".tbz2": if not os.path.exists(x): if os.path.exists(self.pkgsettings["PKGDIR"]+"/All/"+x): x=self.pkgsettings["PKGDIR"]+"/All/"+x elif os.path.exists(self.pkgsettings["PKGDIR"]+"/"+x): x=self.pkgsettings["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.splitext(os.path.basename(x))[0] if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x): print red("\n*** You need to adjust PKGDIR to emerge this package.\n") sys.exit(1) if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts): return (0,myfavorites) elif not "--oneshot" in myopts: myfavorites.append(mykey) elif ext==".ebuild": x = os.path.realpath(x) mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0] ebuild_path = portage.db["/"]["porttree"].dbapi.findname(mykey) if ebuild_path: if os.path.realpath(ebuild_path) != x: print red("\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") sys.exit(1) if mykey not in portage.db["/"]["porttree"].dbapi.xmatch("match-visible", portage.dep_getkey(mykey)): print red("\n*** You are emerging a masked package. It is MUCH better to use") print red("*** /etc/portage/package.* to accomplish this. See portage(5) man") print red("*** page for details.") countdown(EMERGE_WARNING_DELAY, "Continuing...") else: print red("\n*** %s is not in a valid PORTDIR heirarchy or does not exist" % x) sys.exit(1) 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: testkey = portage.dep_getkey(x) if testkey.startswith("null/"): testatom = x.replace(testkey[5:], "cat/"+testkey[5:]) elif "/" not in x: testatom = "cat/"+x else: testatom = x if not portage.isvalidatom(testatom): print ("\n\n!!! '%s' is not a valid package atom." % x) print "!!! Please check ebuild(5) for full details." print "!!! (Did you specify a version but forget to prefix with '='?)" return (0,[]) try: mykey=portage.dep_expand(x,mydb=portage.portdb) except ValueError, errpkgs: print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" print "!!! one of the following fully-qualified ebuild names instead:\n" for i in errpkgs[0]: print " " + green(i) print sys.exit(1) # select needs to return 0 on dep_check failure sys.stdout.flush() sys.stderr.flush() try: self.mysd = self.select_dep(portage.root,mykey,arg=x) except portage_exception.MissingSignature, e: portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n") portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") portage.writemsg("!!! Affected file: %s\n" % (e)) sys.exit(1) except portage_exception.InvalidSignature, e: portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n") portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF A TAMPERED FILES -- CHECK CAREFULLY.\n") portage.writemsg("!!! Affected file: %s\n" % (e)) sys.exit(1) except SystemExit, e: raise # Needed else can't exit except Exception, e: if "--debug" in myopts: raise print "\n\n!!! Problem in",mykey,"dependencies." print "!!!",str(e),e.__module__ sys.exit(1) if not self.mysd: return (0,myfavorites) elif not "--oneshot" in myopts: myfavorites.append(portage.dep_getkey(mykey)) missing=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 missing == 0: print missing += 1 print "Missing binary for:",xs[2] # We're true here unless we are missing binaries. return (not missing,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 matches=portage.db[myroot]["vartree"].dbapi.match(pkg) if matches: myslot=portage.db["/"]["porttree"].getslot(pkgver) for match in matches: if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(match)[1:]) < 0: curslot=portage.db[myroot]["vartree"].getslot(match) if curslot == myslot: return match def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None,raise_on_missing=False): "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],self.pkgsettings,myuse=myuse,use_binaries=("--usepkgonly" in myopts),myroot=myroot) if not mycheck[0]: mymerge=[] else: mymerge=mycheck[1] else: #we're processing a command-line argument; unconditionally merge it even if it's already merged mymerge=[depstring] # dep_check has been run so we can now add our parent to our # build state to update virtuals and other settings. This # happens after the package is added to the tree so that a # package can depend on a virtual which it satisfies. if myparent: myp = myparent.split() if myp[3]=="merge": self.mydbapi[myroot].cpv_inject(myp[2]) if myp[0]=="binary": self.pkgsettings.setinst(myp[2],portage.db["/"]["bintree"].dbapi) else: self.pkgsettings.setinst(myp[2],portage.db[myroot]["porttree"].dbapi) if not mymerge: return 1 if "--debug" in myopts: print "Candidates:",mymerge for x in mymerge: myk=None binpkguseflags=None if x[0]=="!": # if this package is myself, don't append it to block list. if "--debug" in myopts: print "Myparent",myparent if (myparent): if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]): # myself, so exit. continue # adding block myk=["blocks",myroot,x[1:]] else: #We are not processing a blocker but a normal dependency myeb=None myeb_matches = portage.portdb.xmatch("match-visible",x) if ("--usepkgonly" not in myopts): myeb=portage.best(myeb_matches) myeb_pkg=None if ("--usepkg" in myopts): # The next line assumes the binarytree has been populated. # XXX: Need to work out how we use the binary tree with roots. myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x) if ("--usepkgonly" not in myopts): # Remove any binary package entries that are masked in the portage tree (#55871) for idx in range(len(myeb_pkg_matches)-1,-1,-1): if myeb_pkg_matches[idx] not in myeb_matches: del myeb_pkg_matches[idx] myeb_pkg = portage.best(myeb_pkg_matches) if not myeb_pkg: myeb_pkg = None elif ("--newuse" in myopts): iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["IUSE"])[0]) old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["USE"])[0]) self.pkgsettings.setcpv(myeb_pkg) now_use=string.split(self.pkgsettings["USE"]) for x in iuses: if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): myeb_pkg = None break if (not myeb) and (not myeb_pkg): if raise_on_missing: raise ValueError 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: pass #print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") #print "!!! One of the following masked packages is required to complete your request:" #oldcomment = "" #for p in alleb: # mreasons = portage.getmaskingstatus(p) # print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")" # comment = portage.getmaskingreason(p) # if comment and comment != oldcomment: # print comment # oldcomment = comment #print #print "For more information, see MASKED PACKAGES section in the emerge man page or " #print "refer to the Gentoo Handbook." else: pass #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 ebuilds to satisfy "+green(xinfo)+"." if myparent: print xfrom print return 0 if "--debug" in myopts: print "ebuild:",myeb print "binpkg:",myeb_pkg if myeb and myeb_pkg: myeb_s = portage.catpkgsplit(myeb) myeb_s = [myeb_s[0]+"/"+myeb_s[1], myeb_s[2], myeb_s[3]] myeb_pkg_s = portage.catpkgsplit(myeb_pkg) myeb_pkg_s = [myeb_pkg_s[0]+"/"+myeb_pkg_s[1], myeb_pkg_s[2], myeb_pkg_s[3]] if portage.pkgcmp(myeb_s, myeb_pkg_s) == 0: # pkg is same version as ebuild myeb = None else: myeb_pkg = None if "--upgradeonly" in myopts: # Check that there isn't a newer version of this package already installed cand = None try: # XXX: This can throw an exception if the ebuild doesn't exist if myeb: cand=self.is_newer_ver_installed(myroot,x,myeb) elif myeb_pkg: cand=self.is_newer_ver_installed(myroot,x,myeb_pkg) except SystemExit, e: raise # Needed else can't exit except Exception, e: print "Warning: "+str(e) if cand: # --newuse can't work because the installed version isn't available # just pretend like the package doesn't matter # XXX: hidden assumption here that the higher versioned package # satisfies the atom that was given continue if myeb: myk=["ebuild",myroot,myeb] elif myeb_pkg: binpkguseflags=portage.db[portage.root]["bintree"].get_use(myeb_pkg) myk=["binary",myroot,myeb_pkg] else: sys.stderr.write("!!! Confused... Don't know what I'm using for dependency info. :(\n") sys.exit(1) #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,myuse=binpkguseflags): 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,myuse=binpkguseflags): 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 world_problems = False if mode=="system": mylist=syslist else: #world mode worldlist=getlist("world") sysdict=genericdict(syslist) worlddict=genericdict(worldlist) for x in worlddict.keys(): if not portage.isvalidatom(x): world_problems = True elif not portage.db["/"]["vartree"].dbapi.match(x): world_problems = True else: sysdict[x]=worlddict[x] mylist = sysdict.keys() newlist = [] for atom in mylist: if portage.dep_getkey(atom).split("/")[-1] == "portage": newlist.insert(0, atom) else: newlist.append(atom) mylist = newlist missing_atoms = [] for mydep in mylist: try: if not self.select_dep(portage.root, mydep, raise_on_missing=True): print "\n\n!!! Problem resolving dependencies for", mydep return 0 except ValueError: if "--debug" in myopts: raise missing_atoms.append(mydep) if world_problems: print "\n!!! Problems have been detected with your world file" print "!!! Please run "+green("emaint --check world")+"\n" if missing_atoms and "--verbose" in myopts: print "\n!!! Packages for the following atoms are either all" print "!!! masked or don't exist:" print " ".join(missing_atoms) + "\n" 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=[] p=[] totalsize=0 if "--quiet" in myopts: def create_use_string(*args): return "" else: def create_use_string(name, cur_iuse, cur_use, old_iuse, old_use, is_new, all_flags=("--verbose" in myopts)): enabled = [] disabled = [] for flag in cur_iuse: if flag in cur_use: if is_new or flag in old_use and all_flags: enabled.append(red(flag)) elif flag not in old_iuse: enabled.append(yellow(flag)+"%") elif flag not in old_use: enabled.append(green(flag)+"*") else: if is_new or flag in old_iuse and flag not in old_use and all_flags: disabled.append(blue("-"+flag)) elif flag not in old_iuse: disabled.append(yellow("-"+flag)+"%") elif flag in old_use: disabled.append(green("-"+flag)+"*") enabled = " ".join(enabled) disabled = " ".join(disabled) if enabled and disabled: ret = enabled + " " + disabled elif enabled: ret = enabled else: ret = disabled if ret: ret = '%s="%s" ' % (name, ret) return ret if "--verbose" in myopts: overlays = string.split(portage.settings['PORTDIR_OVERLAY']) if "--tree" in myopts: mylist.reverse() mygraph=self.digraph.copy() i = 0 while i < len(mylist): if mylist[i][-1]=="nomerge": if not ("--tree" in myopts): # we don't care about this elements mylist.pop(i) continue if (i == (len(mylist) - 1)) \ or (mygraph.depth(string.join(mylist[i])) \ >= mygraph.depth(string.join(mylist[i+1]))): # end of a useless branch (may be the last one) # -> delete the element and test the previous one mylist.pop(i) if i > 0: i -= 1 continue # the branch continues, or we've found a good element. # -> let's see what's next, if anything i += 1 display_overlays=False # files to fetch list - avoids counting a same file twice # in size display (verbose mode) myfetchlist=[] for x in mylist: fetch=" " if x[0]=="blocks": addl=""+red("B")+" "+fetch+" " 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]+"\" is blocking "+x[3]+")") else: print red("(\""+x[2]+"\")") else: if x[3]: print red("(is blocking "+x[3]+")") else: print else: if (x[0]!="binary") and ("fetch" in string.split(portage.portdb.aux_get(x[2],["RESTRICT"])[0])): fetch = red("F") if portage.portdb.fetch_check(x[2], self.applied_useflags[x[2]]): fetch = green("f") #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")+fetch+" " elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]): if x[0] == "binary": mynewslot=portage.db["/"]["bintree"].getslot(x[2]) elif x[0] == "ebuild": mynewslot=portage.db["/"]["porttree"].getslot(x[2]) myoldlist=portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0]) myinslotlist=filter((lambda p: portage.db[portage.root]["vartree"].getslot(p)==mynewslot),myoldlist) if myinslotlist: myoldbest=portage.best(myinslotlist) addl=" "+fetch if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: # Downgrade in slot addl+=turquoise("U")+blue("D") else: # Update in slot addl+=turquoise("U")+" " else: # New slot, mark it new. addl=" "+green("NS")+fetch+" " 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")+" "+fetch+" " verboseadd="" if x[2] in self.applied_useflags: # USE flag display if x[0] == "binary": cur_iuse = string.split(portage.db["/"]["bintree"].dbapi.aux_get(x[2],["IUSE"])[0]) elif x[0] == "ebuild": cur_iuse = string.split(portage.portdb.aux_get(x[2],["IUSE"])[0]) else: cur_iuse = [] cur_iuse = portage.unique_array(cur_iuse) cur_iuse = [flag for flag in cur_iuse if flag not in portage.settings.usemask] cur_iuse.sort() cur_use = self.applied_useflags[x[2]] cur_use = [flag for flag in cur_use if flag in cur_iuse] if myoldbest: pkg = myoldbest else: pkg = x[2] if portage.db["/"]["vartree"].dbapi.cpv_exists(pkg): (old_iuse, old_use) = portage.db["/"]["vartree"].dbapi.aux_get(pkg, ["IUSE", "USE"]) old_iuse = portage.unique_array(old_iuse.split()) old_iuse.sort() old_use = old_use.split() is_new = False else: old_iuse = [] old_use = [] is_new = True old_iuse = [flag for flag in old_iuse if flag not in portage.settings.usemask] old_use = [flag for flag in old_use if flag in old_iuse] use_expand = portage.settings["USE_EXPAND"].lower().split() use_expand.sort() use_expand.reverse() use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].lower().split() def map_to_use_expand(myvals): ret = {} for exp in use_expand: ret[exp] = [] for val in myvals[:]: if val.startswith(exp.lower()+"_"): ret[exp].append(val[len(exp)+1:]) myvals.remove(val) ret["USE"] = myvals for exp in use_expand_hidden: if exp in ret: del ret[exp] return ret cur_iuse_map = map_to_use_expand(cur_iuse) cur_use_map = map_to_use_expand(cur_use) old_iuse_map = map_to_use_expand(old_iuse) old_use_map = map_to_use_expand(old_use) use_expand.sort() use_expand.insert(0, "USE") for key in use_expand: verboseadd += create_use_string(key.upper(), cur_iuse_map[key], cur_use_map[key], old_iuse_map[key], old_use_map[key], is_new) if "--verbose" in myopts: # size verbose mysize=0 if x[0] == "ebuild" and x[-1]!="nomerge": myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug) if myfilesdict==None: myfilesdict="[empty/missing/bad digest]" else: for myfetchfile in myfilesdict.keys(): if myfetchfile not in myfetchlist: mysize+=myfilesdict[myfetchfile] myfetchlist.append(myfetchfile) totalsize+=mysize verboseadd+=format_size(mysize)+" " # overlay verbose # XXX: Invalid binaries have caused tracebacks here. 'if file_name' # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge'] file_name=portage.portdb.findname(x[2]) if file_name: # It might not exist in the tree dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..") if (overlays.count(dir_name)>0): verboseadd+=teal("["+str(overlays.index(os.path.normpath(dir_name))+1)+"]")+" " display_overlays=True else: verboseadd += "[No ebuild?]" xs=portage.pkgsplit(x[2]) if xs[2]=="r0": xs[2]="" else: xs[2]="-"+xs[2] if self.pkgsettings.has_key("COLUMNWIDTH"): mywidth=int(self.pkgsettings.settings["COLUMNWIDTH"]) else: mywidth=130 oldlp=mywidth-30 newlp=oldlp-30 indent="" if ("--tree" in myopts): indent=" "*mygraph.depth(string.join(x)) if myoldbest: myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] if myoldbest[-3:]=="-r0": myoldbest=myoldbest[:-3] myoldbest=blue("["+myoldbest+"]") if x[1]!="/": if "--columns" in myopts: myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) if (newlp-nc_len(myprint)) > 0: myprint=myprint+(" "*(newlp-nc_len(myprint))) myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " if (oldlp-nc_len(myprint)) > 0: myprint=myprint+" "*(oldlp-nc_len(myprint)) myprint=myprint+myoldbest myprint=myprint+darkgreen(" to "+x[1])+" "+verboseadd else: myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd else: if "--columns" in myopts: myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) if (newlp-nc_len(myprint)) > 0: myprint=myprint+(" "*(newlp-nc_len(myprint))) myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") if (oldlp-nc_len(myprint)) > 0: myprint=myprint+(" "*(oldlp-nc_len(myprint))) myprint=myprint+myoldbest+" "+verboseadd else: if x[3]=="nomerge": myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd else: myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd p.append(myprint) if ("--tree" not in myopts): 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) and \ ("livecvsportage" not in portage.settings.features): if mylist.index(x)>> Recording",myfavkey,"in \"world\" favorites file..." if not "--fetchonly" in myopts: portage.writedict(myfavdict,portage.root+portage.WORLD_FILE,writekey=0) portage.mtimedb["resume"]["mergelist"]=mymergelist[:] # We need to yank the harmful-to-new-builds settings from features. myorigfeat=self.pkgsettings["FEATURES"] myfeat=myorigfeat.split() while ("keeptemp" in myfeat): del myfeat[myfeat.index("keeptemp")] while ("keepwork" in myfeat): del myfeat[myfeat.index("keepwork")] self.pkgsettings["FEATURES"]=string.join(myfeat) if "parallel-fetch" in myfeat and not ("--ask" in myopts or "--pretend" in myopts or "--fetchonly" in myopts): if "distlocks" not in myfeat: print red("!!!") print red("!!!")+" parallel-fetching requires the distlocks feature enabled" print red("!!!")+" you have it disabled, thus parallel-fetching is being disabled" print red("!!!") elif len(mymergelist) > 1: print ">>> starting parallel fetching" pid = os.fork() if not pid: sys.stdin.close() sys.stdout.close() sys.stderr.close() sys.stdout = open("/dev/null","w") sys.stderr = open("/dev/null","w") os.dup2(sys.stdout.fileno(), 1) os.dup2(sys.stdout.fileno(), 2) for x in ("autoaddcvs", "cvs"): try: myfeat.remove(x) except ValueError: pass self.pkgsettings["FEATURES"] = " ".join(myfeat) ret = 0 for x in mymergelist: if x[0] != "ebuild": continue try: ret = portage.doebuild(portage.portdb.findname(x[2]), "fetch", x[1], self.pkgsettings, cleanup=0, fetchonly=True, tree="porttree") except SystemExit: raise except Exception: ret = 1 sys.exit(0) portage.portage_exec.spawned_pids.append(pid) 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]) self.pkgsettings["EMERGE_FROM"] = x[0][:] self.pkgsettings.backup_changes("EMERGE_FROM") self.pkgsettings.reset() #buildsyspkg: Check if we need to _force_ binary package creation issyspkg = ("buildsyspkg" in myfeat) \ and x[0] != "blocks" \ and mysysdict.has_key(portage.cpv_getkey(x[2])) \ and not ("--buildpkg" in myopts) if x[0] in ["ebuild","blocks"]: if (x[0]=="blocks") and ("--fetchonly" not in myopts): raise Exception, "Merging a blocker" elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): if ("--fetch-all-uri" in myopts): retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1,tree="porttree") else: retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,tree="porttree") if (retval == None) or retval: print print "!!! Fetch for",y,"failed, continuing..." print returnme=1 continue elif "--buildpkg" in myopts or issyspkg: #buildsyspkg: Sounds useful to display something, but I don't know if we should also log it if issyspkg: print ">>> This is a system package, let's pack a rescue tarball." #emergelog(">>> This is a system package, let's pack a rescue tarball.") #create pkg, then merge pkg short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree") if (retval == None): portage_util.writemsg("Unable to run required binary.\n") sys.exit(127) if retval: sys.exit(retval) short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug,tree="porttree") if (retval == None): portage_util.writemsg("Unable to run required binary.\n") sys.exit(127) if retval: sys.exit(retval) #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]) short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) self.pkgsettings["EMERGE_FROM"] = "binary" self.pkgsettings.backup_changes("EMERGE_FROM") retval=portage.pkgmerge(mytbz2,myroot,self.pkgsettings) if retval==None: sys.exit(1) else: short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree") if (retval == None): portage_util.writemsg("Unable to run required binary.\n") sys.exit(127) if retval: sys.exit(retval) short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug,tree="porttree") if (retval == None): portage_util.writemsg("Unable to run required binary.\n") sys.exit(127) if retval: sys.exit(retval) #dynamically update our database elif x[0]=="binary": #merge the tbz2 mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) if portage.db[portage.root]["bintree"].isremote(x[2]): short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch" emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) if not portage.db[portage.root]["bintree"].gettbz2(x[2]): sys.exit(1) if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): continue short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings) 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 "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts and myfavkey in favorites: myfavs=portage.grabfile(myroot+portage.WORLD_FILE) 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 ("+x[pkgindex]+")") portage.writedict(myfavdict,myroot+portage.WORLD_FILE,writekey=0) if ("noclean" not in portage.features) and (x[0] != "binary"): short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean Post" emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Post-Build Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree") if (retval == None): portage_util.writemsg("Unable to run required binary.\n") sys.exit(127) if retval: sys.exit(retval) if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): # Clean the old package that we have merged over top of it. if self.pkgsettings["AUTOCLEAN"]=="yes": xsplit=portage.pkgsplit(x[2]) emergelog(" >>> AUTOCLEAN: "+xsplit[0]) retval=unmerge("clean", [xsplit[0]]) if not retval: 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) and \ ("livecvsportage" not in portage.settings.features): 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() # Remove --ask from options before restarting mynewargv=[] badlongopts = ["--ask","--tree","--changelog"] badshortopts = ["a","t","l"] for arg in myargv: if arg[0:2] == "--": if arg in badlongopts: continue mynewargv += [arg] elif arg[0] == "-": myarg = "-" for ch in arg[1:]: if ch in badshortopts: continue myarg += ch mynewargv += [myarg] else: mynewargv += [arg] os.execv("/usr/lib/portage/bin/emerge", mynewargv) if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1]) # 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) and ("--fetch-all-uri" not in myopts): if (mergecount>0): if retval: 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 or "--fetch-all-uri" 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) if __name__ == "__main__": main()