From eedc9cefc37526a6d1f224458fe3b1aef81e0de3 Mon Sep 17 00:00:00 2001 From: Zac Medico Date: Tue, 16 Oct 2007 06:15:01 +0000 Subject: Move the emerge module to _emerge to make it private since it's mostly unsuitable for api consumers at this time. svn path=/main/trunk/; revision=8142 --- pym/_emerge/__init__.py | 6844 +++++++++++++++++++++++++++++++++++++++++++++++ pym/_emerge/help.py | 394 +++ pym/emerge/__init__.py | 6844 ----------------------------------------------- pym/emerge/help.py | 394 --- 4 files changed, 7238 insertions(+), 7238 deletions(-) create mode 100644 pym/_emerge/__init__.py create mode 100644 pym/_emerge/help.py delete mode 100644 pym/emerge/__init__.py delete mode 100644 pym/emerge/help.py (limited to 'pym') diff --git a/pym/_emerge/__init__.py b/pym/_emerge/__init__.py new file mode 100644 index 000000000..357b9aa06 --- /dev/null +++ b/pym/_emerge/__init__.py @@ -0,0 +1,6844 @@ +#!/usr/bin/python -O +# Copyright 1999-2006 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id: emerge 5976 2007-02-17 09:14:53Z genone $ + +import sys +# This block ensures that ^C interrupts are handled quietly. +try: + import signal + + def exithandler(signum,frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + sys.exit(1) + + signal.signal(signal.SIGINT, exithandler) + signal.signal(signal.SIGTERM, exithandler) + signal.signal(signal.SIGPIPE, signal.SIG_DFL) + +except KeyboardInterrupt: + sys.exit(1) + +import os, stat + +os.environ["PORTAGE_LEGACY_GLOBALS"] = "false" +try: + import portage +except ImportError: + from os import path as osp + sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) + import portage +del os.environ["PORTAGE_LEGACY_GLOBALS"] +from portage import digraph, portdbapi +from portage.const import NEWS_LIB_PATH, CACHE_PATH, PRIVATE_PATH, USER_CONFIG_PATH, GLOBAL_CONFIG_PATH + +import _emerge.help +import portage.xpak, commands, errno, re, socket, time, types +from portage.output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \ + havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \ + xtermTitleReset, yellow +from portage.output import create_color_func +good = create_color_func("GOOD") +bad = create_color_func("BAD") +# white looks bad on terminals with white background +from portage.output import bold as white + +import portage.dep +portage.dep._dep_check_strict = True +import portage.util +import portage.locks +import portage.exception +from portage.data import secpass +from portage.util import normalize_path as normpath +from portage.util import writemsg +from portage.sets import InternalPackageSet, SetConfig, make_default_config +from portage.sets.profiles import PackagesSystemSet as SystemSet +from portage.sets.files import WorldSet + +from itertools import chain, izip +from UserDict import DictMixin + +try: + import cPickle +except ImportError: + import pickle as cPickle + +class stdout_spinner(object): + scroll_msgs = [ + "Gentoo Rocks ("+os.uname()[0]+")", + "Thank you for using Gentoo. :)", + "Are you actually trying to read this?", + "How many times have you stared at this?", + "We are generating the cache right now", + "You are paying too much attention.", + "A theory is better than its explanation.", + "Phasers locked on target, Captain.", + "Thrashing is just virtual crashing.", + "To be is to program.", + "Real Users hate Real Programmers.", + "When all else fails, read the instructions.", + "Functionality breeds Contempt.", + "The future lies ahead.", + "3.1415926535897932384626433832795028841971694", + "Sometimes insanity is the only alternative.", + "Inaccuracy saves a world of explanation.", + ] + + twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" + + def __init__(self): + self.spinpos = 0 + self.update = self.update_twirl + self.scroll_sequence = self.scroll_msgs[ + int(time.time() * 100) % len(self.scroll_msgs)] + + def update_basic(self): + self.spinpos = (self.spinpos + 1) % 500 + if (self.spinpos % 100) == 0: + if self.spinpos == 0: + sys.stdout.write(". ") + else: + sys.stdout.write(".") + sys.stdout.flush() + + def update_scroll(self): + if(self.spinpos >= len(self.scroll_sequence)): + sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[ + len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))])) + else: + sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos])) + sys.stdout.flush() + self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence)) + + def update_twirl(self): + self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence) + sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos]) + sys.stdout.flush() + + def update_quiet(self): + return + +def userquery(prompt, responses=None, colours=None): + """Displays a prompt and a set of responses, then waits for a response + which is checked against the responses and the first to match is + returned. An empty response will match the first value in responses. The + input buffer is *not* cleared prior to the prompt! + + prompt: a String. + responses: a List of Strings. + colours: a List of Functions taking and returning a String, used to + process the responses for display. Typically these will be functions + like red() but could be e.g. lambda x: "DisplayString". + If responses is omitted, defaults to ["Yes", "No"], [green, red]. + If only colours is omitted, defaults to [bold, ...]. + + Returns a member of the List responses. (If called without optional + arguments, returns "Yes" or "No".) + KeyboardInterrupt is converted to SystemExit to avoid tracebacks being + printed.""" + if responses is None: + responses = ["Yes", "No"] + colours = [ + create_color_func("PROMPT_CHOICE_DEFAULT"), + create_color_func("PROMPT_CHOICE_OTHER") + ] + elif colours is None: + colours=[bold] + colours=(colours*len(responses))[:len(responses)] + print bold(prompt), + try: + while True: + response=raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ") + for key in responses: + # An empty response will match the first value in responses. + if response.upper()==key[:len(response)].upper(): + return key + print "Sorry, response '%s' not understood." % response, + except (EOFError, KeyboardInterrupt): + print "Interrupted." + sys.exit(1) + +actions=[ +"clean", "config", "depclean", +"info", "metadata", +"prune", "regen", "search", +"sync", "system", "unmerge", "world", +] +options=[ +"--ask", "--alphabetical", +"--buildpkg", "--buildpkgonly", +"--changelog", "--columns", +"--debug", "--deep", +"--digest", +"--emptytree", +"--fetchonly", "--fetch-all-uri", +"--getbinpkg", "--getbinpkgonly", +"--help", "--ignore-default-opts", +"--noconfmem", +"--newuse", "--nocolor", +"--nodeps", "--noreplace", +"--nospinner", "--oneshot", +"--onlydeps", "--pretend", +"--quiet", "--resume", +"--searchdesc", "--selective", +"--skipfirst", +"--tree", +"--update", +"--usepkg", "--usepkgonly", +"--verbose", "--version" +] + +shortmapping={ +"1":"--oneshot", +"a":"--ask", +"b":"--buildpkg", "B":"--buildpkgonly", +"c":"--clean", "C":"--unmerge", +"d":"--debug", "D":"--deep", +"e":"--emptytree", +"f":"--fetchonly", "F":"--fetch-all-uri", +"g":"--getbinpkg", "G":"--getbinpkgonly", +"h":"--help", +"k":"--usepkg", "K":"--usepkgonly", +"l":"--changelog", +"n":"--noreplace", "N":"--newuse", +"o":"--onlydeps", "O":"--nodeps", +"p":"--pretend", "P":"--prune", +"q":"--quiet", +"s":"--search", "S":"--searchdesc", +'t':"--tree", +"u":"--update", +"v":"--verbose", "V":"--version" +} + +def emergelog(xterm_titles, mystr, short_msg=None): + if xterm_titles: + if short_msg == None: + short_msg = mystr + if "HOSTNAME" in os.environ: + short_msg = os.environ["HOSTNAME"]+": "+short_msg + xtermTitle(short_msg) + try: + file_path = "/var/log/emerge.log" + mylogfile = open(file_path, "a") + portage.util.apply_secpass_permissions(file_path, + uid=portage.portage_uid, gid=portage.portage_gid, + mode=0660) + mylock = None + try: + mylock = portage.locks.lockfile(mylogfile) + # seek because we may have gotten held up by the lock. + # if so, we may not be positioned at the end of the file. + mylogfile.seek(0, 2) + mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") + mylogfile.flush() + finally: + if mylock: + portage.locks.unlockfile(mylock) + mylogfile.close() + except (IOError,OSError,portage.exception.PortageException), e: + if secpass >= 1: + print >> sys.stderr, "emergelog():",e + +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(colorize("UNMERGE_WARN", str(sec+1)+" ")) + sys.stdout.flush() + time.sleep(1) + print + +# formats a size given in bytes nicely +def format_size(mysize): + if type(mysize) not in [types.IntType,types.LongType]: + return str(mysize) + if 0 != mysize % 1024: + # Always round up to the next kB so that it doesn't show 0 kB when + # some small file still needs to be fetched. + mysize += 1024 - mysize % 1024 + mystr=str(mysize/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + return mystr+" kB" + + +def getgccversion(chost): + """ + rtype: C{str} + return: the current in-use gcc version + """ + + gcc_ver_command = 'gcc -dumpversion' + gcc_ver_prefix = 'gcc-' + + gcc_not_found_error = red( + "!!! No gcc found. You probably need to 'source /etc/profile'\n" + + "!!! to update the environment of this terminal and possibly\n" + + "!!! other terminals also.\n" + ) + + mystatus, myoutput = commands.getstatusoutput("eselect compiler show") + if mystatus == os.EX_OK and len(myoutput.split("/")) == 2: + part1, part2 = myoutput.split("/") + if part1.startswith(chost + "-"): + return myoutput.replace(chost + "-", gcc_ver_prefix, 1) + + mystatus, myoutput = commands.getstatusoutput("gcc-config -c") + if mystatus == os.EX_OK and myoutput.startswith(chost + "-"): + return myoutput.replace(chost + "-", gcc_ver_prefix, 1) + + mystatus, myoutput = commands.getstatusoutput( + chost + "-" + gcc_ver_command) + if mystatus == os.EX_OK: + return gcc_ver_prefix + myoutput + + mystatus, myoutput = commands.getstatusoutput(gcc_ver_command) + if mystatus == os.EX_OK: + return gcc_ver_prefix + myoutput + + portage.writemsg(gcc_not_found_error, noiselevel=-1) + return "[unavailable]" + +def getportageversion(portdir, target_root, profile, chost, vardb): + profilever = "unavailable" + if profile: + realpath = os.path.realpath(profile) + basepath = os.path.realpath(os.path.join(portdir, "profiles")) + if realpath.startswith(basepath): + profilever = realpath[1 + len(basepath):] + else: + try: + profilever = "!" + os.readlink(profile) + except (OSError): + pass + del realpath, basepath + + libcver=[] + libclist = vardb.match("virtual/libc") + libclist += vardb.match("virtual/glibc") + libclist = portage.util.unique_array(libclist) + for x in libclist: + xs=portage.catpkgsplit(x) + if libcver: + libcver+=","+"-".join(xs[1:]) + else: + libcver="-".join(xs[1:]) + if libcver==[]: + libcver="unavailable" + + gccver = getgccversion(chost) + unameout=os.uname()[2]+" "+os.uname()[4] + + return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")" + +def create_depgraph_params(myopts, myaction): + #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 + # deep: go into the dependencies of already merged packages + # empty: pretend nothing is merged + myparams = set(["recurse"]) + if "--update" in myopts or \ + "--newuse" in myopts or \ + "--reinstall" in myopts or \ + "--noreplace" in myopts or \ + myaction in ("system", "world"): + myparams.add("selective") + if "--emptytree" in myopts: + myparams.add("empty") + myparams.discard("selective") + if "--nodeps" in myopts: + myparams.discard("recurse") + if "--deep" in myopts: + myparams.add("deep") + return myparams + +# search functionality +class search(object): + + # + # class constants + # + VERSION_SHORT=1 + VERSION_RELEASE=2 + + # + # public interface + # + def __init__(self, settings, portdb, vartree, spinner, searchdesc, + verbose, setconfig): + """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.settings = settings + self.portdb = portdb + self.vartree = vartree + self.spinner = spinner + self.verbose = verbose + self.searchdesc = searchdesc + self.setconfig = setconfig + + def execute(self,searchkey): + """Performs the search for the supplied search key""" + match_category = 0 + self.searchkey=searchkey + self.packagematches = [] + if self.searchdesc: + self.searchdesc=1 + self.matches = {"pkg":[], "desc":[], "set":[]} + else: + self.searchdesc=0 + self.matches = {"pkg":[], "set":[]} + print "Searching... ", + + regexsearch = False + if self.searchkey.startswith('%'): + regexsearch = True + self.searchkey = self.searchkey[1:] + if self.searchkey.startswith('@'): + match_category = 1 + self.searchkey = self.searchkey[1:] + if regexsearch: + self.searchre=re.compile(self.searchkey,re.I) + else: + self.searchre=re.compile(re.escape(self.searchkey), re.I) + for package in self.portdb.cp_all(): + self.spinner.update() + + if match_category: + match_string = package[:] + else: + match_string = package.split("/")[-1] + + masked=0 + if self.searchre.search(match_string): + if not self.portdb.xmatch("match-visible", package): + masked=1 + self.matches["pkg"].append([package,masked]) + elif self.searchdesc: # DESCRIPTION searching + full_package = self.portdb.xmatch("bestmatch-visible", package) + if not full_package: + #no match found; we don't want to query description + full_package = portage.best( + self.portdb.xmatch("match-all", package)) + if not full_package: + continue + else: + masked=1 + try: + full_desc = self.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.sdict = self.setconfig.getSets()[0] + for setname in self.sdict: + self.spinner.update() + if match_category: + match_string = setname + else: + match_string = setname.split("/")[-1] + + if self.searchre.search(match_string): + self.matches["set"].append([setname, False]) + elif self.searchdesc: + if self.searchre.search(sdict[setname].getMetadata("DESCRIPTION")): + self.matches["set"].append([setname, False]) + + self.mlen=0 + for mtype in self.matches: + 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: + for match,masked in self.matches[mtype]: + full_package = None + if mtype == "pkg": + catpack = match + full_package = self.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( + self.portdb.xmatch("match-all",match)) + elif mtype == "desc": + full_package = match + match = portage.pkgsplit(match)[0] + elif mtype == "set": + print green("*")+" "+white(match) + print " ", darkgreen("Description:")+" ", self.sdict[match].getMetadata("DESCRIPTION") + print + if full_package: + try: + desc, homepage, license = self.portdb.aux_get( + full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"]) + 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] + mycpv = match + "-" + myversion + myebuild = self.portdb.findname(mycpv) + pkgdir = os.path.dirname(myebuild) + from portage import manifest + mf = manifest.Manifest( + pkgdir, self.settings["DISTDIR"]) + fetchlist = self.portdb.getfetchlist(mycpv, + mysettings=self.settings, all=True)[1] + try: + mysum[0] = mf.getDistfilesSize(fetchlist) + mystr = str(mysum[0]/1024) + mycount=len(mystr) + while (mycount > 3): + mycount-=3 + mystr=mystr[:mycount]+","+mystr[mycount:] + mysum[0]=mystr+" kB" + except KeyError, e: + mysum[0] = "Unknown (missing digest for %s)" % str(e) + + if self.verbose: + print " ", darkgreen("Latest version available:"),myversion + print " ", self.getInstallationStatus(mycat+'/'+mypkg) + print " ", darkgreen("Size of files:"),mysum[0] + print " ", darkgreen("Homepage:")+" ",homepage + print " ", darkgreen("Description:")+" ",desc + print " ", darkgreen("License:")+" ",license + print + print + # + # private interface + # + def getInstallationStatus(self,package): + installed_package = self.vartree.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(settings, mode): + if mode=="system": + mylines = settings.packages + elif mode=="world": + try: + file_path = os.path.join(settings["ROOT"], portage.WORLD_FILE) + myfile = open(file_path, "r") + mylines = myfile.readlines() + myfile.close() + except (OSError, IOError), e: + if e.errno == errno.ENOENT: + portage.writemsg("\n!!! World file does not exist: '%s'\n" % file_path) + mylines=[] + else: + raise + mynewlines=[] + for x in mylines: + myline=" ".join(x.split()) + 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 clean_world(vardb, cpv): + """Remove a package from the world file when unmerged.""" + world_set = WorldSet(vardb.settings["ROOT"]) + world_set.lock() + worldlist = list(world_set) # loads latest from disk + mykey = portage.cpv_getkey(cpv) + newworldlist = [] + for x in worldlist: + if portage.dep_getkey(x) == mykey: + matches = vardb.match(x, use_cache=0) + if not matches: + #zap our world entry + pass + elif len(matches) == 1 and matches[0] == cpv: + #zap our world entry + pass + else: + #others are around; keep it. + newworldlist.append(x) + else: + #this doesn't match the package we're unmerging; keep it. + newworldlist.append(x) + + world_set.replace(newworldlist) + world_set.unlock() + + +class RootConfig(object): + """This is used internally by depgraph to track information about a + particular $ROOT.""" + def __init__(self, trees): + self.trees = trees + self.settings = trees["vartree"].settings + self.root = self.settings["ROOT"] + self.sets = {} + world_set = WorldSet(self.root) + self.sets["world"] = world_set + system_set = SystemSet(self.settings.profiles) + self.sets["system"] = system_set + +def create_world_atom(pkg_key, metadata, args_set, root_config): + """Create a new atom for the world file if one does not exist. If the + argument atom is precise enough to identify a specific slot then a slot + atom will be returned. Atoms that are in the system set may also be stored + in world since system atoms can only match one slot while world atoms can + be greedy with respect to slots. Unslotted system packages will not be + stored in world.""" + arg_atom = args_set.findAtomForPackage(pkg_key, metadata) + cp = portage.dep_getkey(arg_atom) + new_world_atom = cp + sets = root_config.sets + portdb = root_config.trees["porttree"].dbapi + vardb = root_config.trees["vartree"].dbapi + available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \ + for cpv in portdb.match(cp)) + slotted = len(available_slots) > 1 or \ + (len(available_slots) == 1 and "0" not in available_slots) + if not slotted: + # check the vdb in case this is multislot + available_slots = set(vardb.aux_get(cpv, ["SLOT"])[0] \ + for cpv in vardb.match(cp)) + slotted = len(available_slots) > 1 or \ + (len(available_slots) == 1 and "0" not in available_slots) + if slotted and arg_atom != cp: + # If the user gave a specific atom, store it as a + # slot atom in the world file. + slot_atom = "%s:%s" % (cp, metadata["SLOT"]) + # First verify the slot is in the portage tree to avoid + # adding a bogus slot like that produced by multislot. + if portdb.match(slot_atom): + # Now verify that the argument is precise enough to identify a + # specific slot. + matches = portdb.match(arg_atom) + matched_slots = set() + for cpv in matches: + matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0]) + if len(matched_slots) == 1: + new_world_atom = slot_atom + if new_world_atom == sets["world"].findAtomForPackage(pkg_key, metadata): + # Both atoms would be identical, so there's nothing to add. + return None + if not slotted: + # Unlike world atoms, system atoms are not greedy for slots, so they + # can't be safely excluded from world if they are slotted. + system_atom = sets["system"].findAtomForPackage(pkg_key, metadata) + if system_atom: + if not portage.dep_getkey(system_atom).startswith("virtual/"): + return None + # System virtuals aren't safe to exclude from world since they can + # match multiple old-style virtuals but only one of them will be + # pulled in by update or depclean. + providers = portdb.mysettings.getvirtuals().get( + portage.dep_getkey(system_atom)) + if providers and len(providers) == 1 and providers[0] == cp: + return None + return new_world_atom + +def filter_iuse_defaults(iuse): + for flag in iuse: + if flag.startswith("+") or flag.startswith("-"): + yield flag[1:] + else: + yield flag + +class DepPriority(object): + """ + This class generates an integer priority level based of various + attributes of the dependency relationship. Attributes can be assigned + at any time and the new integer value will be generated on calls to the + __int__() method. Rich comparison operators are supported. + + The boolean attributes that affect the integer value are "satisfied", + "buildtime", "runtime", and "system". Various combinations of + attributes lead to the following priority levels: + + Combination of properties Priority level + + not satisfied and buildtime 0 + not satisfied and runtime -1 + satisfied and buildtime -2 + satisfied and runtime -3 + (none of the above) -4 + + Several integer constants are defined for categorization of priority + levels: + + MEDIUM The upper boundary for medium dependencies. + MEDIUM_SOFT The upper boundary for medium-soft dependencies. + SOFT The upper boundary for soft dependencies. + MIN The lower boundary for soft dependencies. + """ + __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime", "runtime_post", "rebuild") + MEDIUM = -1 + MEDIUM_SOFT = -2 + SOFT = -3 + MIN = -6 + def __init__(self, **kwargs): + for myattr in self.__slots__: + if myattr == "__weakref__": + continue + myvalue = kwargs.get(myattr, False) + setattr(self, myattr, myvalue) + def __int__(self): + if not self.satisfied: + if self.buildtime: + return 0 + if self.runtime: + return -1 + if self.runtime_post: + return -2 + if self.buildtime: + if self.rebuild: + return -3 + return -4 + if self.runtime: + return -5 + if self.runtime_post: + return -6 + return -6 + def __lt__(self, other): + return self.__int__() < other + def __le__(self, other): + return self.__int__() <= other + def __eq__(self, other): + return self.__int__() == other + def __ne__(self, other): + return self.__int__() != other + def __gt__(self, other): + return self.__int__() > other + def __ge__(self, other): + return self.__int__() >= other + def copy(self): + import copy + return copy.copy(self) + def __str__(self): + myvalue = self.__int__() + if myvalue > self.MEDIUM: + return "hard" + if myvalue > self.MEDIUM_SOFT: + return "medium" + if myvalue > self.SOFT: + return "medium-soft" + return "soft" + +class FakeVartree(portage.vartree): + """This is implements an in-memory copy of a vartree instance that provides + all the interfaces required for use by the depgraph. The vardb is locked + during the constructor call just long enough to read a copy of the + installed package information. This allows the depgraph to do it's + dependency calculations without holding a lock on the vardb. It also + allows things like vardb global updates to be done in memory so that the + user doesn't necessarily need write access to the vardb in cases where + global updates are necessary (updates are performed when necessary if there + is not a matching ebuild in the tree).""" + def __init__(self, real_vartree, portdb, db_keys): + self.root = real_vartree.root + self.settings = real_vartree.settings + mykeys = db_keys[:] + for required_key in ("COUNTER", "SLOT"): + if required_key not in mykeys: + mykeys.append(required_key) + self.dbapi = portage.fakedbapi(settings=real_vartree.settings) + vdb_path = os.path.join(self.root, portage.VDB_PATH) + try: + # At least the parent needs to exist for the lock file. + portage.util.ensure_dirs(vdb_path) + except portage.exception.PortageException: + pass + vdb_lock = None + try: + if os.access(vdb_path, os.W_OK): + vdb_lock = portage.locks.lockdir(vdb_path) + real_dbapi = real_vartree.dbapi + slot_counters = {} + for cpv in real_dbapi.cpv_all(): + metadata = dict(izip(mykeys, real_dbapi.aux_get(cpv, mykeys))) + myslot = metadata["SLOT"] + mycp = portage.dep_getkey(cpv) + myslot_atom = "%s:%s" % (mycp, myslot) + try: + mycounter = long(metadata["COUNTER"]) + except ValueError: + mycounter = 0 + metadata["COUNTER"] = str(mycounter) + other_counter = slot_counters.get(myslot_atom, None) + if other_counter is not None: + if other_counter > mycounter: + continue + slot_counters[myslot_atom] = mycounter + self.dbapi.cpv_inject(cpv, metadata=metadata) + real_dbapi.flush_cache() + finally: + if vdb_lock: + portage.locks.unlockdir(vdb_lock) + # Populate the old-style virtuals using the cached values. + if not self.settings.treeVirtuals: + self.settings.treeVirtuals = portage.util.map_dictlist_vals( + portage.getCPFromCPV, self.get_all_provides()) + + # Intialize variables needed for lazy cache pulls of the live ebuild + # metadata. This ensures that the vardb lock is released ASAP, without + # being delayed in case cache generation is triggered. + self._aux_get = self.dbapi.aux_get + self.dbapi.aux_get = self._aux_get_wrapper + self._aux_get_history = set() + self._portdb_keys = ["DEPEND", "RDEPEND", "PDEPEND"] + self._portdb = portdb + self._global_updates = None + + def _aux_get_wrapper(self, pkg, wants): + if pkg in self._aux_get_history: + return self._aux_get(pkg, wants) + self._aux_get_history.add(pkg) + try: + # Use the live ebuild metadata if possible. + live_metadata = dict(izip(self._portdb_keys, + self._portdb.aux_get(pkg, self._portdb_keys))) + self.dbapi.aux_update(pkg, live_metadata) + except (KeyError, portage.exception.PortageException): + if self._global_updates is None: + self._global_updates = \ + grab_global_updates(self._portdb.porttree_root) + perform_global_updates( + pkg, self.dbapi, self._global_updates) + return self._aux_get(pkg, wants) + +def grab_global_updates(portdir): + from portage.update import grab_updates, parse_updates + updpath = os.path.join(portdir, "profiles", "updates") + try: + rawupdates = grab_updates(updpath) + except portage.exception.DirectoryNotFound: + rawupdates = [] + upd_commands = [] + for mykey, mystat, mycontent in rawupdates: + commands, errors = parse_updates(mycontent) + upd_commands.extend(commands) + return upd_commands + +def perform_global_updates(mycpv, mydb, mycommands): + from portage.update import update_dbentries + aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"] + aux_dict = dict(izip(aux_keys, mydb.aux_get(mycpv, aux_keys))) + updates = update_dbentries(mycommands, aux_dict) + if updates: + mydb.aux_update(mycpv, updates) + +def cpv_sort_descending(cpv_list): + """Sort in place, returns None.""" + if len(cpv_list) <= 1: + return + first_split = portage.catpkgsplit(cpv_list[0]) + cat = first_split[0] + cpv_list[0] = first_split[1:] + for i in xrange(1, len(cpv_list)): + cpv_list[i] = portage.catpkgsplit(cpv_list[i])[1:] + cpv_list.sort(portage.pkgcmp, reverse=True) + for i, (pn, ver, rev) in enumerate(cpv_list): + if rev == "r0": + cpv = cat + "/" + pn + "-" + ver + else: + cpv = cat + "/" + pn + "-" + ver + "-" + rev + cpv_list[i] = cpv + +def visible(pkgsettings, cpv, metadata, built=False, installed=False): + """ + Check if a package is visible. This can raise an InvalidDependString + exception if LICENSE is invalid. + TODO: optionally generate a list of masking reasons + @rtype: Boolean + @returns: True if the package is visible, False otherwise. + """ + if built and not installed and \ + metadata["CHOST"] != pkgsettings["CHOST"]: + return False + if not portage.eapi_is_supported(metadata["EAPI"]): + return False + if pkgsettings.getMissingKeywords(cpv, metadata): + return False + if pkgsettings.getMaskAtom(cpv, metadata): + return False + if pkgsettings.getProfileMaskAtom(cpv, metadata): + return False + if pkgsettings.getMissingLicenses(cpv, metadata): + return False + return True + +def iter_atoms(deps): + """Take a dependency structure as returned by paren_reduce or use_reduce + and iterate over all the atoms.""" + i = iter(deps) + for x in i: + if isinstance(x, basestring): + if x == '||' or x.endswith('?'): + for x in iter_atoms(i.next()): + yield x + else: + yield x + else: + for x in iter_atoms(x): + yield x + +class BlockerCache(DictMixin): + """This caches blockers of installed packages so that dep_check does not + have to be done for every single installed package on every invocation of + emerge. The cache is invalidated whenever it is detected that something + has changed that might alter the results of dep_check() calls: + 1) the set of installed packages (including COUNTER) has changed + 2) the old-style virtuals have changed + """ + class BlockerData(object): + def __init__(self, counter, atoms): + self.counter = counter + self.atoms = atoms + + def __init__(self, myroot, vardb): + self._vardb = vardb + self._installed_pkgs = set(vardb.cpv_all()) + self._virtuals = vardb.settings.getvirtuals() + self._cache_filename = os.path.join(myroot, + portage.CACHE_PATH.lstrip(os.path.sep), "vdb_blockers.pickle") + self._cache_version = "1" + self._cache_data = None + self._modified = False + self._load() + + def _load(self): + try: + f = open(self._cache_filename) + mypickle = cPickle.Unpickler(f) + mypickle.find_global = None + self._cache_data = mypickle.load() + f.close() + del f + except (IOError, OSError, EOFError, cPickle.UnpicklingError): + pass + cache_valid = self._cache_data and \ + isinstance(self._cache_data, dict) and \ + self._cache_data.get("version") == self._cache_version and \ + self._cache_data.get("virtuals") == self._virtuals and \ + set(self._cache_data.get("blockers", [])) == self._installed_pkgs + if cache_valid: + for pkg in self._installed_pkgs: + if long(self._vardb.aux_get(pkg, ["COUNTER"])[0]) != \ + self[pkg].counter: + cache_valid = False + break + if not cache_valid: + self._cache_data = {"version":self._cache_version} + self._cache_data["blockers"] = {} + self._cache_data["virtuals"] = self._virtuals + self._modified = False + + def flush(self): + """If the current user has permission and the internal blocker cache + been updated, save it to disk and mark it unmodified. This is called + by emerge after it has proccessed blockers for all installed packages. + Currently, the cache is only written if the user has superuser + privileges (since that's required to obtain a lock), but all users + have read access and benefit from faster blocker lookups (as long as + the entire cache is still valid). The cache is stored as a pickled + dict object with the following format: + + { + version : "1", + "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...}, + "virtuals" : vardb.settings.getvirtuals() + } + """ + if self._modified and \ + secpass >= 2: + try: + f = portage.util.atomic_ofstream(self._cache_filename) + cPickle.dump(self._cache_data, f, -1) + f.close() + portage.util.apply_secpass_permissions( + self._cache_filename, gid=portage.portage_gid, mode=0644) + except (IOError, OSError), e: + pass + self._modified = False + + def __setitem__(self, cpv, blocker_data): + """ + Update the cache and mark it as modified for a future call to + self.flush(). + + @param cpv: Package for which to cache blockers. + @type cpv: String + @param blocker_data: An object with counter and atoms attributes. + @type blocker_data: BlockerData + """ + self._cache_data["blockers"][cpv] = \ + (blocker_data.counter, blocker_data.atoms) + self._modified = True + + def __getitem__(self, cpv): + """ + @rtype: BlockerData + @returns: An object with counter and atoms attributes. + """ + return self.BlockerData(*self._cache_data["blockers"][cpv]) + + def keys(self): + """This needs to be implemented so that self.__repr__() doesn't raise + an AttributeError.""" + if self._cache_data and "blockers" in self._cache_data: + return self._cache_data["blockers"].keys() + return [] + +def show_invalid_depstring_notice(parent_node, depstring, error_msg): + + from formatter import AbstractFormatter, DumbWriter + f = AbstractFormatter(DumbWriter(maxcol=72)) + + print "\n\n!!! Invalid or corrupt dependency specification: " + print + print error_msg + print + print parent_node + print + print depstring + print + p_type, p_root, p_key, p_status = parent_node + msg = [] + if p_status == "nomerge": + category, pf = portage.catsplit(p_key) + pkg_location = os.path.join(p_root, portage.VDB_PATH, category, pf) + msg.append("Portage is unable to process the dependencies of the ") + msg.append("'%s' package. " % p_key) + msg.append("In order to correct this problem, the package ") + msg.append("should be uninstalled, reinstalled, or upgraded. ") + msg.append("As a temporary workaround, the --nodeps option can ") + msg.append("be used to ignore all dependencies. For reference, ") + msg.append("the problematic dependencies can be found in the ") + msg.append("*DEPEND files located in '%s/'." % pkg_location) + else: + msg.append("This package can not be installed. ") + msg.append("Please notify the '%s' package maintainer " % p_key) + msg.append("about this problem.") + + for x in msg: + f.add_flowing_data(x) + f.end_paragraph(1) + +class depgraph(object): + + pkg_tree_map = { + "ebuild":"porttree", + "binary":"bintree", + "installed":"vartree"} + + _mydbapi_keys = [ + "CHOST", "DEPEND", "EAPI", "IUSE", "KEYWORDS", + "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND", + "repository", "RESTRICT", "SLOT", "USE"] + + _dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] + + def __init__(self, settings, trees, myopts, myparams, spinner): + self.settings = settings + self.target_root = settings["ROOT"] + self.myopts = myopts + self.myparams = myparams + self.edebug = 0 + if settings.get("PORTAGE_DEBUG", "") == "1": + self.edebug = 1 + self.spinner = spinner + self.pkgsettings = {} + # Maps cpv to digraph node for all nodes added to the graph. + self.pkg_node_map = {} + # Maps slot atom to digraph node for all nodes added to the graph. + self._slot_node_map = {} + # Maps nodes to the reasons they were selected for reinstallation. + self._reinstall_nodes = {} + self.mydbapi = {} + self.trees = {} + self.roots = {} + # Contains a filtered view of preferred packages that are selected + # from available repositories. + self._filtered_trees = {} + for myroot in trees: + self.trees[myroot] = {} + for tree in ("porttree", "bintree"): + self.trees[myroot][tree] = trees[myroot][tree] + self.trees[myroot]["vartree"] = \ + FakeVartree(trees[myroot]["vartree"], + trees[myroot]["porttree"].dbapi, + self._mydbapi_keys) + self.pkgsettings[myroot] = portage.config( + clone=self.trees[myroot]["vartree"].settings) + self.pkg_node_map[myroot] = {} + self._slot_node_map[myroot] = {} + vardb = self.trees[myroot]["vartree"].dbapi + self.roots[myroot] = RootConfig(self.trees[myroot]) + # This fakedbapi instance will model the state that the vdb will + # have after new packages have been installed. + fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot]) + self.mydbapi[myroot] = fakedb + if "--nodeps" not in self.myopts and \ + "--buildpkgonly" not in self.myopts: + # --nodeps bypasses this, since it isn't needed in this case + # and the cache pulls might trigger (slow) cache generation. + for pkg in vardb.cpv_all(): + self.spinner.update() + fakedb.cpv_inject(pkg, + metadata=dict(izip(self._mydbapi_keys, + vardb.aux_get(pkg, self._mydbapi_keys)))) + del vardb, fakedb + self._filtered_trees[myroot] = {} + self._filtered_trees[myroot]["vartree"] = self.trees[myroot]["vartree"] + def filtered_tree(): + pass + filtered_tree.dbapi = portage.fakedbapi( + settings=self.pkgsettings[myroot], exclusive_slots=False) + self._filtered_trees[myroot]["porttree"] = filtered_tree + self._filtered_trees[myroot]["atoms"] = set() + dbs = [] + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + vardb = self.trees[myroot]["vartree"].dbapi + # (db, pkg_type, built, installed, db_keys) + if "--usepkgonly" not in self.myopts: + db_keys = list(portdb._aux_cache_keys) + dbs.append((portdb, "ebuild", False, False, db_keys)) + if "--usepkg" in self.myopts: + db_keys = list(bindb._aux_cache_keys) + dbs.append((bindb, "binary", True, False, db_keys)) + db_keys = self._mydbapi_keys + dbs.append((vardb, "installed", True, True, db_keys)) + self._filtered_trees[myroot]["dbs"] = dbs + if "--usepkg" in self.myopts: + self.trees[myroot]["bintree"].populate( + "--getbinpkg" in self.myopts, + "--getbinpkgonly" in self.myopts) + del trees + + self.missingbins=[] + self.digraph=portage.digraph() + # Tracks simple parent/child relationships (PDEPEND relationships are + # not reversed). + self._parent_child_digraph = digraph() + self.orderedkeys=[] + self.outdatedpackages=[] + # contains all sets added to the graph + self._sets = {} + # contains atoms given as arguments + self._sets["args"] = InternalPackageSet() + # contains all atoms from all sets added to the graph, including + # atoms given as arguments + self._set_atoms = InternalPackageSet() + # contains all nodes pulled in by self._set_atoms + self._set_nodes = set() + self.blocker_digraph = digraph() + self.blocker_parents = {} + self._unresolved_blocker_parents = {} + self._slot_collision_info = [] + # Slot collision nodes are not allowed to block other packages since + # blocker validation is only able to account for one package per slot. + self._slot_collision_nodes = set() + self._altlist_cache = {} + self._pprovided_args = [] + + def _show_slot_collision_notice(self, packages): + """Show an informational message advising the user to mask one of the + the packages. In some cases it may be possible to resolve this + automatically, but support for backtracking (removal nodes that have + already been selected) will be required in order to handle all possible + cases.""" + + msg = [] + msg.append("\n!!! Multiple versions within a single " + \ + "package slot have been \n") + msg.append("!!! pulled into the dependency graph:\n\n") + for node, parents in packages: + msg.append(str(node)) + if parents: + msg.append(" pulled in by\n") + for parent in parents: + msg.append(" ") + msg.append(str(parent)) + msg.append("\n") + else: + msg.append(" (no parents)\n") + msg.append("\n") + sys.stderr.write("".join(msg)) + sys.stderr.flush() + + if "--quiet" in self.myopts: + return + + msg = [] + msg.append("It may be possible to solve this problem ") + msg.append("by using package.mask to prevent one of ") + msg.append("those packages from being selected. ") + msg.append("However, it is also possible that conflicting ") + msg.append("dependencies exist such that they are impossible to ") + msg.append("satisfy simultaneously. If such a conflict exists in ") + msg.append("the dependencies of two different packages, then those ") + msg.append("packages can not be installed simultaneously.") + + from formatter import AbstractFormatter, DumbWriter + f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72)) + for x in msg: + f.add_flowing_data(x) + f.end_paragraph(1) + + msg = [] + msg.append("For more information, see MASKED PACKAGES ") + msg.append("section in the emerge man page or refer ") + msg.append("to the Gentoo Handbook.") + for x in msg: + f.add_flowing_data(x) + f.end_paragraph(1) + f.writer.flush() + + def _reinstall_for_flags(self, forced_flags, + orig_use, orig_iuse, cur_use, cur_iuse): + """Return a set of flags that trigger reinstallation, or None if there + are no such flags.""" + if "--newuse" in self.myopts: + flags = orig_iuse.symmetric_difference( + cur_iuse).difference(forced_flags) + flags.update(orig_iuse.intersection(orig_use).symmetric_difference( + cur_iuse.intersection(cur_use))) + if flags: + return flags + elif "changed-use" == self.myopts.get("--reinstall"): + flags = orig_iuse.intersection(orig_use).symmetric_difference( + cur_iuse.intersection(cur_use)) + if flags: + return flags + return None + + def create(self, mybigkey, myparent=None, addme=1, metadata=None, + priority=DepPriority(), rev_dep=False, arg=None): + """ + Fills the digraph with nodes comprised of packages to merge. + mybigkey is the package spec of the package to merge. + myparent is the package depending on mybigkey ( or None ) + addme = Should we add this package to the digraph or are we just looking at it's deps? + Think --onlydeps, we need to ignore packages in that case. + #stuff to add: + #SLOT-aware emerge + #IUSE-aware emerge -> USE DEP aware depgraph + #"no downgrade" emerge + """ + + # unused parameters + rev_dep = False + + mytype, myroot, mykey = mybigkey + + # select the correct /var database that we'll be checking against + vardbapi = self.trees[myroot]["vartree"].dbapi + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + pkgsettings = self.pkgsettings[myroot] + + # if the package is already on the system, we add a "nomerge" + # directive, otherwise we add a "merge" directive. + + mydbapi = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi + if metadata is None: + metadata = dict(izip(self._mydbapi_keys, + mydbapi.aux_get(mykey, self._mydbapi_keys))) + if mytype == "ebuild": + pkgsettings.setcpv(mykey, mydb=portdb) + metadata["USE"] = pkgsettings["USE"] + myuse = metadata["USE"].split() + + if not arg and myroot == self.target_root: + try: + arg = self._set_atoms.findAtomForPackage(mykey, metadata) + except portage.exception.InvalidDependString, e: + if mytype != "installed": + show_invalid_depstring_notice(tuple(mybigkey+["merge"]), + metadata["PROVIDE"], str(e)) + return 0 + del e + + if "--nodeps" not in self.myopts: + self.spinner.update() + + merging = mytype != "installed" + + if addme and mytype != "installed": + mybigkey.append("merge") + else: + mybigkey.append("nomerge") + jbigkey = tuple(mybigkey) + + if addme: + slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"]) + if merging and \ + "empty" not in self.myparams and \ + vardbapi.match(slot_atom): + # Increase the priority of dependencies on packages that + # are being rebuilt. This optimizes merge order so that + # dependencies are rebuilt/updated as soon as possible, + # which is needed especially when emerge is called by + # revdep-rebuild since dependencies may be affected by ABI + # breakage that has rendered them useless. Don't adjust + # priority here when in "empty" mode since all packages + # are being merged in that case. + priority.rebuild = True + + existing_node = self._slot_node_map[myroot].get( + slot_atom, None) + slot_collision = False + if existing_node: + e_type, myroot, e_cpv, e_status = existing_node + if mykey == e_cpv: + # The existing node can be reused. + if existing_node != myparent: + # Refuse to make a node depend on itself so that + # we don't create a bogus circular dependency + # in self.altlist(). + self._parent_child_digraph.add(existing_node, myparent) + self.digraph.addnode(existing_node, myparent, + priority=priority) + return 1 + else: + if jbigkey in self._slot_collision_nodes: + return 1 + # A slot collision has occurred. Sometimes this coincides + # with unresolvable blockers, so the slot collision will be + # shown later if there are no unresolvable blockers. + e_parents = self._parent_child_digraph.parent_nodes( + existing_node) + myparents = [] + if myparent: + myparents.append(myparent) + self._slot_collision_info.append( + ((jbigkey, myparents), (existing_node, e_parents))) + self._slot_collision_nodes.add(jbigkey) + slot_collision = True + + if slot_collision: + # Now add this node to the graph so that self.display() + # can show use flags and --tree portage.output. This node is + # only being partially added to the graph. It must not be + # allowed to interfere with the other nodes that have been + # added. Do not overwrite data for existing nodes in + # self.pkg_node_map and self.mydbapi since that data will + # be used for blocker validation. + self.pkg_node_map[myroot].setdefault(mykey, jbigkey) + # Even though the graph is now invalid, continue to process + # dependencies so that things like --fetchonly can still + # function despite collisions. + else: + self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata) + self._slot_node_map[myroot][slot_atom] = jbigkey + self.pkg_node_map[myroot][mykey] = jbigkey + + if rev_dep and myparent: + self.digraph.addnode(myparent, jbigkey, + priority=priority) + else: + self.digraph.addnode(jbigkey, myparent, + priority=priority) + + if arg: + self._set_nodes.add(jbigkey) + + # Do this even when addme is False (--onlydeps) so that the + # parent/child relationship is always known in case + # self._show_slot_collision_notice() needs to be called later. + self._parent_child_digraph.add(jbigkey, myparent) + + """ This section determines whether we go deeper into dependencies or not. + We want to go deeper on a few occasions: + Installing package A, we need to make sure package A's deps are met. + emerge --deep ; we need to recursively check dependencies of pkgspec + If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies. + """ + if "deep" not in self.myparams and not merging and \ + not ("--update" in self.myopts and arg and merging): + return 1 + elif "recurse" not in self.myparams: + return 1 + + """ Check DEPEND/RDEPEND/PDEPEND/SLOT + Pull from bintree if it's binary package, porttree if it's ebuild. + Binpkg's can be either remote or local. """ + + edepend={} + depkeys = ["DEPEND","RDEPEND","PDEPEND"] + for k in depkeys: + edepend[k] = metadata[k] + + if mytype == "ebuild": + if "--buildpkgonly" in self.myopts: + edepend["RDEPEND"] = "" + edepend["PDEPEND"] = "" + bdeps_satisfied = False + if mytype in ("installed", "binary"): + if self.myopts.get("--with-bdeps", "n") == "y": + # Pull in build time deps as requested, but marked them as + # "satisfied" since they are not strictly required. This allows + # more freedom in the merge order calculation for solving + # circular dependencies. Don't convert to PDEPEND since that + # could make --with-bdeps=y less effective if it is used to + # adjust merge order to prevent built_with_use() calls from + # failing. + bdeps_satisfied = True + else: + # built packages do not have build time dependencies. + edepend["DEPEND"] = "" + + """ We have retrieve the dependency information, now we need to recursively + process them. DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """ + + mp = tuple(mybigkey) + + try: + if not self.select_dep("/", edepend["DEPEND"], myparent=mp, + myuse=myuse, priority=DepPriority(buildtime=True, + satisfied=bdeps_satisfied), + parent_arg=arg): + return 0 + """RDEPEND is soft by definition. However, in order to ensure + correct merge order, we make it a hard dependency. Otherwise, a + build time dependency might not be usable due to it's run time + dependencies not being installed yet. + """ + if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp, + myuse=myuse, priority=DepPriority(runtime=True), + parent_arg=arg): + 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"], myparent=mp, + myuse=myuse, priority=DepPriority(runtime_post=True), + parent_arg=arg): + return 0 + except ValueError, e: + pkgs = e.args[0] + portage.writemsg("\n\n!!! An atom in the dependencies " + \ + "is not fully-qualified. Multiple matches:\n\n", noiselevel=-1) + for cpv in pkgs: + portage.writemsg(" %s\n" % cpv, noiselevel=-1) + portage.writemsg("\n", noiselevel=-1) + if mytype == "binary": + portage.writemsg( + "!!! This binary package cannot be installed: '%s'\n" % \ + mykey, noiselevel=-1) + elif mytype == "ebuild": + myebuild, mylocation = portdb.findname2(mykey) + portage.writemsg("!!! This ebuild cannot be installed: " + \ + "'%s'\n" % myebuild, noiselevel=-1) + portage.writemsg("!!! Please notify the package maintainer " + \ + "that atoms must be fully-qualified.\n", noiselevel=-1) + 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=[] + myroot = self.target_root + dbs = self._filtered_trees[myroot]["dbs"] + filtered_db = self._filtered_trees[myroot]["porttree"].dbapi + vardb = self.trees[myroot]["vartree"].dbapi + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + pkgsettings = self.pkgsettings[myroot] + arg_atoms = [] + for x in myfiles: + ext = os.path.splitext(x)[1] + if ext==".tbz2": + if not os.path.exists(x): + if os.path.exists( + os.path.join(pkgsettings["PKGDIR"], "All", x)): + x = os.path.join(pkgsettings["PKGDIR"], "All", x) + elif os.path.exists( + os.path.join(pkgsettings["PKGDIR"], x)): + x = os.path.join(pkgsettings["PKGDIR"], x) + else: + print "\n\n!!! Binary package '"+str(x)+"' does not exist." + print "!!! Please ensure the tbz2 exists as specified.\n" + return 0, myfavorites + mytbz2=portage.xpak.tbz2(x) + mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0] + if os.path.realpath(x) != \ + os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)): + print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n") + return 0, myfavorites + if not self.create(["binary", myroot, mykey], + addme=("--onlydeps" not in self.myopts), arg=x): + return (0,myfavorites) + arg_atoms.append((x, "="+mykey)) + elif ext==".ebuild": + ebuild_path = portage.util.normalize_path(os.path.abspath(x)) + pkgdir = os.path.dirname(ebuild_path) + tree_root = os.path.dirname(os.path.dirname(pkgdir)) + cp = pkgdir[len(tree_root)+1:] + e = portage.exception.PackageNotFound( + ("%s is not in a valid portage tree " + \ + "hierarchy or does not exist") % x) + if not portage.isvalidatom(cp): + raise e + cat = portage.catsplit(cp)[0] + mykey = cat + "/" + os.path.basename(ebuild_path[:-7]) + if not portage.isvalidatom("="+mykey): + raise e + ebuild_path = portdb.findname(mykey) + if ebuild_path: + if ebuild_path != os.path.join(os.path.realpath(tree_root), + cp, os.path.basename(ebuild_path)): + print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") + return 0, myfavorites + if mykey not in portdb.xmatch( + "match-visible", portage.dep_getkey(mykey)): + print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use") + print colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man") + print colorize("BAD", "*** page for details.") + countdown(int(self.settings["EMERGE_WARNING_DELAY"]), + "Continuing...") + else: + raise portage.exception.PackageNotFound( + "%s is not in a valid portage tree hierarchy or does not exist" % x) + if not self.create(["ebuild", myroot, mykey], + None, "--onlydeps" not in self.myopts, arg=x): + return (0,myfavorites) + arg_atoms.append((x, "="+mykey)) + else: + if not is_valid_package_atom(x): + portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x, + noiselevel=-1) + portage.writemsg("!!! Please check ebuild(5) for full details.\n") + portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") + return (0,[]) + try: + try: + for db, pkg_type, built, installed, db_keys in dbs: + mykey = portage.dep_expand(x, + mydb=db, settings=pkgsettings) + if portage.dep_getkey(mykey).startswith("null/"): + continue + break + except ValueError, e: + if not e.args or not isinstance(e.args[0], list) or \ + len(e.args[0]) < 2: + raise + mykey = portage.dep_expand(x, + mydb=vardb, settings=pkgsettings) + cp = portage.dep_getkey(mykey) + if cp.startswith("null/") or \ + cp not in e[0]: + raise + del e + arg_atoms.append((x, mykey)) + except ValueError, errpkgs: + if not e.args or not isinstance(e.args[0], list) or \ + len(e.args[0]) < 2: + raise + 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 + return False, myfavorites + + if "--update" in self.myopts: + """Make sure all installed slots are updated when possible. Do this + with --emptytree also, to ensure that all slots are remerged.""" + greedy_atoms = [] + for myarg, atom in arg_atoms: + greedy_atoms.append((myarg, atom)) + mykey = portage.dep_getkey(atom) + myslots = set() + for cpv in vardb.match(mykey): + myslots.add(vardb.aux_get(cpv, ["SLOT"])[0]) + if myslots: + if not self._populate_filtered_repo(myroot, atom, + exclude_installed=True): + return False, myfavorites + mymatches = filtered_db.match(atom) + best_pkg = portage.best(mymatches) + if best_pkg: + best_slot = filtered_db.aux_get(best_pkg, ["SLOT"])[0] + myslots.add(best_slot) + if len(myslots) > 1: + for myslot in myslots: + myslot_atom = "%s:%s" % (mykey, myslot) + if not self._populate_filtered_repo( + myroot, myslot_atom, + exclude_installed=True): + return False, myfavorites + if filtered_db.match(myslot_atom): + greedy_atoms.append((myarg, myslot_atom)) + arg_atoms = greedy_atoms + + # Since populate_filtered_repo() was called with the + # exclude_installed flag, these atoms will need to be processed + # again in case installed packages are required to satisfy + # dependencies. + self._filtered_trees[myroot]["atoms"].clear() + + oneshot = "--oneshot" in self.myopts or \ + "--onlydeps" in self.myopts + """ These are used inside self.create() in order to ensure packages + that happen to match arguments are not incorrectly marked as nomerge.""" + args_set = self._sets["args"] + for myarg, myatom in arg_atoms: + if myatom in args_set: + continue + args_set.add(myatom) + self._set_atoms.add(myatom) + if not oneshot: + myfavorites.append(myatom) + for myarg, myatom in arg_atoms: + try: + self.mysd = self.select_dep(myroot, myatom, arg=myarg) + 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 TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1) + 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 TAMPERED FILES -- CHECK CAREFULLY.\n") + portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1) + sys.exit(1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print >> sys.stderr, "\n\n!!! Problem in '%s' dependencies." % mykey + print >> sys.stderr, "!!!", str(e), getattr(e, "__module__", None) + raise + + if not self.mysd: + return (0,myfavorites) + + missing=0 + if "--usepkgonly" in self.myopts: + for xs in self.digraph.all_nodes(): + if len(xs) >= 4 and xs[0] != "binary" and xs[3] == "merge": + if missing == 0: + print + missing += 1 + print "Missing binary for:",xs[2] + + if not self.validate_blockers(): + return False, myfavorites + + # We're true here unless we are missing binaries. + return (not missing,myfavorites) + + def _populate_filtered_repo(self, myroot, depstring, + myparent=None, myuse=None, exclude_installed=False): + """Extract all of the atoms from the depstring, select preferred + packages from appropriate repositories, and use them to populate + the filtered repository.""" + + filtered_db = self._filtered_trees[myroot]["porttree"].dbapi + pkgsettings = self.pkgsettings[myroot] + usepkgonly = "--usepkgonly" in self.myopts + if myparent: + p_type, p_root, p_key, p_status = myparent + + from portage.dep import paren_reduce, use_reduce + try: + if myparent and p_type == "installed": + portage.dep._dep_check_strict = False + try: + atoms = paren_reduce(depstring) + atoms = use_reduce(atoms, uselist=myuse) + atoms = list(iter_atoms(atoms)) + for x in atoms: + if portage.dep._dep_check_strict and \ + not portage.isvalidatom(x, allow_blockers=True): + raise portage.exception.InvalidDependString( + "Invalid atom: %s" % x) + except portage.exception.InvalidDependString, e: + if myparent: + show_invalid_depstring_notice( + myparent, depstring, str(e)) + else: + sys.stderr.write("\n%s\n%s\n" % (depstring, str(e))) + return 0 + finally: + portage.dep._dep_check_strict = True + + filtered_atoms = self._filtered_trees[myroot]["atoms"] + dbs = self._filtered_trees[myroot]["dbs"] + old_virts = pkgsettings.getvirtuals() + while atoms: + x = atoms.pop() + if x.startswith("!"): + continue + if x in filtered_atoms: + continue + filtered_atoms.add(x) + cp = portage.dep_getkey(x) + cat = portage.catsplit(cp)[0] + slot = portage.dep.dep_getslot(x) + is_virt = cp.startswith("virtual/") + atom_populated = False + for db, pkg_type, built, installed, db_keys in dbs: + if installed and \ + (exclude_installed or not usepkgonly): + continue + cpv_list = db.cp_list(cp) + if not cpv_list: + if is_virt: + # old-style virtual + # Create a transformed atom for each choice + # and add it to the stack for processing. + for choice in old_virts.get(cp, []): + atoms.append(x.replace(cp, choice)) + # Maybe a new-style virtual exists in another db, so + # we have to try all of them to prevent the old-style + # virtuals from overriding available new-styles. + continue + cpv_sort_descending(cpv_list) + for cpv in cpv_list: + if filtered_db.cpv_exists(cpv): + continue + if not portage.match_from_list(x, [cpv]): + continue + if is_virt: + mykeys = db_keys[:] + mykeys.extend(self._dep_keys) + else: + mykeys = db_keys + try: + metadata = dict(izip(mykeys, + db.aux_get(cpv, mykeys))) + except KeyError: + # masked by corruption + continue + if slot is not None: + if slot != metadata["SLOT"]: + continue + if not built: + if (is_virt or "?" in metadata["LICENSE"]): + pkgsettings.setcpv(cpv, mydb=metadata) + metadata["USE"] = pkgsettings["USE"] + else: + metadata["USE"] = "" + + try: + if not visible(pkgsettings, cpv, metadata, + built=built, installed=installed): + continue + except portage.exception.InvalidDependString: + # masked by corruption + continue + + filtered_db.cpv_inject(cpv, metadata=metadata) + if not is_virt: + # break here since we only want the best version + # for now (eventually will be configurable). + atom_populated = True + break + # For new-style virtuals, we explore all available + # versions and recurse on their deps. This is a + # preparation for the lookahead that happens when + # new-style virtuals are expanded by dep_check(). + virtual_deps = " ".join(metadata[k] \ + for k in self._dep_keys) + try: + if installed: + portage.dep._dep_check_strict = False + try: + deps = paren_reduce(virtual_deps) + deps = use_reduce(deps, + uselist=metadata["USE"].split()) + for y in iter_atoms(deps): + if portage.dep._dep_check_strict and \ + not portage.isvalidatom(y, + allow_blockers=True): + raise portage.exception.InvalidDependString( + "Invalid atom: %s" % y) + atoms.append(y) + except portage.exception.InvalidDependString, e: + show_invalid_depstring_notice( + (pkg_type, myroot, cpv, "nomerge"), + virtual_deps, str(e)) + return 0 + finally: + portage.dep._dep_check_strict = True + if atom_populated: + break + return 1 + + def select_dep(self, myroot, depstring, myparent=None, arg=None, + myuse=None, raise_on_missing=False, priority=DepPriority(), + rev_deps=False, parent_arg=None): + """ Given a depstring, create the depgraph such that all dependencies are satisfied. + myroot = $ROOT from environment, where {R,P}DEPENDs are merged to. + myparent = the node whose depstring is being passed in + arg = package was specified on the command line, merge even if it's already installed + myuse = USE flags at present + raise_on_missing = Given that the depgraph is not proper, raise an exception if true + else continue trying. + return 1 on success, 0 for failure + """ + + if not depstring: + return 1 # nothing to do + + filtered_db = self._filtered_trees[myroot]["porttree"].dbapi + dbs = self._filtered_trees[myroot]["dbs"] + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + vardb = self.trees[myroot]["vartree"].dbapi + pkgsettings = self.pkgsettings[myroot] + if myparent: + p_type, p_root, p_key, p_status = myparent + + if "--debug" in self.myopts: + print + print "Parent: ",myparent + print "Depstring:",depstring + if rev_deps: + print "Reverse:", rev_deps + print "Priority:", priority + + if not self._populate_filtered_repo( + myroot, depstring, myparent=myparent, myuse=myuse): + return 0 + + #processing dependencies + """ Call portage.dep_check to evaluate the use? conditionals and make sure all + dependencies are satisfiable. """ + if arg: + mymerge = [depstring] + pprovided = pkgsettings.pprovideddict.get( + portage.dep_getkey(depstring)) + if pprovided and portage.match_from_list(depstring, pprovided): + mymerge = [] + else: + try: + if myparent and p_type == "installed": + portage.dep._dep_check_strict = False + mycheck = portage.dep_check(depstring, None, + pkgsettings, myuse=myuse, + myroot=myroot, trees=self._filtered_trees) + finally: + portage.dep._dep_check_strict = True + + if not mycheck[0]: + if myparent: + show_invalid_depstring_notice( + myparent, depstring, mycheck[1]) + else: + sys.stderr.write("\n%s\n%s\n" % (depstring, mycheck[1])) + return 0 + mymerge = mycheck[1] + + if not mymerge and arg: + # A provided package has been specified on the command line. The + # package will not be merged and a warning will be displayed. + if depstring in self._set_atoms: + self._pprovided_args.append((arg, depstring)) + + if myparent: + # The parent is added after it's own dep_check call so that it + # isn't allowed to satisfy a direct bootstrap dependency on itself + # via an old-style virtual. This isn't a problem with new-style + # virtuals, which are preferenced in dep_zapdeps by looking only at + # the depstring, vdb, and available packages. + + p_type, p_root, p_key, p_status = myparent + if p_status == "merge": + # Update old-style virtuals if this package provides any. + # These are needed for dep_virtual calls inside dep_check. + p_db = self.mydbapi[p_root] # contains cached metadata + if myparent in self._slot_collision_nodes: + # The metadata isn't cached due to the slot collision. + p_db = self.trees[p_root][self.pkg_tree_map[p_type]].dbapi + try: + self.pkgsettings[p_root].setinst(p_key, p_db) + # For consistency, also update the global virtuals. + settings = self.roots[p_root].settings + settings.unlock() + settings.setinst(p_key, p_db) + settings.lock() + except portage.exception.InvalidDependString, e: + provide = p_db.aux_get(p_key, ["PROVIDE"])[0] + show_invalid_depstring_notice(myparent, provide, str(e)) + del e + return 0 + + if "--debug" in self.myopts: + print "Candidates:",mymerge + for x in mymerge: + selected_pkg = None + if x.startswith("!"): + if "--buildpkgonly" not in self.myopts and \ + "--nodeps" not in self.myopts and \ + myparent not in self._slot_collision_nodes: + p_type, p_root, p_key, p_status = myparent + if p_type != "installed" and p_status != "merge": + # It's safe to ignore blockers from --onlydeps nodes. + continue + self.blocker_parents.setdefault( + ("blocks", p_root, x[1:]), set()).add(myparent) + continue + else: + # List of acceptable packages, ordered by type preference. + matched_packages = [] + existing_node = None + myeb = None + usepkgonly = "--usepkgonly" in self.myopts + empty = "empty" in self.myparams + selective = "selective" in self.myparams + for find_existing_node in True, False: + if existing_node: + break + for db, pkg_type, built, installed, db_keys in dbs: + if existing_node: + break + if installed and not find_existing_node and \ + (matched_packages or empty): + # We only need to select an installed package here + # if there is no other choice. + continue + if hasattr(db, "xmatch"): + cpv_list = db.xmatch("match-all", x) + else: + cpv_list = db.match(x) + cpv_sort_descending(cpv_list) + for cpv in cpv_list: + reinstall_for_flags = None + try: + metadata = dict(izip(db_keys, + db.aux_get(cpv, db_keys))) + except KeyError: + continue + if not built: + if "?" in metadata["LICENSE"]: + pkgsettings.setcpv(cpv, mydb=metadata) + metadata["USE"] = pkgsettings.get("USE","") + else: + metadata["USE"] = "" + if not installed: + try: + if not visible(pkgsettings, cpv, metadata, + built=built, installed=installed): + continue + except portage.exception.InvalidDependString: + # masked by corruption + continue + # At this point, we've found the highest visible + # match from the current repo. Any lower versions + # from this repo are ignored, so this so the loop + # will always end with a break statement below + # this point. + if find_existing_node: + slot_atom = "%s:%s" % ( + portage.cpv_getkey(cpv), metadata["SLOT"]) + existing_node = self._slot_node_map[myroot].get( + slot_atom) + if not existing_node: + break + e_type, myroot, e_cpv, e_status = existing_node + metadata = dict(izip(self._mydbapi_keys, + self.mydbapi[myroot].aux_get( + e_cpv, self._mydbapi_keys))) + cpv_slot = "%s:%s" % (e_cpv, metadata["SLOT"]) + if portage.dep.match_from_list(x, [cpv_slot]): + matched_packages.append( + ([e_type, myroot, e_cpv], metadata)) + else: + existing_node = None + break + # Compare built package to current config and + # reject the built package if necessary. + if built and not installed and \ + ("--newuse" in self.myopts or \ + "--reinstall" in self.myopts): + iuses = set(filter_iuse_defaults( + metadata["IUSE"].split())) + old_use = metadata["USE"].split() + mydb = metadata + if myeb and not usepkgonly: + mydb = portdb + if myeb: + pkgsettings.setcpv(myeb, mydb=mydb) + else: + pkgsettings.setcpv(cpv, mydb=mydb) + now_use = pkgsettings["USE"].split() + forced_flags = set() + forced_flags.update(pkgsettings.useforce) + forced_flags.update(pkgsettings.usemask) + cur_iuse = iuses + if myeb and not usepkgonly: + cur_iuse = set(filter_iuse_defaults( + portdb.aux_get(myeb, + ["IUSE"])[0].split())) + if self._reinstall_for_flags(forced_flags, + old_use, iuses, + now_use, cur_iuse): + break + # Compare current config to installed package + # and do not reinstall if possible. + if not installed and \ + ("--newuse" in self.myopts or \ + "--reinstall" in self.myopts) and \ + vardb.cpv_exists(cpv): + pkgsettings.setcpv(cpv, mydb=metadata) + forced_flags = set() + forced_flags.update(pkgsettings.useforce) + forced_flags.update(pkgsettings.usemask) + old_use = vardb.aux_get(cpv, ["USE"])[0].split() + old_iuse = set(filter_iuse_defaults( + vardb.aux_get(cpv, ["IUSE"])[0].split())) + cur_use = pkgsettings["USE"].split() + cur_iuse = set(filter_iuse_defaults(metadata["IUSE"].split())) + reinstall_for_flags = \ + self._reinstall_for_flags( + forced_flags, old_use, old_iuse, + cur_use, cur_iuse) + myarg = arg + if not myarg and \ + myroot == self.target_root: + try: + myarg = self._set_atoms.findAtomForPackage( + cpv, metadata) + except portage.exception.InvalidDependString, e: + if mytype != "installed": + pkg_node = (pkg_type, myroot, cpv, "merge") + show_invalid_depstring_notice(pkg_node, + metadata["PROVIDE"], str(e)) + return 0 + del e + if not installed and not reinstall_for_flags and \ + ("selective" in self.myparams or \ + not myarg) and \ + "empty" not in self.myparams and \ + vardb.cpv_exists(cpv): + break + if installed and not (selective or not myarg): + break + # Metadata accessed above is cached internally by + # each db in order to optimize visibility checks. + # Now that all possible checks visibility checks + # are complete, it's time to pull the rest of the + # metadata (including *DEPEND). This part is more + # expensive, so avoid it whenever possible. + metadata.update(izip(self._mydbapi_keys, + db.aux_get(cpv, self._mydbapi_keys))) + if not built: + pkgsettings.setcpv(cpv, mydb=metadata) + metadata["USE"] = pkgsettings.get("USE","") + myeb = cpv + matched_packages.append( + ([pkg_type, myroot, cpv], metadata)) + if reinstall_for_flags: + pkg_node = (pkg_type, myroot, cpv, "merge") + self._reinstall_nodes[pkg_node] = \ + reinstall_for_flags + break + + if not matched_packages: + if raise_on_missing: + raise portage.exception.PackageNotFound(x) + if not arg: + xinfo='"'+x+'"' + else: + xinfo='"'+arg+'"' + if myparent: + xfrom = '(dependency required by '+ \ + green('"%s"' % myparent[2]) + \ + red(' [%s]' % myparent[0]) + ')' + masked_packages = [] + missing_licenses = [] + dbs = self._filtered_trees[myroot]["dbs"] + for db, pkg_type, built, installed, db_keys in dbs: + match = db.match + if hasattr(db, "xmatch"): + def match(atom): + return db.xmatch("match-all", atom) + cpv_list = match(x) + cpv_sort_descending(cpv_list) + for cpv in cpv_list: + try: + metadata = dict(izip(db_keys, + db.aux_get(cpv, db_keys))) + except KeyError: + mreasons = ["corruption"] + metadata = None + if metadata and not built: + if "?" in metadata["LICENSE"]: + pkgsettings.setcpv(p, mydb=portdb) + metadata["USE"] = pkgsettings.get("USE", "") + else: + metadata["USE"] = "" + mreasons = portage.getmaskingstatus( + cpv, metadata=metadata, + settings=pkgsettings, portdb=portdb) + comment, filename = None, None + if "package.mask" in mreasons: + comment, filename = \ + portage.getmaskingreason( + cpv, metadata=metadata, + settings=pkgsettings, portdb=portdb, + return_location=True) + if built and \ + metadata["CHOST"] != pkgsettings["CHOST"]: + mreasons.append("CHOST: %s" % \ + metadata["CHOST"]) + missing_licenses = [] + if metadata: + try: + missing_licenses = \ + pkgsettings.getMissingLicenses( + cpv, metadata) + except portage.exception.InvalidDependString: + # This will have already been reported + # above via mreasons. + pass + masked_packages.append((cpv, mreasons, + comment, filename, missing_licenses)) + if masked_packages: + 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:" + shown_licenses = set() + shown_comments = set() + # Maybe there is both an ebuild and a binary. Only + # show one of them to avoid redundant appearance. + shown_cpvs = set() + for cpv, mreasons, comment, filename, missing_licenses in masked_packages: + if cpv in shown_cpvs: + continue + shown_cpvs.add(cpv) + print "- "+cpv+" (masked by: "+", ".join(mreasons)+")" + if comment and comment not in shown_comments: + print filename+":" + print comment + shown_comments.add(comment) + for l in missing_licenses: + l_path = portdb.findLicensePath(l) + if l in shown_licenses: + continue + msg = ("A copy of the '%s' license" + \ + " is located at '%s'.") % (l, l_path) + print msg + print + shown_licenses.add(l) + print + print "For more information, see MASKED PACKAGES section in the emerge man page or " + print "refer to the Gentoo Handbook." + else: + print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"." + if myparent: + print xfrom + print + return 0 + + if "--debug" in self.myopts: + for pkg, metadata in matched_packages: + print (pkg[0] + ":").rjust(10), pkg[2] + + if len(matched_packages) > 1: + bestmatch = portage.best( + [pkg[2] for pkg, metadata in matched_packages]) + matched_packages = [pkg for pkg in matched_packages \ + if pkg[0][2] == bestmatch] + + # ordered by type preference ("ebuild" type is the last resort) + selected_pkg = matched_packages[-1] + + # In some cases, dep_check will return deps that shouldn't + # be proccessed any further, so they are identified and + # discarded here. Try to discard as few as possible since + # discarded dependencies reduce the amount of information + # available for optimization of merge order. + if myparent and not arg and vardb.match(x) and \ + not existing_node and \ + "empty" not in self.myparams and \ + "deep" not in self.myparams and \ + not ("--update" in self.myopts and parent_arg): + (mytype, myroot, mykey), metadata = selected_pkg + myarg = None + if myroot == self.target_root: + try: + myarg = self._set_atoms.findAtomForPackage( + mykey, metadata) + except portage.exception.InvalidDependString: + # This is already handled inside + # self.create() when necessary. + pass + if not myarg: + continue + + if myparent: + #we are a dependency, so we want to be unconditionally added + mypriority = priority.copy() + if vardb.match(x): + mypriority.satisfied = True + if not self.create(selected_pkg[0], myparent=myparent, + metadata=selected_pkg[1], priority=mypriority, + rev_dep=rev_deps, arg=arg): + 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(selected_pkg[0], myparent=myparent, + addme=("--onlydeps" not in self.myopts), + metadata=selected_pkg[1], rev_dep=rev_deps, arg=arg): + return 0 + + if "--debug" in self.myopts: + print "Exiting...",myparent + return 1 + + def validate_blockers(self): + """Remove any blockers from the digraph that do not match any of the + packages within the graph. If necessary, create hard deps to ensure + correct merge order such that mutually blocking packages are never + installed simultaneously.""" + + if "--buildpkgonly" in self.myopts or \ + "--nodeps" in self.myopts: + return True + + modified_slots = {} + for myroot in self.trees: + myslots = {} + modified_slots[myroot] = myslots + final_db = self.mydbapi[myroot] + slot_node_map = self._slot_node_map[myroot] + for slot_atom, mynode in slot_node_map.iteritems(): + mytype, myroot, mycpv, mystatus = mynode + if mystatus == "merge": + myslots[slot_atom] = mycpv + + #if "deep" in self.myparams: + if True: + # Pull in blockers from all installed packages that haven't already + # been pulled into the depgraph. This is not enabled by default + # due to the performance penalty that is incurred by all the + # additional dep_check calls that are required. + + # Optimization hack for dep_check calls that minimizes the + # available matches by replacing the portdb with a fakedbapi + # instance. + class FakePortageTree(object): + def __init__(self, mydb): + self.dbapi = mydb + dep_check_trees = {} + for myroot in self.trees: + dep_check_trees[myroot] = self.trees[myroot].copy() + dep_check_trees[myroot]["porttree"] = \ + FakePortageTree(self.mydbapi[myroot]) + + dep_keys = ["DEPEND","RDEPEND","PDEPEND"] + for myroot in self.trees: + pkg_node_map = self.pkg_node_map[myroot] + vardb = self.trees[myroot]["vartree"].dbapi + portdb = self.trees[myroot]["porttree"].dbapi + pkgsettings = self.pkgsettings[myroot] + final_db = self.mydbapi[myroot] + cpv_all_installed = self.trees[myroot]["vartree"].dbapi.cpv_all() + blocker_cache = BlockerCache(myroot, vardb) + for pkg in cpv_all_installed: + blocker_atoms = None + matching_node = pkg_node_map.get(pkg, None) + if matching_node and \ + matching_node[3] == "nomerge": + continue + # If this node has any blockers, create a "nomerge" + # node for it so that they can be enforced. + self.spinner.update() + blocker_data = blocker_cache.get(pkg) + if blocker_data: + blocker_atoms = blocker_data.atoms + else: + dep_vals = vardb.aux_get(pkg, dep_keys) + myuse = vardb.aux_get(pkg, ["USE"])[0].split() + depstr = " ".join(dep_vals) + # It is crucial to pass in final_db here in order to + # optimize dep_check calls by eliminating atoms via + # dep_wordreduce and dep_eval calls. + try: + portage.dep._dep_check_strict = False + try: + success, atoms = portage.dep_check(depstr, + final_db, pkgsettings, myuse=myuse, + trees=dep_check_trees, myroot=myroot) + except Exception, e: + if isinstance(e, SystemExit): + raise + # This is helpful, for example, if a ValueError + # is thrown from cpv_expand due to multiple + # matches (this can happen if an atom lacks a + # category). + show_invalid_depstring_notice( + ("installed", myroot, pkg, "nomerge"), + depstr, str(e)) + del e + raise + finally: + portage.dep._dep_check_strict = True + if not success: + slot_atom = "%s:%s" % (portage.dep_getkey(pkg), + vardb.aux_get(pkg, ["SLOT"])[0]) + if slot_atom in modified_slots[myroot]: + # This package is being replaced anyway, so + # ignore invalid dependencies so as not to + # annoy the user too much (otherwise they'd be + # forced to manually unmerge it first). + continue + show_invalid_depstring_notice( + ("installed", myroot, pkg, "nomerge"), + depstr, atoms) + return False + blocker_atoms = [myatom for myatom in atoms \ + if myatom.startswith("!")] + counter = long(vardb.aux_get(pkg, ["COUNTER"])[0]) + blocker_cache[pkg] = \ + blocker_cache.BlockerData(counter, blocker_atoms) + if blocker_atoms: + # Don't store this parent in pkg_node_map, because it's + # not needed there and it might overwrite a "merge" + # node with the same cpv. + myparent = ("installed", myroot, pkg, "nomerge") + for myatom in blocker_atoms: + blocker = ("blocks", myroot, myatom[1:]) + myparents = \ + self.blocker_parents.get(blocker, None) + if not myparents: + myparents = set() + self.blocker_parents[blocker] = myparents + myparents.add(myparent) + blocker_cache.flush() + del blocker_cache + + for blocker in self.blocker_parents.keys(): + mytype, myroot, mydep = blocker + initial_db = self.trees[myroot]["vartree"].dbapi + final_db = self.mydbapi[myroot] + blocked_initial = initial_db.match(mydep) + blocked_final = final_db.match(mydep) + if not blocked_initial and not blocked_final: + del self.blocker_parents[blocker] + continue + blocked_slots_initial = {} + blocked_slots_final = {} + for cpv in blocked_initial: + blocked_slots_initial[cpv] = \ + "%s:%s" % (portage.dep_getkey(cpv), + initial_db.aux_get(cpv, ["SLOT"])[0]) + for cpv in blocked_final: + blocked_slots_final[cpv] = \ + "%s:%s" % (portage.dep_getkey(cpv), + final_db.aux_get(cpv, ["SLOT"])[0]) + for parent in list(self.blocker_parents[blocker]): + ptype, proot, pcpv, pstatus = parent + pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi + pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0] + pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot) + parent_static = pslot_atom not in modified_slots[proot] + unresolved_blocks = False + depends_on_order = set() + for cpv in blocked_initial: + slot_atom = blocked_slots_initial[cpv] + if slot_atom == pslot_atom: + # TODO: Support blocks within slots in cases where it + # might make sense. For example, a new version might + # require that the old version be uninstalled at build + # time. + continue + if parent_static and \ + slot_atom not in modified_slots[myroot]: + # This blocker will be handled the next time that a + # merge of either package is triggered. + continue + if pstatus == "merge" and \ + slot_atom in modified_slots[myroot]: + replacement = final_db.match(slot_atom) + if replacement: + if not portage.match_from_list(mydep, replacement): + # Apparently a replacement may be able to + # invalidate this block. + replacement_node = \ + self.pkg_node_map[proot][replacement[0]] + depends_on_order.add((replacement_node, parent)) + continue + # None of the above blocker resolutions techniques apply, + # so apparently this one is unresolvable. + unresolved_blocks = True + for cpv in blocked_final: + slot_atom = blocked_slots_final[cpv] + if slot_atom == pslot_atom: + # TODO: Support blocks within slots. + continue + if parent_static and \ + slot_atom not in modified_slots[myroot]: + # This blocker will be handled the next time that a + # merge of either package is triggered. + continue + if not parent_static and pstatus == "nomerge" and \ + slot_atom in modified_slots[myroot]: + replacement = final_db.match(pslot_atom) + if replacement: + replacement_node = \ + self.pkg_node_map[proot][replacement[0]] + if replacement_node not in \ + self.blocker_parents[blocker]: + # Apparently a replacement may be able to + # invalidate this block. + blocked_node = self.pkg_node_map[proot][cpv] + depends_on_order.add( + (replacement_node, blocked_node)) + continue + # None of the above blocker resolutions techniques apply, + # so apparently this one is unresolvable. + unresolved_blocks = True + if not unresolved_blocks and depends_on_order: + for node, pnode in depends_on_order: + # Enforce correct merge order with a hard dep. + self.digraph.addnode(node, pnode, + priority=DepPriority(buildtime=True)) + # Count references to this blocker so that it can be + # invalidated after nodes referencing it have been + # merged. + self.blocker_digraph.addnode(node, blocker) + if not unresolved_blocks and not depends_on_order: + self.blocker_parents[blocker].remove(parent) + if unresolved_blocks: + self._unresolved_blocker_parents.setdefault( + blocker, set()).add(parent) + if not self.blocker_parents[blocker]: + del self.blocker_parents[blocker] + # Validate blockers that depend on merge order. + if not self.blocker_digraph.empty(): + self.altlist() + if self._slot_collision_info: + # The user is only notified of a slot collision if there are no + # unresolvable blocks. + for x in self.altlist(): + if x[0] == "blocks": + return True + self._show_slot_collision_notice(self._slot_collision_info[0]) + if not self._accept_collisions(): + return False + return True + + def _accept_collisions(self): + acceptable = False + for x in ("--nodeps", "--pretend", "--fetchonly", "--fetch-all-uri"): + if x in self.myopts: + acceptable = True + break + return acceptable + + def _merge_order_bias(self, mygraph): + """Order nodes from highest to lowest overall reference count for + optimal leaf node selection.""" + node_info = {} + for node in mygraph.order: + node_info[node] = len(mygraph.parent_nodes(node)) + def cmp_merge_preference(node1, node2): + return node_info[node2] - node_info[node1] + mygraph.order.sort(cmp_merge_preference) + + def altlist(self, reversed=False): + if reversed in self._altlist_cache: + return self._altlist_cache[reversed][:] + if reversed: + retlist = self.altlist() + retlist.reverse() + self._altlist_cache[reversed] = retlist[:] + return retlist + mygraph=self.digraph.copy() + self._merge_order_bias(mygraph) + myblockers = self.blocker_digraph.copy() + retlist=[] + circular_blocks = False + blocker_deps = None + asap_nodes = [] + portage_node = None + if reversed: + get_nodes = mygraph.root_nodes + else: + get_nodes = mygraph.leaf_nodes + for cpv, node in self.pkg_node_map["/"].iteritems(): + if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]: + portage_node = node + asap_nodes.append(node) + break + ignore_priority_soft_range = [None] + ignore_priority_soft_range.extend( + xrange(DepPriority.MIN, DepPriority.SOFT + 1)) + tree_mode = "--tree" in self.myopts + # Tracks whether or not the current iteration should prefer asap_nodes + # if available. This is set to False when the previous iteration + # failed to select any nodes. It is reset whenever nodes are + # successfully selected. + prefer_asap = True + + # By default, try to avoid selecting root nodes whenever possible. This + # helps ensure that the maximimum possible number of soft dependencies + # have been removed from the graph before their parent nodes have + # selected. This is especially important when those dependencies are + # going to be rebuilt by revdep-rebuild or `emerge -e system` after the + # CHOST has been changed (like when building a stage3 from a stage2). + accept_root_node = False + + # State of prefer_asap and accept_root_node flags for successive + # iterations that loosen the criteria for node selection. + # + # iteration prefer_asap accept_root_node + # 1 True False + # 2 False False + # 3 False True + # + # If no nodes are selected on the 3rd iteration, it is due to + # unresolved blockers or circular dependencies. + + while not mygraph.empty(): + selected_nodes = None + if prefer_asap and asap_nodes: + """ASAP nodes are merged before their soft deps.""" + asap_nodes = [node for node in asap_nodes \ + if mygraph.contains(node)] + for node in asap_nodes: + if not mygraph.child_nodes(node, + ignore_priority=DepPriority.SOFT): + selected_nodes = [node] + asap_nodes.remove(node) + break + if not selected_nodes and \ + not (prefer_asap and asap_nodes): + for ignore_priority in ignore_priority_soft_range: + nodes = get_nodes(ignore_priority=ignore_priority) + if nodes: + break + if nodes: + if ignore_priority is None and not tree_mode: + # Greedily pop all of these nodes since no relationship + # has been ignored. This optimization destroys --tree + # output, so it's disabled in reversed mode. + selected_nodes = nodes + else: + # For optimal merge order: + # * Only pop one node. + # * Removing a root node (node without a parent) + # will not produce a leaf node, so avoid it. + for node in nodes: + if mygraph.parent_nodes(node): + # found a non-root node + selected_nodes = [node] + break + if not selected_nodes and \ + (accept_root_node or ignore_priority is None): + # settle for a root node + selected_nodes = [nodes[0]] + if not selected_nodes: + nodes = get_nodes(ignore_priority=DepPriority.MEDIUM) + if nodes: + """Recursively gather a group of nodes that RDEPEND on + eachother. This ensures that they are merged as a group + and get their RDEPENDs satisfied as soon as possible.""" + def gather_deps(ignore_priority, + mergeable_nodes, selected_nodes, node): + if node in selected_nodes: + return True + if node not in mergeable_nodes: + return False + if node == portage_node and mygraph.child_nodes(node, + ignore_priority=DepPriority.MEDIUM_SOFT): + # Make sure that portage always has all of it's + # RDEPENDs installed first. + return False + selected_nodes.add(node) + for child in mygraph.child_nodes(node, + ignore_priority=ignore_priority): + if not gather_deps(ignore_priority, + mergeable_nodes, selected_nodes, child): + return False + return True + mergeable_nodes = set(nodes) + if prefer_asap and asap_nodes: + nodes = asap_nodes + for ignore_priority in xrange(DepPriority.SOFT, + DepPriority.MEDIUM_SOFT + 1): + for node in nodes: + if nodes is not asap_nodes and \ + not accept_root_node and \ + not mygraph.parent_nodes(node): + continue + selected_nodes = set() + if gather_deps(ignore_priority, + mergeable_nodes, selected_nodes, node): + break + else: + selected_nodes = None + if selected_nodes: + break + + if prefer_asap and asap_nodes and not selected_nodes: + # We failed to find any asap nodes to merge, so ignore + # them for the next iteration. + prefer_asap = False + continue + + if not selected_nodes and not accept_root_node: + # Maybe there are only root nodes left, so accept them + # for the next iteration. + accept_root_node = True + continue + + if selected_nodes and ignore_priority > DepPriority.SOFT: + # Try to merge ignored medium deps as soon as possible. + for node in selected_nodes: + children = set(mygraph.child_nodes(node)) + soft = children.difference( + mygraph.child_nodes(node, + ignore_priority=DepPriority.SOFT)) + medium_soft = children.difference( + mygraph.child_nodes(node, + ignore_priority=DepPriority.MEDIUM_SOFT)) + medium_soft.difference_update(soft) + for child in medium_soft: + if child in selected_nodes: + continue + if child in asap_nodes: + continue + # TODO: Try harder to make these nodes get + # merged absolutely as soon as possible. + asap_nodes.append(child) + + if not selected_nodes: + if not myblockers.is_empty(): + """A blocker couldn't be circumnavigated while keeping all + dependencies satisfied. The user will have to resolve this + manually. This is a panic condition and thus the order + doesn't really matter, so just pop a random node in order + to avoid a circular dependency panic if possible.""" + if not circular_blocks: + circular_blocks = True + blocker_deps = myblockers.leaf_nodes() + while blocker_deps: + # Some of these nodes might have already been selected + # by the normal node selection process after the + # circular_blocks flag has been set. Therefore, we + # have to verify that they're still in the graph so + # that they're not selected more than once. + node = blocker_deps.pop() + if mygraph.contains(node): + selected_nodes = [node] + break + + if not selected_nodes: + # No leaf nodes are available, so we have a circular + # dependency panic situation. Reduce the noise level to a + # minimum via repeated elimination of root nodes since they + # have no parents and thus can not be part of a cycle. + while True: + root_nodes = mygraph.root_nodes( + ignore_priority=DepPriority.SOFT) + if not root_nodes: + break + for node in root_nodes: + mygraph.remove(node) + # Display the USE flags that are enabled on nodes that are part + # of dependency cycles in case that helps the user decide to + # disable some of them. + display_order = [] + tempgraph = mygraph.copy() + while not tempgraph.empty(): + nodes = tempgraph.leaf_nodes() + if not nodes: + node = tempgraph.order[0] + else: + node = nodes[0] + display_order.append(list(node)) + tempgraph.remove(node) + display_order.reverse() + self.myopts.pop("--quiet", None) + self.myopts.pop("--verbose", None) + self.myopts["--tree"] = True + self.display(display_order) + print "!!! Error: circular dependencies:" + print + mygraph.debug_print() + print + print "!!! Note that circular dependencies can often be avoided by temporarily" + print "!!! disabling USE flags that trigger optional dependencies." + sys.exit(1) + + # At this point, we've succeeded in selecting one or more nodes, so + # it's now safe to reset the prefer_asap and accept_root_node flags + # to their default states. + prefer_asap = True + accept_root_node = False + + for node in selected_nodes: + if node[-1] != "nomerge": + retlist.append(list(node)) + mygraph.remove(node) + if not reversed and not circular_blocks and myblockers.contains(node): + """This node may have invalidated one or more blockers.""" + myblockers.remove(node) + for blocker in myblockers.root_nodes(): + if not myblockers.child_nodes(blocker): + myblockers.remove(blocker) + unresolved = \ + self._unresolved_blocker_parents.get(blocker) + if unresolved: + self.blocker_parents[blocker] = unresolved + else: + del self.blocker_parents[blocker] + + if not reversed: + """Blocker validation does not work with reverse mode, + so self.altlist() should first be called with reverse disabled + so that blockers are properly validated.""" + self.blocker_digraph = myblockers + + """ Add any unresolved blocks so that they can be displayed.""" + for blocker in self.blocker_parents: + retlist.append(list(blocker)) + self._altlist_cache[reversed] = retlist[:] + return retlist + + def xcreate(self,mode="system"): + vardb = self.trees[self.target_root]["vartree"].dbapi + filtered_db = self._filtered_trees[self.target_root]["porttree"].dbapi + world_problems = False + + root_config = self.roots[self.target_root] + world_set = root_config.sets["world"] + system_set = root_config.sets["system"] + mylist = list(system_set) + self._sets["system"] = system_set + if mode == "world": + self._sets["world"] = world_set + for x in world_set: + if not portage.isvalidatom(x): + world_problems = True + continue + elif not vardb.match(x): + world_problems = True + if not self._populate_filtered_repo(self.target_root, x, + exclude_installed=True): + return 0 + if not filtered_db.match(x): + continue + mylist.append(x) + + newlist = [] + for atom in mylist: + mykey = portage.dep_getkey(atom) + if True: + newlist.append(atom) + if mode == "system" or atom not in world_set: + # only world is greedy for slots, not system + continue + # Make sure all installed slots are updated when possible. + # Do this with --emptytree also, to ensure that all slots are + # remerged. + myslots = set() + for cpv in vardb.match(mykey): + myslots.add(vardb.aux_get(cpv, ["SLOT"])[0]) + if myslots: + if not self._populate_filtered_repo(self.target_root, atom, + exclude_installed=True): + return 0 + mymatches = filtered_db.match(atom) + best_pkg = portage.best(mymatches) + if best_pkg: + best_slot = filtered_db.aux_get(best_pkg, ["SLOT"])[0] + myslots.add(best_slot) + if len(myslots) > 1: + for myslot in myslots: + myslot_atom = "%s:%s" % (mykey, myslot) + if not self._populate_filtered_repo( + self.target_root, myslot_atom, + exclude_installed=True): + return 0 + if filtered_db.match(myslot_atom): + newlist.append(myslot_atom) + mylist = newlist + + for myatom in mylist: + self._set_atoms.add(myatom) + + # Since populate_filtered_repo() was called with the exclude_installed + # flag, these atoms will need to be processed again in case installed + # packages are required to satisfy dependencies. + self._filtered_trees[self.target_root]["atoms"].clear() + + missing_atoms = [] + for mydep in mylist: + try: + if not self.select_dep( + self.target_root, mydep, raise_on_missing=True, arg=mydep): + print >> sys.stderr, "\n\n!!! Problem resolving dependencies for", mydep + return 0 + except portage.exception.PackageNotFound: + missing_atoms.append(mydep) + + if not self.validate_blockers(): + return False + + if world_problems: + print >> sys.stderr, "\n!!! Problems have been detected with your world file" + print >> sys.stderr, "!!! Please run "+green("emaint --check world")+"\n" + + if missing_atoms: + print >> sys.stderr, "\n" + colorize("BAD", "!!!") + \ + " Ebuilds for the following packages are either all" + print >> sys.stderr, colorize("BAD", "!!!") + " masked or don't exist:" + print >> sys.stderr, " ".join(missing_atoms) + "\n" + + return 1 + + def display(self, mylist, favorites=[], verbosity=None): + if verbosity is None: + verbosity = ("--quiet" in self.myopts and 1 or \ + "--verbose" in self.myopts and 3 or 2) + favorites_set = InternalPackageSet(favorites) + changelogs=[] + p=[] + blockers = [] + + counters = PackageCounters() + + if verbosity == 1 and "--verbose" not in self.myopts: + def create_use_string(*args): + return "" + else: + def create_use_string(name, cur_iuse, iuse_forced, cur_use, + old_iuse, old_use, + is_new, reinst_flags, + all_flags=(verbosity == 3 or "--quiet" in self.myopts), + alphabetical=("--alphabetical" in self.myopts)): + enabled = [] + if alphabetical: + disabled = enabled + removed = enabled + else: + disabled = [] + removed = [] + cur_iuse = set(cur_iuse) + enabled_flags = cur_iuse.intersection(cur_use) + removed_iuse = set(old_iuse).difference(cur_iuse) + any_iuse = cur_iuse.union(old_iuse) + any_iuse = list(any_iuse) + any_iuse.sort() + for flag in any_iuse: + flag_str = None + isEnabled = False + reinst_flag = reinst_flags and flag in reinst_flags + if flag in enabled_flags: + isEnabled = True + if is_new or flag in old_use and \ + (all_flags or reinst_flag): + flag_str = red(flag) + elif flag not in old_iuse: + flag_str = yellow(flag) + "%*" + elif flag not in old_use: + flag_str = green(flag) + "*" + elif flag in removed_iuse: + if all_flags or reinst_flag: + flag_str = yellow("-" + flag) + "%" + if flag in old_use: + flag_str += "*" + flag_str = "(" + flag_str + ")" + removed.append(flag_str) + continue + else: + if is_new or flag in old_iuse and \ + flag not in old_use and \ + (all_flags or reinst_flag): + flag_str = blue("-" + flag) + elif flag not in old_iuse: + flag_str = yellow("-" + flag) + if flag not in iuse_forced: + flag_str += "%" + elif flag in old_use: + flag_str = green("-" + flag) + "*" + if flag_str: + if flag in iuse_forced: + flag_str = "(" + flag_str + ")" + if isEnabled: + enabled.append(flag_str) + else: + disabled.append(flag_str) + + if alphabetical: + ret = " ".join(enabled) + else: + ret = " ".join(enabled + disabled + removed) + if ret: + ret = '%s="%s" ' % (name, ret) + return ret + + repo_display = RepoDisplay(self.roots) + show_repos = False + + tree_nodes = [] + display_list = [] + mygraph = self._parent_child_digraph + i = 0 + depth = 0 + shown_edges = set() + for x in mylist: + if "blocks" == x[0]: + display_list.append((x, 0, True)) + continue + graph_key = tuple(x) + if "--tree" in self.myopts: + depth = len(tree_nodes) + while depth and graph_key not in \ + mygraph.child_nodes(tree_nodes[depth-1]): + depth -= 1 + if depth: + tree_nodes = tree_nodes[:depth] + tree_nodes.append(graph_key) + display_list.append((x, depth, True)) + shown_edges.add((graph_key, tree_nodes[depth-1])) + else: + traversed_nodes = set() # prevent endless circles + traversed_nodes.add(graph_key) + def add_parents(current_node, ordered): + parent_nodes = None + # Do not traverse to parents if this node is an + # an argument or a direct member of a set that has + # been specified as an argument (system or world). + if current_node not in self._set_nodes: + parent_nodes = mygraph.parent_nodes(current_node) + if parent_nodes: + child_nodes = set(mygraph.child_nodes(current_node)) + selected_parent = None + # First, try to avoid a direct cycle. + for node in parent_nodes: + if node not in traversed_nodes and \ + node not in child_nodes: + edge = (current_node, node) + if edge in shown_edges: + continue + selected_parent = node + break + if not selected_parent: + # A direct cycle is unavoidable. + for node in parent_nodes: + if node not in traversed_nodes: + edge = (current_node, node) + if edge in shown_edges: + continue + selected_parent = node + break + if selected_parent: + shown_edges.add((current_node, selected_parent)) + traversed_nodes.add(selected_parent) + add_parents(selected_parent, False) + display_list.append((list(current_node), + len(tree_nodes), ordered)) + tree_nodes.append(current_node) + tree_nodes = [] + add_parents(graph_key, True) + else: + display_list.append((x, depth, True)) + mylist = display_list + + last_merge_depth = 0 + for i in xrange(len(mylist)-1,-1,-1): + graph_key, depth, ordered = mylist[i] + if not ordered and depth == 0 and i > 0 \ + and graph_key == mylist[i-1][0] and \ + mylist[i-1][1] == 0: + # An ordered node got a consecutive duplicate when the tree was + # being filled in. + del mylist[i] + continue + if "blocks" == graph_key[0]: + continue + if ordered and graph_key[-1] != "nomerge": + last_merge_depth = depth + continue + if depth >= last_merge_depth or \ + i < len(mylist) - 1 and \ + depth >= mylist[i+1][1]: + del mylist[i] + + from portage import flatten + from portage.dep import use_reduce, paren_reduce + # files to fetch list - avoids counting a same file twice + # in size display (verbose mode) + myfetchlist=[] + + for mylist_index in xrange(len(mylist)): + x, depth, ordered = mylist[mylist_index] + pkg_node = tuple(x) + pkg_type = x[0] + myroot = x[1] + pkg_key = x[2] + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + vardb = self.trees[myroot]["vartree"].dbapi + vartree = self.trees[myroot]["vartree"] + pkgsettings = self.pkgsettings[myroot] + + fetch=" " + + if x[0]=="blocks": + addl=""+red("B")+" "+fetch+" " + if ordered: + counters.blocks += 1 + resolved = portage.key_expand( + pkg_key, mydb=vardb, settings=pkgsettings) + if "--columns" in self.myopts and "--quiet" in self.myopts: + addl = addl + " " + red(resolved) + else: + addl = "[blocks " + addl + "] " + red(resolved) + block_parents = self.blocker_parents[tuple(x)] + block_parents = set([pnode[2] for pnode in block_parents]) + block_parents = ", ".join(block_parents) + if resolved!=x[2]: + addl += bad(" (\"%s\" is blocking %s)") % \ + (pkg_key, block_parents) + else: + addl += bad(" (is blocking %s)") % block_parents + blockers.append(addl) + else: + pkg_status = x[3] + pkg_merge = ordered and pkg_status != "nomerge" + if pkg_node in self._slot_collision_nodes or \ + (pkg_status == "nomerge" and pkg_type != "installed"): + # The metadata isn't cached due to a slot collision or + # --onlydeps. + mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi + else: + mydbapi = self.mydbapi[myroot] # contains cached metadata + metadata = dict(izip(self._mydbapi_keys, + mydbapi.aux_get(pkg_key, self._mydbapi_keys))) + ebuild_path = None + repo_name = metadata["repository"] + if pkg_type == "ebuild": + ebuild_path = portdb.findname(pkg_key) + if not ebuild_path: # shouldn't happen + raise portage.exception.PackageNotFound(pkg_key) + repo_path_real = os.path.dirname(os.path.dirname( + os.path.dirname(ebuild_path))) + pkgsettings.setcpv(pkg_key, mydb=mydbapi) + metadata["USE"] = pkgsettings["USE"] + else: + repo_path_real = portdb.getRepositoryPath(repo_name) + pkg_use = metadata["USE"].split() + try: + restrict = flatten(use_reduce(paren_reduce( + mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]), + uselist=pkg_use)) + except portage.exception.InvalidDependString, e: + if pkg_status != "nomerge": + restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0] + show_invalid_depstring_notice(x, restrict, str(e)) + del e + return 1 + restrict = [] + if "ebuild" == pkg_type and x[3] != "nomerge" and \ + "fetch" in restrict: + fetch = red("F") + if ordered: + counters.restrict_fetch += 1 + if portdb.fetch_check(pkg_key, pkg_use): + fetch = green("f") + if ordered: + counters.restrict_fetch_satisfied += 1 + + #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="" + installed_versions = vardb.match(portage.cpv_getkey(pkg_key)) + if vardb.cpv_exists(pkg_key): + addl=" "+yellow("R")+fetch+" " + if x[3] != "nomerge": + if ordered: + counters.reinst += 1 + # filter out old-style virtual matches + elif installed_versions and \ + portage.cpv_getkey(installed_versions[0]) == \ + portage.cpv_getkey(pkg_key): + mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0] + slot_atom = "%s:%s" % \ + (portage.cpv_getkey(pkg_key), mynewslot) + myinslotlist = vardb.match(slot_atom) + # If this is the first install of a new-style virtual, we + # need to filter out old-style virtual matches. + if myinslotlist and \ + portage.cpv_getkey(myinslotlist[0]) != \ + portage.cpv_getkey(pkg_key): + myinslotlist = None + 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") + if ordered: + counters.downgrades += 1 + else: + # Update in slot + addl+=turquoise("U")+" " + if ordered: + counters.upgrades += 1 + else: + # New slot, mark it new. + addl=" "+green("NS")+fetch+" " + if ordered: + counters.newslot += 1 + + if "--changelog" in self.myopts: + slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key), + mydbapi.aux_get(pkg_key, ["SLOT"])[0]) + inst_matches = vardb.match(slot_atom) + if inst_matches: + changelogs.extend(self.calc_changelog( + portdb.findname(pkg_key), + inst_matches[0], pkg_key)) + else: + addl=" "+green("N")+" "+fetch+" " + if ordered: + counters.new += 1 + + verboseadd="" + + if True: + # USE flag display + cur_iuse = list(filter_iuse_defaults( + mydbapi.aux_get(pkg_key, ["IUSE"])[0].split())) + + forced_flags = set() + pkgsettings.setcpv(pkg_key, mydb=mydbapi) # for package.use.{mask,force} + forced_flags.update(pkgsettings.useforce) + forced_flags.update(pkgsettings.usemask) + + cur_iuse = portage.unique_array(cur_iuse) + cur_iuse.sort() + cur_use = pkg_use + cur_use = [flag for flag in cur_use if flag in cur_iuse] + + if myoldbest: + pkg = myoldbest + else: + pkg = x[2] + if self.trees[x[1]]["vartree"].dbapi.cpv_exists(pkg): + old_iuse, old_use = \ + self.trees[x[1]]["vartree"].dbapi.aux_get( + pkg, ["IUSE", "USE"]) + old_iuse = list(set( + filter_iuse_defaults(old_iuse.split()))) + old_iuse.sort() + old_use = old_use.split() + is_new = False + else: + old_iuse = [] + old_use = [] + is_new = True + + old_use = [flag for flag in old_use if flag in old_iuse] + + use_expand = pkgsettings["USE_EXPAND"].lower().split() + use_expand.sort() + use_expand.reverse() + use_expand_hidden = \ + pkgsettings["USE_EXPAND_HIDDEN"].lower().split() + + def map_to_use_expand(myvals, forcedFlags=False, + removeHidden=True): + ret = {} + forced = {} + for exp in use_expand: + ret[exp] = [] + forced[exp] = set() + for val in myvals[:]: + if val.startswith(exp.lower()+"_"): + if val in forced_flags: + forced[exp].add(val[len(exp)+1:]) + ret[exp].append(val[len(exp)+1:]) + myvals.remove(val) + ret["USE"] = myvals + forced["USE"] = [val for val in myvals \ + if val in forced_flags] + if removeHidden: + for exp in use_expand_hidden: + ret.pop(exp, None) + if forcedFlags: + return ret, forced + return ret + + # Prevent USE_EXPAND_HIDDEN flags from being hidden if they + # are the only thing that triggered reinstallation. + reinst_flags_map = {} + reinstall_for_flags = self._reinstall_nodes.get(pkg_node) + reinst_expand_map = None + if reinstall_for_flags: + reinst_flags_map = map_to_use_expand( + list(reinstall_for_flags), removeHidden=False) + for k in list(reinst_flags_map): + if not reinst_flags_map[k]: + del reinst_flags_map[k] + if not reinst_flags_map.get("USE"): + reinst_expand_map = reinst_flags_map.copy() + reinst_expand_map.pop("USE", None) + if reinst_expand_map and \ + not set(reinst_expand_map).difference( + use_expand_hidden): + use_expand_hidden = \ + set(use_expand_hidden).difference( + reinst_expand_map) + + cur_iuse_map, iuse_forced = \ + map_to_use_expand(cur_iuse, forcedFlags=True) + 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: + if key in use_expand_hidden: + continue + verboseadd += create_use_string(key.upper(), + cur_iuse_map[key], iuse_forced[key], + cur_use_map[key], old_iuse_map[key], + old_use_map[key], is_new, + reinst_flags_map.get(key)) + + if verbosity == 3: + # size verbose + mysize=0 + if pkg_type == "ebuild" and pkg_merge: + try: + myfilesdict = portdb.getfetchsizes(pkg_key, + useflags=pkg_use, debug=self.edebug) + except portage.exception.InvalidDependString, e: + src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0] + show_invalid_depstring_notice(x, src_uri, str(e)) + del e + return 1 + if myfilesdict is None: + myfilesdict="[empty/missing/bad digest]" + else: + for myfetchfile in myfilesdict: + if myfetchfile not in myfetchlist: + mysize+=myfilesdict[myfetchfile] + myfetchlist.append(myfetchfile) + counters.totalsize += mysize + verboseadd+=format_size(mysize)+" " + + # overlay verbose + # assign index for a previous version in the same slot + has_previous = False + repo_name_prev = None + slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key), + metadata["SLOT"]) + slot_matches = vardb.match(slot_atom) + if slot_matches: + has_previous = True + repo_name_prev = vardb.aux_get(slot_matches[0], + ["repository"])[0] + + # now use the data to generate output + repoadd = None + if pkg_status == "nomerge" or not has_previous: + repoadd = repo_display.repoStr(repo_path_real) + else: + repo_path_prev = None + if repo_name_prev: + repo_path_prev = portdb.getRepositoryPath( + repo_name_prev) + # To avoid spam during the transition period, don't + # show ? if the installed package is missing a + # repository label. + if not repo_path_prev or \ + repo_path_prev == repo_path_real: + repoadd = repo_display.repoStr(repo_path_real) + else: + repoadd = "%s=>%s" % ( + repo_display.repoStr(repo_path_prev), + repo_display.repoStr(repo_path_real)) + if repoadd and repoadd != "0": + show_repos = True + verboseadd += teal("[%s]" % repoadd) + + xs = list(portage.pkgsplit(x[2])) + if xs[2]=="r0": + xs[2]="" + else: + xs[2]="-"+xs[2] + + mywidth = 130 + if "COLUMNWIDTH" in self.settings: + try: + mywidth = int(self.settings["COLUMNWIDTH"]) + except ValueError, e: + portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) + portage.writemsg( + "!!! Unable to parse COLUMNWIDTH='%s'\n" % \ + self.settings["COLUMNWIDTH"], noiselevel=-1) + del e + oldlp=mywidth-30 + newlp=oldlp-30 + + indent = " " * depth + + if myoldbest: + myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] + if myoldbest[-3:]=="-r0": + myoldbest=myoldbest[:-3] + myoldbest=blue("["+myoldbest+"]") + + pkg_cp = xs[0] + root_config = self.roots[myroot] + system_set = root_config.sets["system"] + world_set = root_config.sets["world"] + + pkg_system = False + pkg_world = False + try: + pkg_system = system_set.findAtomForPackage(pkg_key, metadata) + pkg_world = world_set.findAtomForPackage(pkg_key, metadata) + if not pkg_world and myroot == self.target_root and \ + favorites_set.findAtomForPackage(pkg_key, metadata): + # Maybe it will be added to world now. + if create_world_atom(pkg_key, metadata, + favorites_set, root_config): + pkg_world = True + except portage.exception.InvalidDependString: + # This is reported elsewhere if relevant. + pass + + def pkgprint(pkg): + if pkg_merge: + if pkg_system: + return colorize("PKG_MERGE_SYSTEM", pkg) + elif pkg_world: + return colorize("PKG_MERGE_WORLD", pkg) + else: + return colorize("PKG_MERGE", pkg) + else: + if pkg_system: + return colorize("PKG_NOMERGE_SYSTEM", pkg) + elif pkg_world: + return colorize("PKG_NOMERGE_WORLD", pkg) + else: + return colorize("PKG_NOMERGE", pkg) + + if x[1]!="/": + if myoldbest: + myoldbest +=" " + if "--columns" in self.myopts: + if "--quiet" in self.myopts: + myprint=addl+" "+indent+pkgprint(pkg_cp) + myprint=myprint+darkblue(" "+xs[1]+xs[2])+" " + myprint=myprint+myoldbest + myprint=myprint+darkgreen("to "+x[1]) + else: + myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp) + 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: + if not pkg_merge: + myprint = "[%s ] " % pkgprint("nomerge") + else: + myprint = "[" + pkg_type + " " + addl + "] " + myprint += indent + pkgprint(pkg_key) + " " + \ + myoldbest + darkgreen("to " + myroot) + " " + \ + verboseadd + else: + if "--columns" in self.myopts: + if "--quiet" in self.myopts: + myprint=addl+" "+indent+pkgprint(pkg_cp) + myprint=myprint+" "+green(xs[1]+xs[2])+" " + myprint=myprint+myoldbest + else: + myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp) + 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 not pkg_merge: + myprint="["+pkgprint("nomerge")+" ] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd + else: + myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd + p.append(myprint) + + mysplit = portage.pkgsplit(x[2]) + if "--tree" not in self.myopts and mysplit and \ + len(mysplit) == 3 and mysplit[0] == "sys-apps/portage" and \ + x[1] == "/": + + if mysplit[2] == "r0": + myversion = mysplit[1] + else: + myversion = "%s-%s" % (mysplit[1], mysplit[2]) + + if myversion != portage.VERSION and "--quiet" not in self.myopts: + if mylist_index < len(mylist) - 1 and \ + "livecvsportage" not in self.settings.features: + p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,")) + p.append(colorize("WARN", " then resume the merge.")) + print + del mysplit + + for x in p: + print x + for x in blockers: + print x + + if verbosity == 3: + print + print counters + if show_repos: + sys.stdout.write(str(repo_display)) + + if "--changelog" in self.myopts: + print + for revision,text in changelogs: + print bold('*'+revision) + sys.stdout.write(text) + + if self._pprovided_args: + arg_refs = {} + for arg_atom in self._pprovided_args: + arg, atom = arg_atom + arg_refs[arg_atom] = [] + cp = portage.dep_getkey(atom) + for set_name, atom_set in self._sets.iteritems(): + if atom in atom_set: + arg_refs[arg_atom].append(set_name) + msg = [] + msg.append(bad("\nWARNING: ")) + if len(self._pprovided_args) > 1: + msg.append("Requested packages will not be " + \ + "merged because they are listed in\n") + else: + msg.append("A requested package will not be " + \ + "merged because it is listed in\n") + msg.append("package.provided:\n\n") + problems_sets = set() + for (arg, atom), refs in arg_refs.iteritems(): + ref_string = "" + if refs: + problems_sets.update(refs) + refs.sort() + ref_string = ", ".join(["'%s'" % name for name in refs]) + ref_string = " pulled in by " + ref_string + msg.append(" %s%s\n" % (colorize("INFORM", arg), ref_string)) + msg.append("\n") + if "world" in problems_sets: + msg.append("This problem can be solved in one of the following ways:\n\n") + msg.append(" A) Use emaint to clean offending packages from world (if not installed).\n") + msg.append(" B) Uninstall offending packages (cleans them from world).\n") + msg.append(" C) Remove offending entries from package.provided.\n\n") + msg.append("The best course of action depends on the reason that an offending\n") + msg.append("package.provided entry exists.\n\n") + sys.stderr.write("".join(msg)) + return os.EX_OK + + def calc_changelog(self,ebuildpath,current,next): + if ebuildpath == None or not os.path.exists(ebuildpath): + return [] + current = '-'.join(portage.catpkgsplit(current)[1:]) + if current.endswith('-r0'): + current = current[:-3] + next = '-'.join(portage.catpkgsplit(next)[1:]) + if next.endswith('-r0'): + next = next[:-3] + changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') + try: + changelog = open(changelogpath).read() + except SystemExit, e: + raise # Needed else can't exit + except: + return [] + divisions = self.find_changelog_tags(changelog) + #print 'XX from',current,'to',next + #for div,text in divisions: print 'XX',div + # skip entries for all revisions above the one we are about to emerge + for i in range(len(divisions)): + if divisions[i][0]==next: + divisions = divisions[i:] + break + # find out how many entries we are going to display + for i in range(len(divisions)): + if divisions[i][0]==current: + divisions = divisions[:i] + break + else: + # couldnt find the current revision in the list. display nothing + return [] + return divisions + + def find_changelog_tags(self,changelog): + divs = [] + release = None + while 1: + match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M) + if match is None: + if release is not None: + divs.append((release,changelog)) + return divs + if release is not None: + divs.append((release,changelog[:match.start()])) + changelog = changelog[match.end():] + release = match.group(1) + if release.endswith('.ebuild'): + release = release[:-7] + if release.endswith('-r0'): + release = release[:-3] + + def saveNomergeFavorites(self): + """Find atoms in favorites that are not in the mergelist and add them + to the world file if necessary.""" + for x in ("--fetchonly", "--fetch-all-uri", + "--oneshot", "--onlydeps", "--pretend"): + if x in self.myopts: + return + root_config = self.roots[self.target_root] + world_set = root_config.sets["world"] + world_set.lock() + world_set.load() # maybe it's changed on disk + args_set = self._sets["args"] + portdb = self.trees[self.target_root]["porttree"].dbapi + added_favorites = set() + for x in self._set_nodes: + pkg_type, root, pkg_key, pkg_status = x + if pkg_status != "nomerge": + continue + metadata = dict(izip(self._mydbapi_keys, + self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys))) + try: + myfavkey = create_world_atom(pkg_key, metadata, + args_set, root_config) + if myfavkey: + if myfavkey in added_favorites: + continue + added_favorites.add(myfavkey) + world_set.add(myfavkey) + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + except portage.exception.InvalidDependString, e: + writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \ + (pkg_key, str(e)), noiselevel=-1) + writemsg("!!! see '%s'\n\n" % os.path.join( + root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1) + del e + world_set.unlock() + + def loadResumeCommand(self, resume_data): + """ + Add a resume command to the graph and validate it in the process. This + will raise a PackageNotFound exception if a package is not available. + """ + self._sets["args"].update(resume_data.get("favorites", [])) + mergelist = resume_data.get("mergelist", []) + fakedb = self.mydbapi + trees = self.trees + for x in mergelist: + if len(x) != 4: + continue + pkg_type, myroot, pkg_key, action = x + if pkg_type not in self.pkg_tree_map: + continue + if action != "merge": + continue + mydb = trees[myroot][self.pkg_tree_map[pkg_type]].dbapi + try: + metadata = dict(izip(self._mydbapi_keys, + mydb.aux_get(pkg_key, self._mydbapi_keys))) + except KeyError: + # It does no exist or it is corrupt. + raise portage.exception.PackageNotFound(pkg_key) + fakedb[myroot].cpv_inject(pkg_key, metadata=metadata) + if pkg_type == "ebuild": + pkgsettings = self.pkgsettings[myroot] + pkgsettings.setcpv(pkg_key, mydb=fakedb[myroot]) + fakedb[myroot].aux_update(pkg_key, {"USE":pkgsettings["USE"]}) + self.spinner.update() + +class RepoDisplay(object): + def __init__(self, roots): + self._shown_repos = {} + self._unknown_repo = False + repo_paths = set() + for root_config in roots.itervalues(): + portdir = root_config.settings.get("PORTDIR") + if portdir: + repo_paths.add(portdir) + overlays = root_config.settings.get("PORTDIR_OVERLAY") + if overlays: + repo_paths.update(overlays.split()) + repo_paths = list(repo_paths) + self._repo_paths = repo_paths + self._repo_paths_real = [ os.path.realpath(repo_path) \ + for repo_path in repo_paths ] + + # pre-allocate index for PORTDIR so that it always has index 0. + for root_config in roots.itervalues(): + portdb = root_config.trees["porttree"].dbapi + portdir = portdb.porttree_root + if portdir: + self.repoStr(portdir) + + def repoStr(self, repo_path_real): + real_index = -1 + if repo_path_real: + real_index = self._repo_paths_real.index(repo_path_real) + if real_index == -1: + s = "?" + self._unknown_repo = True + else: + shown_repos = self._shown_repos + repo_paths = self._repo_paths + repo_path = repo_paths[real_index] + index = shown_repos.get(repo_path) + if index is None: + index = len(shown_repos) + shown_repos[repo_path] = index + s = str(index) + return s + + def __str__(self): + output = [] + shown_repos = self._shown_repos + unknown_repo = self._unknown_repo + if shown_repos or self._unknown_repo: + output.append("Portage tree and overlays:\n") + show_repo_paths = list(shown_repos) + for repo_path, repo_index in shown_repos.iteritems(): + show_repo_paths[repo_index] = repo_path + if show_repo_paths: + for index, repo_path in enumerate(show_repo_paths): + output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path) + if unknown_repo: + output.append(" "+teal("[?]") + \ + " indicates that the source repository could not be determined\n") + return "".join(output) + +class PackageCounters(object): + + def __init__(self): + self.upgrades = 0 + self.downgrades = 0 + self.new = 0 + self.newslot = 0 + self.reinst = 0 + self.blocks = 0 + self.totalsize = 0 + self.restrict_fetch = 0 + self.restrict_fetch_satisfied = 0 + + def __str__(self): + total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst + myoutput = [] + details = [] + myoutput.append("Total: %s package" % total_installs) + if total_installs != 1: + myoutput.append("s") + if total_installs != 0: + myoutput.append(" (") + if self.upgrades > 0: + details.append("%s upgrade" % self.upgrades) + if self.upgrades > 1: + details[-1] += "s" + if self.downgrades > 0: + details.append("%s downgrade" % self.downgrades) + if self.downgrades > 1: + details[-1] += "s" + if self.new > 0: + details.append("%s new" % self.new) + if self.newslot > 0: + details.append("%s in new slot" % self.newslot) + if self.newslot > 1: + details[-1] += "s" + if self.reinst > 0: + details.append("%s reinstall" % self.reinst) + if self.reinst > 1: + details[-1] += "s" + if self.blocks > 0: + details.append("%s block" % self.blocks) + if self.blocks > 1: + details[-1] += "s" + myoutput.append(", ".join(details)) + if total_installs != 0: + myoutput.append(")") + myoutput.append(", Size of downloads: %s" % format_size(self.totalsize)) + if self.restrict_fetch: + myoutput.append("\nFetch Restriction: %s package" % \ + self.restrict_fetch) + if self.restrict_fetch > 1: + myoutput.append("s") + if self.restrict_fetch_satisfied < self.restrict_fetch: + myoutput.append(bad(" (%s unsatisfied)") % \ + (self.restrict_fetch - self.restrict_fetch_satisfied)) + return "".join(myoutput) + +class MergeTask(object): + + def __init__(self, settings, trees, myopts): + self.settings = settings + self.target_root = settings["ROOT"] + self.trees = trees + self.myopts = myopts + self.edebug = 0 + if settings.get("PORTAGE_DEBUG", "") == "1": + self.edebug = 1 + self.pkgsettings = {} + self.pkgsettings[self.target_root] = portage.config(clone=settings) + if self.target_root != "/": + self.pkgsettings["/"] = \ + portage.config(clone=trees["/"]["vartree"].settings) + self.curval = 0 + + def merge(self, mylist, favorites, mtimedb): + from portage.elog import elog_process + from portage.elog.filtering import filter_mergephases + failed_fetches = [] + fetchonly = "--fetchonly" in self.myopts or \ + "--fetch-all-uri" in self.myopts + pretend = "--pretend" in self.myopts + mymergelist=[] + ldpath_mtimes = mtimedb["ldpath"] + xterm_titles = "notitles" not in self.settings.features + + #check for blocking dependencies + if "--fetchonly" not in self.myopts and \ + "--fetch-all-uri" not in self.myopts and \ + "--buildpkgonly" not in self.myopts: + for x in mylist: + if x[0]=="blocks": + print "\n!!! Error: the "+x[2]+" package conflicts with another package;" + print "!!! the two packages cannot be installed on the same system together." + print "!!! Please use 'emerge --pretend' to determine blockers." + if "--quiet" not in self.myopts: + show_blocker_docs_link() + return 1 + + if "--resume" in self.myopts: + # We're resuming. + print colorize("GOOD", "*** Resuming merge...") + emergelog(xterm_titles, " *** Resuming merge...") + mylist = mtimedb["resume"]["mergelist"][:] + if "--skipfirst" in self.myopts and mylist: + del mtimedb["resume"]["mergelist"][0] + del mylist[0] + mtimedb.commit() + mymergelist = mylist + + # Verify all the manifests now so that the user is notified of failure + # as soon as possible. + if "--fetchonly" not in self.myopts and \ + "--fetch-all-uri" not in self.myopts and \ + "strict" in self.settings.features: + shown_verifying_msg = False + quiet_settings = {} + for myroot, pkgsettings in self.pkgsettings.iteritems(): + quiet_config = portage.config(clone=pkgsettings) + quiet_config["PORTAGE_QUIET"] = "1" + quiet_config.backup_changes("PORTAGE_QUIET") + quiet_settings[myroot] = quiet_config + del quiet_config + for x in mylist: + if x[0] != "ebuild" or x[-1] == "nomerge": + continue + if not shown_verifying_msg: + shown_verifying_msg = True + print ">>> Verifying ebuild Manifests..." + mytype, myroot, mycpv, mystatus = x + portdb = self.trees[myroot]["porttree"].dbapi + quiet_config = quiet_settings[myroot] + quiet_config["O"] = os.path.dirname(portdb.findname(mycpv)) + if not portage.digestcheck([], quiet_config, strict=True): + return 1 + del x, mytype, myroot, mycpv, mystatus, quiet_config + del shown_verifying_msg, quiet_settings + + root_config = RootConfig(self.trees[self.target_root]) + system_set = root_config.sets["system"] + args_set = InternalPackageSet(favorites) + world_set = root_config.sets["world"] + if "--resume" not in self.myopts: + mymergelist = mylist + mtimedb["resume"]["mergelist"]=mymergelist[:] + mtimedb.commit() + + myfeat = self.settings.features[:] + bad_resume_opts = set(["--ask", "--tree", "--changelog", "--skipfirst", + "--resume"]) + if "parallel-fetch" in myfeat and \ + not ("--pretend" in self.myopts or \ + "--fetch-all-uri" in self.myopts or \ + "--fetchonly" in self.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" + fetch_log = "/var/log/emerge-fetch.log" + logfile = open(fetch_log, "w") + fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()} + portage.util.apply_secpass_permissions(fetch_log, + uid=portage.portage_uid, gid=portage.portage_gid, + mode=0660) + fetch_env = os.environ.copy() + fetch_env["FEATURES"] = fetch_env.get("FEATURES", "") + " -cvs" + fetch_env["PORTAGE_NICENESS"] = "0" + fetch_args = [sys.argv[0], "--resume", "--fetchonly"] + resume_opts = self.myopts.copy() + # For automatic resume, we need to prevent + # any of bad_resume_opts from leaking in + # via EMERGE_DEFAULT_OPTS. + resume_opts["--ignore-default-opts"] = True + for myopt, myarg in resume_opts.iteritems(): + if myopt not in bad_resume_opts: + if myarg is True: + fetch_args.append(myopt) + else: + fetch_args.append(myopt +"="+ myarg) + portage.process.spawn(fetch_args, env=fetch_env, + fd_pipes=fd_pipes, returnpid=True) + logfile.close() # belongs to the spawned process + del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \ + resume_opts + + metadata_keys = [k for k in portage.auxdbkeys \ + if not k.startswith("UNUSED_")] + ["USE"] + + mergecount=0 + for x in mymergelist: + mergecount+=1 + pkg_type = x[0] + myroot=x[1] + pkg_key = x[2] + pkgindex=2 + portdb = self.trees[myroot]["porttree"].dbapi + bindb = self.trees[myroot]["bintree"].dbapi + vartree = self.trees[myroot]["vartree"] + pkgsettings = self.pkgsettings[myroot] + metadata = {} + if pkg_type == "blocks": + pass + elif pkg_type == "ebuild": + mydbapi = portdb + metadata.update(izip(metadata_keys, + mydbapi.aux_get(pkg_key, metadata_keys))) + pkgsettings.setcpv(pkg_key, mydb=mydbapi) + metadata["USE"] = pkgsettings["USE"] + else: + if pkg_type == "binary": + mydbapi = bindb + else: + raise AssertionError("Package type: '%s'" % pkg_type) + metadata.update(izip(metadata_keys, + mydbapi.aux_get(pkg_key, metadata_keys))) + if x[0]=="blocks": + pkgindex=3 + y = portdb.findname(pkg_key) + if "--pretend" not in self.myopts: + print "\n>>> Emerging (" + \ + colorize("MERGE_LIST_PROGRESS", str(mergecount)) + " of " + \ + colorize("MERGE_LIST_PROGRESS", str(len(mymergelist))) + ") " + \ + colorize("GOOD", x[pkgindex]) + " to " + x[1] + emergelog(xterm_titles, " >>> emerge ("+\ + str(mergecount)+" of "+str(len(mymergelist))+\ + ") "+x[pkgindex]+" to "+x[1]) + + pkgsettings["EMERGE_FROM"] = x[0] + pkgsettings.backup_changes("EMERGE_FROM") + pkgsettings.reset() + + #buildsyspkg: Check if we need to _force_ binary package creation + issyspkg = ("buildsyspkg" in myfeat) \ + and x[0] != "blocks" \ + and system_set.findAtomForPackage(pkg_key, metadata) \ + and "--buildpkg" not in self.myopts + if x[0] in ["ebuild","blocks"]: + if x[0] == "blocks" and "--fetchonly" not in self.myopts: + raise Exception, "Merging a blocker" + elif "--fetchonly" in self.myopts or \ + "--fetch-all-uri" in self.myopts: + if "--fetch-all-uri" in self.myopts: + retval = portage.doebuild(y, "fetch", myroot, + pkgsettings, self.edebug, + "--pretend" in self.myopts, fetchonly=1, + fetchall=1, mydbapi=portdb, tree="porttree") + else: + retval = portage.doebuild(y, "fetch", myroot, + pkgsettings, self.edebug, + "--pretend" in self.myopts, fetchonly=1, + mydbapi=portdb, tree="porttree") + if (retval is None) or retval: + print + print "!!! Fetch for",y,"failed, continuing..." + print + failed_fetches.append(pkg_key) + self.curval += 1 + continue + + portage.doebuild_environment(y, "setup", myroot, + pkgsettings, self.edebug, 1, portdb) + catdir = os.path.dirname(pkgsettings["PORTAGE_BUILDDIR"]) + portage.util.ensure_dirs(os.path.dirname(catdir), + uid=portage.portage_uid, gid=portage.portage_gid, + mode=070, mask=0) + builddir_lock = None + catdir_lock = None + try: + catdir_lock = portage.locks.lockdir(catdir) + portage.util.ensure_dirs(catdir, + uid=portage.portage_uid, gid=portage.portage_gid, + mode=070, mask=0) + builddir_lock = portage.locks.lockdir( + pkgsettings["PORTAGE_BUILDDIR"]) + try: + portage.locks.unlockdir(catdir_lock) + finally: + catdir_lock = None + msg = " === (%s of %s) Cleaning (%s::%s)" % \ + (mergecount, len(mymergelist), pkg_key, y) + short_msg = "emerge: (%s of %s) %s Clean" % \ + (mergecount, len(mymergelist), pkg_key) + emergelog(xterm_titles, msg, short_msg=short_msg) + retval = portage.doebuild(y, "clean", myroot, + pkgsettings, self.edebug, cleanup=1, + mydbapi=portdb, tree="porttree") + if retval != os.EX_OK: + return retval + if "--buildpkg" in self.myopts or issyspkg: + if issyspkg: + print ">>> This is a system package, " + \ + "let's pack a rescue tarball." + msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \ + (mergecount, len(mymergelist), pkg_key, y) + short_msg = "emerge: (%s of %s) %s Compile" % \ + (mergecount, len(mymergelist), pkg_key) + emergelog(xterm_titles, msg, short_msg=short_msg) + self.trees[myroot]["bintree"].prevent_collision(pkg_key) + binpkg_tmpfile = os.path.join(pkgsettings["PKGDIR"], + pkg_key + ".tbz2." + str(os.getpid())) + pkgsettings["PORTAGE_BINPKG_TMPFILE"] = binpkg_tmpfile + pkgsettings.backup_changes("PORTAGE_BINPKG_TMPFILE") + retval = portage.doebuild(y, "package", myroot, + pkgsettings, self.edebug, mydbapi=portdb, + tree="porttree") + del pkgsettings["PORTAGE_BINPKG_TMPFILE"] + if retval != os.EX_OK or \ + "--buildpkgonly" in self.myopts: + elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases) + if retval != os.EX_OK: + return retval + bintree = self.trees[myroot]["bintree"] + bintree.inject(pkg_key, filename=binpkg_tmpfile) + if "--buildpkgonly" not in self.myopts: + msg = " === (%s of %s) Merging (%s::%s)" % \ + (mergecount, len(mymergelist), pkg_key, y) + short_msg = "emerge: (%s of %s) %s Merge" % \ + (mergecount, len(mymergelist), pkg_key) + emergelog(xterm_titles, msg, short_msg=short_msg) + retval = portage.merge(pkgsettings["CATEGORY"], + pkgsettings["PF"], pkgsettings["D"], + os.path.join(pkgsettings["PORTAGE_BUILDDIR"], + "build-info"), myroot, pkgsettings, + myebuild=pkgsettings["EBUILD"], + mytree="porttree", mydbapi=portdb, + vartree=vartree, prev_mtimes=ldpath_mtimes) + if retval != os.EX_OK: + return retval + elif "noclean" not in pkgsettings.features: + portage.doebuild(y, "clean", myroot, + pkgsettings, self.edebug, mydbapi=portdb, + tree="porttree") + else: + msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \ + (mergecount, len(mymergelist), pkg_key, y) + short_msg = "emerge: (%s of %s) %s Compile" % \ + (mergecount, len(mymergelist), pkg_key) + emergelog(xterm_titles, msg, short_msg=short_msg) + retval = portage.doebuild(y, "merge", myroot, + pkgsettings, self.edebug, vartree=vartree, + mydbapi=portdb, tree="porttree", + prev_mtimes=ldpath_mtimes) + if retval != os.EX_OK: + return retval + finally: + if builddir_lock: + portage.locks.unlockdir(builddir_lock) + try: + if not catdir_lock: + # Lock catdir for removal if empty. + catdir_lock = portage.locks.lockdir(catdir) + finally: + if catdir_lock: + try: + os.rmdir(catdir) + except OSError, e: + if e.errno not in (errno.ENOENT, + errno.ENOTEMPTY, errno.EEXIST): + raise + del e + portage.locks.unlockdir(catdir_lock) + + elif x[0]=="binary": + #merge the tbz2 + mytbz2 = self.trees[myroot]["bintree"].getname(pkg_key) + if "--getbinpkg" in self.myopts: + tbz2_lock = None + try: + if "distlocks" in pkgsettings.features and \ + os.access(pkgsettings["PKGDIR"], os.W_OK): + portage.util.ensure_dirs(os.path.dirname(mytbz2)) + tbz2_lock = portage.locks.lockfile(mytbz2, + wantnewlockfile=1) + if self.trees[myroot]["bintree"].isremote(pkg_key): + msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\ + (mergecount, len(mymergelist), pkg_key, mytbz2) + short_msg = "emerge: (%s of %s) %s Fetch" % \ + (mergecount, len(mymergelist), pkg_key) + emergelog(xterm_titles, msg, short_msg=short_msg) + try: + self.trees[myroot]["bintree"].gettbz2(pkg_key) + except portage.exception.FileNotFound: + writemsg("!!! Fetching Binary failed " + \ + "for '%s'\n" % pkg_key, noiselevel=-1) + if not fetchonly: + return 1 + failed_fetches.append(pkg_key) + except portage.exception.DigestException, e: + writemsg("\n!!! Digest verification failed:\n", + noiselevel=-1) + writemsg("!!! %s\n" % e.value[0], + noiselevel=-1) + writemsg("!!! Reason: %s\n" % e.value[1], + noiselevel=-1) + writemsg("!!! Got: %s\n" % e.value[2], + noiselevel=-1) + writemsg("!!! Expected: %s\n" % e.value[3], + noiselevel=-1) + os.unlink(mytbz2) + if not fetchonly: + return 1 + failed_fetches.append(pkg_key) + finally: + if tbz2_lock: + portage.locks.unlockfile(tbz2_lock) + + if "--fetchonly" in self.myopts or \ + "--fetch-all-uri" in self.myopts: + self.curval += 1 + continue + + short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" + emergelog(xterm_titles, " === ("+str(mergecount)+\ + " of "+str(len(mymergelist))+") Merging Binary ("+\ + x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) + retval = portage.pkgmerge(mytbz2, x[1], pkgsettings, + mydbapi=bindb, + vartree=self.trees[myroot]["vartree"], + prev_mtimes=ldpath_mtimes) + if retval != os.EX_OK: + return retval + #need to check for errors + if "--buildpkgonly" not in self.myopts: + self.trees[x[1]]["vartree"].inject(x[2]) + myfavkey = portage.cpv_getkey(x[2]) + if not fetchonly and not pretend and \ + args_set.findAtomForPackage(pkg_key, metadata): + world_set.lock() + world_set.load() # maybe it's changed on disk + myfavkey = create_world_atom(pkg_key, metadata, + args_set, root_config) + if myfavkey: + print ">>> Recording",myfavkey,"in \"world\" favorites file..." + emergelog(xterm_titles, " === ("+\ + str(mergecount)+" of "+\ + str(len(mymergelist))+\ + ") Updating world file ("+x[pkgindex]+")") + world_set.add(myfavkey) + world_set.unlock() + + if "--pretend" not in self.myopts and \ + "--fetchonly" not in self.myopts and \ + "--fetch-all-uri" not in self.myopts: + # Clean the old package that we have merged over top of it. + if pkgsettings.get("AUTOCLEAN", "yes") == "yes": + xsplit=portage.pkgsplit(x[2]) + emergelog(xterm_titles, " >>> AUTOCLEAN: " + xsplit[0]) + retval = unmerge(pkgsettings, self.myopts, vartree, + "clean", [xsplit[0]], ldpath_mtimes, autoclean=1) + if not retval: + emergelog(xterm_titles, + " --- AUTOCLEAN: Nothing unmerged.") + else: + portage.writemsg_stdout(colorize("WARN", "WARNING:") + + " AUTOCLEAN is disabled. This can cause serious" + + " problems due to overlapping packages.\n") + + # Figure out if we need a restart. + mysplit=portage.pkgsplit(x[2]) + if mysplit[0] == "sys-apps/portage" and x[1] == "/": + myver=mysplit[1]+"-"+mysplit[2] + if myver[-3:]=='-r0': + myver=myver[:-3] + if (myver != portage.VERSION) and \ + "livecvsportage" not in self.settings.features: + if len(mymergelist) > mergecount: + emergelog(xterm_titles, + " ::: completed emerge ("+ \ + str(mergecount)+" of "+ \ + str(len(mymergelist))+") "+ \ + x[2]+" to "+x[1]) + emergelog(xterm_titles, " *** RESTARTING " + \ + "emerge via exec() after change of " + \ + "portage version.") + del mtimedb["resume"]["mergelist"][0] + mtimedb.commit() + portage.run_exitfuncs() + mynewargv=[sys.argv[0],"--resume"] + resume_opts = self.myopts.copy() + # For automatic resume, we need to prevent + # any of bad_resume_opts from leaking in + # via EMERGE_DEFAULT_OPTS. + resume_opts["--ignore-default-opts"] = True + for myopt, myarg in resume_opts.iteritems(): + if myopt not in bad_resume_opts: + if myarg is True: + mynewargv.append(myopt) + else: + mynewargv.append(myopt +"="+ myarg) + # priority only needs to be adjusted on the first run + os.environ["PORTAGE_NICENESS"] = "0" + os.execv(mynewargv[0], mynewargv) + + if "--pretend" not in self.myopts and \ + "--fetchonly" not in self.myopts and \ + "--fetch-all-uri" not in self.myopts: + if "noclean" not in self.settings.features: + short_msg = "emerge: (%s of %s) %s Clean Post" % \ + (mergecount, len(mymergelist), x[pkgindex]) + emergelog(xterm_titles, (" === (%s of %s) " + \ + "Post-Build Cleaning (%s::%s)") % \ + (mergecount, len(mymergelist), x[pkgindex], y), + short_msg=short_msg) + emergelog(xterm_titles, " ::: completed emerge ("+\ + str(mergecount)+" of "+str(len(mymergelist))+") "+\ + x[2]+" to "+x[1]) + + # Unsafe for parallel merges + del mtimedb["resume"]["mergelist"][0] + # Commit after each merge so that --resume may still work in + # in the event that portage is not allowed to exit normally + # due to power failure, SIGKILL, etc... + mtimedb.commit() + self.curval += 1 + + if "--pretend" not in self.myopts: + emergelog(xterm_titles, " *** Finished. Cleaning up...") + + # We're out of the loop... We're done. Delete the resume data. + if mtimedb.has_key("resume"): + del mtimedb["resume"] + mtimedb.commit() + + #by doing an exit this way, --fetchonly can continue to try to + #fetch everything even if a particular download fails. + if "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts: + if failed_fetches: + sys.stderr.write("\n\n!!! Some fetch errors were " + \ + "encountered. Please see above for details.\n\n") + for cpv in failed_fetches: + sys.stderr.write(" ") + sys.stderr.write(cpv) + sys.stderr.write("\n") + sys.stderr.write("\n") + sys.exit(1) + else: + sys.exit(0) + return os.EX_OK + +def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files, + ldpath_mtimes, autoclean=0): + candidate_catpkgs=[] + global_unmerge=0 + xterm_titles = "notitles" not in settings.features + + vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH) + try: + # At least the parent needs to exist for the lock file. + portage.util.ensure_dirs(vdb_path) + except portage.exception.PortageException: + pass + vdb_lock = None + try: + if os.access(vdb_path, os.W_OK): + vdb_lock = portage.locks.lockdir(vdb_path) + realsyslist = getlist(settings, "system") + syslist = [] + for x in realsyslist: + mycp = portage.dep_getkey(x) + if mycp in settings.getvirtuals(): + providers = [] + for provider in settings.getvirtuals()[mycp]: + if vartree.dbapi.match(provider): + providers.append(provider) + if len(providers) == 1: + syslist.extend(providers) + else: + syslist.append(mycp) + + mysettings = portage.config(clone=settings) + + 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 = 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(vartree.dbapi.cp_all()) + elif "system" in unmerge_files: + candidate_catpkgs.extend(getlist(settings, "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 x[0] not in [".","/"] and \ + 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) + sp_absx = absx.split("/") + if sp_absx[-1][-7:] == ".ebuild": + del sp_absx[-1] + absx = "/".join(sp_absx) + + sp_absx_len = len(sp_absx) + + vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH) + vdb_len = len(vdb_path) + + sp_vdb = vdb_path.split("/") + sp_vdb_len = len(sp_vdb) + + if not os.path.exists(absx+"/CONTENTS"): + print "!!! Not a valid db dir: "+str(absx) + return 0 + + if sp_absx_len <= sp_vdb_len: + # The Path is shorter... so it can't be inside the vdb. + print sp_absx + print absx + print "\n!!!",x,"cannot be inside "+ \ + vdb_path+"; aborting.\n" + return 0 + + for idx in range(0,sp_vdb_len): + if idx >= sp_absx_len or sp_vdb[idx] != sp_absx[idx]: + print sp_absx + print absx + print "\n!!!", x, "is not inside "+\ + vdb_path+"; aborting.\n" + return 0 + + print "="+"/".join(sp_absx[sp_vdb_len:]) + candidate_catpkgs.append( + "="+"/".join(sp_absx[sp_vdb_len:])) + + newline="" + if (not "--quiet" in myopts): + newline="\n" + if settings["ROOT"] != "/": + print darkgreen(newline+ \ + ">>> Using system located in ROOT tree "+settings["ROOT"]) + if (("--pretend" in myopts) or ("--ask" in myopts)) and \ + not ("--quiet" in myopts): + print darkgreen(newline+\ + ">>> These are the packages that would be unmerged:") + + pkgmap={} + numselected=0 + for x in candidate_catpkgs: + # cycle through all our candidate deps and determine + # what will and will not get unmerged + try: + mymatch=localtree.dep_match(x) + except KeyError: + mymatch=None + 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) + + if not mymatch and x[0] not in "<>=~": + #add a "=" if missing + mymatch=localtree.dep_match("="+x) + if not mymatch: + portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \ + (x, unmerge_action), noiselevel=-1) + continue + mykey = portage.key_expand( + portage.dep_getkey( + mymatch[0]), mydb=vartree.dbapi, settings=settings) + if not pkgmap.has_key(mykey): + pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } + if unmerge_action=="unmerge": + for y in mymatch: + if y not in pkgmap[mykey]["selected"]: + pkgmap[mykey]["selected"].append(y) + numselected=numselected+len(mymatch) + elif unmerge_action == "prune": + if len(mymatch) == 1: + continue + best_version = mymatch[0] + best_slot = vartree.getslot(best_version) + best_counter = vartree.dbapi.cpv_counter(best_version) + for mypkg in mymatch[1:]: + myslot = vartree.getslot(mypkg) + mycounter = vartree.dbapi.cpv_counter(mypkg) + if (myslot == best_slot and mycounter > best_counter) or \ + mypkg == portage.best([mypkg, best_version]): + if myslot == best_slot: + if mycounter < best_counter: + # On slot collision, keep the one with the + # highest counter since it is the most + # recently installed. + continue + best_version = mypkg + best_slot = myslot + best_counter = mycounter + pkgmap[mykey]["protected"].append(best_version) + pkgmap[mykey]["selected"] = [mypkg for mypkg in mymatch \ + if mypkg != best_version] + numselected = numselected + len(pkgmap[mykey]["selected"]) + else: + # unmerge_action == "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: + 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 + if global_unmerge and not numselected: + portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n") + return 0 + + if not numselected: + portage.writemsg_stdout( + "\n>>> No packages selected for removal by " + \ + unmerge_action + "\n") + return 0 + finally: + if vdb_lock: + portage.locks.unlockdir(vdb_lock) + for x in pkgmap: + for y in localtree.dep_match(x): + if y not in pkgmap[x]["omitted"] and \ + y not in pkgmap[x]["selected"] and \ + y not in pkgmap[x]["protected"]: + pkgmap[x]["omitted"].append(y) + if global_unmerge and not pkgmap[x]["selected"]: + #avoid cluttering the preview printout with stuff that isn't getting unmerged + continue + if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist): + print colorize("BAD","\a\n\n!!! '%s' is part of your system profile." % x) + print colorize("WARN","\a!!! Unmerging it may be damaging to your system.\n") + if "--pretend" not in myopts and "--ask" not in myopts: + countdown(int(settings["EMERGE_WARNING_DELAY"]), + colorize("UNMERGE_WARN", "Press Ctrl-C to Stop")) + if "--quiet" not in myopts: + print "\n "+white(x) + else: + print white(x)+": ", + for mytype in ["selected","protected","omitted"]: + if "--quiet" not in myopts: + portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1) + if pkgmap[x][mytype]: + sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] \ + for mypkg in pkgmap[x][mytype]] + sorted_pkgs.sort(portage.pkgcmp) + for pn, ver, rev in sorted_pkgs: + if rev == "r0": + myversion = ver + else: + myversion = ver + "-" + rev + if mytype=="selected": + portage.writemsg_stdout( + colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1) + else: + portage.writemsg_stdout( + colorize("GOOD", myversion + " "), noiselevel=-1) + else: + portage.writemsg_stdout("none ", noiselevel=-1) + if "--quiet" not in myopts: + portage.writemsg_stdout("\n", noiselevel=-1) + if "--quiet" in myopts: + portage.writemsg_stdout("\n", noiselevel=-1) + + portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \ + " packages are slated for removal.\n") + portage.writemsg_stdout(">>> " + colorize("GOOD", "'Protected'") + \ + " and " + colorize("GOOD", "'omitted'") + \ + " packages will not be removed.\n\n") + + if "--pretend" in myopts: + #we're done... return + return 0 + if "--ask" in myopts: + if userquery("Would you like to unmerge these packages?")=="No": + # enter pretend mode for correct formatting of results + myopts["--pretend"] = True + print + print "Quitting." + print + return 0 + #the real unmerging begins, after a short delay.... + if not autoclean: + countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging") + + for x in pkgmap: + for y in pkgmap[x]["selected"]: + print ">>> Unmerging "+y+"..." + emergelog(xterm_titles, "=== Unmerging... ("+y+")") + mysplit=y.split("/") + #unmerge... + retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"], + mysettings, unmerge_action not in ["clean","prune"], + vartree=vartree, ldpath_mtimes=ldpath_mtimes) + if retval != os.EX_OK: + emergelog(xterm_titles, " !!! unmerge FAILURE: "+y) + ebuild = vartree.dbapi.findname(y) + show_unmerge_failure_message(y, ebuild, retval) + sys.exit(retval) + else: + clean_world(vartree.dbapi, y) + emergelog(xterm_titles, " >>> unmerge success: "+y) + return 1 + +def show_unmerge_failure_message(pkg, ebuild, retval): + + from formatter import AbstractFormatter, DumbWriter + f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72)) + + msg = [] + msg.append("A removal phase of the '%s' package " % pkg) + msg.append("has failed with exit value %s. " % retval) + msg.append("The problem occurred while executing ") + msg.append("the ebuild located at '%s'. " % ebuild) + msg.append("If necessary, manually remove the ebuild " ) + msg.append("in order to skip the execution of removal phases.") + + f.end_paragraph(1) + for x in msg: + f.add_flowing_data(x) + f.end_paragraph(1) + f.writer.flush() + +def chk_updated_info_files(root, infodirs, prev_mtimes, retval): + + if os.path.exists("/usr/bin/install-info"): + regen_infodirs=[] + for z in infodirs: + if z=='': + continue + inforoot=normpath(root+z) + if os.path.isdir(inforoot): + infomtime = long(os.stat(inforoot).st_mtime) + if inforoot not in prev_mtimes or \ + prev_mtimes[inforoot] != infomtime: + regen_infodirs.append(inforoot) + + if not regen_infodirs: + portage.writemsg_stdout(" "+green("*")+" GNU info directory index is up-to-date.\n") + else: + portage.writemsg_stdout(" "+green("*")+" Regenerating GNU info directory index...\n") + + dir_extensions = ("", ".gz", ".bz2") + icount=0 + badcount=0 + for inforoot in regen_infodirs: + if inforoot=='': + continue + + if not os.path.isdir(inforoot): + continue + errmsg = "" + file_list = os.listdir(inforoot) + file_list.sort() + dir_file = os.path.join(inforoot, "dir") + moved_old_dir = False + processed_count = 0 + for x in file_list: + if x.startswith(".") or \ + os.path.isdir(os.path.join(inforoot, x)): + continue + if x.startswith("dir"): + skip = False + for ext in dir_extensions: + if x == "dir" + ext or \ + x == "dir" + ext + ".old": + skip = True + break + if skip: + continue + if processed_count == 0: + for ext in dir_extensions: + try: + os.rename(dir_file + ext, dir_file + ext + ".old") + moved_old_dir = True + except EnvironmentError, e: + if e.errno != errno.ENOENT: + raise + del e + processed_count += 1 + myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] + existsstr="already exists, for file `" + if myso!="": + if re.search(existsstr,myso): + # Already exists... Don't increment the count for this. + pass + elif myso[:44]=="install-info: warning: no info dir entry in ": + # This info file doesn't contain a DIR-header: install-info produces this + # (harmless) warning (the --quiet switch doesn't seem to work). + # Don't increment the count for this. + pass + else: + badcount=badcount+1 + errmsg += myso + "\n" + icount=icount+1 + + if moved_old_dir and not os.path.exists(dir_file): + # We didn't generate a new dir file, so put the old file + # back where it was originally found. + for ext in dir_extensions: + try: + os.rename(dir_file + ext + ".old", dir_file + ext) + except EnvironmentError, e: + if e.errno != errno.ENOENT: + raise + del e + + # Clean dir.old cruft so that they don't prevent + # unmerge of otherwise empty directories. + for ext in dir_extensions: + try: + os.unlink(dir_file + ext + ".old") + except EnvironmentError, e: + if e.errno != errno.ENOENT: + raise + del e + + #update mtime so we can potentially avoid regenerating. + prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime) + + if badcount: + print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors." + print errmsg + else: + print " "+green("*")+" Processed",icount,"info files." + + +def display_news_notification(trees): + for target_root in trees: + if len(trees) > 1 and target_root != "/": + break + settings = trees[target_root]["vartree"].settings + portdb = trees[target_root]["porttree"].dbapi + vardb = trees[target_root]["vartree"].dbapi + NEWS_PATH = os.path.join("metadata", "news") + UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news") + newsReaderDisplay = False + + for repo in portdb.getRepositories(): + unreadItems = checkUpdatedNewsItems( + portdb, vardb, NEWS_PATH, UNREAD_PATH, repo) + if unreadItems: + if not newsReaderDisplay: + newsReaderDisplay = True + print + print colorize("WARN", " * IMPORTANT:"), + print "%s news items need reading for repository '%s'." % (unreadItems, repo) + + + if newsReaderDisplay: + print colorize("WARN", " *"), + print "Use " + colorize("GOOD", "eselect news") + " to read news items." + print + +def post_emerge(trees, mtimedb, retval): + """ + Misc. things to run at the end of a merge session. + + Update Info Files + Update Config Files + Update News Items + Commit mtimeDB + Display preserved libs warnings + Exit Emerge + + @param trees: A dictionary mapping each ROOT to it's package databases + @type trees: dict + @param mtimedb: The mtimeDB to store data needed across merge invocations + @type mtimedb: MtimeDB class instance + @param retval: Emerge's return value + @type retval: Int + @rype: None + @returns: + 1. Calls sys.exit(retval) + """ + for target_root in trees: + if len(trees) > 1 and target_root != "/": + break + vardbapi = trees[target_root]["vartree"].dbapi + settings = vardbapi.settings + info_mtimes = mtimedb["info"] + + # Load the most current variables from ${ROOT}/etc/profile.env + settings.unlock() + settings.reload() + settings.regenerate() + settings.lock() + + config_protect = settings.get("CONFIG_PROTECT","").split() + infodirs = settings.get("INFOPATH","").split(":") + \ + settings.get("INFODIR","").split(":") + + os.chdir("/") + + if retval == os.EX_OK: + exit_msg = " *** exiting successfully." + else: + exit_msg = " *** exiting unsuccessfully with status '%s'." % retval + emergelog("notitles" not in settings.features, exit_msg) + + # Dump the mod_echo output now so that our other notifications are shown + # last. + try: + from portage.elog import mod_echo + except ImportError: + pass # happens during downgrade to a version without the module + else: + mod_echo.finalize() + + vdb_path = os.path.join(target_root, portage.VDB_PATH) + portage.util.ensure_dirs(vdb_path) + vdb_lock = portage.locks.lockdir(vdb_path) + try: + if "noinfo" not in settings.features: + chk_updated_info_files(target_root, infodirs, info_mtimes, retval) + mtimedb.commit() + finally: + portage.locks.unlockdir(vdb_lock) + + chk_updated_cfg_files(target_root, config_protect) + + display_news_notification(trees) + + if vardbapi.plib_registry.hasEntries(): + print colorize("WARN", "!!!") + " existing preserved libs:" + plibdata = vardbapi.plib_registry.getPreservedLibs() + for cpv in plibdata: + print colorize("WARN", ">>>") + " package: %s" % cpv + for f in plibdata[cpv]: + print colorize("WARN", " * ") + " - %s" % f + print "Use " + colorize("GOOD", "revdep-rebuild") + " to rebuild packages using these libraries" + print "and then remerge the packages listed above." + + sys.exit(retval) + + +def chk_updated_cfg_files(target_root, config_protect): + if config_protect: + #number of directories with some protect files in them + procount=0 + for x in config_protect: + x = os.path.join(target_root, x.lstrip(os.path.sep)) + try: + mymode = os.lstat(x).st_mode + except OSError: + continue + if stat.S_ISLNK(mymode): + # We want to treat it like a directory if it + # is a symlink to an existing directory. + try: + real_mode = os.stat(x).st_mode + if stat.S_ISDIR(real_mode): + mymode = real_mode + except OSError: + pass + if stat.S_ISDIR(mymode): + mycommand = "find '%s' -iname '._cfg????_*'" % x + else: + mycommand = "find '%s' -maxdepth 1 -iname '._cfg????_%s'" % \ + os.path.split(x.rstrip(os.path.sep)) + mycommand += " ! -iname '.*~' ! -iname '.*.bak' -print0" + a = commands.getstatusoutput(mycommand) + if a[0] != 0: + sys.stderr.write(" %s error scanning '%s': " % (bad("*"), x)) + sys.stderr.flush() + # Show the error message alone, sending stdout to /dev/null. + os.system(mycommand + " 1>/dev/null") + else: + files = a[1].split('\0') + # split always produces an empty string as the last element + if files and not files[-1]: + del files[-1] + if files: + procount += 1 + print colorize("WARN", " * IMPORTANT:"), + if stat.S_ISDIR(mymode): + print "%d config files in '%s' need updating." % \ + (len(files), x) + else: + print "config file '%s' needs updating." % x + + if procount: + print " "+yellow("*")+" See the "+colorize("INFORM","CONFIGURATION FILES")+ \ + " section of the " + bold("emerge") + print " "+yellow("*")+" man page to learn how to update config files." + +def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id): + """ + Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items + Returns the number of unread (yet relevent) items. + + @param portdb: a portage tree database + @type portdb: pordbapi + @param vardb: an installed package database + @type vardb: vardbapi + @param NEWS_PATH: + @type NEWS_PATH: + @param UNREAD_PATH: + @type UNREAD_PATH: + @param repo_id: + @type repo_id: + @rtype: Integer + @returns: + 1. The number of unread but relevant news items. + + """ + from portage.news import NewsManager + manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH) + return manager.getUnreadItems( repo_id, update=True ) + +def is_valid_package_atom(x): + try: + testkey = portage.dep_getkey(x) + except portage.exception.InvalidData: + return False + if testkey.startswith("null/"): + testatom = x.replace(testkey[5:], "cat/"+testkey[5:]) + elif "/" not in x: + testatom = "cat/"+x + else: + testatom = x + return portage.isvalidatom(testatom) + +def show_blocker_docs_link(): + print + print "For more information about " + bad("Blocked Packages") + ", please refer to the following" + print "section of the Gentoo Linux x86 Handbook (architecture is irrelevant):" + print + print "http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked" + print + +def action_sync(settings, trees, mtimedb, myopts, myaction): + xterm_titles = "notitles" not in settings.features + emergelog(xterm_titles, " === sync") + myportdir = settings.get("PORTDIR", None) + if not myportdir: + sys.stderr.write("!!! PORTDIR is undefined. Is /etc/make.globals missing?\n") + sys.exit(1) + if myportdir[-1]=="/": + myportdir=myportdir[:-1] + if not os.path.exists(myportdir): + print ">>>",myportdir,"not found, creating it." + os.makedirs(myportdir,0755) + syncuri=settings["SYNC"].rstrip() + os.umask(0022) + updatecache_flg = False + if myaction == "metadata": + print "skipping sync" + updatecache_flg = True + 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 + + rsync_opts = [] + import shlex, StringIO + if settings["PORTAGE_RSYNC_OPTS"] == "": + portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n") + rsync_opts.extend([ + "--recursive", # Recurse directories + "--links", # Consider symlinks + "--safe-links", # Ignore links outside of tree + "--perms", # Preserve permissions + "--times", # Preserive mod times + "--compress", # Compress the data transmitted + "--force", # Force deletion on non-empty dirs + "--whole-file", # Don't do block transfers, only entire files + "--delete", # Delete files that aren't in the master tree + "--delete-after", # Delete only after everything else is done + "--stats", # Show final statistics about what was transfered + "--timeout="+str(mytimeout), # IO timeout if not done in X seconds + "--exclude=/distfiles", # Exclude distfiles from consideration + "--exclude=/local", # Exclude local from consideration + "--exclude=/packages", # Exclude packages from consideration + "--filter=H_**/files/digest-*", # Exclude manifest1 digests and delete on the receiving side + ]) + + else: + # The below validation is not needed when using the above hardcoded + # defaults. + + portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1) + lexer = shlex.shlex(StringIO.StringIO( + settings.get("PORTAGE_RSYNC_OPTS","")), posix=True) + lexer.whitespace_split = True + rsync_opts.extend(lexer) + del lexer + + for opt in ("--recursive", "--times"): + if opt not in rsync_opts: + portage.writemsg(yellow("WARNING:") + " adding required option " + \ + "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) + rsync_opts.append(opt) + + for exclude in ("distfiles", "local", "packages"): + opt = "--exclude=/%s" % exclude + if opt not in rsync_opts: + portage.writemsg(yellow("WARNING:") + \ + " adding required option %s not included in " % opt + \ + "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n") + rsync_opts.append(opt) + + if settings["RSYNC_TIMEOUT"] != "": + portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \ + "use PORTAGE_RSYNC_EXTRA_OPTS instead\n") + try: + mytimeout = int(settings["RSYNC_TIMEOUT"]) + rsync_opts.append("--timeout=%d" % mytimeout) + except ValueError, e: + portage.writemsg("!!! %s\n" % str(e)) + + # TODO: determine options required for official servers + if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"): + + def rsync_opt_startswith(opt_prefix): + for x in rsync_opts: + if x.startswith(opt_prefix): + return True + return False + + if not rsync_opt_startswith("--timeout="): + rsync_opts.append("--timeout=%d" % mytimeout) + + for opt in ("--compress", "--whole-file"): + if opt not in rsync_opts: + portage.writemsg(yellow("WARNING:") + " adding required option " + \ + "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) + rsync_opts.append(opt) + + if "--quiet" in myopts: + rsync_opts.append("--quiet") # Shut up a lot + else: + rsync_opts.append("--verbose") # Print filelist + + if "--verbose" in myopts: + rsync_opts.append("--progress") # Progress meter for each file + + if "--debug" in myopts: + rsync_opts.append("--checksum") # Force checksum on all files + + if settings["RSYNC_EXCLUDEFROM"] != "": + portage.writemsg(yellow("WARNING:") + \ + " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \ + "PORTAGE_RSYNC_EXTRA_OPTS instead\n") + if os.path.exists(settings["RSYNC_EXCLUDEFROM"]): + rsync_opts.append("--exclude-from=%s" % \ + settings["RSYNC_EXCLUDEFROM"]) + else: + portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \ + " but file does not exist.\n") + + if settings["RSYNC_RATELIMIT"] != "": + portage.writemsg(yellow("WARNING:") + \ + " usage of RSYNC_RATELIMIT is deprecated, use " + \ + "PORTAGE_RSYNC_EXTRA_OPTS instead") + rsync_opts.append("--bwlimit=%s" % \ + settings["RSYNC_RATELIMIT"]) + + # Real local timestamp file. + servertimestampfile = os.path.join( + myportdir, "metadata", "timestamp.chk") + + content = portage.util.grabfile(servertimestampfile) + mytimestamp = 0 + if content: + try: + mytimestamp = time.mktime(time.strptime(content[0], + "%a, %d %b %Y %H:%M:%S +0000")) + except (OverflowError, ValueError): + pass + del content + + try: + rsync_initial_timeout = \ + int(settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15")) + except ValueError: + rsync_initial_timeout = 15 + + try: + if settings.has_key("RSYNC_RETRIES"): + print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead" + maxretries=int(settings["RSYNC_RETRIES"]) + else: + maxretries=int(settings["PORTAGE_RSYNC_RETRIES"]) + except SystemExit, e: + raise # Needed else can't exit + except: + maxretries=3 #default number of retries + + retries=0 + user_name, hostname, port = re.split( + "rsync://([^:/]+@)?([^:/]*)(:[0-9]+)?", syncuri, maxsplit=3)[1:4] + if port is None: + port="" + if user_name is None: + user_name="" + updatecache_flg=True + all_rsync_opts = set(rsync_opts) + lexer = shlex.shlex(StringIO.StringIO( + settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")), posix=True) + lexer.whitespace_split = True + extra_rsync_opts = list(lexer) + del lexer + all_rsync_opts.update(extra_rsync_opts) + family = socket.AF_INET + if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts: + family = socket.AF_INET + elif socket.has_ipv6 and \ + ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts): + family = socket.AF_INET6 + ips=[] + while (1): + if ips: + del ips[0] + if ips==[]: + try: + for addrinfo in socket.getaddrinfo( + hostname, None, family, socket.SOCK_STREAM): + if addrinfo[0] == socket.AF_INET6: + # IPv6 addresses need to be enclosed in square brackets + ips.append("[%s]" % addrinfo[4][0]) + else: + ips.append(addrinfo[4][0]) + from random import shuffle + shuffle(ips) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if ips: + try: + dosyncuri = syncuri.replace( + "//" + user_name + hostname + port + "/", + "//" + user_name + ips[0] + port + "/", 1) + except SystemExit, e: + raise # Needed else can't exit + except Exception, e: + print "Notice:",str(e) + dosyncuri=syncuri + + if (retries==0): + if "--ask" in myopts: + if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No": + print + print "Quitting." + print + sys.exit(0) + emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri) + if "--quiet" not in myopts: + print ">>> Starting rsync with "+dosyncuri+"..." + else: + emergelog(xterm_titles, + ">>> Starting retry %d of %d with %s" % \ + (retries,maxretries,dosyncuri)) + print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri) + + if mytimestamp != 0 and "--quiet" not in myopts: + print ">>> Checking server timestamp ..." + + rsynccommand = ["/usr/bin/rsync"] + rsync_opts + extra_rsync_opts + + if "--debug" in myopts: + print rsynccommand + + exitcode = os.EX_OK + servertimestamp = 0 + # Even if there's no timestamp available locally, fetch the + # timestamp anyway as an initial probe to verify that the server is + # responsive. This protects us from hanging indefinitely on a + # connection attempt to an unresponsive server which rsync's + # --timeout option does not prevent. + if True: + # Temporary file for remote server timestamp comparison. + from tempfile import mkstemp + fd, tmpservertimestampfile = mkstemp() + os.close(fd) + mycommand = rsynccommand[:] + mycommand.append(dosyncuri.rstrip("/") + \ + "/metadata/timestamp.chk") + mycommand.append(tmpservertimestampfile) + content = None + mypids = [] + try: + def timeout_handler(signum, frame): + raise portage.exception.PortageException("timed out") + signal.signal(signal.SIGALRM, timeout_handler) + # Timeout here in case the server is unresponsive. The + # --timeout rsync option doesn't apply to the initial + # connection attempt. + if rsync_initial_timeout: + signal.alarm(rsync_initial_timeout) + try: + mypids.extend(portage.process.spawn( + mycommand, env=settings.environ(), returnpid=True)) + exitcode = os.waitpid(mypids[0], 0)[1] + content = portage.grabfile(tmpservertimestampfile) + finally: + if rsync_initial_timeout: + signal.alarm(0) + try: + os.unlink(tmpservertimestampfile) + except OSError: + pass + except portage.exception.PortageException, e: + # timed out + print e + del e + if mypids and os.waitpid(mypids[0], os.WNOHANG) == (0,0): + os.kill(mypids[0], signal.SIGTERM) + os.waitpid(mypids[0], 0) + # This is the same code rsync uses for timeout. + exitcode = 30 + else: + if exitcode != os.EX_OK: + if exitcode & 0xff: + exitcode = (exitcode & 0xff) << 8 + else: + exitcode = exitcode >> 8 + if mypids: + portage.process.spawned_pids.remove(mypids[0]) + if content: + try: + servertimestamp = time.mktime(time.strptime( + content[0], "%a, %d %b %Y %H:%M:%S +0000")) + except (OverflowError, ValueError): + pass + del mycommand, mypids, content + if exitcode == os.EX_OK: + if (servertimestamp != 0) and (servertimestamp == mytimestamp): + emergelog(xterm_titles, + ">>> Cancelling sync -- Already current.") + print + print ">>>" + print ">>> Timestamps on the server and in the local repository are the same." + print ">>> Cancelling all further sync action. You are already up to date." + print ">>>" + print ">>> In order to force sync, remove '%s'." % servertimestampfile + print ">>>" + print + sys.exit(0) + elif (servertimestamp != 0) and (servertimestamp < mytimestamp): + emergelog(xterm_titles, + ">>> Server out of date: %s" % dosyncuri) + print + print ">>>" + print ">>> SERVER OUT OF DATE: %s" % dosyncuri + print ">>>" + print ">>> In order to force sync, remove '%s'." % servertimestampfile + print ">>>" + print + elif (servertimestamp == 0) or (servertimestamp > mytimestamp): + # actual sync + mycommand = rsynccommand + [dosyncuri+"/", myportdir] + exitcode = portage.process.spawn(mycommand, + env=settings.environ()) + if exitcode in [0,1,3,4,11,14,20,21]: + break + elif exitcode in [1,3,4,11,14,20,21]: + break + else: + # Code 2 indicates protocol incompatibility, which is expected + # for servers with protocol < 29 that don't support + # --prune-empty-directories. Retry for a server that supports + # at least rsync protocol version 29 (>=rsync-2.6.4). + pass + + retries=retries+1 + + if retries<=maxretries: + print ">>> Retrying..." + time.sleep(11) + else: + # over retries + # exit loop + updatecache_flg=False + break + + if (exitcode==0): + emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri) + elif (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="+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="+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 CVS 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 os.path.exists(cvsdir+"/gentoo-x86"): + print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." + sys.exit(1) + try: + os.rmdir(myportdir) + except OSError, e: + if e.errno != errno.ENOENT: + sys.stderr.write( + "!!! existing '%s' directory; exiting.\n" % myportdir) + sys.exit(1) + del e + if portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",settings,free=1): + print "!!! cvs checkout error; exiting." + sys.exit(1) + os.rename(os.path.join(cvsdir, "gentoo-x86"), myportdir) + else: + #cvs update + print ">>> Starting cvs update with "+syncuri+"..." + retval = portage.spawn("cd '%s'; cvs -z0 -q update -dP" % \ + myportdir, settings, free=1) + if retval != os.EX_OK: + sys.exit(retval) + dosyncuri = syncuri + else: + print "!!! rsync setting: ",syncuri,"not recognized; exiting." + sys.exit(1) + + if updatecache_flg and \ + myaction != "metadata" and \ + "metadata-transfer" not in settings.features: + updatecache_flg = False + + # Reload the whole config from scratch. + settings, trees, mtimedb = load_emerge_config(trees=trees) + portdb = trees[settings["ROOT"]]["porttree"].dbapi + + if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg: + action_metadata(settings, portdb, myopts) + + if portage._global_updates(trees, mtimedb["updates"]): + mtimedb.commit() + # Reload the whole config from scratch. + settings, trees, mtimedb = load_emerge_config(trees=trees) + portdb = trees[settings["ROOT"]]["porttree"].dbapi + + mybestpv = portdb.xmatch("bestmatch-visible", "sys-apps/portage") + mypvs = portage.best( + trees[settings["ROOT"]]["vartree"].dbapi.match("sys-apps/portage")) + + chk_updated_cfg_files("/", settings.get("CONFIG_PROTECT","").split()) + + if myaction != "metadata": + if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK): + retval = portage.process.spawn( + [os.path.join(portage.USER_CONFIG_PATH, "bin", "post_sync"), + dosyncuri], env=settings.environ()) + if retval != os.EX_OK: + print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync") + + if(mybestpv != mypvs) and not "--quiet" in myopts: + 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 + print red(" * ")+"To update portage, run 'emerge portage' now." + print + + display_news_notification(trees) + +def action_metadata(settings, portdb, myopts): + portage.writemsg_stdout("\n>>> Updating Portage cache: ") + old_umask = os.umask(0002) + cachedir = os.path.normpath(settings.depcachedir) + if cachedir in ["/", "/bin", "/dev", "/etc", "/home", + "/lib", "/opt", "/proc", "/root", "/sbin", + "/sys", "/tmp", "/usr", "/var"]: + print >> sys.stderr, "!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \ + "ROOT DIRECTORY ON YOUR SYSTEM." + print >> sys.stderr, \ + "!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir + sys.exit(73) + if not os.path.exists(cachedir): + os.mkdir(cachedir) + + ec = portage.eclass_cache.cache(portdb.porttree_root) + myportdir = os.path.realpath(settings["PORTDIR"]) + cm = settings.load_best_module("portdbapi.metadbmodule")( + myportdir, "metadata/cache", portage.auxdbkeys[:]) + + from portage.cache import util + + class percentage_noise_maker(util.quiet_mirroring): + def __init__(self, dbapi): + self.dbapi = dbapi + self.cp_all = dbapi.cp_all() + l = len(self.cp_all) + self.call_update_min = 100000000 + self.min_cp_all = l/100.0 + self.count = 1 + self.pstr = '' + + def __iter__(self): + for x in self.cp_all: + self.count += 1 + if self.count > self.min_cp_all: + self.call_update_min = 0 + self.count = 0 + for y in self.dbapi.cp_list(x): + yield y + self.call_update_mine = 0 + + def update(self, *arg): + try: self.pstr = int(self.pstr) + 1 + except ValueError: self.pstr = 1 + sys.stdout.write("%s%i%%" % \ + ("\b" * (len(str(self.pstr))+1), self.pstr)) + sys.stdout.flush() + self.call_update_min = 10000000 + + def finish(self, *arg): + sys.stdout.write("\b\b\b\b100%\n") + sys.stdout.flush() + + if "--quiet" in myopts: + def quicky_cpv_generator(cp_all_list): + for x in cp_all_list: + for y in portdb.cp_list(x): + yield y + source = quicky_cpv_generator(portdb.cp_all()) + noise_maker = portage.cache.util.quiet_mirroring() + else: + noise_maker = source = percentage_noise_maker(portdb) + portage.cache.util.mirror_cache(source, cm, portdb.auxdb[myportdir], + eclass_cache=ec, verbose_instance=noise_maker) + + sys.stdout.flush() + os.umask(old_umask) + +def action_regen(settings, portdb): + xterm_titles = "notitles" not in settings.features + emergelog(xterm_titles, " === regen") + #regenerate cache entries + print "Regenerating cache entries... " + try: + os.close(sys.stdin.fileno()) + except SystemExit, e: + raise # Needed else can't exit + except: + pass + sys.stdout.flush() + mynodes = portdb.cp_all() + from portage.cache.cache_errors import CacheError + dead_nodes = {} + for mytree in portdb.porttrees: + try: + dead_nodes[mytree] = set(portdb.auxdb[mytree].iterkeys()) + except CacheError, e: + print "\n error listing cache entries for " + \ + "'%s': %s, continuing..." % (mytree, e) + del e + dead_nodes = None + break + for x in mynodes: + mymatches = portdb.cp_list(x) + portage.writemsg_stdout("processing %s\n" % x) + for y in mymatches: + try: + foo = portdb.aux_get(y,["DEPEND"]) + except SystemExit, e: + # sys.exit is an exception... And consequently, we can't catch it. + raise + except Exception, e: + print "\n error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)} + if dead_nodes: + for mytree in portdb.porttrees: + if portdb.findname2(y, mytree=mytree)[0]: + dead_nodes[mytree].discard(y) + if dead_nodes: + for mytree, nodes in dead_nodes.iteritems(): + auxdb = portdb.auxdb[mytree] + for y in nodes: + try: + del auxdb[y] + except (KeyError, CacheError): + pass + print "done!" + +def action_config(settings, trees, myopts, myfiles): + if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles: + print red("!!! config can only take a single package atom at this time\n") + sys.exit(1) + if not is_valid_package_atom(myfiles[0]): + portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0], + noiselevel=-1) + portage.writemsg("!!! Please check ebuild(5) for full details.\n") + portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") + sys.exit(1) + print + try: + pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0]) + except ValueError, e: + # Multiple matches thrown from cpv_expand + pkgs = e.args[0] + if len(pkgs) == 0: + print "No packages found.\n" + sys.exit(0) + elif len(pkgs) > 1: + if "--ask" in myopts: + options = [] + print "Please select a package to configure:" + idx = 0 + for pkg in pkgs: + idx += 1 + options.append(str(idx)) + print options[-1]+") "+pkg + print "X) Cancel" + options.append("X") + idx = userquery("Selection?", options) + if idx == "X": + sys.exit(0) + pkg = pkgs[int(idx)-1] + else: + print "The following packages available:" + for pkg in pkgs: + print "* "+pkg + print "\nPlease use a specific atom or the --ask option." + sys.exit(1) + else: + pkg = pkgs[0] + + print + if "--ask" in myopts: + if userquery("Ready to configure "+pkg+"?") == "No": + sys.exit(0) + else: + print "Configuring pkg..." + print + ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg) + mysettings = portage.config(clone=settings) + portage.doebuild(ebuildpath, "config", settings["ROOT"], mysettings, + debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True, + mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree") + print + +def action_info(settings, trees, myopts, myfiles): + unameout=commands.getstatusoutput("uname -mrp")[1] + print getportageversion(settings["PORTDIR"], settings["ROOT"], + settings.profile_path, settings["CHOST"], + trees[settings["ROOT"]]["vartree"].dbapi) + header_width = 65 + header_title = "System Settings" + if myfiles: + print header_width * "=" + print header_title.rjust(int(header_width/2 + len(header_title)/2)) + print header_width * "=" + print "System uname: "+unameout + + lastSync = portage.grabfile(os.path.join( + settings["PORTDIR"], "metadata", "timestamp.chk")) + print "Timestamp of tree:", + if lastSync: + print lastSync[0] + else: + print "Unknown" + + output=commands.getstatusoutput("distcc --version") + if not output[0]: + print str(output[1].split("\n",1)[0]), + if "distcc" in settings.features: + print "[enabled]" + else: + print "[disabled]" + + output=commands.getstatusoutput("ccache -V") + if not output[0]: + print str(output[1].split("\n",1)[0]), + if "ccache" in settings.features: + print "[enabled]" + else: + print "[disabled]" + + myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers", + "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] + myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs") + myvars = portage.util.unique_array(myvars) + myvars.sort() + + for x in myvars: + if portage.isvalidatom(x): + pkg_matches = trees["/"]["vartree"].dbapi.match(x) + pkg_matches = [portage.catpkgsplit(cpv)[1:] for cpv in pkg_matches] + pkg_matches.sort(portage.pkgcmp) + pkgs = [] + for pn, ver, rev in pkg_matches: + if rev != "r0": + pkgs.append(ver + "-" + rev) + else: + pkgs.append(ver) + if pkgs: + pkgs = ", ".join(pkgs) + print "%-20s %s" % (x+":", pkgs) + else: + print "%-20s %s" % (x+":", "[NOT VALID]") + + libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool")) + + if "--verbose" in myopts: + myvars=settings.keys() + else: + myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK', + 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR', + 'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS', + 'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS'] + + myvars.extend(portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_vars")) + + myvars = portage.util.unique_array(myvars) + unset_vars = [] + myvars.sort() + for x in myvars: + if x in settings: + if x != "USE": + print '%s="%s"' % (x, settings[x]) + else: + use = set(settings["USE"].split()) + use_expand = settings["USE_EXPAND"].split() + use_expand.sort() + for varname in use_expand: + flag_prefix = varname.lower() + "_" + for f in list(use): + if f.startswith(flag_prefix): + use.remove(f) + use = list(use) + use.sort() + print 'USE="%s"' % " ".join(use), + for varname in use_expand: + myval = settings.get(varname) + if myval: + print '%s="%s"' % (varname, myval), + print + else: + unset_vars.append(x) + if unset_vars: + print "Unset: "+", ".join(unset_vars) + print + + if "--debug" in myopts: + for x in dir(portage): + module = getattr(portage, x) + if "cvs_id_string" in dir(module): + print "%s: %s" % (str(x), str(module.cvs_id_string)) + + # See if we can find any packages installed matching the strings + # passed on the command line + mypkgs = [] + vardb = trees[settings["ROOT"]]["vartree"].dbapi + portdb = trees[settings["ROOT"]]["porttree"].dbapi + for x in myfiles: + mypkgs.extend(vardb.match(x)) + + # If some packages were found... + if mypkgs: + # Get our global settings (we only print stuff if it varies from + # the current config) + mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS' ] + auxkeys = mydesiredvars + [ "USE", "IUSE"] + global_vals = {} + pkgsettings = portage.config(clone=settings) + + for myvar in mydesiredvars: + global_vals[myvar] = set(settings.get(myvar, "").split()) + + # Loop through each package + # Only print settings if they differ from global settings + header_title = "Package Settings" + print header_width * "=" + print header_title.rjust(int(header_width/2 + len(header_title)/2)) + print header_width * "=" + from portage.output import EOutput + out = EOutput() + for pkg in mypkgs: + # Get all package specific variables + auxvalues = vardb.aux_get(pkg, auxkeys) + valuesmap = {} + for i in xrange(len(auxkeys)): + valuesmap[auxkeys[i]] = set(auxvalues[i].split()) + diff_values = {} + for myvar in mydesiredvars: + # If the package variable doesn't match the + # current global variable, something has changed + # so set diff_found so we know to print + if valuesmap[myvar] != global_vals[myvar]: + diff_values[myvar] = valuesmap[myvar] + valuesmap["IUSE"] = set(filter_iuse_defaults(valuesmap["IUSE"])) + valuesmap["USE"] = valuesmap["USE"].intersection(valuesmap["IUSE"]) + pkgsettings.reset() + # If a matching ebuild is no longer available in the tree, maybe it + # would make sense to compare against the flags for the best + # available version with the same slot? + mydb = None + if portdb.cpv_exists(pkg): + mydb = portdb + pkgsettings.setcpv(pkg, mydb=mydb) + if valuesmap["IUSE"].intersection(pkgsettings["USE"].split()) != \ + valuesmap["USE"]: + diff_values["USE"] = valuesmap["USE"] + # If a difference was found, print the info for + # this package. + if diff_values: + # Print package info + print "%s was built with the following:" % pkg + for myvar in mydesiredvars + ["USE"]: + if myvar in diff_values: + mylist = list(diff_values[myvar]) + mylist.sort() + print "%s=\"%s\"" % (myvar, " ".join(mylist)) + print + print ">>> Attempting to run pkg_info() for '%s'" % pkg + ebuildpath = vardb.findname(pkg) + if not ebuildpath or not os.path.exists(ebuildpath): + out.ewarn("No ebuild found for '%s'" % pkg) + continue + portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"], + pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), + mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, + tree="vartree") + +def action_search(settings, portdb, vartree, myopts, myfiles, spinner, setconfig): + if not myfiles: + print "emerge: no search terms provided." + else: + searchinstance = search(settings, portdb, + vartree, spinner, "--searchdesc" in myopts, + "--quiet" not in myopts, setconfig) + 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() + +def action_depclean(settings, trees, ldpath_mtimes, + myopts, action, myfiles, spinner): + # Kill packages that aren't explicitly merged or are required as a + # dependency of another package. World file is explicit. + + msg = [] + msg.append("Depclean may break link level dependencies. Thus, it is\n") + msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n") + msg.append("app-portage/gentoolkit) in order to detect such breakage.\n") + msg.append("\n") + msg.append("Also study the list of packages to be cleaned for any obvious\n") + msg.append("mistakes. Packages that are part of the world set will always\n") + msg.append("be kept. They can be manually added to this set with\n") + msg.append(good("`emerge --noreplace `") + ". Packages that are listed in\n") + msg.append("package.provided (see portage(5)) will be removed by\n") + msg.append("depclean, even if they are part of the world set.\n") + msg.append("\n") + msg.append("As a safety measure, depclean will not remove any packages\n") + msg.append("unless *all* required dependencies have been resolved. As a\n") + msg.append("consequence, it is often necessary to run\n") + msg.append(good("`emerge --update --newuse --deep world`") + " prior to depclean.\n") + + if action == "depclean" and "--quiet" not in myopts and not myfiles: + portage.writemsg_stdout("\n") + for x in msg: + portage.writemsg_stdout(colorize("BAD", "*** WARNING *** ") + x) + + xterm_titles = "notitles" not in settings.features + myroot = settings["ROOT"] + portdb = trees[myroot]["porttree"].dbapi + dep_check_trees = {} + dep_check_trees[myroot] = {} + dep_check_trees[myroot]["vartree"] = \ + FakeVartree(trees[myroot]["vartree"], + trees[myroot]["porttree"].dbapi, + depgraph._mydbapi_keys) + vardb = dep_check_trees[myroot]["vartree"].dbapi + # Constrain dependency selection to the installed packages. + dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"] + system_set = SystemSet(settings.profiles) + syslist = list(system_set) + world_set = WorldSet(myroot) + worldlist = list(world_set) + args_set = InternalPackageSet() + fakedb = portage.fakedbapi(settings=settings) + myvarlist = vardb.cpv_all() + + if not syslist: + print "\n!!! You have no system list.", + if not worldlist: + print "\n!!! You have no world file.", + if not myvarlist: + print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH, + + if not (syslist and worldlist and myvarlist): + print "\n!!! Proceeding "+(syslist and myvarlist and "may" or "will") + print " break your installation.\n" + if "--pretend" not in myopts: + countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean") + + if action == "depclean": + emergelog(xterm_titles, " >>> depclean") + if myfiles: + for x in myfiles: + if not is_valid_package_atom(x): + portage.writemsg("!!! '%s' is not a valid package atom.\n" % x, + noiselevel=-1) + portage.writemsg("!!! Please check ebuild(5) for full details.\n") + return + try: + atom = portage.dep_expand(x, mydb=vardb, settings=settings) + except ValueError, e: + print "!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" + print "!!! one of the following fully-qualified ebuild names instead:\n" + for i in e[0]: + print " " + colorize("INFORM", i) + print + return + args_set.add(atom) + matched_packages = False + for x in args_set: + if vardb.match(x): + matched_packages = True + break + if not matched_packages: + portage.writemsg_stdout( + ">>> No packages selected for removal by %s\n" % action) + return + + if "--quiet" not in myopts: + print "\nCalculating dependencies ", + + soft = 0 + hard = 1 + remaining_atoms = [] + if action == "depclean": + for atom in worldlist: + if vardb.match(atom): + remaining_atoms.append((atom, 'world', hard)) + for atom in syslist: + if vardb.match(atom): + remaining_atoms.append((atom, 'system', hard)) + elif action == "prune": + for atom in syslist: + if vardb.match(atom): + remaining_atoms.append((atom, 'system', hard)) + # Pull in everything that's installed since we don't want to prune a + # package if something depends on it. + remaining_atoms.extend((atom, 'world', hard) for atom in vardb.cp_all()) + if not myfiles: + # Try to prune everything that's slotted. + for cp in vardb.cp_all(): + if len(vardb.cp_list(cp)) > 1: + args_set.add(cp) + + unresolveable = {} + aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"] + metadata_keys = ["PROVIDE", "SLOT", "USE"] + graph = digraph() + + while remaining_atoms: + atom, parent, priority = remaining_atoms.pop() + pkgs = vardb.match(atom) + if not pkgs: + if not atom.startswith("!") and priority == hard: + unresolveable.setdefault(atom, []).append(parent) + continue + if action == "depclean" and parent == "world" and myfiles: + # Filter out packages given as arguments since the user wants + # to remove those. + filtered_pkgs = [] + for pkg in pkgs: + metadata = dict(izip(metadata_keys, + vardb.aux_get(pkg, metadata_keys))) + arg_atom = None + try: + arg_atom = args_set.findAtomForPackage(pkg, metadata) + except portage.exception.InvalidDependString, e: + file_path = os.path.join(myroot, VDB_PATH, pkg, "PROVIDE") + portage.writemsg("\n\nInvalid PROVIDE: %s\n" % str(s), + noiselevel=-1) + portage.writemsg("See '%s'\n" % file_path, + noiselevel=-1) + del e + if not arg_atom: + filtered_pkgs.append(pkg) + pkgs = filtered_pkgs + prune_this = False + if action == "prune": + for pkg in pkgs: + metadata = dict(izip(metadata_keys, + vardb.aux_get(pkg, metadata_keys))) + try: + arg_atom = args_set.findAtomForPackage(pkg, metadata) + except portage.exception.InvalidDependString, e: + file_path = os.path.join(myroot, VDB_PATH, pkg, "PROVIDE") + portage.writemsg("\n\nInvalid PROVIDE: %s\n" % str(s), + noiselevel=-1) + portage.writemsg("See '%s'\n" % file_path, + noiselevel=-1) + del e + continue + if arg_atom: + prune_this = True + break + if len(pkgs) > 1 and (parent != "world" or prune_this): + # Prune all but the best matching slot, since that's all that a + # deep world update would pull in. Don't prune if this atom comes + # directly from world though, since world atoms are greedy when + # they don't specify a slot. + visible_in_portdb = [cpv for cpv in pkgs if portdb.match("="+cpv)] + if visible_in_portdb: + # For consistency with the update algorithm, keep the highest + # visible version and prune any versions that are either masked + # or no longer exist in the portage tree. + pkgs = visible_in_portdb + pkgs = [portage.best(pkgs)] + for pkg in pkgs: + graph.add(pkg, parent) + if fakedb.cpv_exists(pkg): + continue + spinner.update() + fakedb.cpv_inject(pkg) + myaux = dict(izip(aux_keys, vardb.aux_get(pkg, aux_keys))) + mydeps = [] + if myopts.get("--with-bdeps", "y") == "y": + mydeps.append((myaux["DEPEND"], soft)) + del myaux["DEPEND"] + mydeps.append((" ".join(myaux.values()), hard)) + usedef = vardb.aux_get(pkg, ["USE"])[0].split() + for depstr, priority in mydeps: + + if not depstr: + continue + + if "--debug" in myopts: + print + print "Parent: ", pkg + print "Depstring:", depstr + print "Priority:", + if priority == soft: + print "soft" + else: + print "hard" + + try: + portage.dep._dep_check_strict = False + success, atoms = portage.dep_check(depstr, None, settings, + myuse=usedef, trees=dep_check_trees, myroot=myroot) + finally: + portage.dep._dep_check_strict = True + if not success: + show_invalid_depstring_notice( + ("installed", myroot, pkg, "nomerge"), + depstr, atoms) + return + + if "--debug" in myopts: + print "Candidates:", atoms + + for atom in atoms: + remaining_atoms.append((atom, pkg, priority)) + + if "--quiet" not in myopts: + print "\b\b... done!\n" + + if unresolveable: + print "Dependencies could not be completely resolved due to" + print "the following required packages not being installed:" + print + for atom in unresolveable: + print atom, "required by", " ".join(unresolveable[atom]) + if unresolveable: + print + print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to" + print "%s? It may be necessary to manually uninstall packages that no longer" % action + print "exist in the portage tree since it may not be possible to satisfy their" + print "dependencies. Also, be aware of the --with-bdeps option that is documented" + print "in " + good("`man emerge`") + "." + print + if action == "prune": + print "If you would like to ignore dependencies then use %s." % \ + good("--nodeps") + return + + def show_parents(child_node): + parent_nodes = graph.parent_nodes(child_node) + if not parent_nodes: + # With --prune, the highest version can be pulled in without any + # real parent since all installed packages are pulled in. In that + # case there's nothing to show here. + return + parent_nodes.sort() + msg = [] + msg.append(" %s pulled in by:\n" % str(child_node)) + for parent_node in parent_nodes: + msg.append(" %s\n" % str(parent_node)) + msg.append("\n") + portage.writemsg_stdout("".join(msg), noiselevel=-1) + + cleanlist = [] + if action == "depclean": + if myfiles: + for pkg in vardb.cpv_all(): + metadata = dict(izip(metadata_keys, + vardb.aux_get(pkg, metadata_keys))) + arg_atom = None + try: + arg_atom = args_set.findAtomForPackage(pkg, metadata) + except portage.exception.InvalidDependString: + # this error has already been displayed by now + continue + if arg_atom: + if not fakedb.cpv_exists(pkg): + cleanlist.append(pkg) + elif "--verbose" in myopts: + show_parents(pkg) + else: + for pkg in vardb.cpv_all(): + if not fakedb.cpv_exists(pkg): + cleanlist.append(pkg) + elif "--verbose" in myopts: + show_parents(pkg) + elif action == "prune": + # Prune really uses all installed instead of world. It's not a real + # reverse dependency so don't display it as such. + if graph.contains("world"): + graph.remove("world") + for atom in args_set: + for pkg in vardb.match(atom): + if not fakedb.cpv_exists(pkg): + cleanlist.append(pkg) + elif "--verbose" in myopts: + show_parents(pkg) + + if not cleanlist: + portage.writemsg_stdout( + ">>> No packages selected for removal by %s\n" % action) + if "--verbose" not in myopts: + portage.writemsg_stdout( + ">>> To see reverse dependencies, use %s\n" % \ + good("--verbose")) + if action == "prune": + portage.writemsg_stdout( + ">>> To ignore dependencies, use %s\n" % \ + good("--nodeps")) + + if len(cleanlist): + unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"], + "unmerge", cleanlist, ldpath_mtimes) + + if action == "prune": + return + + if not cleanlist and "--quiet" in myopts: + return + + 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(myvarlist)) + print "Required packages: "+str(len(fakedb.cpv_all())) + if "--pretend" in myopts: + print "Number to remove: "+str(len(cleanlist)) + else: + print "Number removed: "+str(len(cleanlist)) + +def action_build(settings, trees, mtimedb, + myopts, myaction, myfiles, spinner): + ldpath_mtimes = mtimedb["ldpath"] + favorites=[] + merge_count = 0 + pretend = "--pretend" in myopts + fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts + if pretend or fetchonly: + # make the mtimedb readonly + mtimedb.filename = None + if "--quiet" not in myopts and \ + ("--pretend" in myopts or "--ask" in myopts or \ + "--tree" in myopts or "--verbose" in myopts): + action = "" + if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + action = "fetched" + elif "--buildpkgonly" in myopts: + action = "built" + else: + action = "merged" + if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching + print + print darkgreen("These are the packages that would be %s, in reverse order:") % action + print + else: + print + print darkgreen("These are the packages that would be %s, in order:") % action + print + + # validate the state of the resume data + # so that we can make assumptions later. + for k in ("resume", "resume_backup"): + if k in mtimedb: + if "mergelist" in mtimedb[k]: + if not mtimedb[k]["mergelist"]: + del mtimedb[k] + else: + del mtimedb[k] + + if "--resume" in myopts and \ + ("resume" in mtimedb or + "resume_backup" in mtimedb): + if "resume" not in mtimedb: + mtimedb["resume"] = mtimedb["resume_backup"] + del mtimedb["resume_backup"] + mtimedb.commit() + + # Adjust config according to options of the command being resumed. + for myroot in trees: + mysettings = trees[myroot]["vartree"].settings + mysettings.unlock() + adjust_config(myopts, mysettings) + mysettings.lock() + del myroot, mysettings + + # "myopts" is a list for backward compatibility. + resume_opts = mtimedb["resume"].get("myopts", []) + if isinstance(resume_opts, list): + resume_opts = dict((k,True) for k in resume_opts) + for opt in ("--skipfirst", "--ask", "--tree"): + resume_opts.pop(opt, None) + myopts.update(resume_opts) + show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts + if not show_spinner: + spinner.update = spinner.update_quiet + if show_spinner: + print "Calculating dependencies ", + myparams = create_depgraph_params(myopts, myaction) + mydepgraph = depgraph(settings, trees, + myopts, myparams, spinner) + try: + mydepgraph.loadResumeCommand(mtimedb["resume"]) + except portage.exception.PackageNotFound: + if show_spinner: + print + from portage.output import EOutput + out = EOutput() + out.eerror("Error: The resume list contains packages that are no longer") + out.eerror(" available to be emerged. Please restart/continue") + out.eerror(" the merge operation manually.") + return 1 + if show_spinner: + print "\b\b... done!" + else: + if ("--resume" in myopts): + print darkgreen("emerge: It seems we have nothing to resume...") + return os.EX_OK + + myparams = create_depgraph_params(myopts, myaction) + if myaction in ["system","world"]: + if "--quiet" not in myopts and "--nodeps" not in myopts: + print "Calculating",myaction,"dependencies ", + sys.stdout.flush() + mydepgraph = depgraph(settings, trees, myopts, myparams, spinner) + if not mydepgraph.xcreate(myaction): + print "!!! Depgraph creation failed." + return 1 + if "--quiet" not in myopts and "--nodeps" not in myopts: + print "\b\b... done!" + else: + if "--quiet" not in myopts and "--nodeps" not in myopts: + print "Calculating dependencies ", + sys.stdout.flush() + mydepgraph = depgraph(settings, trees, myopts, myparams, spinner) + try: + retval, favorites = mydepgraph.select_files(myfiles) + except portage.exception.PackageNotFound, e: + portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1) + return 1 + if not retval: + return 1 + if "--quiet" not in myopts and "--nodeps" not in myopts: + print "\b\b... done!" + + if ("--usepkgonly" in myopts) and mydepgraph.missingbins: + sys.stderr.write(red("The following binaries are not available for merging...\n")) + + if mydepgraph.missingbins: + for x in mydepgraph.missingbins: + sys.stderr.write(" "+str(x)+"\n") + sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") + return 1 + + if "--pretend" not in myopts and \ + ("--ask" in myopts or "--tree" in myopts or \ + "--verbose" in myopts) and \ + not ("--quiet" in myopts and "--ask" not in myopts): + if "--resume" in myopts: + mymergelist = mtimedb["resume"]["mergelist"] + if "--skipfirst" in myopts: + mymergelist = mymergelist[1:] + if len(mymergelist) == 0: + print colorize("INFORM", "emerge: It seems we have nothing to resume...") + return os.EX_OK + favorites = mtimedb["resume"]["favorites"] + retval = mydepgraph.display(mymergelist, favorites=favorites) + if retval != os.EX_OK: + return retval + prompt="Would you like to resume merging these packages?" + else: + retval = mydepgraph.display( + mydepgraph.altlist(reversed=("--tree" in myopts)), + favorites=favorites) + if retval != os.EX_OK: + return retval + mergecount=0 + for x in mydepgraph.altlist(): + if x[0] != "blocks" and x[3] != "nomerge": + mergecount+=1 + #check for blocking dependencies + if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts: + print "\n!!! Error: The above package list contains packages which cannot be installed" + print "!!! at the same time on the same system." + if "--quiet" not in myopts: + show_blocker_docs_link() + return 1 + if mergecount==0: + if "--noreplace" in myopts and favorites: + print + for x in favorites: + print " %s %s" % (good("*"), x) + prompt="Would you like to add these packages to your world favorites?" + elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]: + prompt="Nothing to merge; would you like to auto-clean packages?" + else: + print + print "Nothing to merge; quitting." + print + return os.EX_OK + elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + prompt="Would you like to fetch the source files for these packages?" + else: + prompt="Would you like to merge these packages?" + print + if "--ask" in myopts and userquery(prompt) == "No": + print + print "Quitting." + print + return os.EX_OK + # Don't ask again (e.g. when auto-cleaning packages after merge) + myopts.pop("--ask", None) + + if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + if ("--resume" in myopts): + mymergelist = mtimedb["resume"]["mergelist"] + if "--skipfirst" in myopts: + mymergelist = mymergelist[1:] + if len(mymergelist) == 0: + print colorize("INFORM", "emerge: It seems we have nothing to resume...") + return os.EX_OK + favorites = mtimedb["resume"]["favorites"] + retval = mydepgraph.display(mymergelist, favorites=favorites) + if retval != os.EX_OK: + return retval + else: + retval = mydepgraph.display( + mydepgraph.altlist(reversed=("--tree" in myopts)), + favorites=favorites) + if retval != os.EX_OK: + return retval + if "--buildpkgonly" in myopts and \ + not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM): + print "\n!!! --buildpkgonly requires all dependencies to be merged." + print "!!! You have to merge the dependencies before you can build this package.\n" + return 1 + else: + if ("--buildpkgonly" in myopts): + if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM): + print "\n!!! --buildpkgonly requires all dependencies to be merged." + print "!!! Cannot merge requested packages. Merge deps and try again.\n" + return 1 + + if ("--resume" in myopts): + favorites=mtimedb["resume"]["favorites"] + mergetask = MergeTask(settings, trees, myopts) + if "--fetchonly" in myopts: + """ parallel-fetch uses --resume --fetchonly and we don't want + it to write the mtimedb""" + mtimedb.filename = None + time.sleep(3) # allow the parent to have first fetch + del mydepgraph + retval = mergetask.merge( + mtimedb["resume"]["mergelist"], favorites, mtimedb) + merge_count = mergetask.curval + else: + if "resume" in mtimedb and \ + "mergelist" in mtimedb["resume"] and \ + len(mtimedb["resume"]["mergelist"]) > 1: + mtimedb["resume_backup"] = mtimedb["resume"] + del mtimedb["resume"] + mtimedb.commit() + mtimedb["resume"]={} + # XXX: Stored as a list for backward compatibility. + mtimedb["resume"]["myopts"] = \ + [k for k in myopts if myopts[k] is True] + mtimedb["resume"]["favorites"]=favorites + if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): + for pkgline in mydepgraph.altlist(): + if pkgline[0]=="ebuild" and pkgline[3]=="merge": + y = trees[pkgline[1]]["porttree"].dbapi.findname(pkgline[2]) + tmpsettings = portage.config(clone=settings) + edebug = 0 + if settings.get("PORTAGE_DEBUG", "") == "1": + edebug = 1 + retval = portage.doebuild( + y, "digest", settings["ROOT"], tmpsettings, edebug, + ("--pretend" in myopts), + mydbapi=trees[pkgline[1]]["porttree"].dbapi, + tree="porttree") + if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: + pkglist = [] + for pkg in mydepgraph.altlist(): + if pkg[0] != "blocks": + pkglist.append(pkg) + else: + pkglist = mydepgraph.altlist() + if favorites: + mydepgraph.saveNomergeFavorites() + del mydepgraph + mergetask = MergeTask(settings, trees, myopts) + retval = mergetask.merge(pkglist, favorites, mtimedb) + merge_count = mergetask.curval + + if retval == os.EX_OK and not (pretend or fetchonly): + mtimedb.pop("resume", None) + if "yes" == settings.get("AUTOCLEAN"): + portage.writemsg_stdout(">>> Auto-cleaning packages...\n") + vartree = trees[settings["ROOT"]]["vartree"] + unmerge(settings, myopts, vartree, "clean", ["world"], + ldpath_mtimes, autoclean=1) + else: + portage.writemsg_stdout(colorize("WARN", "WARNING:") + + " AUTOCLEAN is disabled. This can cause serious" + + " problems due to overlapping packages.\n") + + if merge_count and not (pretend or fetchonly): + post_emerge(trees, mtimedb, retval) + return retval + +def multiple_actions(action1, action2): + sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n") + sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2)) + sys.exit(1) + +def parse_opts(tmpcmdline, silent=False): + myaction=None + myopts = {} + myfiles=[] + + global actions, options, shortmapping + + longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} + argument_options = { + "--config-root": { + "help":"specify the location for portage configuration files", + "action":"store" + }, + "--color": { + "help":"enable or disable color output", + "type":"choice", + "choices":("y", "n") + }, + "--with-bdeps": { + "help":"include unnecessary build time dependencies", + "type":"choice", + "choices":("y", "n") + }, + "--reinstall": { + "help":"specify conditions to trigger package reinstallation", + "type":"choice", + "choices":["changed-use"] + } + } + + from optparse import OptionParser + parser = OptionParser() + if parser.has_option("--help"): + parser.remove_option("--help") + + for action_opt in actions: + parser.add_option("--" + action_opt, action="store_true", + dest=action_opt.replace("-", "_"), default=False) + for myopt in options: + parser.add_option(myopt, action="store_true", + dest=myopt.lstrip("--").replace("-", "_"), default=False) + for shortopt, longopt in shortmapping.iteritems(): + parser.add_option("-" + shortopt, action="store_true", + dest=longopt.lstrip("--").replace("-", "_"), default=False) + for myalias, myopt in longopt_aliases.iteritems(): + parser.add_option(myalias, action="store_true", + dest=myopt.lstrip("--").replace("-", "_"), default=False) + + for myopt, kwargs in argument_options.iteritems(): + parser.add_option(myopt, + dest=myopt.lstrip("--").replace("-", "_"), **kwargs) + + myoptions, myargs = parser.parse_args(args=tmpcmdline) + + for myopt in options: + v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) + if v: + myopts[myopt] = True + + for myopt in argument_options: + v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) + if v is not None: + myopts[myopt] = v + + for action_opt in actions: + v = getattr(myoptions, action_opt.replace("-", "_")) + if v: + if myaction: + multiple_actions(myaction, action_opt) + sys.exit(1) + myaction = action_opt + + for x in myargs: + if x in actions and myaction != "search": + if not silent and x not in ["system", "world"]: + print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x)) + # special case "search" so people can search for action terms, e.g. emerge -s sync + if myaction: + multiple_actions(myaction, x) + sys.exit(1) + myaction = x + else: + myfiles.append(x) + + if "--nocolor" in myopts: + if not silent: + sys.stderr.write("*** Deprecated use of '--nocolor', " + \ + "use '--color=n' instead.\n") + del myopts["--nocolor"] + myopts["--color"] = "n" + + return myaction, myopts, myfiles + +def validate_ebuild_environment(trees): + for myroot in trees: + mysettings = trees[myroot]["vartree"].settings + for var in "ARCH", "USERLAND": + if mysettings.get(var): + continue + print >> sys.stderr, bad(("\a!!! %s is not set... " % var) + \ + "Are you missing the '%setc/make.profile' symlink?" % \ + mysettings["PORTAGE_CONFIGROOT"]) + print >> sys.stderr, bad("\a!!! Is the symlink correct? " + \ + "Is your portage tree complete?\n") + sys.exit(9) + del myroot, mysettings + +def load_emerge_config(trees=None): + kwargs = {} + for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): + kwargs[k] = os.environ.get(envvar, None) + trees = portage.create_trees(trees=trees, **kwargs) + + settings = trees["/"]["vartree"].settings + + for myroot in trees: + if myroot != "/": + settings = trees[myroot]["vartree"].settings + break + + mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb") + mtimedb = portage.MtimeDB(mtimedbfile) + return settings, trees, mtimedb + +def adjust_config(myopts, settings): + """Make emerge specific adjustments to the config.""" + + # To enhance usability, make some vars case insensitive by forcing them to + # lower case. + for myvar in ("AUTOCLEAN", "NOCOLOR"): + if myvar in settings: + settings[myvar] = settings[myvar].lower() + settings.backup_changes(myvar) + del myvar + + # Kill noauto as it will break merges otherwise. + if "noauto" in settings.features: + while "noauto" in settings.features: + settings.features.remove("noauto") + settings["FEATURES"] = " ".join(settings.features) + settings.backup_changes("FEATURES") + + CLEAN_DELAY = 5 + try: + CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY))) + except ValueError, e: + portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) + portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \ + settings["CLEAN_DELAY"], noiselevel=-1) + settings["CLEAN_DELAY"] = str(CLEAN_DELAY) + settings.backup_changes("CLEAN_DELAY") + + EMERGE_WARNING_DELAY = 10 + try: + EMERGE_WARNING_DELAY = int(settings.get( + "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY))) + except ValueError, e: + portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) + portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \ + settings["EMERGE_WARNING_DELAY"], noiselevel=-1) + settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY) + settings.backup_changes("EMERGE_WARNING_DELAY") + + if "--quiet" in myopts: + settings["PORTAGE_QUIET"]="1" + settings.backup_changes("PORTAGE_QUIET") + + # Set so that configs will be merged regardless of remembered status + if ("--noconfmem" in myopts): + settings["NOCONFMEM"]="1" + settings.backup_changes("NOCONFMEM") + + # Set various debug markers... They should be merged somehow. + PORTAGE_DEBUG = 0 + try: + PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG))) + if PORTAGE_DEBUG not in (0, 1): + portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \ + PORTAGE_DEBUG, noiselevel=-1) + portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n", + noiselevel=-1) + PORTAGE_DEBUG = 0 + except ValueError, e: + portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) + portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\ + settings["PORTAGE_DEBUG"], noiselevel=-1) + del e + if "--debug" in myopts: + PORTAGE_DEBUG = 1 + settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG) + settings.backup_changes("PORTAGE_DEBUG") + + if settings.get("NOCOLOR") not in ("yes","true"): + portage.output.havecolor = 1 + + """The explicit --color < y | n > option overrides the NOCOLOR environment + variable and stdout auto-detection.""" + if "--color" in myopts: + if "y" == myopts["--color"]: + portage.output.havecolor = 1 + settings["NOCOLOR"] = "false" + else: + portage.output.havecolor = 0 + settings["NOCOLOR"] = "true" + settings.backup_changes("NOCOLOR") + elif not sys.stdout.isatty() and settings.get("NOCOLOR") != "no": + portage.output.havecolor = 0 + settings["NOCOLOR"] = "true" + settings.backup_changes("NOCOLOR") + +def emerge_main(): + global portage # NFC why this is necessary now - genone + # Disable color until we're sure that it should be enabled (after + # EMERGE_DEFAULT_OPTS has been parsed). + portage.output.havecolor = 0 + # This first pass is just for options that need to be known as early as + # possible, such as --config-root. They will be parsed again later, + # together with EMERGE_DEFAULT_OPTS (which may vary depending on the + # the value of --config-root). + myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True) + if "--debug" in myopts: + os.environ["PORTAGE_DEBUG"] = "1" + if "--config-root" in myopts: + os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] + + # Portage needs to ensure a sane umask for the files it creates. + os.umask(022) + settings, trees, mtimedb = load_emerge_config() + portdb = trees[settings["ROOT"]]["porttree"].dbapi + + try: + os.nice(int(settings.get("PORTAGE_NICENESS", "0"))) + except (OSError, ValueError), e: + portage.writemsg("!!! Failed to change nice value to '%s'\n" % \ + settings["PORTAGE_NICENESS"]) + portage.writemsg("!!! %s\n" % str(e)) + del e + + if portage._global_updates(trees, mtimedb["updates"]): + mtimedb.commit() + # Reload the whole config from scratch. + settings, trees, mtimedb = load_emerge_config(trees=trees) + portdb = trees[settings["ROOT"]]["porttree"].dbapi + + xterm_titles = "notitles" not in settings.features + + tmpcmdline = [] + if "--ignore-default-opts" not in myopts: + tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) + tmpcmdline.extend(sys.argv[1:]) + myaction, myopts, myfiles = parse_opts(tmpcmdline) + + if "--digest" in myopts: + os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" + # Reload the whole config from scratch so that the portdbapi internal + # config is updated with new FEATURES. + settings, trees, mtimedb = load_emerge_config(trees=trees) + portdb = trees[settings["ROOT"]]["porttree"].dbapi + + for myroot in trees: + mysettings = trees[myroot]["vartree"].settings + mysettings.unlock() + adjust_config(myopts, mysettings) + mysettings.lock() + del myroot, mysettings + + spinner = stdout_spinner() + if "candy" in settings.features: + spinner.update = spinner.update_scroll + + if "--quiet" not in myopts: + portage.deprecated_profile_check() + + #Freeze the portdbapi for enhanced performance: + for myroot in trees: + trees[myroot]["porttree"].dbapi.freeze() + del myroot + + if "moo" in myfiles: + print """ + + Larry loves Gentoo (""" + os.uname()[0] + """) + + _______________________ +< Have you mooed today? > + ----------------------- + \ ^__^ + \ (oo)\_______ + (__)\ )\/\ + ||----w | + || || + +""" + + if (myaction in ["world", "system"]) and myfiles: + print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both." + sys.exit(1) + + for x in myfiles: + ext = os.path.splitext(x)[1] + if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): + print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n") + break + + setconfigpaths = [os.path.join(GLOBAL_CONFIG_PATH, "sets.conf")] + setconfigpaths.append(os.path.join(settings["PORTDIR"], "sets.conf")) + setconfigpaths += [os.path.join(x, "sets.conf") for x in settings["PORDIR_OVERLAY"].split()] + setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], + USER_CONFIG_PATH.lstrip(os.path.sep), "sets.conf")) + #setconfig = SetConfig(setconfigpaths, settings, trees[settings["ROOT"]]) + setconfig = make_default_config(settings, trees[settings["ROOT"]]) + del setconfigpaths + if myaction not in ["search", "metadata", "sync"]: + oldargs = myfiles[:] + packagesets, setconfig_errors = setconfig.getSetsWithAliases() + for s in packagesets: + if s in myfiles: + # TODO: check if the current setname also resolves to a package name + if myaction in ["unmerge", "prune", "clean", "depclean"] and not packagesets[s].supportsOperation("unmerge"): + print "emerge: the given set %s does not support unmerge operations" % s + sys.exit(1) + if not packagesets[s].getAtoms(): + print "emerge: '%s' is an empty set" % s + else: + myfiles.extend(packagesets[s].getAtoms()) + for e in packagesets[s].errors: + print e + myfiles.remove(s) + # Need to handle empty sets specially, otherwise emerge will react + # with the help message for empty argument lists + if oldargs and not myfiles: + print "emerge: no targets left after set expansion" + sys.exit(0) + del oldargs + + if ("--tree" in myopts) and ("--columns" in myopts): + print "emerge: can't specify both of \"--tree\" and \"--columns\"." + sys.exit(1) + + if ("--quiet" in myopts): + spinner.update = spinner.update_quiet + portage.util.noiselimit = -1 + + # Always create packages if FEATURES=buildpkg + # Imply --buildpkg if --buildpkgonly + if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts): + if "--buildpkg" not in myopts: + myopts["--buildpkg"] = True + + # Also allow -S to invoke search action (-sS) + if ("--searchdesc" in myopts): + if myaction and myaction != "search": + myfiles.append(myaction) + if "--search" not in myopts: + myopts["--search"] = True + myaction = "search" + + # Always try and fetch binary packages if FEATURES=getbinpkg + if ("getbinpkg" in settings.features): + myopts["--getbinpkg"] = True + + if "--skipfirst" in myopts and "--resume" not in myopts: + myopts["--resume"] = True + + if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): + myopts["--usepkgonly"] = True + + if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): + myopts["--getbinpkg"] = True + + if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): + myopts["--usepkg"] = True + + # Also allow -K to apply --usepkg/-k + if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): + myopts["--usepkg"] = True + + # Allow -p to remove --ask + if ("--pretend" in myopts) and ("--ask" in myopts): + print ">>> --pretend disables --ask... removing --ask from options." + del myopts["--ask"] + + # forbid --ask when not in a terminal + # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. + if ("--ask" in myopts) and (not sys.stdin.isatty()): + portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", + noiselevel=-1) + sys.exit(1) + + if settings.get("PORTAGE_DEBUG", "") == "1": + spinner.update = spinner.update_quiet + portage.debug=1 + if "python-trace" in settings.features: + import portage.debug + portage.debug.set_trace(True) + + if ("--resume" in myopts): + if "--tree" in myopts: + print "* --tree is currently broken with --resume. Disabling..." + del myopts["--tree"] + + if not ("--quiet" in myopts): + if not sys.stdout.isatty() or ("--nospinner" in myopts): + spinner.update = spinner.update_basic + + if "--version" in myopts: + print getportageversion(settings["PORTDIR"], settings["ROOT"], + settings.profile_path, settings["CHOST"], + trees[settings["ROOT"]]["vartree"].dbapi) + sys.exit(0) + elif "--help" in myopts: + _emerge.help.help(myaction, myopts, portage.output.havecolor) + sys.exit(0) + + if "--debug" in myopts: + print "myaction", myaction + print "myopts", myopts + + if not myaction and not myfiles and "--resume" not in myopts: + _emerge.help.help(myaction, myopts, portage.output.havecolor) + sys.exit(1) + + # check if root user is the current user for the actions where emerge needs this + if portage.secpass < 2: + # We've already allowed "--version" and "--help" above. + if "--pretend" not in myopts and myaction not in ("search","info"): + need_superuser = not \ + ("--fetchonly" in myopts or \ + "--fetch-all-uri" in myopts or \ + myaction in ("metadata", "regen") or \ + (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK))) + if portage.secpass < 1 or \ + need_superuser: + if need_superuser: + access_desc = "superuser" + else: + access_desc = "portage group" + # Always show portage_group_warning() when only portage group + # access is required but the user is not in the portage group. + from portage.data import portage_group_warning + if "--ask" in myopts: + myopts["--pretend"] = True + del myopts["--ask"] + print ("%s access is required... " + \ + "adding --pretend to options.\n") % access_desc + if portage.secpass < 1 and not need_superuser: + portage_group_warning() + else: + sys.stderr.write(("emerge: %s access is " + \ + "required.\n\n") % access_desc) + if portage.secpass < 1 and not need_superuser: + portage_group_warning() + return 1 + + disable_emergelog = False + for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): + if x in myopts: + disable_emergelog = True + break + if myaction in ("search", "info"): + disable_emergelog = True + if disable_emergelog: + """ Disable emergelog for everything except build or unmerge + operations. This helps minimize parallel emerge.log entries that can + confuse log parsers. We especially want it disabled during + parallel-fetch, which uses --resume --fetchonly.""" + global emergelog + def emergelog(*pargs, **kargs): + pass + + if not "--pretend" in myopts: + emergelog(xterm_titles, "Started emerge on: "+\ + time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) + myelogstr="" + if myopts: + myelogstr=" ".join(myopts) + if myaction: + myelogstr+=" "+myaction + if myfiles: + myelogstr+=" "+" ".join(myfiles) + emergelog(xterm_titles, " *** emerge " + myelogstr) + + def emergeexitsig(signum, frame): + signal.signal(signal.SIGINT, signal.SIG_IGN) + signal.signal(signal.SIGTERM, signal.SIG_IGN) + portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) + sys.exit(100+signum) + signal.signal(signal.SIGINT, emergeexitsig) + signal.signal(signal.SIGTERM, emergeexitsig) + + def emergeexit(): + """This gets out final log message in before we quit.""" + if "--pretend" not in myopts: + emergelog(xterm_titles, " *** terminating.") + if "notitles" not in settings.features: + xtermTitleReset() + portage.atexit_register(emergeexit) + + if myaction in ("config", "metadata", "regen", "sync"): + if "--pretend" in myopts: + sys.stderr.write(("emerge: The '%s' action does " + \ + "not support '--pretend'.\n") % myaction) + return 1 + if "sync" == myaction: + action_sync(settings, trees, mtimedb, myopts, myaction) + elif "metadata" == myaction: + action_metadata(settings, portdb, myopts) + elif myaction=="regen": + validate_ebuild_environment(trees) + action_regen(settings, portdb) + # HELP action + elif "config"==myaction: + validate_ebuild_environment(trees) + action_config(settings, trees, myopts, myfiles) + + # INFO action + elif "info"==myaction: + action_info(settings, trees, myopts, myfiles) + + # SEARCH action + elif "search"==myaction: + validate_ebuild_environment(trees) + action_search(settings, portdb, trees["/"]["vartree"], + myopts, myfiles, spinner, setconfig) + elif myaction in ("clean", "unmerge") or \ + (myaction == "prune" and "--nodeps" in myopts): + validate_ebuild_environment(trees) + vartree = trees[settings["ROOT"]]["vartree"] + if 1 == unmerge(settings, myopts, vartree, myaction, myfiles, + mtimedb["ldpath"]): + if "--pretend" not in myopts: + post_emerge(trees, mtimedb, os.EX_OK) + + elif myaction in ("depclean", "prune"): + validate_ebuild_environment(trees) + action_depclean(settings, trees, mtimedb["ldpath"], + myopts, myaction, myfiles, spinner) + if "--pretend" not in myopts: + post_emerge(trees, mtimedb, os.EX_OK) + # "update", "system", or just process files: + else: + validate_ebuild_environment(trees) + if "--pretend" not in myopts: + display_news_notification(trees) + retval = action_build(settings, trees, mtimedb, + myopts, myaction, myfiles, spinner) + if "--pretend" in myopts: + display_news_notification(trees) + return retval + +if __name__ == "__main__": + retval = emerge_main() + sys.exit(retval) diff --git a/pym/_emerge/help.py b/pym/_emerge/help.py new file mode 100644 index 000000000..5bb93a1f4 --- /dev/null +++ b/pym/_emerge/help.py @@ -0,0 +1,394 @@ +# Copyright 1999-2007 Gentoo Foundation +# Distributed under the terms of the GNU General Public License v2 +# $Id$ + + +import os,sys +from portage.output import bold, turquoise, green + +def shorthelp(): + print bold("emerge:")+" the other white meat (command-line interface to the Portage system)" + print bold("Usage:") + print " "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] [ "+turquoise("ebuildfile")+" | "+turquoise("tbz2file")+" | "+turquoise("dependency")+" ] [ ... ]" + print " "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] < "+turquoise("system")+" | "+turquoise("world")+" >" + print " "+turquoise("emerge")+" < "+turquoise("--sync")+" | "+turquoise("--metadata")+" | "+turquoise("--info")+" >" + print " "+turquoise("emerge")+" "+turquoise("--resume")+" [ "+green("--pretend")+" | "+green("--ask")+" | "+green("--skipfirst")+" ]" + print " "+turquoise("emerge")+" "+turquoise("--help")+" [ "+green("system")+" | "+green("world")+" | "+green("--sync")+" ] " + print bold("Options:")+" "+green("-")+"["+green("abBcCdDefgGhkKlnNoOpqPsStuvV")+"] ["+green("--oneshot")+"] ["+green("--newuse")+"] ["+green("--noconfmem")+"]" + print " [ " + green("--color")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ] [ "+green("--columns")+" ]" + print " [ "+green("--reinstall ")+turquoise("changed-use")+" ] ["+green("--nospinner")+"]" + print " [ "+green("--deep")+" ] [" + green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ]" + print bold("Actions:")+" [ "+green("--clean")+" | "+green("--depclean")+" | "+green("--prune")+" | "+green("--regen")+" | "+green("--search")+" | "+green("--unmerge")+" ]" + +def help(myaction,myopts,havecolor=1): + if not myaction and ("--verbose" not in myopts): + shorthelp() + print + print " For more help try 'emerge --help --verbose' or consult the man page." + elif not myaction: + shorthelp() + print + print turquoise("Help (this screen):") + print " "+green("--help")+" ("+green("-h")+" short option)" + print " Displays this help; an additional argument (see above) will tell" + print " emerge to display detailed help." + print + print turquoise("Actions:") + print " "+green("--clean")+" ("+green("-c")+" short option)" + print " Cleans the system by removing outdated packages which will not" + print " remove functionalities or prevent your system from working." + print " The arguments can be in several different formats :" + print " * world " + print " * system or" + print " * 'dependency specification' (in single quotes is best.)" + print " Here are a few examples of the dependency specification format:" + print " "+bold("binutils")+" matches" + print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" + print " "+bold("sys-devel/binutils")+" matches" + print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" + print " "+bold(">sys-devel/binutils-2.11.90.0.7")+" matches" + print " binutils-2.11.92.0.12.3-r1" + print " "+bold(">=sys-devel/binutils-2.11.90.0.7")+" matches" + print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" + print " "+bold("<=sys-devel/binutils-2.11.92.0.12.3-r1")+" matches" + print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" + print + print " "+green("--config") + print " Runs package-specific operations that must be executed after an" + print " emerge process has completed. This usually entails configuration" + print " file setup or other similar setups that the user may wish to run." + print + print " "+green("--depclean") + print " Cleans the system by removing packages that are not associated" + print " with explicitly merged packages. Depclean works by creating the" + print " full dependency tree from the system list and the world file," + print " then comparing it to installed packages. Packages installed, but" + print " not associated with an explicit merge are listed as candidates" + print " for unmerging. Inexperienced users are advised to use --pretend" + print " with this option in order to see a preview of which packages will" + print " be uninstalled. "+turquoise(" WARNING: Removing some packages may cause") + print " "+turquoise("packages which link to the removed package to stop working and") + print " "+turquoise("complain about missing libraries. Rebuild the complaining package") + print " "+turquoise("to fix this issue.")+" Also see --with-bdeps for behavior with" + print " respect to build time dependencies that are not strictly" + print " required. Depclean serves as a dependency aware version of" + print " --unmerge. When given one or more atoms, it will unmerge matched" + print " packages that have no reverse dependencies. Use --depclean" + print " together with --verbose to show reverse dependencies." + print + print " "+green("--info") + print " Displays important portage variables that will be exported to" + print " ebuild.sh when performing merges. This information is useful" + print " for bug reports and verification of settings. All settings in" + print " make.{conf,globals,defaults} and the environment show up if" + print " run with the '--verbose' flag." + print + print " "+green("--metadata") + print " Transfers metadata cache from ${PORTDIR}/metadata/cache/ to" + print " /var/cache/edb/dep/ as is normally done on the tail end of an" + print " rsync update using " + bold("emerge --sync") + ". This process populates the" + print " cache database that portage uses for pre-parsed lookups of" + print " package data. It does not populate cache for the overlays" + print " listed in PORTDIR_OVERLAY. In order to generate cache for" + print " overlays, use " + bold("--regen") + "." + print + print " "+green("--prune")+" ("+green("-P")+" short option)" + print " "+turquoise("WARNING: This action can remove important packages!") + print " Removes all but the highest installed version of a package" + print " from your system. This action doesn't verify the possible binary" + print " compatibility between versions and can thus remove essential" + print " dependencies from your system. Use --prune together with" + print " --verbose to show reverse dependencies or with --nodeps to" + print " ignore all dependencies." + print + print " "+green("--regen") + print " Causes portage to check and update the dependency cache of all" + print " ebuilds in the portage tree. This is not recommended for rsync" + print " users as rsync updates the cache using server-side caches." + print " Rsync users should simply 'emerge --sync' to regenerate." + print + print " "+green("--resume") + print " Resumes the most recent merge list that has been aborted due to an" + print " error. Please note that this operation will only return an error" + print " on failure. If there is nothing for portage to do, then portage" + print " will exit with a message and a success condition. A resume list" + print " will persist until it has been completed in entirety or until" + print " another aborted merge list replaces it. The resume history is" + print " capable of storing two merge lists. After one resume list" + print " completes, it is possible to invoke --resume once again in order" + print " to resume an older list." + print + print " "+green("--search")+" ("+green("-s")+" short option)" + print " Searches for matches of the supplied string in the current local" + print " portage tree. By default emerge uses a case-insensitive simple " + print " search, but you can enable a regular expression search by " + print " prefixing the search string with %." + print " Prepending the expression with a '@' will cause the category to" + print " be included in the search." + print " A few examples:" + print " "+bold("emerge --search libc") + print " list all packages that contain libc in their name" + print " "+bold("emerge --search '%^kde'") + print " list all packages starting with kde" + print " "+bold("emerge --search '%gcc$'") + print " list all packages ending with gcc" + print " "+bold("emerge --search '%@^dev-java.*jdk'") + print " list all available Java JDKs" + print + print " "+green("--searchdesc")+" ("+green("-S")+" short option)" + print " Matches the search string against the description field as well" + print " the package's name. Take caution as the descriptions are also" + print " matched as regular expressions." + print " emerge -S html" + print " emerge -S applet" + print " emerge -S 'perl.*module'" + print + print " "+green("--unmerge")+" ("+green("-C")+" short option)" + print " "+turquoise("WARNING: This action can remove important packages!") + print " Removes all matching packages. This does no checking of" + print " dependencies, so it may remove packages necessary for the proper" + print " operation of your system. Its arguments can be atoms or" + print " ebuilds. For a dependency aware version of --unmerge, use" + print " --depclean or --prune." + print + print " "+green("--update")+" ("+green("-u")+" short option)" + print " Updates packages to the best version available, which may not" + print " always be the highest version number due to masking for testing" + print " and development. This will also update direct dependencies which" + print " may not what you want. Package atoms specified on the command line" + print " are greedy, meaning that unspecific atoms may match multiple" + print " installed versions of slotted packages." + print + print " "+green("--version")+" ("+green("-V")+" short option)" + print " Displays the currently installed version of portage along with" + print " other information useful for quick reference on a system. See" + print " "+bold("emerge info")+" for more advanced information." + print + print turquoise("Options:") + print " "+green("--alphabetical") + print " When displaying USE and other flag output, combines the enabled" + print " and disabled flags into a single list and sorts it alphabetically." + print " With this option, output such as USE=\"dar -bar -foo\" will instead" + print " be displayed as USE=\"-bar dar -foo\"" + print + print " "+green("--ask")+" ("+green("-a")+" short option)" + print " before performing the merge, display what ebuilds and tbz2s will" + print " be installed, in the same format as when using --pretend; then" + print " ask whether to continue with the merge or abort. Using --ask is" + print " more efficient than using --pretend and then executing the same" + print " command without --pretend, as dependencies will only need to be" + print " calculated once. WARNING: If the \"Enter\" key is pressed at the" + print " prompt (with no other input), it is interpreted as acceptance of" + print " the first choice. Note that the input buffer is not cleared prior" + print " to the prompt, so an accidental press of the \"Enter\" key at any" + print " time prior to the prompt will be interpreted as a choice!" + print + print " "+green("--buildpkg")+" ("+green("-b")+" short option)" + print " Tell emerge to build binary packages for all ebuilds processed" + print " (in addition to actually merging the packages. Useful for" + print " maintainers or if you administrate multiple Gentoo Linux" + print " systems (build once, emerge tbz2s everywhere) as well as disaster" + print " recovery." + print + print " "+green("--buildpkgonly")+" ("+green("-B")+" short option)" + print " Creates a binary package, but does not merge it to the" + print " system. This has the restriction that unsatisfied dependencies" + print " must not exist for the desired package as they cannot be used if" + print " they do not exist on the system." + print + print " "+green("--changelog")+" ("+green("-l")+" short option)" + print " When pretending, also display the ChangeLog entries for packages" + print " that will be upgraded." + print + print " "+green("--color") + " < " + turquoise("y") + " | "+ turquoise("n")+" >" + print " Enable or disable color output. This option will override NOCOLOR" + print " (see make.conf(5)) and may also be used to force color output when" + print " stdout is not a tty (by default, color is disabled unless stdout" + print " is a tty)." + print + print " "+green("--columns") + print " Display the pretend output in a tabular form. Versions are" + print " aligned vertically." + print + print " "+green("--debug")+" ("+green("-d")+" short option)" + print " Tell emerge to run the ebuild command in --debug mode. In this" + print " mode, the bash build environment will run with the -x option," + print " causing it to output verbose debug information print to stdout." + print " --debug is great for finding bash syntax errors as providing" + print " very verbose information about the dependency and build process." + print + print " "+green("--deep")+" ("+green("-D")+" short option)" + print " This flag forces emerge to consider the entire dependency tree of" + print " packages, instead of checking only the immediate dependencies of" + print " the packages. As an example, this catches updates in libraries" + print " that are not directly listed in the dependencies of a package." + print " Also see --with-bdeps for behavior with respect to build time" + print " dependencies that are not strictly required." + print + print " "+green("--emptytree")+" ("+green("-e")+" short option)" + print " Virtually tweaks the tree of installed packages to contain" + print " nothing. This is great to use together with --pretend. This makes" + print " it possible for developers to get a complete overview of the" + print " complete dependency tree of a certain package." + print + print " "+green("--fetchonly")+" ("+green("-f")+" short option)" + print " Instead of doing any package building, just perform fetches for" + print " all packages (main package as well as all dependencies.) When" + print " used in combination with --pretend all the SRC_URIs will be" + print " displayed multiple mirrors per line, one line per file." + print + print " "+green("--fetch-all-uri")+" ("+green("-F")+" short option)" + print " Same as --fetchonly except that all package files, including those" + print " not required to build the package, will be processed." + print + print " "+green("--getbinpkg")+" ("+green("-g")+" short option)" + print " Using the server and location defined in PORTAGE_BINHOST, portage" + print " will download the information from each binary file there and it" + print " will use that information to help build the dependency list. This" + print " option implies '-k'. (Use -gK for binary-only merging.)" + print + print " "+green("--getbinpkgonly")+" ("+green("-G")+" short option)" + print " This option is identical to -g, as above, except it will not use" + print " ANY information from the local machine. All binaries will be" + print " downloaded from the remote server without consulting packages" + print " existing in the packages directory." + print + print " "+green("--newuse")+" ("+green("-N")+" short option)" + print " Tells emerge to include installed packages where USE flags have " + print " changed since installation." + print + print " "+green("--noconfmem") + print " Portage keeps track of files that have been placed into" + print " CONFIG_PROTECT directories, and normally it will not merge the" + print " same file more than once, as that would become annoying. This" + print " can lead to problems when the user wants the file in the case" + print " of accidental deletion. With this option, files will always be" + print " merged to the live fs instead of silently dropped." + print + print " "+green("--nodeps")+" ("+green("-O")+" short option)" + print " Merge specified packages, but don't merge any dependencies." + print " Note that the build may fail if deps aren't satisfied." + print + print " "+green("--noreplace")+" ("+green("-n")+" short option)" + print " Skip the packages specified on the command-line that have" + print " already been installed. Without this option, any packages," + print " ebuilds, or deps you specify on the command-line *will* cause" + print " Portage to remerge the package, even if it is already installed." + print " Note that Portage won't remerge dependencies by default." + print + print " "+green("--nospinner") + print " Disables the spinner regardless of terminal type." + print + print " "+green("--oneshot")+" ("+green("-1")+" short option)" + print " Emerge as normal, but don't add packages to the world profile." + print " This package will only be updated if it is depended upon by" + print " another package." + print + print " "+green("--onlydeps")+" ("+green("-o")+" short option)" + print " Only merge (or pretend to merge) the dependencies of the" + print " specified packages, not the packages themselves." + print + print " "+green("--pretend")+" ("+green("-p")+" short option)" + print " Instead of actually performing the merge, simply display what" + print " ebuilds and tbz2s *would* have been installed if --pretend" + print " weren't used. Using --pretend is strongly recommended before" + print " installing an unfamiliar package. In the printout, N = new," + print " U = updating, R = replacing, F = fetch restricted, B = blocked" + print " by an already installed package, D = possible downgrading," + print " S = slotted install. --verbose causes affecting use flags to be" + print " printed out accompanied by a '+' for enabled and a '-' for" + print " disabled USE flags." + print + print " "+green("--quiet")+" ("+green("-q")+" short option)" + print " Effects vary, but the general outcome is a reduced or condensed" + print " output from portage's displays." + print + print " "+green("--reinstall ") + turquoise("changed-use") + print " Tells emerge to include installed packages where USE flags have" + print " changed since installation. Unlike --newuse, this option does" + print " not trigger reinstallation when flags that the user has not" + print " enabled are added or removed." + print + print " "+green("--skipfirst") + print " This option is only valid in a resume situation. It removes the" + print " first package in the resume list so that a merge may continue in" + print " the presence of an uncorrectable or inconsequential error. This" + print " should only be used in cases where skipping the package will not" + print " result in failed dependencies." + print + print " "+green("--tree")+" ("+green("-t")+" short option)" + print " Shows the dependency tree using indentation for dependencies." + print " The packages are also listed in reverse merge order so that" + print " a package's dependencies follow the package. Only really useful" + print " in combination with --emptytree, --update or --deep." + print + print " "+green("--usepkg")+" ("+green("-k")+" short option)" + print " Tell emerge to use binary packages (from $PKGDIR) if they are" + print " available, thus possibly avoiding some time-consuming compiles." + print " This option is useful for CD installs; you can export" + print " PKGDIR=/mnt/cdrom/packages and then use this option to have" + print " emerge \"pull\" binary packages from the CD in order to satisfy" + print " dependencies." + print + print " "+green("--usepkgonly")+" ("+green("-K")+" short option)" + print " Like --usepkg above, except this only allows the use of binary" + print " packages, and it will abort the emerge if the package is not" + print " available at the time of dependency calculation." + print + print " "+green("--verbose")+" ("+green("-v")+" short option)" + print " Effects vary, but the general outcome is an increased or expanded" + print " display of content in portage's displays." + print + print " "+green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" >" + print " In dependency calculations, pull in build time dependencies that" + print " are not strictly required. This defaults to 'n' for installation" + print " actions and 'y' for the --depclean action. This setting can be" + print " added to EMERGE_DEFAULT_OPTS (see make.conf(5)) and later" + print " overridden via the command line." + print + elif myaction == "sync": + print + print bold("Usage: ")+turquoise("emerge")+" "+turquoise("--sync") + print + print " 'emerge --sync' tells emerge to update the Portage tree as specified in" + print " The SYNC variable found in /etc/make.conf. By default, SYNC instructs" + print " emerge to perform an rsync-style update with rsync.gentoo.org." + print + print " 'emerge-webrsync' exists as a helper app to emerge --sync, providing a" + print " method to receive the entire portage tree as a tarball that can be" + print " extracted and used. First time syncs would benefit greatly from this." + print + print " "+turquoise("WARNING:") + print " If using our rsync server, emerge will clean out all files that do not" + print " exist on it, including ones that you may have created. The exceptions" + print " to this are the distfiles, local and packages directories." + print + elif myaction=="system": + print + print bold("Usage: ")+turquoise("emerge")+" [ "+green("options")+" ] "+turquoise("system") + print + print " \"emerge system\" is the Portage system update command. When run, it" + print " will scan the etc/make.profile/packages file and determine what" + print " packages need to be installed so that your system meets the minimum" + print " requirements of your current system profile. Note that this doesn't" + print " necessarily bring your system up-to-date at all; instead, it just" + print " ensures that you have no missing parts. For example, if your system" + print " profile specifies that you should have sys-apps/iptables installed" + print " and you don't, then \"emerge system\" will install it (the most" + print " recent version that matches the profile spec) for you. It's always a" + print " good idea to do an \"emerge --pretend system\" before an \"emerge" + print " system\", just so you know what emerge is planning to do." + print + elif myaction=="world": + print + print bold("Usage: ")+turquoise("emerge")+" [ "+green("options")+" ] "+turquoise("world") + print + print " 'emerge world' is the Portage command for completely updating your" + print " system. The normal procedure is to first do an 'emerge --sync' and" + print " then an 'emerge --update --deep world'. The first command brings your" + print " local Portage tree up-to-date with the latest version information and" + print " ebuilds. The second command then rebuilds all packages for which newer" + print " versions or newer ebuilds have become available since you last did a" + print " sync and update." + print + diff --git a/pym/emerge/__init__.py b/pym/emerge/__init__.py deleted file mode 100644 index e1fa5e4b6..000000000 --- a/pym/emerge/__init__.py +++ /dev/null @@ -1,6844 +0,0 @@ -#!/usr/bin/python -O -# Copyright 1999-2006 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Id: emerge 5976 2007-02-17 09:14:53Z genone $ - -import sys -# This block ensures that ^C interrupts are handled quietly. -try: - import signal - - def exithandler(signum,frame): - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTERM, signal.SIG_IGN) - sys.exit(1) - - signal.signal(signal.SIGINT, exithandler) - signal.signal(signal.SIGTERM, exithandler) - signal.signal(signal.SIGPIPE, signal.SIG_DFL) - -except KeyboardInterrupt: - sys.exit(1) - -import os, stat - -os.environ["PORTAGE_LEGACY_GLOBALS"] = "false" -try: - import portage -except ImportError: - from os import path as osp - sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym")) - import portage -del os.environ["PORTAGE_LEGACY_GLOBALS"] -from portage import digraph, portdbapi -from portage.const import NEWS_LIB_PATH, CACHE_PATH, PRIVATE_PATH, USER_CONFIG_PATH, GLOBAL_CONFIG_PATH - -import emerge.help -import portage.xpak, commands, errno, re, socket, time, types -from portage.output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \ - havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \ - xtermTitleReset, yellow -from portage.output import create_color_func -good = create_color_func("GOOD") -bad = create_color_func("BAD") -# white looks bad on terminals with white background -from portage.output import bold as white - -import portage.dep -portage.dep._dep_check_strict = True -import portage.util -import portage.locks -import portage.exception -from portage.data import secpass -from portage.util import normalize_path as normpath -from portage.util import writemsg -from portage.sets import InternalPackageSet, SetConfig, make_default_config -from portage.sets.profiles import PackagesSystemSet as SystemSet -from portage.sets.files import WorldSet - -from itertools import chain, izip -from UserDict import DictMixin - -try: - import cPickle -except ImportError: - import pickle as cPickle - -class stdout_spinner(object): - scroll_msgs = [ - "Gentoo Rocks ("+os.uname()[0]+")", - "Thank you for using Gentoo. :)", - "Are you actually trying to read this?", - "How many times have you stared at this?", - "We are generating the cache right now", - "You are paying too much attention.", - "A theory is better than its explanation.", - "Phasers locked on target, Captain.", - "Thrashing is just virtual crashing.", - "To be is to program.", - "Real Users hate Real Programmers.", - "When all else fails, read the instructions.", - "Functionality breeds Contempt.", - "The future lies ahead.", - "3.1415926535897932384626433832795028841971694", - "Sometimes insanity is the only alternative.", - "Inaccuracy saves a world of explanation.", - ] - - twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" - - def __init__(self): - self.spinpos = 0 - self.update = self.update_twirl - self.scroll_sequence = self.scroll_msgs[ - int(time.time() * 100) % len(self.scroll_msgs)] - - def update_basic(self): - self.spinpos = (self.spinpos + 1) % 500 - if (self.spinpos % 100) == 0: - if self.spinpos == 0: - sys.stdout.write(". ") - else: - sys.stdout.write(".") - sys.stdout.flush() - - def update_scroll(self): - if(self.spinpos >= len(self.scroll_sequence)): - sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[ - len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))])) - else: - sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos])) - sys.stdout.flush() - self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence)) - - def update_twirl(self): - self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence) - sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos]) - sys.stdout.flush() - - def update_quiet(self): - return - -def userquery(prompt, responses=None, colours=None): - """Displays a prompt and a set of responses, then waits for a response - which is checked against the responses and the first to match is - returned. An empty response will match the first value in responses. The - input buffer is *not* cleared prior to the prompt! - - prompt: a String. - responses: a List of Strings. - colours: a List of Functions taking and returning a String, used to - process the responses for display. Typically these will be functions - like red() but could be e.g. lambda x: "DisplayString". - If responses is omitted, defaults to ["Yes", "No"], [green, red]. - If only colours is omitted, defaults to [bold, ...]. - - Returns a member of the List responses. (If called without optional - arguments, returns "Yes" or "No".) - KeyboardInterrupt is converted to SystemExit to avoid tracebacks being - printed.""" - if responses is None: - responses = ["Yes", "No"] - colours = [ - create_color_func("PROMPT_CHOICE_DEFAULT"), - create_color_func("PROMPT_CHOICE_OTHER") - ] - elif colours is None: - colours=[bold] - colours=(colours*len(responses))[:len(responses)] - print bold(prompt), - try: - while True: - response=raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ") - for key in responses: - # An empty response will match the first value in responses. - if response.upper()==key[:len(response)].upper(): - return key - print "Sorry, response '%s' not understood." % response, - except (EOFError, KeyboardInterrupt): - print "Interrupted." - sys.exit(1) - -actions=[ -"clean", "config", "depclean", -"info", "metadata", -"prune", "regen", "search", -"sync", "system", "unmerge", "world", -] -options=[ -"--ask", "--alphabetical", -"--buildpkg", "--buildpkgonly", -"--changelog", "--columns", -"--debug", "--deep", -"--digest", -"--emptytree", -"--fetchonly", "--fetch-all-uri", -"--getbinpkg", "--getbinpkgonly", -"--help", "--ignore-default-opts", -"--noconfmem", -"--newuse", "--nocolor", -"--nodeps", "--noreplace", -"--nospinner", "--oneshot", -"--onlydeps", "--pretend", -"--quiet", "--resume", -"--searchdesc", "--selective", -"--skipfirst", -"--tree", -"--update", -"--usepkg", "--usepkgonly", -"--verbose", "--version" -] - -shortmapping={ -"1":"--oneshot", -"a":"--ask", -"b":"--buildpkg", "B":"--buildpkgonly", -"c":"--clean", "C":"--unmerge", -"d":"--debug", "D":"--deep", -"e":"--emptytree", -"f":"--fetchonly", "F":"--fetch-all-uri", -"g":"--getbinpkg", "G":"--getbinpkgonly", -"h":"--help", -"k":"--usepkg", "K":"--usepkgonly", -"l":"--changelog", -"n":"--noreplace", "N":"--newuse", -"o":"--onlydeps", "O":"--nodeps", -"p":"--pretend", "P":"--prune", -"q":"--quiet", -"s":"--search", "S":"--searchdesc", -'t':"--tree", -"u":"--update", -"v":"--verbose", "V":"--version" -} - -def emergelog(xterm_titles, mystr, short_msg=None): - if xterm_titles: - if short_msg == None: - short_msg = mystr - if "HOSTNAME" in os.environ: - short_msg = os.environ["HOSTNAME"]+": "+short_msg - xtermTitle(short_msg) - try: - file_path = "/var/log/emerge.log" - mylogfile = open(file_path, "a") - portage.util.apply_secpass_permissions(file_path, - uid=portage.portage_uid, gid=portage.portage_gid, - mode=0660) - mylock = None - try: - mylock = portage.locks.lockfile(mylogfile) - # seek because we may have gotten held up by the lock. - # if so, we may not be positioned at the end of the file. - mylogfile.seek(0, 2) - mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") - mylogfile.flush() - finally: - if mylock: - portage.locks.unlockfile(mylock) - mylogfile.close() - except (IOError,OSError,portage.exception.PortageException), e: - if secpass >= 1: - print >> sys.stderr, "emergelog():",e - -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(colorize("UNMERGE_WARN", str(sec+1)+" ")) - sys.stdout.flush() - time.sleep(1) - print - -# formats a size given in bytes nicely -def format_size(mysize): - if type(mysize) not in [types.IntType,types.LongType]: - return str(mysize) - if 0 != mysize % 1024: - # Always round up to the next kB so that it doesn't show 0 kB when - # some small file still needs to be fetched. - mysize += 1024 - mysize % 1024 - mystr=str(mysize/1024) - mycount=len(mystr) - while (mycount > 3): - mycount-=3 - mystr=mystr[:mycount]+","+mystr[mycount:] - return mystr+" kB" - - -def getgccversion(chost): - """ - rtype: C{str} - return: the current in-use gcc version - """ - - gcc_ver_command = 'gcc -dumpversion' - gcc_ver_prefix = 'gcc-' - - gcc_not_found_error = red( - "!!! No gcc found. You probably need to 'source /etc/profile'\n" + - "!!! to update the environment of this terminal and possibly\n" + - "!!! other terminals also.\n" - ) - - mystatus, myoutput = commands.getstatusoutput("eselect compiler show") - if mystatus == os.EX_OK and len(myoutput.split("/")) == 2: - part1, part2 = myoutput.split("/") - if part1.startswith(chost + "-"): - return myoutput.replace(chost + "-", gcc_ver_prefix, 1) - - mystatus, myoutput = commands.getstatusoutput("gcc-config -c") - if mystatus == os.EX_OK and myoutput.startswith(chost + "-"): - return myoutput.replace(chost + "-", gcc_ver_prefix, 1) - - mystatus, myoutput = commands.getstatusoutput( - chost + "-" + gcc_ver_command) - if mystatus == os.EX_OK: - return gcc_ver_prefix + myoutput - - mystatus, myoutput = commands.getstatusoutput(gcc_ver_command) - if mystatus == os.EX_OK: - return gcc_ver_prefix + myoutput - - portage.writemsg(gcc_not_found_error, noiselevel=-1) - return "[unavailable]" - -def getportageversion(portdir, target_root, profile, chost, vardb): - profilever = "unavailable" - if profile: - realpath = os.path.realpath(profile) - basepath = os.path.realpath(os.path.join(portdir, "profiles")) - if realpath.startswith(basepath): - profilever = realpath[1 + len(basepath):] - else: - try: - profilever = "!" + os.readlink(profile) - except (OSError): - pass - del realpath, basepath - - libcver=[] - libclist = vardb.match("virtual/libc") - libclist += vardb.match("virtual/glibc") - libclist = portage.util.unique_array(libclist) - for x in libclist: - xs=portage.catpkgsplit(x) - if libcver: - libcver+=","+"-".join(xs[1:]) - else: - libcver="-".join(xs[1:]) - if libcver==[]: - libcver="unavailable" - - gccver = getgccversion(chost) - unameout=os.uname()[2]+" "+os.uname()[4] - - return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")" - -def create_depgraph_params(myopts, myaction): - #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 - # deep: go into the dependencies of already merged packages - # empty: pretend nothing is merged - myparams = set(["recurse"]) - if "--update" in myopts or \ - "--newuse" in myopts or \ - "--reinstall" in myopts or \ - "--noreplace" in myopts or \ - myaction in ("system", "world"): - myparams.add("selective") - if "--emptytree" in myopts: - myparams.add("empty") - myparams.discard("selective") - if "--nodeps" in myopts: - myparams.discard("recurse") - if "--deep" in myopts: - myparams.add("deep") - return myparams - -# search functionality -class search(object): - - # - # class constants - # - VERSION_SHORT=1 - VERSION_RELEASE=2 - - # - # public interface - # - def __init__(self, settings, portdb, vartree, spinner, searchdesc, - verbose, setconfig): - """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.settings = settings - self.portdb = portdb - self.vartree = vartree - self.spinner = spinner - self.verbose = verbose - self.searchdesc = searchdesc - self.setconfig = setconfig - - def execute(self,searchkey): - """Performs the search for the supplied search key""" - match_category = 0 - self.searchkey=searchkey - self.packagematches = [] - if self.searchdesc: - self.searchdesc=1 - self.matches = {"pkg":[], "desc":[], "set":[]} - else: - self.searchdesc=0 - self.matches = {"pkg":[], "set":[]} - print "Searching... ", - - regexsearch = False - if self.searchkey.startswith('%'): - regexsearch = True - self.searchkey = self.searchkey[1:] - if self.searchkey.startswith('@'): - match_category = 1 - self.searchkey = self.searchkey[1:] - if regexsearch: - self.searchre=re.compile(self.searchkey,re.I) - else: - self.searchre=re.compile(re.escape(self.searchkey), re.I) - for package in self.portdb.cp_all(): - self.spinner.update() - - if match_category: - match_string = package[:] - else: - match_string = package.split("/")[-1] - - masked=0 - if self.searchre.search(match_string): - if not self.portdb.xmatch("match-visible", package): - masked=1 - self.matches["pkg"].append([package,masked]) - elif self.searchdesc: # DESCRIPTION searching - full_package = self.portdb.xmatch("bestmatch-visible", package) - if not full_package: - #no match found; we don't want to query description - full_package = portage.best( - self.portdb.xmatch("match-all", package)) - if not full_package: - continue - else: - masked=1 - try: - full_desc = self.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.sdict = self.setconfig.getSets()[0] - for setname in self.sdict: - self.spinner.update() - if match_category: - match_string = setname - else: - match_string = setname.split("/")[-1] - - if self.searchre.search(match_string): - self.matches["set"].append([setname, False]) - elif self.searchdesc: - if self.searchre.search(sdict[setname].getMetadata("DESCRIPTION")): - self.matches["set"].append([setname, False]) - - self.mlen=0 - for mtype in self.matches: - 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: - for match,masked in self.matches[mtype]: - full_package = None - if mtype == "pkg": - catpack = match - full_package = self.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( - self.portdb.xmatch("match-all",match)) - elif mtype == "desc": - full_package = match - match = portage.pkgsplit(match)[0] - elif mtype == "set": - print green("*")+" "+white(match) - print " ", darkgreen("Description:")+" ", self.sdict[match].getMetadata("DESCRIPTION") - print - if full_package: - try: - desc, homepage, license = self.portdb.aux_get( - full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"]) - 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] - mycpv = match + "-" + myversion - myebuild = self.portdb.findname(mycpv) - pkgdir = os.path.dirname(myebuild) - from portage import manifest - mf = manifest.Manifest( - pkgdir, self.settings["DISTDIR"]) - fetchlist = self.portdb.getfetchlist(mycpv, - mysettings=self.settings, all=True)[1] - try: - mysum[0] = mf.getDistfilesSize(fetchlist) - mystr = str(mysum[0]/1024) - mycount=len(mystr) - while (mycount > 3): - mycount-=3 - mystr=mystr[:mycount]+","+mystr[mycount:] - mysum[0]=mystr+" kB" - except KeyError, e: - mysum[0] = "Unknown (missing digest for %s)" % str(e) - - if self.verbose: - print " ", darkgreen("Latest version available:"),myversion - print " ", self.getInstallationStatus(mycat+'/'+mypkg) - print " ", darkgreen("Size of files:"),mysum[0] - print " ", darkgreen("Homepage:")+" ",homepage - print " ", darkgreen("Description:")+" ",desc - print " ", darkgreen("License:")+" ",license - print - print - # - # private interface - # - def getInstallationStatus(self,package): - installed_package = self.vartree.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(settings, mode): - if mode=="system": - mylines = settings.packages - elif mode=="world": - try: - file_path = os.path.join(settings["ROOT"], portage.WORLD_FILE) - myfile = open(file_path, "r") - mylines = myfile.readlines() - myfile.close() - except (OSError, IOError), e: - if e.errno == errno.ENOENT: - portage.writemsg("\n!!! World file does not exist: '%s'\n" % file_path) - mylines=[] - else: - raise - mynewlines=[] - for x in mylines: - myline=" ".join(x.split()) - 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 clean_world(vardb, cpv): - """Remove a package from the world file when unmerged.""" - world_set = WorldSet(vardb.settings["ROOT"]) - world_set.lock() - worldlist = list(world_set) # loads latest from disk - mykey = portage.cpv_getkey(cpv) - newworldlist = [] - for x in worldlist: - if portage.dep_getkey(x) == mykey: - matches = vardb.match(x, use_cache=0) - if not matches: - #zap our world entry - pass - elif len(matches) == 1 and matches[0] == cpv: - #zap our world entry - pass - else: - #others are around; keep it. - newworldlist.append(x) - else: - #this doesn't match the package we're unmerging; keep it. - newworldlist.append(x) - - world_set.replace(newworldlist) - world_set.unlock() - - -class RootConfig(object): - """This is used internally by depgraph to track information about a - particular $ROOT.""" - def __init__(self, trees): - self.trees = trees - self.settings = trees["vartree"].settings - self.root = self.settings["ROOT"] - self.sets = {} - world_set = WorldSet(self.root) - self.sets["world"] = world_set - system_set = SystemSet(self.settings.profiles) - self.sets["system"] = system_set - -def create_world_atom(pkg_key, metadata, args_set, root_config): - """Create a new atom for the world file if one does not exist. If the - argument atom is precise enough to identify a specific slot then a slot - atom will be returned. Atoms that are in the system set may also be stored - in world since system atoms can only match one slot while world atoms can - be greedy with respect to slots. Unslotted system packages will not be - stored in world.""" - arg_atom = args_set.findAtomForPackage(pkg_key, metadata) - cp = portage.dep_getkey(arg_atom) - new_world_atom = cp - sets = root_config.sets - portdb = root_config.trees["porttree"].dbapi - vardb = root_config.trees["vartree"].dbapi - available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \ - for cpv in portdb.match(cp)) - slotted = len(available_slots) > 1 or \ - (len(available_slots) == 1 and "0" not in available_slots) - if not slotted: - # check the vdb in case this is multislot - available_slots = set(vardb.aux_get(cpv, ["SLOT"])[0] \ - for cpv in vardb.match(cp)) - slotted = len(available_slots) > 1 or \ - (len(available_slots) == 1 and "0" not in available_slots) - if slotted and arg_atom != cp: - # If the user gave a specific atom, store it as a - # slot atom in the world file. - slot_atom = "%s:%s" % (cp, metadata["SLOT"]) - # First verify the slot is in the portage tree to avoid - # adding a bogus slot like that produced by multislot. - if portdb.match(slot_atom): - # Now verify that the argument is precise enough to identify a - # specific slot. - matches = portdb.match(arg_atom) - matched_slots = set() - for cpv in matches: - matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0]) - if len(matched_slots) == 1: - new_world_atom = slot_atom - if new_world_atom == sets["world"].findAtomForPackage(pkg_key, metadata): - # Both atoms would be identical, so there's nothing to add. - return None - if not slotted: - # Unlike world atoms, system atoms are not greedy for slots, so they - # can't be safely excluded from world if they are slotted. - system_atom = sets["system"].findAtomForPackage(pkg_key, metadata) - if system_atom: - if not portage.dep_getkey(system_atom).startswith("virtual/"): - return None - # System virtuals aren't safe to exclude from world since they can - # match multiple old-style virtuals but only one of them will be - # pulled in by update or depclean. - providers = portdb.mysettings.getvirtuals().get( - portage.dep_getkey(system_atom)) - if providers and len(providers) == 1 and providers[0] == cp: - return None - return new_world_atom - -def filter_iuse_defaults(iuse): - for flag in iuse: - if flag.startswith("+") or flag.startswith("-"): - yield flag[1:] - else: - yield flag - -class DepPriority(object): - """ - This class generates an integer priority level based of various - attributes of the dependency relationship. Attributes can be assigned - at any time and the new integer value will be generated on calls to the - __int__() method. Rich comparison operators are supported. - - The boolean attributes that affect the integer value are "satisfied", - "buildtime", "runtime", and "system". Various combinations of - attributes lead to the following priority levels: - - Combination of properties Priority level - - not satisfied and buildtime 0 - not satisfied and runtime -1 - satisfied and buildtime -2 - satisfied and runtime -3 - (none of the above) -4 - - Several integer constants are defined for categorization of priority - levels: - - MEDIUM The upper boundary for medium dependencies. - MEDIUM_SOFT The upper boundary for medium-soft dependencies. - SOFT The upper boundary for soft dependencies. - MIN The lower boundary for soft dependencies. - """ - __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime", "runtime_post", "rebuild") - MEDIUM = -1 - MEDIUM_SOFT = -2 - SOFT = -3 - MIN = -6 - def __init__(self, **kwargs): - for myattr in self.__slots__: - if myattr == "__weakref__": - continue - myvalue = kwargs.get(myattr, False) - setattr(self, myattr, myvalue) - def __int__(self): - if not self.satisfied: - if self.buildtime: - return 0 - if self.runtime: - return -1 - if self.runtime_post: - return -2 - if self.buildtime: - if self.rebuild: - return -3 - return -4 - if self.runtime: - return -5 - if self.runtime_post: - return -6 - return -6 - def __lt__(self, other): - return self.__int__() < other - def __le__(self, other): - return self.__int__() <= other - def __eq__(self, other): - return self.__int__() == other - def __ne__(self, other): - return self.__int__() != other - def __gt__(self, other): - return self.__int__() > other - def __ge__(self, other): - return self.__int__() >= other - def copy(self): - import copy - return copy.copy(self) - def __str__(self): - myvalue = self.__int__() - if myvalue > self.MEDIUM: - return "hard" - if myvalue > self.MEDIUM_SOFT: - return "medium" - if myvalue > self.SOFT: - return "medium-soft" - return "soft" - -class FakeVartree(portage.vartree): - """This is implements an in-memory copy of a vartree instance that provides - all the interfaces required for use by the depgraph. The vardb is locked - during the constructor call just long enough to read a copy of the - installed package information. This allows the depgraph to do it's - dependency calculations without holding a lock on the vardb. It also - allows things like vardb global updates to be done in memory so that the - user doesn't necessarily need write access to the vardb in cases where - global updates are necessary (updates are performed when necessary if there - is not a matching ebuild in the tree).""" - def __init__(self, real_vartree, portdb, db_keys): - self.root = real_vartree.root - self.settings = real_vartree.settings - mykeys = db_keys[:] - for required_key in ("COUNTER", "SLOT"): - if required_key not in mykeys: - mykeys.append(required_key) - self.dbapi = portage.fakedbapi(settings=real_vartree.settings) - vdb_path = os.path.join(self.root, portage.VDB_PATH) - try: - # At least the parent needs to exist for the lock file. - portage.util.ensure_dirs(vdb_path) - except portage.exception.PortageException: - pass - vdb_lock = None - try: - if os.access(vdb_path, os.W_OK): - vdb_lock = portage.locks.lockdir(vdb_path) - real_dbapi = real_vartree.dbapi - slot_counters = {} - for cpv in real_dbapi.cpv_all(): - metadata = dict(izip(mykeys, real_dbapi.aux_get(cpv, mykeys))) - myslot = metadata["SLOT"] - mycp = portage.dep_getkey(cpv) - myslot_atom = "%s:%s" % (mycp, myslot) - try: - mycounter = long(metadata["COUNTER"]) - except ValueError: - mycounter = 0 - metadata["COUNTER"] = str(mycounter) - other_counter = slot_counters.get(myslot_atom, None) - if other_counter is not None: - if other_counter > mycounter: - continue - slot_counters[myslot_atom] = mycounter - self.dbapi.cpv_inject(cpv, metadata=metadata) - real_dbapi.flush_cache() - finally: - if vdb_lock: - portage.locks.unlockdir(vdb_lock) - # Populate the old-style virtuals using the cached values. - if not self.settings.treeVirtuals: - self.settings.treeVirtuals = portage.util.map_dictlist_vals( - portage.getCPFromCPV, self.get_all_provides()) - - # Intialize variables needed for lazy cache pulls of the live ebuild - # metadata. This ensures that the vardb lock is released ASAP, without - # being delayed in case cache generation is triggered. - self._aux_get = self.dbapi.aux_get - self.dbapi.aux_get = self._aux_get_wrapper - self._aux_get_history = set() - self._portdb_keys = ["DEPEND", "RDEPEND", "PDEPEND"] - self._portdb = portdb - self._global_updates = None - - def _aux_get_wrapper(self, pkg, wants): - if pkg in self._aux_get_history: - return self._aux_get(pkg, wants) - self._aux_get_history.add(pkg) - try: - # Use the live ebuild metadata if possible. - live_metadata = dict(izip(self._portdb_keys, - self._portdb.aux_get(pkg, self._portdb_keys))) - self.dbapi.aux_update(pkg, live_metadata) - except (KeyError, portage.exception.PortageException): - if self._global_updates is None: - self._global_updates = \ - grab_global_updates(self._portdb.porttree_root) - perform_global_updates( - pkg, self.dbapi, self._global_updates) - return self._aux_get(pkg, wants) - -def grab_global_updates(portdir): - from portage.update import grab_updates, parse_updates - updpath = os.path.join(portdir, "profiles", "updates") - try: - rawupdates = grab_updates(updpath) - except portage.exception.DirectoryNotFound: - rawupdates = [] - upd_commands = [] - for mykey, mystat, mycontent in rawupdates: - commands, errors = parse_updates(mycontent) - upd_commands.extend(commands) - return upd_commands - -def perform_global_updates(mycpv, mydb, mycommands): - from portage.update import update_dbentries - aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"] - aux_dict = dict(izip(aux_keys, mydb.aux_get(mycpv, aux_keys))) - updates = update_dbentries(mycommands, aux_dict) - if updates: - mydb.aux_update(mycpv, updates) - -def cpv_sort_descending(cpv_list): - """Sort in place, returns None.""" - if len(cpv_list) <= 1: - return - first_split = portage.catpkgsplit(cpv_list[0]) - cat = first_split[0] - cpv_list[0] = first_split[1:] - for i in xrange(1, len(cpv_list)): - cpv_list[i] = portage.catpkgsplit(cpv_list[i])[1:] - cpv_list.sort(portage.pkgcmp, reverse=True) - for i, (pn, ver, rev) in enumerate(cpv_list): - if rev == "r0": - cpv = cat + "/" + pn + "-" + ver - else: - cpv = cat + "/" + pn + "-" + ver + "-" + rev - cpv_list[i] = cpv - -def visible(pkgsettings, cpv, metadata, built=False, installed=False): - """ - Check if a package is visible. This can raise an InvalidDependString - exception if LICENSE is invalid. - TODO: optionally generate a list of masking reasons - @rtype: Boolean - @returns: True if the package is visible, False otherwise. - """ - if built and not installed and \ - metadata["CHOST"] != pkgsettings["CHOST"]: - return False - if not portage.eapi_is_supported(metadata["EAPI"]): - return False - if pkgsettings.getMissingKeywords(cpv, metadata): - return False - if pkgsettings.getMaskAtom(cpv, metadata): - return False - if pkgsettings.getProfileMaskAtom(cpv, metadata): - return False - if pkgsettings.getMissingLicenses(cpv, metadata): - return False - return True - -def iter_atoms(deps): - """Take a dependency structure as returned by paren_reduce or use_reduce - and iterate over all the atoms.""" - i = iter(deps) - for x in i: - if isinstance(x, basestring): - if x == '||' or x.endswith('?'): - for x in iter_atoms(i.next()): - yield x - else: - yield x - else: - for x in iter_atoms(x): - yield x - -class BlockerCache(DictMixin): - """This caches blockers of installed packages so that dep_check does not - have to be done for every single installed package on every invocation of - emerge. The cache is invalidated whenever it is detected that something - has changed that might alter the results of dep_check() calls: - 1) the set of installed packages (including COUNTER) has changed - 2) the old-style virtuals have changed - """ - class BlockerData(object): - def __init__(self, counter, atoms): - self.counter = counter - self.atoms = atoms - - def __init__(self, myroot, vardb): - self._vardb = vardb - self._installed_pkgs = set(vardb.cpv_all()) - self._virtuals = vardb.settings.getvirtuals() - self._cache_filename = os.path.join(myroot, - portage.CACHE_PATH.lstrip(os.path.sep), "vdb_blockers.pickle") - self._cache_version = "1" - self._cache_data = None - self._modified = False - self._load() - - def _load(self): - try: - f = open(self._cache_filename) - mypickle = cPickle.Unpickler(f) - mypickle.find_global = None - self._cache_data = mypickle.load() - f.close() - del f - except (IOError, OSError, EOFError, cPickle.UnpicklingError): - pass - cache_valid = self._cache_data and \ - isinstance(self._cache_data, dict) and \ - self._cache_data.get("version") == self._cache_version and \ - self._cache_data.get("virtuals") == self._virtuals and \ - set(self._cache_data.get("blockers", [])) == self._installed_pkgs - if cache_valid: - for pkg in self._installed_pkgs: - if long(self._vardb.aux_get(pkg, ["COUNTER"])[0]) != \ - self[pkg].counter: - cache_valid = False - break - if not cache_valid: - self._cache_data = {"version":self._cache_version} - self._cache_data["blockers"] = {} - self._cache_data["virtuals"] = self._virtuals - self._modified = False - - def flush(self): - """If the current user has permission and the internal blocker cache - been updated, save it to disk and mark it unmodified. This is called - by emerge after it has proccessed blockers for all installed packages. - Currently, the cache is only written if the user has superuser - privileges (since that's required to obtain a lock), but all users - have read access and benefit from faster blocker lookups (as long as - the entire cache is still valid). The cache is stored as a pickled - dict object with the following format: - - { - version : "1", - "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...}, - "virtuals" : vardb.settings.getvirtuals() - } - """ - if self._modified and \ - secpass >= 2: - try: - f = portage.util.atomic_ofstream(self._cache_filename) - cPickle.dump(self._cache_data, f, -1) - f.close() - portage.util.apply_secpass_permissions( - self._cache_filename, gid=portage.portage_gid, mode=0644) - except (IOError, OSError), e: - pass - self._modified = False - - def __setitem__(self, cpv, blocker_data): - """ - Update the cache and mark it as modified for a future call to - self.flush(). - - @param cpv: Package for which to cache blockers. - @type cpv: String - @param blocker_data: An object with counter and atoms attributes. - @type blocker_data: BlockerData - """ - self._cache_data["blockers"][cpv] = \ - (blocker_data.counter, blocker_data.atoms) - self._modified = True - - def __getitem__(self, cpv): - """ - @rtype: BlockerData - @returns: An object with counter and atoms attributes. - """ - return self.BlockerData(*self._cache_data["blockers"][cpv]) - - def keys(self): - """This needs to be implemented so that self.__repr__() doesn't raise - an AttributeError.""" - if self._cache_data and "blockers" in self._cache_data: - return self._cache_data["blockers"].keys() - return [] - -def show_invalid_depstring_notice(parent_node, depstring, error_msg): - - from formatter import AbstractFormatter, DumbWriter - f = AbstractFormatter(DumbWriter(maxcol=72)) - - print "\n\n!!! Invalid or corrupt dependency specification: " - print - print error_msg - print - print parent_node - print - print depstring - print - p_type, p_root, p_key, p_status = parent_node - msg = [] - if p_status == "nomerge": - category, pf = portage.catsplit(p_key) - pkg_location = os.path.join(p_root, portage.VDB_PATH, category, pf) - msg.append("Portage is unable to process the dependencies of the ") - msg.append("'%s' package. " % p_key) - msg.append("In order to correct this problem, the package ") - msg.append("should be uninstalled, reinstalled, or upgraded. ") - msg.append("As a temporary workaround, the --nodeps option can ") - msg.append("be used to ignore all dependencies. For reference, ") - msg.append("the problematic dependencies can be found in the ") - msg.append("*DEPEND files located in '%s/'." % pkg_location) - else: - msg.append("This package can not be installed. ") - msg.append("Please notify the '%s' package maintainer " % p_key) - msg.append("about this problem.") - - for x in msg: - f.add_flowing_data(x) - f.end_paragraph(1) - -class depgraph(object): - - pkg_tree_map = { - "ebuild":"porttree", - "binary":"bintree", - "installed":"vartree"} - - _mydbapi_keys = [ - "CHOST", "DEPEND", "EAPI", "IUSE", "KEYWORDS", - "LICENSE", "PDEPEND", "PROVIDE", "RDEPEND", - "repository", "RESTRICT", "SLOT", "USE"] - - _dep_keys = ["DEPEND", "RDEPEND", "PDEPEND"] - - def __init__(self, settings, trees, myopts, myparams, spinner): - self.settings = settings - self.target_root = settings["ROOT"] - self.myopts = myopts - self.myparams = myparams - self.edebug = 0 - if settings.get("PORTAGE_DEBUG", "") == "1": - self.edebug = 1 - self.spinner = spinner - self.pkgsettings = {} - # Maps cpv to digraph node for all nodes added to the graph. - self.pkg_node_map = {} - # Maps slot atom to digraph node for all nodes added to the graph. - self._slot_node_map = {} - # Maps nodes to the reasons they were selected for reinstallation. - self._reinstall_nodes = {} - self.mydbapi = {} - self.trees = {} - self.roots = {} - # Contains a filtered view of preferred packages that are selected - # from available repositories. - self._filtered_trees = {} - for myroot in trees: - self.trees[myroot] = {} - for tree in ("porttree", "bintree"): - self.trees[myroot][tree] = trees[myroot][tree] - self.trees[myroot]["vartree"] = \ - FakeVartree(trees[myroot]["vartree"], - trees[myroot]["porttree"].dbapi, - self._mydbapi_keys) - self.pkgsettings[myroot] = portage.config( - clone=self.trees[myroot]["vartree"].settings) - self.pkg_node_map[myroot] = {} - self._slot_node_map[myroot] = {} - vardb = self.trees[myroot]["vartree"].dbapi - self.roots[myroot] = RootConfig(self.trees[myroot]) - # This fakedbapi instance will model the state that the vdb will - # have after new packages have been installed. - fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot]) - self.mydbapi[myroot] = fakedb - if "--nodeps" not in self.myopts and \ - "--buildpkgonly" not in self.myopts: - # --nodeps bypasses this, since it isn't needed in this case - # and the cache pulls might trigger (slow) cache generation. - for pkg in vardb.cpv_all(): - self.spinner.update() - fakedb.cpv_inject(pkg, - metadata=dict(izip(self._mydbapi_keys, - vardb.aux_get(pkg, self._mydbapi_keys)))) - del vardb, fakedb - self._filtered_trees[myroot] = {} - self._filtered_trees[myroot]["vartree"] = self.trees[myroot]["vartree"] - def filtered_tree(): - pass - filtered_tree.dbapi = portage.fakedbapi( - settings=self.pkgsettings[myroot], exclusive_slots=False) - self._filtered_trees[myroot]["porttree"] = filtered_tree - self._filtered_trees[myroot]["atoms"] = set() - dbs = [] - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - vardb = self.trees[myroot]["vartree"].dbapi - # (db, pkg_type, built, installed, db_keys) - if "--usepkgonly" not in self.myopts: - db_keys = list(portdb._aux_cache_keys) - dbs.append((portdb, "ebuild", False, False, db_keys)) - if "--usepkg" in self.myopts: - db_keys = list(bindb._aux_cache_keys) - dbs.append((bindb, "binary", True, False, db_keys)) - db_keys = self._mydbapi_keys - dbs.append((vardb, "installed", True, True, db_keys)) - self._filtered_trees[myroot]["dbs"] = dbs - if "--usepkg" in self.myopts: - self.trees[myroot]["bintree"].populate( - "--getbinpkg" in self.myopts, - "--getbinpkgonly" in self.myopts) - del trees - - self.missingbins=[] - self.digraph=portage.digraph() - # Tracks simple parent/child relationships (PDEPEND relationships are - # not reversed). - self._parent_child_digraph = digraph() - self.orderedkeys=[] - self.outdatedpackages=[] - # contains all sets added to the graph - self._sets = {} - # contains atoms given as arguments - self._sets["args"] = InternalPackageSet() - # contains all atoms from all sets added to the graph, including - # atoms given as arguments - self._set_atoms = InternalPackageSet() - # contains all nodes pulled in by self._set_atoms - self._set_nodes = set() - self.blocker_digraph = digraph() - self.blocker_parents = {} - self._unresolved_blocker_parents = {} - self._slot_collision_info = [] - # Slot collision nodes are not allowed to block other packages since - # blocker validation is only able to account for one package per slot. - self._slot_collision_nodes = set() - self._altlist_cache = {} - self._pprovided_args = [] - - def _show_slot_collision_notice(self, packages): - """Show an informational message advising the user to mask one of the - the packages. In some cases it may be possible to resolve this - automatically, but support for backtracking (removal nodes that have - already been selected) will be required in order to handle all possible - cases.""" - - msg = [] - msg.append("\n!!! Multiple versions within a single " + \ - "package slot have been \n") - msg.append("!!! pulled into the dependency graph:\n\n") - for node, parents in packages: - msg.append(str(node)) - if parents: - msg.append(" pulled in by\n") - for parent in parents: - msg.append(" ") - msg.append(str(parent)) - msg.append("\n") - else: - msg.append(" (no parents)\n") - msg.append("\n") - sys.stderr.write("".join(msg)) - sys.stderr.flush() - - if "--quiet" in self.myopts: - return - - msg = [] - msg.append("It may be possible to solve this problem ") - msg.append("by using package.mask to prevent one of ") - msg.append("those packages from being selected. ") - msg.append("However, it is also possible that conflicting ") - msg.append("dependencies exist such that they are impossible to ") - msg.append("satisfy simultaneously. If such a conflict exists in ") - msg.append("the dependencies of two different packages, then those ") - msg.append("packages can not be installed simultaneously.") - - from formatter import AbstractFormatter, DumbWriter - f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72)) - for x in msg: - f.add_flowing_data(x) - f.end_paragraph(1) - - msg = [] - msg.append("For more information, see MASKED PACKAGES ") - msg.append("section in the emerge man page or refer ") - msg.append("to the Gentoo Handbook.") - for x in msg: - f.add_flowing_data(x) - f.end_paragraph(1) - f.writer.flush() - - def _reinstall_for_flags(self, forced_flags, - orig_use, orig_iuse, cur_use, cur_iuse): - """Return a set of flags that trigger reinstallation, or None if there - are no such flags.""" - if "--newuse" in self.myopts: - flags = orig_iuse.symmetric_difference( - cur_iuse).difference(forced_flags) - flags.update(orig_iuse.intersection(orig_use).symmetric_difference( - cur_iuse.intersection(cur_use))) - if flags: - return flags - elif "changed-use" == self.myopts.get("--reinstall"): - flags = orig_iuse.intersection(orig_use).symmetric_difference( - cur_iuse.intersection(cur_use)) - if flags: - return flags - return None - - def create(self, mybigkey, myparent=None, addme=1, metadata=None, - priority=DepPriority(), rev_dep=False, arg=None): - """ - Fills the digraph with nodes comprised of packages to merge. - mybigkey is the package spec of the package to merge. - myparent is the package depending on mybigkey ( or None ) - addme = Should we add this package to the digraph or are we just looking at it's deps? - Think --onlydeps, we need to ignore packages in that case. - #stuff to add: - #SLOT-aware emerge - #IUSE-aware emerge -> USE DEP aware depgraph - #"no downgrade" emerge - """ - - # unused parameters - rev_dep = False - - mytype, myroot, mykey = mybigkey - - # select the correct /var database that we'll be checking against - vardbapi = self.trees[myroot]["vartree"].dbapi - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - pkgsettings = self.pkgsettings[myroot] - - # if the package is already on the system, we add a "nomerge" - # directive, otherwise we add a "merge" directive. - - mydbapi = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi - if metadata is None: - metadata = dict(izip(self._mydbapi_keys, - mydbapi.aux_get(mykey, self._mydbapi_keys))) - if mytype == "ebuild": - pkgsettings.setcpv(mykey, mydb=portdb) - metadata["USE"] = pkgsettings["USE"] - myuse = metadata["USE"].split() - - if not arg and myroot == self.target_root: - try: - arg = self._set_atoms.findAtomForPackage(mykey, metadata) - except portage.exception.InvalidDependString, e: - if mytype != "installed": - show_invalid_depstring_notice(tuple(mybigkey+["merge"]), - metadata["PROVIDE"], str(e)) - return 0 - del e - - if "--nodeps" not in self.myopts: - self.spinner.update() - - merging = mytype != "installed" - - if addme and mytype != "installed": - mybigkey.append("merge") - else: - mybigkey.append("nomerge") - jbigkey = tuple(mybigkey) - - if addme: - slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"]) - if merging and \ - "empty" not in self.myparams and \ - vardbapi.match(slot_atom): - # Increase the priority of dependencies on packages that - # are being rebuilt. This optimizes merge order so that - # dependencies are rebuilt/updated as soon as possible, - # which is needed especially when emerge is called by - # revdep-rebuild since dependencies may be affected by ABI - # breakage that has rendered them useless. Don't adjust - # priority here when in "empty" mode since all packages - # are being merged in that case. - priority.rebuild = True - - existing_node = self._slot_node_map[myroot].get( - slot_atom, None) - slot_collision = False - if existing_node: - e_type, myroot, e_cpv, e_status = existing_node - if mykey == e_cpv: - # The existing node can be reused. - if existing_node != myparent: - # Refuse to make a node depend on itself so that - # we don't create a bogus circular dependency - # in self.altlist(). - self._parent_child_digraph.add(existing_node, myparent) - self.digraph.addnode(existing_node, myparent, - priority=priority) - return 1 - else: - if jbigkey in self._slot_collision_nodes: - return 1 - # A slot collision has occurred. Sometimes this coincides - # with unresolvable blockers, so the slot collision will be - # shown later if there are no unresolvable blockers. - e_parents = self._parent_child_digraph.parent_nodes( - existing_node) - myparents = [] - if myparent: - myparents.append(myparent) - self._slot_collision_info.append( - ((jbigkey, myparents), (existing_node, e_parents))) - self._slot_collision_nodes.add(jbigkey) - slot_collision = True - - if slot_collision: - # Now add this node to the graph so that self.display() - # can show use flags and --tree portage.output. This node is - # only being partially added to the graph. It must not be - # allowed to interfere with the other nodes that have been - # added. Do not overwrite data for existing nodes in - # self.pkg_node_map and self.mydbapi since that data will - # be used for blocker validation. - self.pkg_node_map[myroot].setdefault(mykey, jbigkey) - # Even though the graph is now invalid, continue to process - # dependencies so that things like --fetchonly can still - # function despite collisions. - else: - self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata) - self._slot_node_map[myroot][slot_atom] = jbigkey - self.pkg_node_map[myroot][mykey] = jbigkey - - if rev_dep and myparent: - self.digraph.addnode(myparent, jbigkey, - priority=priority) - else: - self.digraph.addnode(jbigkey, myparent, - priority=priority) - - if arg: - self._set_nodes.add(jbigkey) - - # Do this even when addme is False (--onlydeps) so that the - # parent/child relationship is always known in case - # self._show_slot_collision_notice() needs to be called later. - self._parent_child_digraph.add(jbigkey, myparent) - - """ This section determines whether we go deeper into dependencies or not. - We want to go deeper on a few occasions: - Installing package A, we need to make sure package A's deps are met. - emerge --deep ; we need to recursively check dependencies of pkgspec - If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies. - """ - if "deep" not in self.myparams and not merging and \ - not ("--update" in self.myopts and arg and merging): - return 1 - elif "recurse" not in self.myparams: - return 1 - - """ Check DEPEND/RDEPEND/PDEPEND/SLOT - Pull from bintree if it's binary package, porttree if it's ebuild. - Binpkg's can be either remote or local. """ - - edepend={} - depkeys = ["DEPEND","RDEPEND","PDEPEND"] - for k in depkeys: - edepend[k] = metadata[k] - - if mytype == "ebuild": - if "--buildpkgonly" in self.myopts: - edepend["RDEPEND"] = "" - edepend["PDEPEND"] = "" - bdeps_satisfied = False - if mytype in ("installed", "binary"): - if self.myopts.get("--with-bdeps", "n") == "y": - # Pull in build time deps as requested, but marked them as - # "satisfied" since they are not strictly required. This allows - # more freedom in the merge order calculation for solving - # circular dependencies. Don't convert to PDEPEND since that - # could make --with-bdeps=y less effective if it is used to - # adjust merge order to prevent built_with_use() calls from - # failing. - bdeps_satisfied = True - else: - # built packages do not have build time dependencies. - edepend["DEPEND"] = "" - - """ We have retrieve the dependency information, now we need to recursively - process them. DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """ - - mp = tuple(mybigkey) - - try: - if not self.select_dep("/", edepend["DEPEND"], myparent=mp, - myuse=myuse, priority=DepPriority(buildtime=True, - satisfied=bdeps_satisfied), - parent_arg=arg): - return 0 - """RDEPEND is soft by definition. However, in order to ensure - correct merge order, we make it a hard dependency. Otherwise, a - build time dependency might not be usable due to it's run time - dependencies not being installed yet. - """ - if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp, - myuse=myuse, priority=DepPriority(runtime=True), - parent_arg=arg): - 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"], myparent=mp, - myuse=myuse, priority=DepPriority(runtime_post=True), - parent_arg=arg): - return 0 - except ValueError, e: - pkgs = e.args[0] - portage.writemsg("\n\n!!! An atom in the dependencies " + \ - "is not fully-qualified. Multiple matches:\n\n", noiselevel=-1) - for cpv in pkgs: - portage.writemsg(" %s\n" % cpv, noiselevel=-1) - portage.writemsg("\n", noiselevel=-1) - if mytype == "binary": - portage.writemsg( - "!!! This binary package cannot be installed: '%s'\n" % \ - mykey, noiselevel=-1) - elif mytype == "ebuild": - myebuild, mylocation = portdb.findname2(mykey) - portage.writemsg("!!! This ebuild cannot be installed: " + \ - "'%s'\n" % myebuild, noiselevel=-1) - portage.writemsg("!!! Please notify the package maintainer " + \ - "that atoms must be fully-qualified.\n", noiselevel=-1) - 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=[] - myroot = self.target_root - dbs = self._filtered_trees[myroot]["dbs"] - filtered_db = self._filtered_trees[myroot]["porttree"].dbapi - vardb = self.trees[myroot]["vartree"].dbapi - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - pkgsettings = self.pkgsettings[myroot] - arg_atoms = [] - for x in myfiles: - ext = os.path.splitext(x)[1] - if ext==".tbz2": - if not os.path.exists(x): - if os.path.exists( - os.path.join(pkgsettings["PKGDIR"], "All", x)): - x = os.path.join(pkgsettings["PKGDIR"], "All", x) - elif os.path.exists( - os.path.join(pkgsettings["PKGDIR"], x)): - x = os.path.join(pkgsettings["PKGDIR"], x) - else: - print "\n\n!!! Binary package '"+str(x)+"' does not exist." - print "!!! Please ensure the tbz2 exists as specified.\n" - return 0, myfavorites - mytbz2=portage.xpak.tbz2(x) - mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0] - if os.path.realpath(x) != \ - os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)): - print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n") - return 0, myfavorites - if not self.create(["binary", myroot, mykey], - addme=("--onlydeps" not in self.myopts), arg=x): - return (0,myfavorites) - arg_atoms.append((x, "="+mykey)) - elif ext==".ebuild": - ebuild_path = portage.util.normalize_path(os.path.abspath(x)) - pkgdir = os.path.dirname(ebuild_path) - tree_root = os.path.dirname(os.path.dirname(pkgdir)) - cp = pkgdir[len(tree_root)+1:] - e = portage.exception.PackageNotFound( - ("%s is not in a valid portage tree " + \ - "hierarchy or does not exist") % x) - if not portage.isvalidatom(cp): - raise e - cat = portage.catsplit(cp)[0] - mykey = cat + "/" + os.path.basename(ebuild_path[:-7]) - if not portage.isvalidatom("="+mykey): - raise e - ebuild_path = portdb.findname(mykey) - if ebuild_path: - if ebuild_path != os.path.join(os.path.realpath(tree_root), - cp, os.path.basename(ebuild_path)): - print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") - return 0, myfavorites - if mykey not in portdb.xmatch( - "match-visible", portage.dep_getkey(mykey)): - print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use") - print colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man") - print colorize("BAD", "*** page for details.") - countdown(int(self.settings["EMERGE_WARNING_DELAY"]), - "Continuing...") - else: - raise portage.exception.PackageNotFound( - "%s is not in a valid portage tree hierarchy or does not exist" % x) - if not self.create(["ebuild", myroot, mykey], - None, "--onlydeps" not in self.myopts, arg=x): - return (0,myfavorites) - arg_atoms.append((x, "="+mykey)) - else: - if not is_valid_package_atom(x): - portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x, - noiselevel=-1) - portage.writemsg("!!! Please check ebuild(5) for full details.\n") - portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") - return (0,[]) - try: - try: - for db, pkg_type, built, installed, db_keys in dbs: - mykey = portage.dep_expand(x, - mydb=db, settings=pkgsettings) - if portage.dep_getkey(mykey).startswith("null/"): - continue - break - except ValueError, e: - if not e.args or not isinstance(e.args[0], list) or \ - len(e.args[0]) < 2: - raise - mykey = portage.dep_expand(x, - mydb=vardb, settings=pkgsettings) - cp = portage.dep_getkey(mykey) - if cp.startswith("null/") or \ - cp not in e[0]: - raise - del e - arg_atoms.append((x, mykey)) - except ValueError, errpkgs: - if not e.args or not isinstance(e.args[0], list) or \ - len(e.args[0]) < 2: - raise - 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 - return False, myfavorites - - if "--update" in self.myopts: - """Make sure all installed slots are updated when possible. Do this - with --emptytree also, to ensure that all slots are remerged.""" - greedy_atoms = [] - for myarg, atom in arg_atoms: - greedy_atoms.append((myarg, atom)) - mykey = portage.dep_getkey(atom) - myslots = set() - for cpv in vardb.match(mykey): - myslots.add(vardb.aux_get(cpv, ["SLOT"])[0]) - if myslots: - if not self._populate_filtered_repo(myroot, atom, - exclude_installed=True): - return False, myfavorites - mymatches = filtered_db.match(atom) - best_pkg = portage.best(mymatches) - if best_pkg: - best_slot = filtered_db.aux_get(best_pkg, ["SLOT"])[0] - myslots.add(best_slot) - if len(myslots) > 1: - for myslot in myslots: - myslot_atom = "%s:%s" % (mykey, myslot) - if not self._populate_filtered_repo( - myroot, myslot_atom, - exclude_installed=True): - return False, myfavorites - if filtered_db.match(myslot_atom): - greedy_atoms.append((myarg, myslot_atom)) - arg_atoms = greedy_atoms - - # Since populate_filtered_repo() was called with the - # exclude_installed flag, these atoms will need to be processed - # again in case installed packages are required to satisfy - # dependencies. - self._filtered_trees[myroot]["atoms"].clear() - - oneshot = "--oneshot" in self.myopts or \ - "--onlydeps" in self.myopts - """ These are used inside self.create() in order to ensure packages - that happen to match arguments are not incorrectly marked as nomerge.""" - args_set = self._sets["args"] - for myarg, myatom in arg_atoms: - if myatom in args_set: - continue - args_set.add(myatom) - self._set_atoms.add(myatom) - if not oneshot: - myfavorites.append(myatom) - for myarg, myatom in arg_atoms: - try: - self.mysd = self.select_dep(myroot, myatom, arg=myarg) - 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 TAMPERED FILES -- CHECK CAREFULLY.\n") - portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1) - 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 TAMPERED FILES -- CHECK CAREFULLY.\n") - portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1) - sys.exit(1) - except SystemExit, e: - raise # Needed else can't exit - except Exception, e: - print >> sys.stderr, "\n\n!!! Problem in '%s' dependencies." % mykey - print >> sys.stderr, "!!!", str(e), getattr(e, "__module__", None) - raise - - if not self.mysd: - return (0,myfavorites) - - missing=0 - if "--usepkgonly" in self.myopts: - for xs in self.digraph.all_nodes(): - if len(xs) >= 4 and xs[0] != "binary" and xs[3] == "merge": - if missing == 0: - print - missing += 1 - print "Missing binary for:",xs[2] - - if not self.validate_blockers(): - return False, myfavorites - - # We're true here unless we are missing binaries. - return (not missing,myfavorites) - - def _populate_filtered_repo(self, myroot, depstring, - myparent=None, myuse=None, exclude_installed=False): - """Extract all of the atoms from the depstring, select preferred - packages from appropriate repositories, and use them to populate - the filtered repository.""" - - filtered_db = self._filtered_trees[myroot]["porttree"].dbapi - pkgsettings = self.pkgsettings[myroot] - usepkgonly = "--usepkgonly" in self.myopts - if myparent: - p_type, p_root, p_key, p_status = myparent - - from portage.dep import paren_reduce, use_reduce - try: - if myparent and p_type == "installed": - portage.dep._dep_check_strict = False - try: - atoms = paren_reduce(depstring) - atoms = use_reduce(atoms, uselist=myuse) - atoms = list(iter_atoms(atoms)) - for x in atoms: - if portage.dep._dep_check_strict and \ - not portage.isvalidatom(x, allow_blockers=True): - raise portage.exception.InvalidDependString( - "Invalid atom: %s" % x) - except portage.exception.InvalidDependString, e: - if myparent: - show_invalid_depstring_notice( - myparent, depstring, str(e)) - else: - sys.stderr.write("\n%s\n%s\n" % (depstring, str(e))) - return 0 - finally: - portage.dep._dep_check_strict = True - - filtered_atoms = self._filtered_trees[myroot]["atoms"] - dbs = self._filtered_trees[myroot]["dbs"] - old_virts = pkgsettings.getvirtuals() - while atoms: - x = atoms.pop() - if x.startswith("!"): - continue - if x in filtered_atoms: - continue - filtered_atoms.add(x) - cp = portage.dep_getkey(x) - cat = portage.catsplit(cp)[0] - slot = portage.dep.dep_getslot(x) - is_virt = cp.startswith("virtual/") - atom_populated = False - for db, pkg_type, built, installed, db_keys in dbs: - if installed and \ - (exclude_installed or not usepkgonly): - continue - cpv_list = db.cp_list(cp) - if not cpv_list: - if is_virt: - # old-style virtual - # Create a transformed atom for each choice - # and add it to the stack for processing. - for choice in old_virts.get(cp, []): - atoms.append(x.replace(cp, choice)) - # Maybe a new-style virtual exists in another db, so - # we have to try all of them to prevent the old-style - # virtuals from overriding available new-styles. - continue - cpv_sort_descending(cpv_list) - for cpv in cpv_list: - if filtered_db.cpv_exists(cpv): - continue - if not portage.match_from_list(x, [cpv]): - continue - if is_virt: - mykeys = db_keys[:] - mykeys.extend(self._dep_keys) - else: - mykeys = db_keys - try: - metadata = dict(izip(mykeys, - db.aux_get(cpv, mykeys))) - except KeyError: - # masked by corruption - continue - if slot is not None: - if slot != metadata["SLOT"]: - continue - if not built: - if (is_virt or "?" in metadata["LICENSE"]): - pkgsettings.setcpv(cpv, mydb=metadata) - metadata["USE"] = pkgsettings["USE"] - else: - metadata["USE"] = "" - - try: - if not visible(pkgsettings, cpv, metadata, - built=built, installed=installed): - continue - except portage.exception.InvalidDependString: - # masked by corruption - continue - - filtered_db.cpv_inject(cpv, metadata=metadata) - if not is_virt: - # break here since we only want the best version - # for now (eventually will be configurable). - atom_populated = True - break - # For new-style virtuals, we explore all available - # versions and recurse on their deps. This is a - # preparation for the lookahead that happens when - # new-style virtuals are expanded by dep_check(). - virtual_deps = " ".join(metadata[k] \ - for k in self._dep_keys) - try: - if installed: - portage.dep._dep_check_strict = False - try: - deps = paren_reduce(virtual_deps) - deps = use_reduce(deps, - uselist=metadata["USE"].split()) - for y in iter_atoms(deps): - if portage.dep._dep_check_strict and \ - not portage.isvalidatom(y, - allow_blockers=True): - raise portage.exception.InvalidDependString( - "Invalid atom: %s" % y) - atoms.append(y) - except portage.exception.InvalidDependString, e: - show_invalid_depstring_notice( - (pkg_type, myroot, cpv, "nomerge"), - virtual_deps, str(e)) - return 0 - finally: - portage.dep._dep_check_strict = True - if atom_populated: - break - return 1 - - def select_dep(self, myroot, depstring, myparent=None, arg=None, - myuse=None, raise_on_missing=False, priority=DepPriority(), - rev_deps=False, parent_arg=None): - """ Given a depstring, create the depgraph such that all dependencies are satisfied. - myroot = $ROOT from environment, where {R,P}DEPENDs are merged to. - myparent = the node whose depstring is being passed in - arg = package was specified on the command line, merge even if it's already installed - myuse = USE flags at present - raise_on_missing = Given that the depgraph is not proper, raise an exception if true - else continue trying. - return 1 on success, 0 for failure - """ - - if not depstring: - return 1 # nothing to do - - filtered_db = self._filtered_trees[myroot]["porttree"].dbapi - dbs = self._filtered_trees[myroot]["dbs"] - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - vardb = self.trees[myroot]["vartree"].dbapi - pkgsettings = self.pkgsettings[myroot] - if myparent: - p_type, p_root, p_key, p_status = myparent - - if "--debug" in self.myopts: - print - print "Parent: ",myparent - print "Depstring:",depstring - if rev_deps: - print "Reverse:", rev_deps - print "Priority:", priority - - if not self._populate_filtered_repo( - myroot, depstring, myparent=myparent, myuse=myuse): - return 0 - - #processing dependencies - """ Call portage.dep_check to evaluate the use? conditionals and make sure all - dependencies are satisfiable. """ - if arg: - mymerge = [depstring] - pprovided = pkgsettings.pprovideddict.get( - portage.dep_getkey(depstring)) - if pprovided and portage.match_from_list(depstring, pprovided): - mymerge = [] - else: - try: - if myparent and p_type == "installed": - portage.dep._dep_check_strict = False - mycheck = portage.dep_check(depstring, None, - pkgsettings, myuse=myuse, - myroot=myroot, trees=self._filtered_trees) - finally: - portage.dep._dep_check_strict = True - - if not mycheck[0]: - if myparent: - show_invalid_depstring_notice( - myparent, depstring, mycheck[1]) - else: - sys.stderr.write("\n%s\n%s\n" % (depstring, mycheck[1])) - return 0 - mymerge = mycheck[1] - - if not mymerge and arg: - # A provided package has been specified on the command line. The - # package will not be merged and a warning will be displayed. - if depstring in self._set_atoms: - self._pprovided_args.append((arg, depstring)) - - if myparent: - # The parent is added after it's own dep_check call so that it - # isn't allowed to satisfy a direct bootstrap dependency on itself - # via an old-style virtual. This isn't a problem with new-style - # virtuals, which are preferenced in dep_zapdeps by looking only at - # the depstring, vdb, and available packages. - - p_type, p_root, p_key, p_status = myparent - if p_status == "merge": - # Update old-style virtuals if this package provides any. - # These are needed for dep_virtual calls inside dep_check. - p_db = self.mydbapi[p_root] # contains cached metadata - if myparent in self._slot_collision_nodes: - # The metadata isn't cached due to the slot collision. - p_db = self.trees[p_root][self.pkg_tree_map[p_type]].dbapi - try: - self.pkgsettings[p_root].setinst(p_key, p_db) - # For consistency, also update the global virtuals. - settings = self.roots[p_root].settings - settings.unlock() - settings.setinst(p_key, p_db) - settings.lock() - except portage.exception.InvalidDependString, e: - provide = p_db.aux_get(p_key, ["PROVIDE"])[0] - show_invalid_depstring_notice(myparent, provide, str(e)) - del e - return 0 - - if "--debug" in self.myopts: - print "Candidates:",mymerge - for x in mymerge: - selected_pkg = None - if x.startswith("!"): - if "--buildpkgonly" not in self.myopts and \ - "--nodeps" not in self.myopts and \ - myparent not in self._slot_collision_nodes: - p_type, p_root, p_key, p_status = myparent - if p_type != "installed" and p_status != "merge": - # It's safe to ignore blockers from --onlydeps nodes. - continue - self.blocker_parents.setdefault( - ("blocks", p_root, x[1:]), set()).add(myparent) - continue - else: - # List of acceptable packages, ordered by type preference. - matched_packages = [] - existing_node = None - myeb = None - usepkgonly = "--usepkgonly" in self.myopts - empty = "empty" in self.myparams - selective = "selective" in self.myparams - for find_existing_node in True, False: - if existing_node: - break - for db, pkg_type, built, installed, db_keys in dbs: - if existing_node: - break - if installed and not find_existing_node and \ - (matched_packages or empty): - # We only need to select an installed package here - # if there is no other choice. - continue - if hasattr(db, "xmatch"): - cpv_list = db.xmatch("match-all", x) - else: - cpv_list = db.match(x) - cpv_sort_descending(cpv_list) - for cpv in cpv_list: - reinstall_for_flags = None - try: - metadata = dict(izip(db_keys, - db.aux_get(cpv, db_keys))) - except KeyError: - continue - if not built: - if "?" in metadata["LICENSE"]: - pkgsettings.setcpv(cpv, mydb=metadata) - metadata["USE"] = pkgsettings.get("USE","") - else: - metadata["USE"] = "" - if not installed: - try: - if not visible(pkgsettings, cpv, metadata, - built=built, installed=installed): - continue - except portage.exception.InvalidDependString: - # masked by corruption - continue - # At this point, we've found the highest visible - # match from the current repo. Any lower versions - # from this repo are ignored, so this so the loop - # will always end with a break statement below - # this point. - if find_existing_node: - slot_atom = "%s:%s" % ( - portage.cpv_getkey(cpv), metadata["SLOT"]) - existing_node = self._slot_node_map[myroot].get( - slot_atom) - if not existing_node: - break - e_type, myroot, e_cpv, e_status = existing_node - metadata = dict(izip(self._mydbapi_keys, - self.mydbapi[myroot].aux_get( - e_cpv, self._mydbapi_keys))) - cpv_slot = "%s:%s" % (e_cpv, metadata["SLOT"]) - if portage.dep.match_from_list(x, [cpv_slot]): - matched_packages.append( - ([e_type, myroot, e_cpv], metadata)) - else: - existing_node = None - break - # Compare built package to current config and - # reject the built package if necessary. - if built and not installed and \ - ("--newuse" in self.myopts or \ - "--reinstall" in self.myopts): - iuses = set(filter_iuse_defaults( - metadata["IUSE"].split())) - old_use = metadata["USE"].split() - mydb = metadata - if myeb and not usepkgonly: - mydb = portdb - if myeb: - pkgsettings.setcpv(myeb, mydb=mydb) - else: - pkgsettings.setcpv(cpv, mydb=mydb) - now_use = pkgsettings["USE"].split() - forced_flags = set() - forced_flags.update(pkgsettings.useforce) - forced_flags.update(pkgsettings.usemask) - cur_iuse = iuses - if myeb and not usepkgonly: - cur_iuse = set(filter_iuse_defaults( - portdb.aux_get(myeb, - ["IUSE"])[0].split())) - if self._reinstall_for_flags(forced_flags, - old_use, iuses, - now_use, cur_iuse): - break - # Compare current config to installed package - # and do not reinstall if possible. - if not installed and \ - ("--newuse" in self.myopts or \ - "--reinstall" in self.myopts) and \ - vardb.cpv_exists(cpv): - pkgsettings.setcpv(cpv, mydb=metadata) - forced_flags = set() - forced_flags.update(pkgsettings.useforce) - forced_flags.update(pkgsettings.usemask) - old_use = vardb.aux_get(cpv, ["USE"])[0].split() - old_iuse = set(filter_iuse_defaults( - vardb.aux_get(cpv, ["IUSE"])[0].split())) - cur_use = pkgsettings["USE"].split() - cur_iuse = set(filter_iuse_defaults(metadata["IUSE"].split())) - reinstall_for_flags = \ - self._reinstall_for_flags( - forced_flags, old_use, old_iuse, - cur_use, cur_iuse) - myarg = arg - if not myarg and \ - myroot == self.target_root: - try: - myarg = self._set_atoms.findAtomForPackage( - cpv, metadata) - except portage.exception.InvalidDependString, e: - if mytype != "installed": - pkg_node = (pkg_type, myroot, cpv, "merge") - show_invalid_depstring_notice(pkg_node, - metadata["PROVIDE"], str(e)) - return 0 - del e - if not installed and not reinstall_for_flags and \ - ("selective" in self.myparams or \ - not myarg) and \ - "empty" not in self.myparams and \ - vardb.cpv_exists(cpv): - break - if installed and not (selective or not myarg): - break - # Metadata accessed above is cached internally by - # each db in order to optimize visibility checks. - # Now that all possible checks visibility checks - # are complete, it's time to pull the rest of the - # metadata (including *DEPEND). This part is more - # expensive, so avoid it whenever possible. - metadata.update(izip(self._mydbapi_keys, - db.aux_get(cpv, self._mydbapi_keys))) - if not built: - pkgsettings.setcpv(cpv, mydb=metadata) - metadata["USE"] = pkgsettings.get("USE","") - myeb = cpv - matched_packages.append( - ([pkg_type, myroot, cpv], metadata)) - if reinstall_for_flags: - pkg_node = (pkg_type, myroot, cpv, "merge") - self._reinstall_nodes[pkg_node] = \ - reinstall_for_flags - break - - if not matched_packages: - if raise_on_missing: - raise portage.exception.PackageNotFound(x) - if not arg: - xinfo='"'+x+'"' - else: - xinfo='"'+arg+'"' - if myparent: - xfrom = '(dependency required by '+ \ - green('"%s"' % myparent[2]) + \ - red(' [%s]' % myparent[0]) + ')' - masked_packages = [] - missing_licenses = [] - dbs = self._filtered_trees[myroot]["dbs"] - for db, pkg_type, built, installed, db_keys in dbs: - match = db.match - if hasattr(db, "xmatch"): - def match(atom): - return db.xmatch("match-all", atom) - cpv_list = match(x) - cpv_sort_descending(cpv_list) - for cpv in cpv_list: - try: - metadata = dict(izip(db_keys, - db.aux_get(cpv, db_keys))) - except KeyError: - mreasons = ["corruption"] - metadata = None - if metadata and not built: - if "?" in metadata["LICENSE"]: - pkgsettings.setcpv(p, mydb=portdb) - metadata["USE"] = pkgsettings.get("USE", "") - else: - metadata["USE"] = "" - mreasons = portage.getmaskingstatus( - cpv, metadata=metadata, - settings=pkgsettings, portdb=portdb) - comment, filename = None, None - if "package.mask" in mreasons: - comment, filename = \ - portage.getmaskingreason( - cpv, metadata=metadata, - settings=pkgsettings, portdb=portdb, - return_location=True) - if built and \ - metadata["CHOST"] != pkgsettings["CHOST"]: - mreasons.append("CHOST: %s" % \ - metadata["CHOST"]) - missing_licenses = [] - if metadata: - try: - missing_licenses = \ - pkgsettings.getMissingLicenses( - cpv, metadata) - except portage.exception.InvalidDependString: - # This will have already been reported - # above via mreasons. - pass - masked_packages.append((cpv, mreasons, - comment, filename, missing_licenses)) - if masked_packages: - 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:" - shown_licenses = set() - shown_comments = set() - # Maybe there is both an ebuild and a binary. Only - # show one of them to avoid redundant appearance. - shown_cpvs = set() - for cpv, mreasons, comment, filename, missing_licenses in masked_packages: - if cpv in shown_cpvs: - continue - shown_cpvs.add(cpv) - print "- "+cpv+" (masked by: "+", ".join(mreasons)+")" - if comment and comment not in shown_comments: - print filename+":" - print comment - shown_comments.add(comment) - for l in missing_licenses: - l_path = portdb.findLicensePath(l) - if l in shown_licenses: - continue - msg = ("A copy of the '%s' license" + \ - " is located at '%s'.") % (l, l_path) - print msg - print - shown_licenses.add(l) - print - print "For more information, see MASKED PACKAGES section in the emerge man page or " - print "refer to the Gentoo Handbook." - else: - print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"." - if myparent: - print xfrom - print - return 0 - - if "--debug" in self.myopts: - for pkg, metadata in matched_packages: - print (pkg[0] + ":").rjust(10), pkg[2] - - if len(matched_packages) > 1: - bestmatch = portage.best( - [pkg[2] for pkg, metadata in matched_packages]) - matched_packages = [pkg for pkg in matched_packages \ - if pkg[0][2] == bestmatch] - - # ordered by type preference ("ebuild" type is the last resort) - selected_pkg = matched_packages[-1] - - # In some cases, dep_check will return deps that shouldn't - # be proccessed any further, so they are identified and - # discarded here. Try to discard as few as possible since - # discarded dependencies reduce the amount of information - # available for optimization of merge order. - if myparent and not arg and vardb.match(x) and \ - not existing_node and \ - "empty" not in self.myparams and \ - "deep" not in self.myparams and \ - not ("--update" in self.myopts and parent_arg): - (mytype, myroot, mykey), metadata = selected_pkg - myarg = None - if myroot == self.target_root: - try: - myarg = self._set_atoms.findAtomForPackage( - mykey, metadata) - except portage.exception.InvalidDependString: - # This is already handled inside - # self.create() when necessary. - pass - if not myarg: - continue - - if myparent: - #we are a dependency, so we want to be unconditionally added - mypriority = priority.copy() - if vardb.match(x): - mypriority.satisfied = True - if not self.create(selected_pkg[0], myparent=myparent, - metadata=selected_pkg[1], priority=mypriority, - rev_dep=rev_deps, arg=arg): - 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(selected_pkg[0], myparent=myparent, - addme=("--onlydeps" not in self.myopts), - metadata=selected_pkg[1], rev_dep=rev_deps, arg=arg): - return 0 - - if "--debug" in self.myopts: - print "Exiting...",myparent - return 1 - - def validate_blockers(self): - """Remove any blockers from the digraph that do not match any of the - packages within the graph. If necessary, create hard deps to ensure - correct merge order such that mutually blocking packages are never - installed simultaneously.""" - - if "--buildpkgonly" in self.myopts or \ - "--nodeps" in self.myopts: - return True - - modified_slots = {} - for myroot in self.trees: - myslots = {} - modified_slots[myroot] = myslots - final_db = self.mydbapi[myroot] - slot_node_map = self._slot_node_map[myroot] - for slot_atom, mynode in slot_node_map.iteritems(): - mytype, myroot, mycpv, mystatus = mynode - if mystatus == "merge": - myslots[slot_atom] = mycpv - - #if "deep" in self.myparams: - if True: - # Pull in blockers from all installed packages that haven't already - # been pulled into the depgraph. This is not enabled by default - # due to the performance penalty that is incurred by all the - # additional dep_check calls that are required. - - # Optimization hack for dep_check calls that minimizes the - # available matches by replacing the portdb with a fakedbapi - # instance. - class FakePortageTree(object): - def __init__(self, mydb): - self.dbapi = mydb - dep_check_trees = {} - for myroot in self.trees: - dep_check_trees[myroot] = self.trees[myroot].copy() - dep_check_trees[myroot]["porttree"] = \ - FakePortageTree(self.mydbapi[myroot]) - - dep_keys = ["DEPEND","RDEPEND","PDEPEND"] - for myroot in self.trees: - pkg_node_map = self.pkg_node_map[myroot] - vardb = self.trees[myroot]["vartree"].dbapi - portdb = self.trees[myroot]["porttree"].dbapi - pkgsettings = self.pkgsettings[myroot] - final_db = self.mydbapi[myroot] - cpv_all_installed = self.trees[myroot]["vartree"].dbapi.cpv_all() - blocker_cache = BlockerCache(myroot, vardb) - for pkg in cpv_all_installed: - blocker_atoms = None - matching_node = pkg_node_map.get(pkg, None) - if matching_node and \ - matching_node[3] == "nomerge": - continue - # If this node has any blockers, create a "nomerge" - # node for it so that they can be enforced. - self.spinner.update() - blocker_data = blocker_cache.get(pkg) - if blocker_data: - blocker_atoms = blocker_data.atoms - else: - dep_vals = vardb.aux_get(pkg, dep_keys) - myuse = vardb.aux_get(pkg, ["USE"])[0].split() - depstr = " ".join(dep_vals) - # It is crucial to pass in final_db here in order to - # optimize dep_check calls by eliminating atoms via - # dep_wordreduce and dep_eval calls. - try: - portage.dep._dep_check_strict = False - try: - success, atoms = portage.dep_check(depstr, - final_db, pkgsettings, myuse=myuse, - trees=dep_check_trees, myroot=myroot) - except Exception, e: - if isinstance(e, SystemExit): - raise - # This is helpful, for example, if a ValueError - # is thrown from cpv_expand due to multiple - # matches (this can happen if an atom lacks a - # category). - show_invalid_depstring_notice( - ("installed", myroot, pkg, "nomerge"), - depstr, str(e)) - del e - raise - finally: - portage.dep._dep_check_strict = True - if not success: - slot_atom = "%s:%s" % (portage.dep_getkey(pkg), - vardb.aux_get(pkg, ["SLOT"])[0]) - if slot_atom in modified_slots[myroot]: - # This package is being replaced anyway, so - # ignore invalid dependencies so as not to - # annoy the user too much (otherwise they'd be - # forced to manually unmerge it first). - continue - show_invalid_depstring_notice( - ("installed", myroot, pkg, "nomerge"), - depstr, atoms) - return False - blocker_atoms = [myatom for myatom in atoms \ - if myatom.startswith("!")] - counter = long(vardb.aux_get(pkg, ["COUNTER"])[0]) - blocker_cache[pkg] = \ - blocker_cache.BlockerData(counter, blocker_atoms) - if blocker_atoms: - # Don't store this parent in pkg_node_map, because it's - # not needed there and it might overwrite a "merge" - # node with the same cpv. - myparent = ("installed", myroot, pkg, "nomerge") - for myatom in blocker_atoms: - blocker = ("blocks", myroot, myatom[1:]) - myparents = \ - self.blocker_parents.get(blocker, None) - if not myparents: - myparents = set() - self.blocker_parents[blocker] = myparents - myparents.add(myparent) - blocker_cache.flush() - del blocker_cache - - for blocker in self.blocker_parents.keys(): - mytype, myroot, mydep = blocker - initial_db = self.trees[myroot]["vartree"].dbapi - final_db = self.mydbapi[myroot] - blocked_initial = initial_db.match(mydep) - blocked_final = final_db.match(mydep) - if not blocked_initial and not blocked_final: - del self.blocker_parents[blocker] - continue - blocked_slots_initial = {} - blocked_slots_final = {} - for cpv in blocked_initial: - blocked_slots_initial[cpv] = \ - "%s:%s" % (portage.dep_getkey(cpv), - initial_db.aux_get(cpv, ["SLOT"])[0]) - for cpv in blocked_final: - blocked_slots_final[cpv] = \ - "%s:%s" % (portage.dep_getkey(cpv), - final_db.aux_get(cpv, ["SLOT"])[0]) - for parent in list(self.blocker_parents[blocker]): - ptype, proot, pcpv, pstatus = parent - pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi - pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0] - pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot) - parent_static = pslot_atom not in modified_slots[proot] - unresolved_blocks = False - depends_on_order = set() - for cpv in blocked_initial: - slot_atom = blocked_slots_initial[cpv] - if slot_atom == pslot_atom: - # TODO: Support blocks within slots in cases where it - # might make sense. For example, a new version might - # require that the old version be uninstalled at build - # time. - continue - if parent_static and \ - slot_atom not in modified_slots[myroot]: - # This blocker will be handled the next time that a - # merge of either package is triggered. - continue - if pstatus == "merge" and \ - slot_atom in modified_slots[myroot]: - replacement = final_db.match(slot_atom) - if replacement: - if not portage.match_from_list(mydep, replacement): - # Apparently a replacement may be able to - # invalidate this block. - replacement_node = \ - self.pkg_node_map[proot][replacement[0]] - depends_on_order.add((replacement_node, parent)) - continue - # None of the above blocker resolutions techniques apply, - # so apparently this one is unresolvable. - unresolved_blocks = True - for cpv in blocked_final: - slot_atom = blocked_slots_final[cpv] - if slot_atom == pslot_atom: - # TODO: Support blocks within slots. - continue - if parent_static and \ - slot_atom not in modified_slots[myroot]: - # This blocker will be handled the next time that a - # merge of either package is triggered. - continue - if not parent_static and pstatus == "nomerge" and \ - slot_atom in modified_slots[myroot]: - replacement = final_db.match(pslot_atom) - if replacement: - replacement_node = \ - self.pkg_node_map[proot][replacement[0]] - if replacement_node not in \ - self.blocker_parents[blocker]: - # Apparently a replacement may be able to - # invalidate this block. - blocked_node = self.pkg_node_map[proot][cpv] - depends_on_order.add( - (replacement_node, blocked_node)) - continue - # None of the above blocker resolutions techniques apply, - # so apparently this one is unresolvable. - unresolved_blocks = True - if not unresolved_blocks and depends_on_order: - for node, pnode in depends_on_order: - # Enforce correct merge order with a hard dep. - self.digraph.addnode(node, pnode, - priority=DepPriority(buildtime=True)) - # Count references to this blocker so that it can be - # invalidated after nodes referencing it have been - # merged. - self.blocker_digraph.addnode(node, blocker) - if not unresolved_blocks and not depends_on_order: - self.blocker_parents[blocker].remove(parent) - if unresolved_blocks: - self._unresolved_blocker_parents.setdefault( - blocker, set()).add(parent) - if not self.blocker_parents[blocker]: - del self.blocker_parents[blocker] - # Validate blockers that depend on merge order. - if not self.blocker_digraph.empty(): - self.altlist() - if self._slot_collision_info: - # The user is only notified of a slot collision if there are no - # unresolvable blocks. - for x in self.altlist(): - if x[0] == "blocks": - return True - self._show_slot_collision_notice(self._slot_collision_info[0]) - if not self._accept_collisions(): - return False - return True - - def _accept_collisions(self): - acceptable = False - for x in ("--nodeps", "--pretend", "--fetchonly", "--fetch-all-uri"): - if x in self.myopts: - acceptable = True - break - return acceptable - - def _merge_order_bias(self, mygraph): - """Order nodes from highest to lowest overall reference count for - optimal leaf node selection.""" - node_info = {} - for node in mygraph.order: - node_info[node] = len(mygraph.parent_nodes(node)) - def cmp_merge_preference(node1, node2): - return node_info[node2] - node_info[node1] - mygraph.order.sort(cmp_merge_preference) - - def altlist(self, reversed=False): - if reversed in self._altlist_cache: - return self._altlist_cache[reversed][:] - if reversed: - retlist = self.altlist() - retlist.reverse() - self._altlist_cache[reversed] = retlist[:] - return retlist - mygraph=self.digraph.copy() - self._merge_order_bias(mygraph) - myblockers = self.blocker_digraph.copy() - retlist=[] - circular_blocks = False - blocker_deps = None - asap_nodes = [] - portage_node = None - if reversed: - get_nodes = mygraph.root_nodes - else: - get_nodes = mygraph.leaf_nodes - for cpv, node in self.pkg_node_map["/"].iteritems(): - if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]: - portage_node = node - asap_nodes.append(node) - break - ignore_priority_soft_range = [None] - ignore_priority_soft_range.extend( - xrange(DepPriority.MIN, DepPriority.SOFT + 1)) - tree_mode = "--tree" in self.myopts - # Tracks whether or not the current iteration should prefer asap_nodes - # if available. This is set to False when the previous iteration - # failed to select any nodes. It is reset whenever nodes are - # successfully selected. - prefer_asap = True - - # By default, try to avoid selecting root nodes whenever possible. This - # helps ensure that the maximimum possible number of soft dependencies - # have been removed from the graph before their parent nodes have - # selected. This is especially important when those dependencies are - # going to be rebuilt by revdep-rebuild or `emerge -e system` after the - # CHOST has been changed (like when building a stage3 from a stage2). - accept_root_node = False - - # State of prefer_asap and accept_root_node flags for successive - # iterations that loosen the criteria for node selection. - # - # iteration prefer_asap accept_root_node - # 1 True False - # 2 False False - # 3 False True - # - # If no nodes are selected on the 3rd iteration, it is due to - # unresolved blockers or circular dependencies. - - while not mygraph.empty(): - selected_nodes = None - if prefer_asap and asap_nodes: - """ASAP nodes are merged before their soft deps.""" - asap_nodes = [node for node in asap_nodes \ - if mygraph.contains(node)] - for node in asap_nodes: - if not mygraph.child_nodes(node, - ignore_priority=DepPriority.SOFT): - selected_nodes = [node] - asap_nodes.remove(node) - break - if not selected_nodes and \ - not (prefer_asap and asap_nodes): - for ignore_priority in ignore_priority_soft_range: - nodes = get_nodes(ignore_priority=ignore_priority) - if nodes: - break - if nodes: - if ignore_priority is None and not tree_mode: - # Greedily pop all of these nodes since no relationship - # has been ignored. This optimization destroys --tree - # output, so it's disabled in reversed mode. - selected_nodes = nodes - else: - # For optimal merge order: - # * Only pop one node. - # * Removing a root node (node without a parent) - # will not produce a leaf node, so avoid it. - for node in nodes: - if mygraph.parent_nodes(node): - # found a non-root node - selected_nodes = [node] - break - if not selected_nodes and \ - (accept_root_node or ignore_priority is None): - # settle for a root node - selected_nodes = [nodes[0]] - if not selected_nodes: - nodes = get_nodes(ignore_priority=DepPriority.MEDIUM) - if nodes: - """Recursively gather a group of nodes that RDEPEND on - eachother. This ensures that they are merged as a group - and get their RDEPENDs satisfied as soon as possible.""" - def gather_deps(ignore_priority, - mergeable_nodes, selected_nodes, node): - if node in selected_nodes: - return True - if node not in mergeable_nodes: - return False - if node == portage_node and mygraph.child_nodes(node, - ignore_priority=DepPriority.MEDIUM_SOFT): - # Make sure that portage always has all of it's - # RDEPENDs installed first. - return False - selected_nodes.add(node) - for child in mygraph.child_nodes(node, - ignore_priority=ignore_priority): - if not gather_deps(ignore_priority, - mergeable_nodes, selected_nodes, child): - return False - return True - mergeable_nodes = set(nodes) - if prefer_asap and asap_nodes: - nodes = asap_nodes - for ignore_priority in xrange(DepPriority.SOFT, - DepPriority.MEDIUM_SOFT + 1): - for node in nodes: - if nodes is not asap_nodes and \ - not accept_root_node and \ - not mygraph.parent_nodes(node): - continue - selected_nodes = set() - if gather_deps(ignore_priority, - mergeable_nodes, selected_nodes, node): - break - else: - selected_nodes = None - if selected_nodes: - break - - if prefer_asap and asap_nodes and not selected_nodes: - # We failed to find any asap nodes to merge, so ignore - # them for the next iteration. - prefer_asap = False - continue - - if not selected_nodes and not accept_root_node: - # Maybe there are only root nodes left, so accept them - # for the next iteration. - accept_root_node = True - continue - - if selected_nodes and ignore_priority > DepPriority.SOFT: - # Try to merge ignored medium deps as soon as possible. - for node in selected_nodes: - children = set(mygraph.child_nodes(node)) - soft = children.difference( - mygraph.child_nodes(node, - ignore_priority=DepPriority.SOFT)) - medium_soft = children.difference( - mygraph.child_nodes(node, - ignore_priority=DepPriority.MEDIUM_SOFT)) - medium_soft.difference_update(soft) - for child in medium_soft: - if child in selected_nodes: - continue - if child in asap_nodes: - continue - # TODO: Try harder to make these nodes get - # merged absolutely as soon as possible. - asap_nodes.append(child) - - if not selected_nodes: - if not myblockers.is_empty(): - """A blocker couldn't be circumnavigated while keeping all - dependencies satisfied. The user will have to resolve this - manually. This is a panic condition and thus the order - doesn't really matter, so just pop a random node in order - to avoid a circular dependency panic if possible.""" - if not circular_blocks: - circular_blocks = True - blocker_deps = myblockers.leaf_nodes() - while blocker_deps: - # Some of these nodes might have already been selected - # by the normal node selection process after the - # circular_blocks flag has been set. Therefore, we - # have to verify that they're still in the graph so - # that they're not selected more than once. - node = blocker_deps.pop() - if mygraph.contains(node): - selected_nodes = [node] - break - - if not selected_nodes: - # No leaf nodes are available, so we have a circular - # dependency panic situation. Reduce the noise level to a - # minimum via repeated elimination of root nodes since they - # have no parents and thus can not be part of a cycle. - while True: - root_nodes = mygraph.root_nodes( - ignore_priority=DepPriority.SOFT) - if not root_nodes: - break - for node in root_nodes: - mygraph.remove(node) - # Display the USE flags that are enabled on nodes that are part - # of dependency cycles in case that helps the user decide to - # disable some of them. - display_order = [] - tempgraph = mygraph.copy() - while not tempgraph.empty(): - nodes = tempgraph.leaf_nodes() - if not nodes: - node = tempgraph.order[0] - else: - node = nodes[0] - display_order.append(list(node)) - tempgraph.remove(node) - display_order.reverse() - self.myopts.pop("--quiet", None) - self.myopts.pop("--verbose", None) - self.myopts["--tree"] = True - self.display(display_order) - print "!!! Error: circular dependencies:" - print - mygraph.debug_print() - print - print "!!! Note that circular dependencies can often be avoided by temporarily" - print "!!! disabling USE flags that trigger optional dependencies." - sys.exit(1) - - # At this point, we've succeeded in selecting one or more nodes, so - # it's now safe to reset the prefer_asap and accept_root_node flags - # to their default states. - prefer_asap = True - accept_root_node = False - - for node in selected_nodes: - if node[-1] != "nomerge": - retlist.append(list(node)) - mygraph.remove(node) - if not reversed and not circular_blocks and myblockers.contains(node): - """This node may have invalidated one or more blockers.""" - myblockers.remove(node) - for blocker in myblockers.root_nodes(): - if not myblockers.child_nodes(blocker): - myblockers.remove(blocker) - unresolved = \ - self._unresolved_blocker_parents.get(blocker) - if unresolved: - self.blocker_parents[blocker] = unresolved - else: - del self.blocker_parents[blocker] - - if not reversed: - """Blocker validation does not work with reverse mode, - so self.altlist() should first be called with reverse disabled - so that blockers are properly validated.""" - self.blocker_digraph = myblockers - - """ Add any unresolved blocks so that they can be displayed.""" - for blocker in self.blocker_parents: - retlist.append(list(blocker)) - self._altlist_cache[reversed] = retlist[:] - return retlist - - def xcreate(self,mode="system"): - vardb = self.trees[self.target_root]["vartree"].dbapi - filtered_db = self._filtered_trees[self.target_root]["porttree"].dbapi - world_problems = False - - root_config = self.roots[self.target_root] - world_set = root_config.sets["world"] - system_set = root_config.sets["system"] - mylist = list(system_set) - self._sets["system"] = system_set - if mode == "world": - self._sets["world"] = world_set - for x in world_set: - if not portage.isvalidatom(x): - world_problems = True - continue - elif not vardb.match(x): - world_problems = True - if not self._populate_filtered_repo(self.target_root, x, - exclude_installed=True): - return 0 - if not filtered_db.match(x): - continue - mylist.append(x) - - newlist = [] - for atom in mylist: - mykey = portage.dep_getkey(atom) - if True: - newlist.append(atom) - if mode == "system" or atom not in world_set: - # only world is greedy for slots, not system - continue - # Make sure all installed slots are updated when possible. - # Do this with --emptytree also, to ensure that all slots are - # remerged. - myslots = set() - for cpv in vardb.match(mykey): - myslots.add(vardb.aux_get(cpv, ["SLOT"])[0]) - if myslots: - if not self._populate_filtered_repo(self.target_root, atom, - exclude_installed=True): - return 0 - mymatches = filtered_db.match(atom) - best_pkg = portage.best(mymatches) - if best_pkg: - best_slot = filtered_db.aux_get(best_pkg, ["SLOT"])[0] - myslots.add(best_slot) - if len(myslots) > 1: - for myslot in myslots: - myslot_atom = "%s:%s" % (mykey, myslot) - if not self._populate_filtered_repo( - self.target_root, myslot_atom, - exclude_installed=True): - return 0 - if filtered_db.match(myslot_atom): - newlist.append(myslot_atom) - mylist = newlist - - for myatom in mylist: - self._set_atoms.add(myatom) - - # Since populate_filtered_repo() was called with the exclude_installed - # flag, these atoms will need to be processed again in case installed - # packages are required to satisfy dependencies. - self._filtered_trees[self.target_root]["atoms"].clear() - - missing_atoms = [] - for mydep in mylist: - try: - if not self.select_dep( - self.target_root, mydep, raise_on_missing=True, arg=mydep): - print >> sys.stderr, "\n\n!!! Problem resolving dependencies for", mydep - return 0 - except portage.exception.PackageNotFound: - missing_atoms.append(mydep) - - if not self.validate_blockers(): - return False - - if world_problems: - print >> sys.stderr, "\n!!! Problems have been detected with your world file" - print >> sys.stderr, "!!! Please run "+green("emaint --check world")+"\n" - - if missing_atoms: - print >> sys.stderr, "\n" + colorize("BAD", "!!!") + \ - " Ebuilds for the following packages are either all" - print >> sys.stderr, colorize("BAD", "!!!") + " masked or don't exist:" - print >> sys.stderr, " ".join(missing_atoms) + "\n" - - return 1 - - def display(self, mylist, favorites=[], verbosity=None): - if verbosity is None: - verbosity = ("--quiet" in self.myopts and 1 or \ - "--verbose" in self.myopts and 3 or 2) - favorites_set = InternalPackageSet(favorites) - changelogs=[] - p=[] - blockers = [] - - counters = PackageCounters() - - if verbosity == 1 and "--verbose" not in self.myopts: - def create_use_string(*args): - return "" - else: - def create_use_string(name, cur_iuse, iuse_forced, cur_use, - old_iuse, old_use, - is_new, reinst_flags, - all_flags=(verbosity == 3 or "--quiet" in self.myopts), - alphabetical=("--alphabetical" in self.myopts)): - enabled = [] - if alphabetical: - disabled = enabled - removed = enabled - else: - disabled = [] - removed = [] - cur_iuse = set(cur_iuse) - enabled_flags = cur_iuse.intersection(cur_use) - removed_iuse = set(old_iuse).difference(cur_iuse) - any_iuse = cur_iuse.union(old_iuse) - any_iuse = list(any_iuse) - any_iuse.sort() - for flag in any_iuse: - flag_str = None - isEnabled = False - reinst_flag = reinst_flags and flag in reinst_flags - if flag in enabled_flags: - isEnabled = True - if is_new or flag in old_use and \ - (all_flags or reinst_flag): - flag_str = red(flag) - elif flag not in old_iuse: - flag_str = yellow(flag) + "%*" - elif flag not in old_use: - flag_str = green(flag) + "*" - elif flag in removed_iuse: - if all_flags or reinst_flag: - flag_str = yellow("-" + flag) + "%" - if flag in old_use: - flag_str += "*" - flag_str = "(" + flag_str + ")" - removed.append(flag_str) - continue - else: - if is_new or flag in old_iuse and \ - flag not in old_use and \ - (all_flags or reinst_flag): - flag_str = blue("-" + flag) - elif flag not in old_iuse: - flag_str = yellow("-" + flag) - if flag not in iuse_forced: - flag_str += "%" - elif flag in old_use: - flag_str = green("-" + flag) + "*" - if flag_str: - if flag in iuse_forced: - flag_str = "(" + flag_str + ")" - if isEnabled: - enabled.append(flag_str) - else: - disabled.append(flag_str) - - if alphabetical: - ret = " ".join(enabled) - else: - ret = " ".join(enabled + disabled + removed) - if ret: - ret = '%s="%s" ' % (name, ret) - return ret - - repo_display = RepoDisplay(self.roots) - show_repos = False - - tree_nodes = [] - display_list = [] - mygraph = self._parent_child_digraph - i = 0 - depth = 0 - shown_edges = set() - for x in mylist: - if "blocks" == x[0]: - display_list.append((x, 0, True)) - continue - graph_key = tuple(x) - if "--tree" in self.myopts: - depth = len(tree_nodes) - while depth and graph_key not in \ - mygraph.child_nodes(tree_nodes[depth-1]): - depth -= 1 - if depth: - tree_nodes = tree_nodes[:depth] - tree_nodes.append(graph_key) - display_list.append((x, depth, True)) - shown_edges.add((graph_key, tree_nodes[depth-1])) - else: - traversed_nodes = set() # prevent endless circles - traversed_nodes.add(graph_key) - def add_parents(current_node, ordered): - parent_nodes = None - # Do not traverse to parents if this node is an - # an argument or a direct member of a set that has - # been specified as an argument (system or world). - if current_node not in self._set_nodes: - parent_nodes = mygraph.parent_nodes(current_node) - if parent_nodes: - child_nodes = set(mygraph.child_nodes(current_node)) - selected_parent = None - # First, try to avoid a direct cycle. - for node in parent_nodes: - if node not in traversed_nodes and \ - node not in child_nodes: - edge = (current_node, node) - if edge in shown_edges: - continue - selected_parent = node - break - if not selected_parent: - # A direct cycle is unavoidable. - for node in parent_nodes: - if node not in traversed_nodes: - edge = (current_node, node) - if edge in shown_edges: - continue - selected_parent = node - break - if selected_parent: - shown_edges.add((current_node, selected_parent)) - traversed_nodes.add(selected_parent) - add_parents(selected_parent, False) - display_list.append((list(current_node), - len(tree_nodes), ordered)) - tree_nodes.append(current_node) - tree_nodes = [] - add_parents(graph_key, True) - else: - display_list.append((x, depth, True)) - mylist = display_list - - last_merge_depth = 0 - for i in xrange(len(mylist)-1,-1,-1): - graph_key, depth, ordered = mylist[i] - if not ordered and depth == 0 and i > 0 \ - and graph_key == mylist[i-1][0] and \ - mylist[i-1][1] == 0: - # An ordered node got a consecutive duplicate when the tree was - # being filled in. - del mylist[i] - continue - if "blocks" == graph_key[0]: - continue - if ordered and graph_key[-1] != "nomerge": - last_merge_depth = depth - continue - if depth >= last_merge_depth or \ - i < len(mylist) - 1 and \ - depth >= mylist[i+1][1]: - del mylist[i] - - from portage import flatten - from portage.dep import use_reduce, paren_reduce - # files to fetch list - avoids counting a same file twice - # in size display (verbose mode) - myfetchlist=[] - - for mylist_index in xrange(len(mylist)): - x, depth, ordered = mylist[mylist_index] - pkg_node = tuple(x) - pkg_type = x[0] - myroot = x[1] - pkg_key = x[2] - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - vardb = self.trees[myroot]["vartree"].dbapi - vartree = self.trees[myroot]["vartree"] - pkgsettings = self.pkgsettings[myroot] - - fetch=" " - - if x[0]=="blocks": - addl=""+red("B")+" "+fetch+" " - if ordered: - counters.blocks += 1 - resolved = portage.key_expand( - pkg_key, mydb=vardb, settings=pkgsettings) - if "--columns" in self.myopts and "--quiet" in self.myopts: - addl = addl + " " + red(resolved) - else: - addl = "[blocks " + addl + "] " + red(resolved) - block_parents = self.blocker_parents[tuple(x)] - block_parents = set([pnode[2] for pnode in block_parents]) - block_parents = ", ".join(block_parents) - if resolved!=x[2]: - addl += bad(" (\"%s\" is blocking %s)") % \ - (pkg_key, block_parents) - else: - addl += bad(" (is blocking %s)") % block_parents - blockers.append(addl) - else: - pkg_status = x[3] - pkg_merge = ordered and pkg_status != "nomerge" - if pkg_node in self._slot_collision_nodes or \ - (pkg_status == "nomerge" and pkg_type != "installed"): - # The metadata isn't cached due to a slot collision or - # --onlydeps. - mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi - else: - mydbapi = self.mydbapi[myroot] # contains cached metadata - metadata = dict(izip(self._mydbapi_keys, - mydbapi.aux_get(pkg_key, self._mydbapi_keys))) - ebuild_path = None - repo_name = metadata["repository"] - if pkg_type == "ebuild": - ebuild_path = portdb.findname(pkg_key) - if not ebuild_path: # shouldn't happen - raise portage.exception.PackageNotFound(pkg_key) - repo_path_real = os.path.dirname(os.path.dirname( - os.path.dirname(ebuild_path))) - pkgsettings.setcpv(pkg_key, mydb=mydbapi) - metadata["USE"] = pkgsettings["USE"] - else: - repo_path_real = portdb.getRepositoryPath(repo_name) - pkg_use = metadata["USE"].split() - try: - restrict = flatten(use_reduce(paren_reduce( - mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]), - uselist=pkg_use)) - except portage.exception.InvalidDependString, e: - if pkg_status != "nomerge": - restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0] - show_invalid_depstring_notice(x, restrict, str(e)) - del e - return 1 - restrict = [] - if "ebuild" == pkg_type and x[3] != "nomerge" and \ - "fetch" in restrict: - fetch = red("F") - if ordered: - counters.restrict_fetch += 1 - if portdb.fetch_check(pkg_key, pkg_use): - fetch = green("f") - if ordered: - counters.restrict_fetch_satisfied += 1 - - #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="" - installed_versions = vardb.match(portage.cpv_getkey(pkg_key)) - if vardb.cpv_exists(pkg_key): - addl=" "+yellow("R")+fetch+" " - if x[3] != "nomerge": - if ordered: - counters.reinst += 1 - # filter out old-style virtual matches - elif installed_versions and \ - portage.cpv_getkey(installed_versions[0]) == \ - portage.cpv_getkey(pkg_key): - mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0] - slot_atom = "%s:%s" % \ - (portage.cpv_getkey(pkg_key), mynewslot) - myinslotlist = vardb.match(slot_atom) - # If this is the first install of a new-style virtual, we - # need to filter out old-style virtual matches. - if myinslotlist and \ - portage.cpv_getkey(myinslotlist[0]) != \ - portage.cpv_getkey(pkg_key): - myinslotlist = None - 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") - if ordered: - counters.downgrades += 1 - else: - # Update in slot - addl+=turquoise("U")+" " - if ordered: - counters.upgrades += 1 - else: - # New slot, mark it new. - addl=" "+green("NS")+fetch+" " - if ordered: - counters.newslot += 1 - - if "--changelog" in self.myopts: - slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key), - mydbapi.aux_get(pkg_key, ["SLOT"])[0]) - inst_matches = vardb.match(slot_atom) - if inst_matches: - changelogs.extend(self.calc_changelog( - portdb.findname(pkg_key), - inst_matches[0], pkg_key)) - else: - addl=" "+green("N")+" "+fetch+" " - if ordered: - counters.new += 1 - - verboseadd="" - - if True: - # USE flag display - cur_iuse = list(filter_iuse_defaults( - mydbapi.aux_get(pkg_key, ["IUSE"])[0].split())) - - forced_flags = set() - pkgsettings.setcpv(pkg_key, mydb=mydbapi) # for package.use.{mask,force} - forced_flags.update(pkgsettings.useforce) - forced_flags.update(pkgsettings.usemask) - - cur_iuse = portage.unique_array(cur_iuse) - cur_iuse.sort() - cur_use = pkg_use - cur_use = [flag for flag in cur_use if flag in cur_iuse] - - if myoldbest: - pkg = myoldbest - else: - pkg = x[2] - if self.trees[x[1]]["vartree"].dbapi.cpv_exists(pkg): - old_iuse, old_use = \ - self.trees[x[1]]["vartree"].dbapi.aux_get( - pkg, ["IUSE", "USE"]) - old_iuse = list(set( - filter_iuse_defaults(old_iuse.split()))) - old_iuse.sort() - old_use = old_use.split() - is_new = False - else: - old_iuse = [] - old_use = [] - is_new = True - - old_use = [flag for flag in old_use if flag in old_iuse] - - use_expand = pkgsettings["USE_EXPAND"].lower().split() - use_expand.sort() - use_expand.reverse() - use_expand_hidden = \ - pkgsettings["USE_EXPAND_HIDDEN"].lower().split() - - def map_to_use_expand(myvals, forcedFlags=False, - removeHidden=True): - ret = {} - forced = {} - for exp in use_expand: - ret[exp] = [] - forced[exp] = set() - for val in myvals[:]: - if val.startswith(exp.lower()+"_"): - if val in forced_flags: - forced[exp].add(val[len(exp)+1:]) - ret[exp].append(val[len(exp)+1:]) - myvals.remove(val) - ret["USE"] = myvals - forced["USE"] = [val for val in myvals \ - if val in forced_flags] - if removeHidden: - for exp in use_expand_hidden: - ret.pop(exp, None) - if forcedFlags: - return ret, forced - return ret - - # Prevent USE_EXPAND_HIDDEN flags from being hidden if they - # are the only thing that triggered reinstallation. - reinst_flags_map = {} - reinstall_for_flags = self._reinstall_nodes.get(pkg_node) - reinst_expand_map = None - if reinstall_for_flags: - reinst_flags_map = map_to_use_expand( - list(reinstall_for_flags), removeHidden=False) - for k in list(reinst_flags_map): - if not reinst_flags_map[k]: - del reinst_flags_map[k] - if not reinst_flags_map.get("USE"): - reinst_expand_map = reinst_flags_map.copy() - reinst_expand_map.pop("USE", None) - if reinst_expand_map and \ - not set(reinst_expand_map).difference( - use_expand_hidden): - use_expand_hidden = \ - set(use_expand_hidden).difference( - reinst_expand_map) - - cur_iuse_map, iuse_forced = \ - map_to_use_expand(cur_iuse, forcedFlags=True) - 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: - if key in use_expand_hidden: - continue - verboseadd += create_use_string(key.upper(), - cur_iuse_map[key], iuse_forced[key], - cur_use_map[key], old_iuse_map[key], - old_use_map[key], is_new, - reinst_flags_map.get(key)) - - if verbosity == 3: - # size verbose - mysize=0 - if pkg_type == "ebuild" and pkg_merge: - try: - myfilesdict = portdb.getfetchsizes(pkg_key, - useflags=pkg_use, debug=self.edebug) - except portage.exception.InvalidDependString, e: - src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0] - show_invalid_depstring_notice(x, src_uri, str(e)) - del e - return 1 - if myfilesdict is None: - myfilesdict="[empty/missing/bad digest]" - else: - for myfetchfile in myfilesdict: - if myfetchfile not in myfetchlist: - mysize+=myfilesdict[myfetchfile] - myfetchlist.append(myfetchfile) - counters.totalsize += mysize - verboseadd+=format_size(mysize)+" " - - # overlay verbose - # assign index for a previous version in the same slot - has_previous = False - repo_name_prev = None - slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key), - metadata["SLOT"]) - slot_matches = vardb.match(slot_atom) - if slot_matches: - has_previous = True - repo_name_prev = vardb.aux_get(slot_matches[0], - ["repository"])[0] - - # now use the data to generate output - repoadd = None - if pkg_status == "nomerge" or not has_previous: - repoadd = repo_display.repoStr(repo_path_real) - else: - repo_path_prev = None - if repo_name_prev: - repo_path_prev = portdb.getRepositoryPath( - repo_name_prev) - # To avoid spam during the transition period, don't - # show ? if the installed package is missing a - # repository label. - if not repo_path_prev or \ - repo_path_prev == repo_path_real: - repoadd = repo_display.repoStr(repo_path_real) - else: - repoadd = "%s=>%s" % ( - repo_display.repoStr(repo_path_prev), - repo_display.repoStr(repo_path_real)) - if repoadd and repoadd != "0": - show_repos = True - verboseadd += teal("[%s]" % repoadd) - - xs = list(portage.pkgsplit(x[2])) - if xs[2]=="r0": - xs[2]="" - else: - xs[2]="-"+xs[2] - - mywidth = 130 - if "COLUMNWIDTH" in self.settings: - try: - mywidth = int(self.settings["COLUMNWIDTH"]) - except ValueError, e: - portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) - portage.writemsg( - "!!! Unable to parse COLUMNWIDTH='%s'\n" % \ - self.settings["COLUMNWIDTH"], noiselevel=-1) - del e - oldlp=mywidth-30 - newlp=oldlp-30 - - indent = " " * depth - - if myoldbest: - myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] - if myoldbest[-3:]=="-r0": - myoldbest=myoldbest[:-3] - myoldbest=blue("["+myoldbest+"]") - - pkg_cp = xs[0] - root_config = self.roots[myroot] - system_set = root_config.sets["system"] - world_set = root_config.sets["world"] - - pkg_system = False - pkg_world = False - try: - pkg_system = system_set.findAtomForPackage(pkg_key, metadata) - pkg_world = world_set.findAtomForPackage(pkg_key, metadata) - if not pkg_world and myroot == self.target_root and \ - favorites_set.findAtomForPackage(pkg_key, metadata): - # Maybe it will be added to world now. - if create_world_atom(pkg_key, metadata, - favorites_set, root_config): - pkg_world = True - except portage.exception.InvalidDependString: - # This is reported elsewhere if relevant. - pass - - def pkgprint(pkg): - if pkg_merge: - if pkg_system: - return colorize("PKG_MERGE_SYSTEM", pkg) - elif pkg_world: - return colorize("PKG_MERGE_WORLD", pkg) - else: - return colorize("PKG_MERGE", pkg) - else: - if pkg_system: - return colorize("PKG_NOMERGE_SYSTEM", pkg) - elif pkg_world: - return colorize("PKG_NOMERGE_WORLD", pkg) - else: - return colorize("PKG_NOMERGE", pkg) - - if x[1]!="/": - if myoldbest: - myoldbest +=" " - if "--columns" in self.myopts: - if "--quiet" in self.myopts: - myprint=addl+" "+indent+pkgprint(pkg_cp) - myprint=myprint+darkblue(" "+xs[1]+xs[2])+" " - myprint=myprint+myoldbest - myprint=myprint+darkgreen("to "+x[1]) - else: - myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp) - 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: - if not pkg_merge: - myprint = "[%s ] " % pkgprint("nomerge") - else: - myprint = "[" + pkg_type + " " + addl + "] " - myprint += indent + pkgprint(pkg_key) + " " + \ - myoldbest + darkgreen("to " + myroot) + " " + \ - verboseadd - else: - if "--columns" in self.myopts: - if "--quiet" in self.myopts: - myprint=addl+" "+indent+pkgprint(pkg_cp) - myprint=myprint+" "+green(xs[1]+xs[2])+" " - myprint=myprint+myoldbest - else: - myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp) - 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 not pkg_merge: - myprint="["+pkgprint("nomerge")+" ] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd - else: - myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd - p.append(myprint) - - mysplit = portage.pkgsplit(x[2]) - if "--tree" not in self.myopts and mysplit and \ - len(mysplit) == 3 and mysplit[0] == "sys-apps/portage" and \ - x[1] == "/": - - if mysplit[2] == "r0": - myversion = mysplit[1] - else: - myversion = "%s-%s" % (mysplit[1], mysplit[2]) - - if myversion != portage.VERSION and "--quiet" not in self.myopts: - if mylist_index < len(mylist) - 1 and \ - "livecvsportage" not in self.settings.features: - p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,")) - p.append(colorize("WARN", " then resume the merge.")) - print - del mysplit - - for x in p: - print x - for x in blockers: - print x - - if verbosity == 3: - print - print counters - if show_repos: - sys.stdout.write(str(repo_display)) - - if "--changelog" in self.myopts: - print - for revision,text in changelogs: - print bold('*'+revision) - sys.stdout.write(text) - - if self._pprovided_args: - arg_refs = {} - for arg_atom in self._pprovided_args: - arg, atom = arg_atom - arg_refs[arg_atom] = [] - cp = portage.dep_getkey(atom) - for set_name, atom_set in self._sets.iteritems(): - if atom in atom_set: - arg_refs[arg_atom].append(set_name) - msg = [] - msg.append(bad("\nWARNING: ")) - if len(self._pprovided_args) > 1: - msg.append("Requested packages will not be " + \ - "merged because they are listed in\n") - else: - msg.append("A requested package will not be " + \ - "merged because it is listed in\n") - msg.append("package.provided:\n\n") - problems_sets = set() - for (arg, atom), refs in arg_refs.iteritems(): - ref_string = "" - if refs: - problems_sets.update(refs) - refs.sort() - ref_string = ", ".join(["'%s'" % name for name in refs]) - ref_string = " pulled in by " + ref_string - msg.append(" %s%s\n" % (colorize("INFORM", arg), ref_string)) - msg.append("\n") - if "world" in problems_sets: - msg.append("This problem can be solved in one of the following ways:\n\n") - msg.append(" A) Use emaint to clean offending packages from world (if not installed).\n") - msg.append(" B) Uninstall offending packages (cleans them from world).\n") - msg.append(" C) Remove offending entries from package.provided.\n\n") - msg.append("The best course of action depends on the reason that an offending\n") - msg.append("package.provided entry exists.\n\n") - sys.stderr.write("".join(msg)) - return os.EX_OK - - def calc_changelog(self,ebuildpath,current,next): - if ebuildpath == None or not os.path.exists(ebuildpath): - return [] - current = '-'.join(portage.catpkgsplit(current)[1:]) - if current.endswith('-r0'): - current = current[:-3] - next = '-'.join(portage.catpkgsplit(next)[1:]) - if next.endswith('-r0'): - next = next[:-3] - changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') - try: - changelog = open(changelogpath).read() - except SystemExit, e: - raise # Needed else can't exit - except: - return [] - divisions = self.find_changelog_tags(changelog) - #print 'XX from',current,'to',next - #for div,text in divisions: print 'XX',div - # skip entries for all revisions above the one we are about to emerge - for i in range(len(divisions)): - if divisions[i][0]==next: - divisions = divisions[i:] - break - # find out how many entries we are going to display - for i in range(len(divisions)): - if divisions[i][0]==current: - divisions = divisions[:i] - break - else: - # couldnt find the current revision in the list. display nothing - return [] - return divisions - - def find_changelog_tags(self,changelog): - divs = [] - release = None - while 1: - match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M) - if match is None: - if release is not None: - divs.append((release,changelog)) - return divs - if release is not None: - divs.append((release,changelog[:match.start()])) - changelog = changelog[match.end():] - release = match.group(1) - if release.endswith('.ebuild'): - release = release[:-7] - if release.endswith('-r0'): - release = release[:-3] - - def saveNomergeFavorites(self): - """Find atoms in favorites that are not in the mergelist and add them - to the world file if necessary.""" - for x in ("--fetchonly", "--fetch-all-uri", - "--oneshot", "--onlydeps", "--pretend"): - if x in self.myopts: - return - root_config = self.roots[self.target_root] - world_set = root_config.sets["world"] - world_set.lock() - world_set.load() # maybe it's changed on disk - args_set = self._sets["args"] - portdb = self.trees[self.target_root]["porttree"].dbapi - added_favorites = set() - for x in self._set_nodes: - pkg_type, root, pkg_key, pkg_status = x - if pkg_status != "nomerge": - continue - metadata = dict(izip(self._mydbapi_keys, - self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys))) - try: - myfavkey = create_world_atom(pkg_key, metadata, - args_set, root_config) - if myfavkey: - if myfavkey in added_favorites: - continue - added_favorites.add(myfavkey) - world_set.add(myfavkey) - print ">>> Recording",myfavkey,"in \"world\" favorites file..." - except portage.exception.InvalidDependString, e: - writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \ - (pkg_key, str(e)), noiselevel=-1) - writemsg("!!! see '%s'\n\n" % os.path.join( - root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1) - del e - world_set.unlock() - - def loadResumeCommand(self, resume_data): - """ - Add a resume command to the graph and validate it in the process. This - will raise a PackageNotFound exception if a package is not available. - """ - self._sets["args"].update(resume_data.get("favorites", [])) - mergelist = resume_data.get("mergelist", []) - fakedb = self.mydbapi - trees = self.trees - for x in mergelist: - if len(x) != 4: - continue - pkg_type, myroot, pkg_key, action = x - if pkg_type not in self.pkg_tree_map: - continue - if action != "merge": - continue - mydb = trees[myroot][self.pkg_tree_map[pkg_type]].dbapi - try: - metadata = dict(izip(self._mydbapi_keys, - mydb.aux_get(pkg_key, self._mydbapi_keys))) - except KeyError: - # It does no exist or it is corrupt. - raise portage.exception.PackageNotFound(pkg_key) - fakedb[myroot].cpv_inject(pkg_key, metadata=metadata) - if pkg_type == "ebuild": - pkgsettings = self.pkgsettings[myroot] - pkgsettings.setcpv(pkg_key, mydb=fakedb[myroot]) - fakedb[myroot].aux_update(pkg_key, {"USE":pkgsettings["USE"]}) - self.spinner.update() - -class RepoDisplay(object): - def __init__(self, roots): - self._shown_repos = {} - self._unknown_repo = False - repo_paths = set() - for root_config in roots.itervalues(): - portdir = root_config.settings.get("PORTDIR") - if portdir: - repo_paths.add(portdir) - overlays = root_config.settings.get("PORTDIR_OVERLAY") - if overlays: - repo_paths.update(overlays.split()) - repo_paths = list(repo_paths) - self._repo_paths = repo_paths - self._repo_paths_real = [ os.path.realpath(repo_path) \ - for repo_path in repo_paths ] - - # pre-allocate index for PORTDIR so that it always has index 0. - for root_config in roots.itervalues(): - portdb = root_config.trees["porttree"].dbapi - portdir = portdb.porttree_root - if portdir: - self.repoStr(portdir) - - def repoStr(self, repo_path_real): - real_index = -1 - if repo_path_real: - real_index = self._repo_paths_real.index(repo_path_real) - if real_index == -1: - s = "?" - self._unknown_repo = True - else: - shown_repos = self._shown_repos - repo_paths = self._repo_paths - repo_path = repo_paths[real_index] - index = shown_repos.get(repo_path) - if index is None: - index = len(shown_repos) - shown_repos[repo_path] = index - s = str(index) - return s - - def __str__(self): - output = [] - shown_repos = self._shown_repos - unknown_repo = self._unknown_repo - if shown_repos or self._unknown_repo: - output.append("Portage tree and overlays:\n") - show_repo_paths = list(shown_repos) - for repo_path, repo_index in shown_repos.iteritems(): - show_repo_paths[repo_index] = repo_path - if show_repo_paths: - for index, repo_path in enumerate(show_repo_paths): - output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path) - if unknown_repo: - output.append(" "+teal("[?]") + \ - " indicates that the source repository could not be determined\n") - return "".join(output) - -class PackageCounters(object): - - def __init__(self): - self.upgrades = 0 - self.downgrades = 0 - self.new = 0 - self.newslot = 0 - self.reinst = 0 - self.blocks = 0 - self.totalsize = 0 - self.restrict_fetch = 0 - self.restrict_fetch_satisfied = 0 - - def __str__(self): - total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst - myoutput = [] - details = [] - myoutput.append("Total: %s package" % total_installs) - if total_installs != 1: - myoutput.append("s") - if total_installs != 0: - myoutput.append(" (") - if self.upgrades > 0: - details.append("%s upgrade" % self.upgrades) - if self.upgrades > 1: - details[-1] += "s" - if self.downgrades > 0: - details.append("%s downgrade" % self.downgrades) - if self.downgrades > 1: - details[-1] += "s" - if self.new > 0: - details.append("%s new" % self.new) - if self.newslot > 0: - details.append("%s in new slot" % self.newslot) - if self.newslot > 1: - details[-1] += "s" - if self.reinst > 0: - details.append("%s reinstall" % self.reinst) - if self.reinst > 1: - details[-1] += "s" - if self.blocks > 0: - details.append("%s block" % self.blocks) - if self.blocks > 1: - details[-1] += "s" - myoutput.append(", ".join(details)) - if total_installs != 0: - myoutput.append(")") - myoutput.append(", Size of downloads: %s" % format_size(self.totalsize)) - if self.restrict_fetch: - myoutput.append("\nFetch Restriction: %s package" % \ - self.restrict_fetch) - if self.restrict_fetch > 1: - myoutput.append("s") - if self.restrict_fetch_satisfied < self.restrict_fetch: - myoutput.append(bad(" (%s unsatisfied)") % \ - (self.restrict_fetch - self.restrict_fetch_satisfied)) - return "".join(myoutput) - -class MergeTask(object): - - def __init__(self, settings, trees, myopts): - self.settings = settings - self.target_root = settings["ROOT"] - self.trees = trees - self.myopts = myopts - self.edebug = 0 - if settings.get("PORTAGE_DEBUG", "") == "1": - self.edebug = 1 - self.pkgsettings = {} - self.pkgsettings[self.target_root] = portage.config(clone=settings) - if self.target_root != "/": - self.pkgsettings["/"] = \ - portage.config(clone=trees["/"]["vartree"].settings) - self.curval = 0 - - def merge(self, mylist, favorites, mtimedb): - from portage.elog import elog_process - from portage.elog.filtering import filter_mergephases - failed_fetches = [] - fetchonly = "--fetchonly" in self.myopts or \ - "--fetch-all-uri" in self.myopts - pretend = "--pretend" in self.myopts - mymergelist=[] - ldpath_mtimes = mtimedb["ldpath"] - xterm_titles = "notitles" not in self.settings.features - - #check for blocking dependencies - if "--fetchonly" not in self.myopts and \ - "--fetch-all-uri" not in self.myopts and \ - "--buildpkgonly" not in self.myopts: - for x in mylist: - if x[0]=="blocks": - print "\n!!! Error: the "+x[2]+" package conflicts with another package;" - print "!!! the two packages cannot be installed on the same system together." - print "!!! Please use 'emerge --pretend' to determine blockers." - if "--quiet" not in self.myopts: - show_blocker_docs_link() - return 1 - - if "--resume" in self.myopts: - # We're resuming. - print colorize("GOOD", "*** Resuming merge...") - emergelog(xterm_titles, " *** Resuming merge...") - mylist = mtimedb["resume"]["mergelist"][:] - if "--skipfirst" in self.myopts and mylist: - del mtimedb["resume"]["mergelist"][0] - del mylist[0] - mtimedb.commit() - mymergelist = mylist - - # Verify all the manifests now so that the user is notified of failure - # as soon as possible. - if "--fetchonly" not in self.myopts and \ - "--fetch-all-uri" not in self.myopts and \ - "strict" in self.settings.features: - shown_verifying_msg = False - quiet_settings = {} - for myroot, pkgsettings in self.pkgsettings.iteritems(): - quiet_config = portage.config(clone=pkgsettings) - quiet_config["PORTAGE_QUIET"] = "1" - quiet_config.backup_changes("PORTAGE_QUIET") - quiet_settings[myroot] = quiet_config - del quiet_config - for x in mylist: - if x[0] != "ebuild" or x[-1] == "nomerge": - continue - if not shown_verifying_msg: - shown_verifying_msg = True - print ">>> Verifying ebuild Manifests..." - mytype, myroot, mycpv, mystatus = x - portdb = self.trees[myroot]["porttree"].dbapi - quiet_config = quiet_settings[myroot] - quiet_config["O"] = os.path.dirname(portdb.findname(mycpv)) - if not portage.digestcheck([], quiet_config, strict=True): - return 1 - del x, mytype, myroot, mycpv, mystatus, quiet_config - del shown_verifying_msg, quiet_settings - - root_config = RootConfig(self.trees[self.target_root]) - system_set = root_config.sets["system"] - args_set = InternalPackageSet(favorites) - world_set = root_config.sets["world"] - if "--resume" not in self.myopts: - mymergelist = mylist - mtimedb["resume"]["mergelist"]=mymergelist[:] - mtimedb.commit() - - myfeat = self.settings.features[:] - bad_resume_opts = set(["--ask", "--tree", "--changelog", "--skipfirst", - "--resume"]) - if "parallel-fetch" in myfeat and \ - not ("--pretend" in self.myopts or \ - "--fetch-all-uri" in self.myopts or \ - "--fetchonly" in self.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" - fetch_log = "/var/log/emerge-fetch.log" - logfile = open(fetch_log, "w") - fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()} - portage.util.apply_secpass_permissions(fetch_log, - uid=portage.portage_uid, gid=portage.portage_gid, - mode=0660) - fetch_env = os.environ.copy() - fetch_env["FEATURES"] = fetch_env.get("FEATURES", "") + " -cvs" - fetch_env["PORTAGE_NICENESS"] = "0" - fetch_args = [sys.argv[0], "--resume", "--fetchonly"] - resume_opts = self.myopts.copy() - # For automatic resume, we need to prevent - # any of bad_resume_opts from leaking in - # via EMERGE_DEFAULT_OPTS. - resume_opts["--ignore-default-opts"] = True - for myopt, myarg in resume_opts.iteritems(): - if myopt not in bad_resume_opts: - if myarg is True: - fetch_args.append(myopt) - else: - fetch_args.append(myopt +"="+ myarg) - portage.process.spawn(fetch_args, env=fetch_env, - fd_pipes=fd_pipes, returnpid=True) - logfile.close() # belongs to the spawned process - del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \ - resume_opts - - metadata_keys = [k for k in portage.auxdbkeys \ - if not k.startswith("UNUSED_")] + ["USE"] - - mergecount=0 - for x in mymergelist: - mergecount+=1 - pkg_type = x[0] - myroot=x[1] - pkg_key = x[2] - pkgindex=2 - portdb = self.trees[myroot]["porttree"].dbapi - bindb = self.trees[myroot]["bintree"].dbapi - vartree = self.trees[myroot]["vartree"] - pkgsettings = self.pkgsettings[myroot] - metadata = {} - if pkg_type == "blocks": - pass - elif pkg_type == "ebuild": - mydbapi = portdb - metadata.update(izip(metadata_keys, - mydbapi.aux_get(pkg_key, metadata_keys))) - pkgsettings.setcpv(pkg_key, mydb=mydbapi) - metadata["USE"] = pkgsettings["USE"] - else: - if pkg_type == "binary": - mydbapi = bindb - else: - raise AssertionError("Package type: '%s'" % pkg_type) - metadata.update(izip(metadata_keys, - mydbapi.aux_get(pkg_key, metadata_keys))) - if x[0]=="blocks": - pkgindex=3 - y = portdb.findname(pkg_key) - if "--pretend" not in self.myopts: - print "\n>>> Emerging (" + \ - colorize("MERGE_LIST_PROGRESS", str(mergecount)) + " of " + \ - colorize("MERGE_LIST_PROGRESS", str(len(mymergelist))) + ") " + \ - colorize("GOOD", x[pkgindex]) + " to " + x[1] - emergelog(xterm_titles, " >>> emerge ("+\ - str(mergecount)+" of "+str(len(mymergelist))+\ - ") "+x[pkgindex]+" to "+x[1]) - - pkgsettings["EMERGE_FROM"] = x[0] - pkgsettings.backup_changes("EMERGE_FROM") - pkgsettings.reset() - - #buildsyspkg: Check if we need to _force_ binary package creation - issyspkg = ("buildsyspkg" in myfeat) \ - and x[0] != "blocks" \ - and system_set.findAtomForPackage(pkg_key, metadata) \ - and "--buildpkg" not in self.myopts - if x[0] in ["ebuild","blocks"]: - if x[0] == "blocks" and "--fetchonly" not in self.myopts: - raise Exception, "Merging a blocker" - elif "--fetchonly" in self.myopts or \ - "--fetch-all-uri" in self.myopts: - if "--fetch-all-uri" in self.myopts: - retval = portage.doebuild(y, "fetch", myroot, - pkgsettings, self.edebug, - "--pretend" in self.myopts, fetchonly=1, - fetchall=1, mydbapi=portdb, tree="porttree") - else: - retval = portage.doebuild(y, "fetch", myroot, - pkgsettings, self.edebug, - "--pretend" in self.myopts, fetchonly=1, - mydbapi=portdb, tree="porttree") - if (retval is None) or retval: - print - print "!!! Fetch for",y,"failed, continuing..." - print - failed_fetches.append(pkg_key) - self.curval += 1 - continue - - portage.doebuild_environment(y, "setup", myroot, - pkgsettings, self.edebug, 1, portdb) - catdir = os.path.dirname(pkgsettings["PORTAGE_BUILDDIR"]) - portage.util.ensure_dirs(os.path.dirname(catdir), - uid=portage.portage_uid, gid=portage.portage_gid, - mode=070, mask=0) - builddir_lock = None - catdir_lock = None - try: - catdir_lock = portage.locks.lockdir(catdir) - portage.util.ensure_dirs(catdir, - uid=portage.portage_uid, gid=portage.portage_gid, - mode=070, mask=0) - builddir_lock = portage.locks.lockdir( - pkgsettings["PORTAGE_BUILDDIR"]) - try: - portage.locks.unlockdir(catdir_lock) - finally: - catdir_lock = None - msg = " === (%s of %s) Cleaning (%s::%s)" % \ - (mergecount, len(mymergelist), pkg_key, y) - short_msg = "emerge: (%s of %s) %s Clean" % \ - (mergecount, len(mymergelist), pkg_key) - emergelog(xterm_titles, msg, short_msg=short_msg) - retval = portage.doebuild(y, "clean", myroot, - pkgsettings, self.edebug, cleanup=1, - mydbapi=portdb, tree="porttree") - if retval != os.EX_OK: - return retval - if "--buildpkg" in self.myopts or issyspkg: - if issyspkg: - print ">>> This is a system package, " + \ - "let's pack a rescue tarball." - msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \ - (mergecount, len(mymergelist), pkg_key, y) - short_msg = "emerge: (%s of %s) %s Compile" % \ - (mergecount, len(mymergelist), pkg_key) - emergelog(xterm_titles, msg, short_msg=short_msg) - self.trees[myroot]["bintree"].prevent_collision(pkg_key) - binpkg_tmpfile = os.path.join(pkgsettings["PKGDIR"], - pkg_key + ".tbz2." + str(os.getpid())) - pkgsettings["PORTAGE_BINPKG_TMPFILE"] = binpkg_tmpfile - pkgsettings.backup_changes("PORTAGE_BINPKG_TMPFILE") - retval = portage.doebuild(y, "package", myroot, - pkgsettings, self.edebug, mydbapi=portdb, - tree="porttree") - del pkgsettings["PORTAGE_BINPKG_TMPFILE"] - if retval != os.EX_OK or \ - "--buildpkgonly" in self.myopts: - elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases) - if retval != os.EX_OK: - return retval - bintree = self.trees[myroot]["bintree"] - bintree.inject(pkg_key, filename=binpkg_tmpfile) - if "--buildpkgonly" not in self.myopts: - msg = " === (%s of %s) Merging (%s::%s)" % \ - (mergecount, len(mymergelist), pkg_key, y) - short_msg = "emerge: (%s of %s) %s Merge" % \ - (mergecount, len(mymergelist), pkg_key) - emergelog(xterm_titles, msg, short_msg=short_msg) - retval = portage.merge(pkgsettings["CATEGORY"], - pkgsettings["PF"], pkgsettings["D"], - os.path.join(pkgsettings["PORTAGE_BUILDDIR"], - "build-info"), myroot, pkgsettings, - myebuild=pkgsettings["EBUILD"], - mytree="porttree", mydbapi=portdb, - vartree=vartree, prev_mtimes=ldpath_mtimes) - if retval != os.EX_OK: - return retval - elif "noclean" not in pkgsettings.features: - portage.doebuild(y, "clean", myroot, - pkgsettings, self.edebug, mydbapi=portdb, - tree="porttree") - else: - msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \ - (mergecount, len(mymergelist), pkg_key, y) - short_msg = "emerge: (%s of %s) %s Compile" % \ - (mergecount, len(mymergelist), pkg_key) - emergelog(xterm_titles, msg, short_msg=short_msg) - retval = portage.doebuild(y, "merge", myroot, - pkgsettings, self.edebug, vartree=vartree, - mydbapi=portdb, tree="porttree", - prev_mtimes=ldpath_mtimes) - if retval != os.EX_OK: - return retval - finally: - if builddir_lock: - portage.locks.unlockdir(builddir_lock) - try: - if not catdir_lock: - # Lock catdir for removal if empty. - catdir_lock = portage.locks.lockdir(catdir) - finally: - if catdir_lock: - try: - os.rmdir(catdir) - except OSError, e: - if e.errno not in (errno.ENOENT, - errno.ENOTEMPTY, errno.EEXIST): - raise - del e - portage.locks.unlockdir(catdir_lock) - - elif x[0]=="binary": - #merge the tbz2 - mytbz2 = self.trees[myroot]["bintree"].getname(pkg_key) - if "--getbinpkg" in self.myopts: - tbz2_lock = None - try: - if "distlocks" in pkgsettings.features and \ - os.access(pkgsettings["PKGDIR"], os.W_OK): - portage.util.ensure_dirs(os.path.dirname(mytbz2)) - tbz2_lock = portage.locks.lockfile(mytbz2, - wantnewlockfile=1) - if self.trees[myroot]["bintree"].isremote(pkg_key): - msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\ - (mergecount, len(mymergelist), pkg_key, mytbz2) - short_msg = "emerge: (%s of %s) %s Fetch" % \ - (mergecount, len(mymergelist), pkg_key) - emergelog(xterm_titles, msg, short_msg=short_msg) - try: - self.trees[myroot]["bintree"].gettbz2(pkg_key) - except portage.exception.FileNotFound: - writemsg("!!! Fetching Binary failed " + \ - "for '%s'\n" % pkg_key, noiselevel=-1) - if not fetchonly: - return 1 - failed_fetches.append(pkg_key) - except portage.exception.DigestException, e: - writemsg("\n!!! Digest verification failed:\n", - noiselevel=-1) - writemsg("!!! %s\n" % e.value[0], - noiselevel=-1) - writemsg("!!! Reason: %s\n" % e.value[1], - noiselevel=-1) - writemsg("!!! Got: %s\n" % e.value[2], - noiselevel=-1) - writemsg("!!! Expected: %s\n" % e.value[3], - noiselevel=-1) - os.unlink(mytbz2) - if not fetchonly: - return 1 - failed_fetches.append(pkg_key) - finally: - if tbz2_lock: - portage.locks.unlockfile(tbz2_lock) - - if "--fetchonly" in self.myopts or \ - "--fetch-all-uri" in self.myopts: - self.curval += 1 - continue - - short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" - emergelog(xterm_titles, " === ("+str(mergecount)+\ - " of "+str(len(mymergelist))+") Merging Binary ("+\ - x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) - retval = portage.pkgmerge(mytbz2, x[1], pkgsettings, - mydbapi=bindb, - vartree=self.trees[myroot]["vartree"], - prev_mtimes=ldpath_mtimes) - if retval != os.EX_OK: - return retval - #need to check for errors - if "--buildpkgonly" not in self.myopts: - self.trees[x[1]]["vartree"].inject(x[2]) - myfavkey = portage.cpv_getkey(x[2]) - if not fetchonly and not pretend and \ - args_set.findAtomForPackage(pkg_key, metadata): - world_set.lock() - world_set.load() # maybe it's changed on disk - myfavkey = create_world_atom(pkg_key, metadata, - args_set, root_config) - if myfavkey: - print ">>> Recording",myfavkey,"in \"world\" favorites file..." - emergelog(xterm_titles, " === ("+\ - str(mergecount)+" of "+\ - str(len(mymergelist))+\ - ") Updating world file ("+x[pkgindex]+")") - world_set.add(myfavkey) - world_set.unlock() - - if "--pretend" not in self.myopts and \ - "--fetchonly" not in self.myopts and \ - "--fetch-all-uri" not in self.myopts: - # Clean the old package that we have merged over top of it. - if pkgsettings.get("AUTOCLEAN", "yes") == "yes": - xsplit=portage.pkgsplit(x[2]) - emergelog(xterm_titles, " >>> AUTOCLEAN: " + xsplit[0]) - retval = unmerge(pkgsettings, self.myopts, vartree, - "clean", [xsplit[0]], ldpath_mtimes, autoclean=1) - if not retval: - emergelog(xterm_titles, - " --- AUTOCLEAN: Nothing unmerged.") - else: - portage.writemsg_stdout(colorize("WARN", "WARNING:") - + " AUTOCLEAN is disabled. This can cause serious" - + " problems due to overlapping packages.\n") - - # Figure out if we need a restart. - mysplit=portage.pkgsplit(x[2]) - if mysplit[0] == "sys-apps/portage" and x[1] == "/": - myver=mysplit[1]+"-"+mysplit[2] - if myver[-3:]=='-r0': - myver=myver[:-3] - if (myver != portage.VERSION) and \ - "livecvsportage" not in self.settings.features: - if len(mymergelist) > mergecount: - emergelog(xterm_titles, - " ::: completed emerge ("+ \ - str(mergecount)+" of "+ \ - str(len(mymergelist))+") "+ \ - x[2]+" to "+x[1]) - emergelog(xterm_titles, " *** RESTARTING " + \ - "emerge via exec() after change of " + \ - "portage version.") - del mtimedb["resume"]["mergelist"][0] - mtimedb.commit() - portage.run_exitfuncs() - mynewargv=[sys.argv[0],"--resume"] - resume_opts = self.myopts.copy() - # For automatic resume, we need to prevent - # any of bad_resume_opts from leaking in - # via EMERGE_DEFAULT_OPTS. - resume_opts["--ignore-default-opts"] = True - for myopt, myarg in resume_opts.iteritems(): - if myopt not in bad_resume_opts: - if myarg is True: - mynewargv.append(myopt) - else: - mynewargv.append(myopt +"="+ myarg) - # priority only needs to be adjusted on the first run - os.environ["PORTAGE_NICENESS"] = "0" - os.execv(mynewargv[0], mynewargv) - - if "--pretend" not in self.myopts and \ - "--fetchonly" not in self.myopts and \ - "--fetch-all-uri" not in self.myopts: - if "noclean" not in self.settings.features: - short_msg = "emerge: (%s of %s) %s Clean Post" % \ - (mergecount, len(mymergelist), x[pkgindex]) - emergelog(xterm_titles, (" === (%s of %s) " + \ - "Post-Build Cleaning (%s::%s)") % \ - (mergecount, len(mymergelist), x[pkgindex], y), - short_msg=short_msg) - emergelog(xterm_titles, " ::: completed emerge ("+\ - str(mergecount)+" of "+str(len(mymergelist))+") "+\ - x[2]+" to "+x[1]) - - # Unsafe for parallel merges - del mtimedb["resume"]["mergelist"][0] - # Commit after each merge so that --resume may still work in - # in the event that portage is not allowed to exit normally - # due to power failure, SIGKILL, etc... - mtimedb.commit() - self.curval += 1 - - if "--pretend" not in self.myopts: - emergelog(xterm_titles, " *** Finished. Cleaning up...") - - # We're out of the loop... We're done. Delete the resume data. - if mtimedb.has_key("resume"): - del mtimedb["resume"] - mtimedb.commit() - - #by doing an exit this way, --fetchonly can continue to try to - #fetch everything even if a particular download fails. - if "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts: - if failed_fetches: - sys.stderr.write("\n\n!!! Some fetch errors were " + \ - "encountered. Please see above for details.\n\n") - for cpv in failed_fetches: - sys.stderr.write(" ") - sys.stderr.write(cpv) - sys.stderr.write("\n") - sys.stderr.write("\n") - sys.exit(1) - else: - sys.exit(0) - return os.EX_OK - -def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files, - ldpath_mtimes, autoclean=0): - candidate_catpkgs=[] - global_unmerge=0 - xterm_titles = "notitles" not in settings.features - - vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH) - try: - # At least the parent needs to exist for the lock file. - portage.util.ensure_dirs(vdb_path) - except portage.exception.PortageException: - pass - vdb_lock = None - try: - if os.access(vdb_path, os.W_OK): - vdb_lock = portage.locks.lockdir(vdb_path) - realsyslist = getlist(settings, "system") - syslist = [] - for x in realsyslist: - mycp = portage.dep_getkey(x) - if mycp in settings.getvirtuals(): - providers = [] - for provider in settings.getvirtuals()[mycp]: - if vartree.dbapi.match(provider): - providers.append(provider) - if len(providers) == 1: - syslist.extend(providers) - else: - syslist.append(mycp) - - mysettings = portage.config(clone=settings) - - 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 = 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(vartree.dbapi.cp_all()) - elif "system" in unmerge_files: - candidate_catpkgs.extend(getlist(settings, "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 x[0] not in [".","/"] and \ - 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) - sp_absx = absx.split("/") - if sp_absx[-1][-7:] == ".ebuild": - del sp_absx[-1] - absx = "/".join(sp_absx) - - sp_absx_len = len(sp_absx) - - vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH) - vdb_len = len(vdb_path) - - sp_vdb = vdb_path.split("/") - sp_vdb_len = len(sp_vdb) - - if not os.path.exists(absx+"/CONTENTS"): - print "!!! Not a valid db dir: "+str(absx) - return 0 - - if sp_absx_len <= sp_vdb_len: - # The Path is shorter... so it can't be inside the vdb. - print sp_absx - print absx - print "\n!!!",x,"cannot be inside "+ \ - vdb_path+"; aborting.\n" - return 0 - - for idx in range(0,sp_vdb_len): - if idx >= sp_absx_len or sp_vdb[idx] != sp_absx[idx]: - print sp_absx - print absx - print "\n!!!", x, "is not inside "+\ - vdb_path+"; aborting.\n" - return 0 - - print "="+"/".join(sp_absx[sp_vdb_len:]) - candidate_catpkgs.append( - "="+"/".join(sp_absx[sp_vdb_len:])) - - newline="" - if (not "--quiet" in myopts): - newline="\n" - if settings["ROOT"] != "/": - print darkgreen(newline+ \ - ">>> Using system located in ROOT tree "+settings["ROOT"]) - if (("--pretend" in myopts) or ("--ask" in myopts)) and \ - not ("--quiet" in myopts): - print darkgreen(newline+\ - ">>> These are the packages that would be unmerged:") - - pkgmap={} - numselected=0 - for x in candidate_catpkgs: - # cycle through all our candidate deps and determine - # what will and will not get unmerged - try: - mymatch=localtree.dep_match(x) - except KeyError: - mymatch=None - 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) - - if not mymatch and x[0] not in "<>=~": - #add a "=" if missing - mymatch=localtree.dep_match("="+x) - if not mymatch: - portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \ - (x, unmerge_action), noiselevel=-1) - continue - mykey = portage.key_expand( - portage.dep_getkey( - mymatch[0]), mydb=vartree.dbapi, settings=settings) - if not pkgmap.has_key(mykey): - pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } - if unmerge_action=="unmerge": - for y in mymatch: - if y not in pkgmap[mykey]["selected"]: - pkgmap[mykey]["selected"].append(y) - numselected=numselected+len(mymatch) - elif unmerge_action == "prune": - if len(mymatch) == 1: - continue - best_version = mymatch[0] - best_slot = vartree.getslot(best_version) - best_counter = vartree.dbapi.cpv_counter(best_version) - for mypkg in mymatch[1:]: - myslot = vartree.getslot(mypkg) - mycounter = vartree.dbapi.cpv_counter(mypkg) - if (myslot == best_slot and mycounter > best_counter) or \ - mypkg == portage.best([mypkg, best_version]): - if myslot == best_slot: - if mycounter < best_counter: - # On slot collision, keep the one with the - # highest counter since it is the most - # recently installed. - continue - best_version = mypkg - best_slot = myslot - best_counter = mycounter - pkgmap[mykey]["protected"].append(best_version) - pkgmap[mykey]["selected"] = [mypkg for mypkg in mymatch \ - if mypkg != best_version] - numselected = numselected + len(pkgmap[mykey]["selected"]) - else: - # unmerge_action == "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: - 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 - if global_unmerge and not numselected: - portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n") - return 0 - - if not numselected: - portage.writemsg_stdout( - "\n>>> No packages selected for removal by " + \ - unmerge_action + "\n") - return 0 - finally: - if vdb_lock: - portage.locks.unlockdir(vdb_lock) - for x in pkgmap: - for y in localtree.dep_match(x): - if y not in pkgmap[x]["omitted"] and \ - y not in pkgmap[x]["selected"] and \ - y not in pkgmap[x]["protected"]: - pkgmap[x]["omitted"].append(y) - if global_unmerge and not pkgmap[x]["selected"]: - #avoid cluttering the preview printout with stuff that isn't getting unmerged - continue - if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist): - print colorize("BAD","\a\n\n!!! '%s' is part of your system profile." % x) - print colorize("WARN","\a!!! Unmerging it may be damaging to your system.\n") - if "--pretend" not in myopts and "--ask" not in myopts: - countdown(int(settings["EMERGE_WARNING_DELAY"]), - colorize("UNMERGE_WARN", "Press Ctrl-C to Stop")) - if "--quiet" not in myopts: - print "\n "+white(x) - else: - print white(x)+": ", - for mytype in ["selected","protected","omitted"]: - if "--quiet" not in myopts: - portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1) - if pkgmap[x][mytype]: - sorted_pkgs = [portage.catpkgsplit(mypkg)[1:] \ - for mypkg in pkgmap[x][mytype]] - sorted_pkgs.sort(portage.pkgcmp) - for pn, ver, rev in sorted_pkgs: - if rev == "r0": - myversion = ver - else: - myversion = ver + "-" + rev - if mytype=="selected": - portage.writemsg_stdout( - colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1) - else: - portage.writemsg_stdout( - colorize("GOOD", myversion + " "), noiselevel=-1) - else: - portage.writemsg_stdout("none ", noiselevel=-1) - if "--quiet" not in myopts: - portage.writemsg_stdout("\n", noiselevel=-1) - if "--quiet" in myopts: - portage.writemsg_stdout("\n", noiselevel=-1) - - portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \ - " packages are slated for removal.\n") - portage.writemsg_stdout(">>> " + colorize("GOOD", "'Protected'") + \ - " and " + colorize("GOOD", "'omitted'") + \ - " packages will not be removed.\n\n") - - if "--pretend" in myopts: - #we're done... return - return 0 - if "--ask" in myopts: - if userquery("Would you like to unmerge these packages?")=="No": - # enter pretend mode for correct formatting of results - myopts["--pretend"] = True - print - print "Quitting." - print - return 0 - #the real unmerging begins, after a short delay.... - if not autoclean: - countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging") - - for x in pkgmap: - for y in pkgmap[x]["selected"]: - print ">>> Unmerging "+y+"..." - emergelog(xterm_titles, "=== Unmerging... ("+y+")") - mysplit=y.split("/") - #unmerge... - retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"], - mysettings, unmerge_action not in ["clean","prune"], - vartree=vartree, ldpath_mtimes=ldpath_mtimes) - if retval != os.EX_OK: - emergelog(xterm_titles, " !!! unmerge FAILURE: "+y) - ebuild = vartree.dbapi.findname(y) - show_unmerge_failure_message(y, ebuild, retval) - sys.exit(retval) - else: - clean_world(vartree.dbapi, y) - emergelog(xterm_titles, " >>> unmerge success: "+y) - return 1 - -def show_unmerge_failure_message(pkg, ebuild, retval): - - from formatter import AbstractFormatter, DumbWriter - f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72)) - - msg = [] - msg.append("A removal phase of the '%s' package " % pkg) - msg.append("has failed with exit value %s. " % retval) - msg.append("The problem occurred while executing ") - msg.append("the ebuild located at '%s'. " % ebuild) - msg.append("If necessary, manually remove the ebuild " ) - msg.append("in order to skip the execution of removal phases.") - - f.end_paragraph(1) - for x in msg: - f.add_flowing_data(x) - f.end_paragraph(1) - f.writer.flush() - -def chk_updated_info_files(root, infodirs, prev_mtimes, retval): - - if os.path.exists("/usr/bin/install-info"): - regen_infodirs=[] - for z in infodirs: - if z=='': - continue - inforoot=normpath(root+z) - if os.path.isdir(inforoot): - infomtime = long(os.stat(inforoot).st_mtime) - if inforoot not in prev_mtimes or \ - prev_mtimes[inforoot] != infomtime: - regen_infodirs.append(inforoot) - - if not regen_infodirs: - portage.writemsg_stdout(" "+green("*")+" GNU info directory index is up-to-date.\n") - else: - portage.writemsg_stdout(" "+green("*")+" Regenerating GNU info directory index...\n") - - dir_extensions = ("", ".gz", ".bz2") - icount=0 - badcount=0 - for inforoot in regen_infodirs: - if inforoot=='': - continue - - if not os.path.isdir(inforoot): - continue - errmsg = "" - file_list = os.listdir(inforoot) - file_list.sort() - dir_file = os.path.join(inforoot, "dir") - moved_old_dir = False - processed_count = 0 - for x in file_list: - if x.startswith(".") or \ - os.path.isdir(os.path.join(inforoot, x)): - continue - if x.startswith("dir"): - skip = False - for ext in dir_extensions: - if x == "dir" + ext or \ - x == "dir" + ext + ".old": - skip = True - break - if skip: - continue - if processed_count == 0: - for ext in dir_extensions: - try: - os.rename(dir_file + ext, dir_file + ext + ".old") - moved_old_dir = True - except EnvironmentError, e: - if e.errno != errno.ENOENT: - raise - del e - processed_count += 1 - myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] - existsstr="already exists, for file `" - if myso!="": - if re.search(existsstr,myso): - # Already exists... Don't increment the count for this. - pass - elif myso[:44]=="install-info: warning: no info dir entry in ": - # This info file doesn't contain a DIR-header: install-info produces this - # (harmless) warning (the --quiet switch doesn't seem to work). - # Don't increment the count for this. - pass - else: - badcount=badcount+1 - errmsg += myso + "\n" - icount=icount+1 - - if moved_old_dir and not os.path.exists(dir_file): - # We didn't generate a new dir file, so put the old file - # back where it was originally found. - for ext in dir_extensions: - try: - os.rename(dir_file + ext + ".old", dir_file + ext) - except EnvironmentError, e: - if e.errno != errno.ENOENT: - raise - del e - - # Clean dir.old cruft so that they don't prevent - # unmerge of otherwise empty directories. - for ext in dir_extensions: - try: - os.unlink(dir_file + ext + ".old") - except EnvironmentError, e: - if e.errno != errno.ENOENT: - raise - del e - - #update mtime so we can potentially avoid regenerating. - prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime) - - if badcount: - print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors." - print errmsg - else: - print " "+green("*")+" Processed",icount,"info files." - - -def display_news_notification(trees): - for target_root in trees: - if len(trees) > 1 and target_root != "/": - break - settings = trees[target_root]["vartree"].settings - portdb = trees[target_root]["porttree"].dbapi - vardb = trees[target_root]["vartree"].dbapi - NEWS_PATH = os.path.join("metadata", "news") - UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news") - newsReaderDisplay = False - - for repo in portdb.getRepositories(): - unreadItems = checkUpdatedNewsItems( - portdb, vardb, NEWS_PATH, UNREAD_PATH, repo) - if unreadItems: - if not newsReaderDisplay: - newsReaderDisplay = True - print - print colorize("WARN", " * IMPORTANT:"), - print "%s news items need reading for repository '%s'." % (unreadItems, repo) - - - if newsReaderDisplay: - print colorize("WARN", " *"), - print "Use " + colorize("GOOD", "eselect news") + " to read news items." - print - -def post_emerge(trees, mtimedb, retval): - """ - Misc. things to run at the end of a merge session. - - Update Info Files - Update Config Files - Update News Items - Commit mtimeDB - Display preserved libs warnings - Exit Emerge - - @param trees: A dictionary mapping each ROOT to it's package databases - @type trees: dict - @param mtimedb: The mtimeDB to store data needed across merge invocations - @type mtimedb: MtimeDB class instance - @param retval: Emerge's return value - @type retval: Int - @rype: None - @returns: - 1. Calls sys.exit(retval) - """ - for target_root in trees: - if len(trees) > 1 and target_root != "/": - break - vardbapi = trees[target_root]["vartree"].dbapi - settings = vardbapi.settings - info_mtimes = mtimedb["info"] - - # Load the most current variables from ${ROOT}/etc/profile.env - settings.unlock() - settings.reload() - settings.regenerate() - settings.lock() - - config_protect = settings.get("CONFIG_PROTECT","").split() - infodirs = settings.get("INFOPATH","").split(":") + \ - settings.get("INFODIR","").split(":") - - os.chdir("/") - - if retval == os.EX_OK: - exit_msg = " *** exiting successfully." - else: - exit_msg = " *** exiting unsuccessfully with status '%s'." % retval - emergelog("notitles" not in settings.features, exit_msg) - - # Dump the mod_echo output now so that our other notifications are shown - # last. - try: - from portage.elog import mod_echo - except ImportError: - pass # happens during downgrade to a version without the module - else: - mod_echo.finalize() - - vdb_path = os.path.join(target_root, portage.VDB_PATH) - portage.util.ensure_dirs(vdb_path) - vdb_lock = portage.locks.lockdir(vdb_path) - try: - if "noinfo" not in settings.features: - chk_updated_info_files(target_root, infodirs, info_mtimes, retval) - mtimedb.commit() - finally: - portage.locks.unlockdir(vdb_lock) - - chk_updated_cfg_files(target_root, config_protect) - - display_news_notification(trees) - - if vardbapi.plib_registry.hasEntries(): - print colorize("WARN", "!!!") + " existing preserved libs:" - plibdata = vardbapi.plib_registry.getPreservedLibs() - for cpv in plibdata: - print colorize("WARN", ">>>") + " package: %s" % cpv - for f in plibdata[cpv]: - print colorize("WARN", " * ") + " - %s" % f - print "Use " + colorize("GOOD", "revdep-rebuild") + " to rebuild packages using these libraries" - print "and then remerge the packages listed above." - - sys.exit(retval) - - -def chk_updated_cfg_files(target_root, config_protect): - if config_protect: - #number of directories with some protect files in them - procount=0 - for x in config_protect: - x = os.path.join(target_root, x.lstrip(os.path.sep)) - try: - mymode = os.lstat(x).st_mode - except OSError: - continue - if stat.S_ISLNK(mymode): - # We want to treat it like a directory if it - # is a symlink to an existing directory. - try: - real_mode = os.stat(x).st_mode - if stat.S_ISDIR(real_mode): - mymode = real_mode - except OSError: - pass - if stat.S_ISDIR(mymode): - mycommand = "find '%s' -iname '._cfg????_*'" % x - else: - mycommand = "find '%s' -maxdepth 1 -iname '._cfg????_%s'" % \ - os.path.split(x.rstrip(os.path.sep)) - mycommand += " ! -iname '.*~' ! -iname '.*.bak' -print0" - a = commands.getstatusoutput(mycommand) - if a[0] != 0: - sys.stderr.write(" %s error scanning '%s': " % (bad("*"), x)) - sys.stderr.flush() - # Show the error message alone, sending stdout to /dev/null. - os.system(mycommand + " 1>/dev/null") - else: - files = a[1].split('\0') - # split always produces an empty string as the last element - if files and not files[-1]: - del files[-1] - if files: - procount += 1 - print colorize("WARN", " * IMPORTANT:"), - if stat.S_ISDIR(mymode): - print "%d config files in '%s' need updating." % \ - (len(files), x) - else: - print "config file '%s' needs updating." % x - - if procount: - print " "+yellow("*")+" See the "+colorize("INFORM","CONFIGURATION FILES")+ \ - " section of the " + bold("emerge") - print " "+yellow("*")+" man page to learn how to update config files." - -def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id): - """ - Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items - Returns the number of unread (yet relevent) items. - - @param portdb: a portage tree database - @type portdb: pordbapi - @param vardb: an installed package database - @type vardb: vardbapi - @param NEWS_PATH: - @type NEWS_PATH: - @param UNREAD_PATH: - @type UNREAD_PATH: - @param repo_id: - @type repo_id: - @rtype: Integer - @returns: - 1. The number of unread but relevant news items. - - """ - from portage.news import NewsManager - manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH) - return manager.getUnreadItems( repo_id, update=True ) - -def is_valid_package_atom(x): - try: - testkey = portage.dep_getkey(x) - except portage.exception.InvalidData: - return False - if testkey.startswith("null/"): - testatom = x.replace(testkey[5:], "cat/"+testkey[5:]) - elif "/" not in x: - testatom = "cat/"+x - else: - testatom = x - return portage.isvalidatom(testatom) - -def show_blocker_docs_link(): - print - print "For more information about " + bad("Blocked Packages") + ", please refer to the following" - print "section of the Gentoo Linux x86 Handbook (architecture is irrelevant):" - print - print "http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked" - print - -def action_sync(settings, trees, mtimedb, myopts, myaction): - xterm_titles = "notitles" not in settings.features - emergelog(xterm_titles, " === sync") - myportdir = settings.get("PORTDIR", None) - if not myportdir: - sys.stderr.write("!!! PORTDIR is undefined. Is /etc/make.globals missing?\n") - sys.exit(1) - if myportdir[-1]=="/": - myportdir=myportdir[:-1] - if not os.path.exists(myportdir): - print ">>>",myportdir,"not found, creating it." - os.makedirs(myportdir,0755) - syncuri=settings["SYNC"].rstrip() - os.umask(0022) - updatecache_flg = False - if myaction == "metadata": - print "skipping sync" - updatecache_flg = True - 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 - - rsync_opts = [] - import shlex, StringIO - if settings["PORTAGE_RSYNC_OPTS"] == "": - portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n") - rsync_opts.extend([ - "--recursive", # Recurse directories - "--links", # Consider symlinks - "--safe-links", # Ignore links outside of tree - "--perms", # Preserve permissions - "--times", # Preserive mod times - "--compress", # Compress the data transmitted - "--force", # Force deletion on non-empty dirs - "--whole-file", # Don't do block transfers, only entire files - "--delete", # Delete files that aren't in the master tree - "--delete-after", # Delete only after everything else is done - "--stats", # Show final statistics about what was transfered - "--timeout="+str(mytimeout), # IO timeout if not done in X seconds - "--exclude=/distfiles", # Exclude distfiles from consideration - "--exclude=/local", # Exclude local from consideration - "--exclude=/packages", # Exclude packages from consideration - "--filter=H_**/files/digest-*", # Exclude manifest1 digests and delete on the receiving side - ]) - - else: - # The below validation is not needed when using the above hardcoded - # defaults. - - portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1) - lexer = shlex.shlex(StringIO.StringIO( - settings.get("PORTAGE_RSYNC_OPTS","")), posix=True) - lexer.whitespace_split = True - rsync_opts.extend(lexer) - del lexer - - for opt in ("--recursive", "--times"): - if opt not in rsync_opts: - portage.writemsg(yellow("WARNING:") + " adding required option " + \ - "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) - rsync_opts.append(opt) - - for exclude in ("distfiles", "local", "packages"): - opt = "--exclude=/%s" % exclude - if opt not in rsync_opts: - portage.writemsg(yellow("WARNING:") + \ - " adding required option %s not included in " % opt + \ - "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n") - rsync_opts.append(opt) - - if settings["RSYNC_TIMEOUT"] != "": - portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \ - "use PORTAGE_RSYNC_EXTRA_OPTS instead\n") - try: - mytimeout = int(settings["RSYNC_TIMEOUT"]) - rsync_opts.append("--timeout=%d" % mytimeout) - except ValueError, e: - portage.writemsg("!!! %s\n" % str(e)) - - # TODO: determine options required for official servers - if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"): - - def rsync_opt_startswith(opt_prefix): - for x in rsync_opts: - if x.startswith(opt_prefix): - return True - return False - - if not rsync_opt_startswith("--timeout="): - rsync_opts.append("--timeout=%d" % mytimeout) - - for opt in ("--compress", "--whole-file"): - if opt not in rsync_opts: - portage.writemsg(yellow("WARNING:") + " adding required option " + \ - "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) - rsync_opts.append(opt) - - if "--quiet" in myopts: - rsync_opts.append("--quiet") # Shut up a lot - else: - rsync_opts.append("--verbose") # Print filelist - - if "--verbose" in myopts: - rsync_opts.append("--progress") # Progress meter for each file - - if "--debug" in myopts: - rsync_opts.append("--checksum") # Force checksum on all files - - if settings["RSYNC_EXCLUDEFROM"] != "": - portage.writemsg(yellow("WARNING:") + \ - " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \ - "PORTAGE_RSYNC_EXTRA_OPTS instead\n") - if os.path.exists(settings["RSYNC_EXCLUDEFROM"]): - rsync_opts.append("--exclude-from=%s" % \ - settings["RSYNC_EXCLUDEFROM"]) - else: - portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \ - " but file does not exist.\n") - - if settings["RSYNC_RATELIMIT"] != "": - portage.writemsg(yellow("WARNING:") + \ - " usage of RSYNC_RATELIMIT is deprecated, use " + \ - "PORTAGE_RSYNC_EXTRA_OPTS instead") - rsync_opts.append("--bwlimit=%s" % \ - settings["RSYNC_RATELIMIT"]) - - # Real local timestamp file. - servertimestampfile = os.path.join( - myportdir, "metadata", "timestamp.chk") - - content = portage.util.grabfile(servertimestampfile) - mytimestamp = 0 - if content: - try: - mytimestamp = time.mktime(time.strptime(content[0], - "%a, %d %b %Y %H:%M:%S +0000")) - except (OverflowError, ValueError): - pass - del content - - try: - rsync_initial_timeout = \ - int(settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15")) - except ValueError: - rsync_initial_timeout = 15 - - try: - if settings.has_key("RSYNC_RETRIES"): - print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead" - maxretries=int(settings["RSYNC_RETRIES"]) - else: - maxretries=int(settings["PORTAGE_RSYNC_RETRIES"]) - except SystemExit, e: - raise # Needed else can't exit - except: - maxretries=3 #default number of retries - - retries=0 - user_name, hostname, port = re.split( - "rsync://([^:/]+@)?([^:/]*)(:[0-9]+)?", syncuri, maxsplit=3)[1:4] - if port is None: - port="" - if user_name is None: - user_name="" - updatecache_flg=True - all_rsync_opts = set(rsync_opts) - lexer = shlex.shlex(StringIO.StringIO( - settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")), posix=True) - lexer.whitespace_split = True - extra_rsync_opts = list(lexer) - del lexer - all_rsync_opts.update(extra_rsync_opts) - family = socket.AF_INET - if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts: - family = socket.AF_INET - elif socket.has_ipv6 and \ - ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts): - family = socket.AF_INET6 - ips=[] - while (1): - if ips: - del ips[0] - if ips==[]: - try: - for addrinfo in socket.getaddrinfo( - hostname, None, family, socket.SOCK_STREAM): - if addrinfo[0] == socket.AF_INET6: - # IPv6 addresses need to be enclosed in square brackets - ips.append("[%s]" % addrinfo[4][0]) - else: - ips.append(addrinfo[4][0]) - from random import shuffle - shuffle(ips) - except SystemExit, e: - raise # Needed else can't exit - except Exception, e: - print "Notice:",str(e) - dosyncuri=syncuri - - if ips: - try: - dosyncuri = syncuri.replace( - "//" + user_name + hostname + port + "/", - "//" + user_name + ips[0] + port + "/", 1) - except SystemExit, e: - raise # Needed else can't exit - except Exception, e: - print "Notice:",str(e) - dosyncuri=syncuri - - if (retries==0): - if "--ask" in myopts: - if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No": - print - print "Quitting." - print - sys.exit(0) - emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri) - if "--quiet" not in myopts: - print ">>> Starting rsync with "+dosyncuri+"..." - else: - emergelog(xterm_titles, - ">>> Starting retry %d of %d with %s" % \ - (retries,maxretries,dosyncuri)) - print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri) - - if mytimestamp != 0 and "--quiet" not in myopts: - print ">>> Checking server timestamp ..." - - rsynccommand = ["/usr/bin/rsync"] + rsync_opts + extra_rsync_opts - - if "--debug" in myopts: - print rsynccommand - - exitcode = os.EX_OK - servertimestamp = 0 - # Even if there's no timestamp available locally, fetch the - # timestamp anyway as an initial probe to verify that the server is - # responsive. This protects us from hanging indefinitely on a - # connection attempt to an unresponsive server which rsync's - # --timeout option does not prevent. - if True: - # Temporary file for remote server timestamp comparison. - from tempfile import mkstemp - fd, tmpservertimestampfile = mkstemp() - os.close(fd) - mycommand = rsynccommand[:] - mycommand.append(dosyncuri.rstrip("/") + \ - "/metadata/timestamp.chk") - mycommand.append(tmpservertimestampfile) - content = None - mypids = [] - try: - def timeout_handler(signum, frame): - raise portage.exception.PortageException("timed out") - signal.signal(signal.SIGALRM, timeout_handler) - # Timeout here in case the server is unresponsive. The - # --timeout rsync option doesn't apply to the initial - # connection attempt. - if rsync_initial_timeout: - signal.alarm(rsync_initial_timeout) - try: - mypids.extend(portage.process.spawn( - mycommand, env=settings.environ(), returnpid=True)) - exitcode = os.waitpid(mypids[0], 0)[1] - content = portage.grabfile(tmpservertimestampfile) - finally: - if rsync_initial_timeout: - signal.alarm(0) - try: - os.unlink(tmpservertimestampfile) - except OSError: - pass - except portage.exception.PortageException, e: - # timed out - print e - del e - if mypids and os.waitpid(mypids[0], os.WNOHANG) == (0,0): - os.kill(mypids[0], signal.SIGTERM) - os.waitpid(mypids[0], 0) - # This is the same code rsync uses for timeout. - exitcode = 30 - else: - if exitcode != os.EX_OK: - if exitcode & 0xff: - exitcode = (exitcode & 0xff) << 8 - else: - exitcode = exitcode >> 8 - if mypids: - portage.process.spawned_pids.remove(mypids[0]) - if content: - try: - servertimestamp = time.mktime(time.strptime( - content[0], "%a, %d %b %Y %H:%M:%S +0000")) - except (OverflowError, ValueError): - pass - del mycommand, mypids, content - if exitcode == os.EX_OK: - if (servertimestamp != 0) and (servertimestamp == mytimestamp): - emergelog(xterm_titles, - ">>> Cancelling sync -- Already current.") - print - print ">>>" - print ">>> Timestamps on the server and in the local repository are the same." - print ">>> Cancelling all further sync action. You are already up to date." - print ">>>" - print ">>> In order to force sync, remove '%s'." % servertimestampfile - print ">>>" - print - sys.exit(0) - elif (servertimestamp != 0) and (servertimestamp < mytimestamp): - emergelog(xterm_titles, - ">>> Server out of date: %s" % dosyncuri) - print - print ">>>" - print ">>> SERVER OUT OF DATE: %s" % dosyncuri - print ">>>" - print ">>> In order to force sync, remove '%s'." % servertimestampfile - print ">>>" - print - elif (servertimestamp == 0) or (servertimestamp > mytimestamp): - # actual sync - mycommand = rsynccommand + [dosyncuri+"/", myportdir] - exitcode = portage.process.spawn(mycommand, - env=settings.environ()) - if exitcode in [0,1,3,4,11,14,20,21]: - break - elif exitcode in [1,3,4,11,14,20,21]: - break - else: - # Code 2 indicates protocol incompatibility, which is expected - # for servers with protocol < 29 that don't support - # --prune-empty-directories. Retry for a server that supports - # at least rsync protocol version 29 (>=rsync-2.6.4). - pass - - retries=retries+1 - - if retries<=maxretries: - print ">>> Retrying..." - time.sleep(11) - else: - # over retries - # exit loop - updatecache_flg=False - break - - if (exitcode==0): - emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri) - elif (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="+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="+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 CVS 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 os.path.exists(cvsdir+"/gentoo-x86"): - print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." - sys.exit(1) - try: - os.rmdir(myportdir) - except OSError, e: - if e.errno != errno.ENOENT: - sys.stderr.write( - "!!! existing '%s' directory; exiting.\n" % myportdir) - sys.exit(1) - del e - if portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",settings,free=1): - print "!!! cvs checkout error; exiting." - sys.exit(1) - os.rename(os.path.join(cvsdir, "gentoo-x86"), myportdir) - else: - #cvs update - print ">>> Starting cvs update with "+syncuri+"..." - retval = portage.spawn("cd '%s'; cvs -z0 -q update -dP" % \ - myportdir, settings, free=1) - if retval != os.EX_OK: - sys.exit(retval) - dosyncuri = syncuri - else: - print "!!! rsync setting: ",syncuri,"not recognized; exiting." - sys.exit(1) - - if updatecache_flg and \ - myaction != "metadata" and \ - "metadata-transfer" not in settings.features: - updatecache_flg = False - - # Reload the whole config from scratch. - settings, trees, mtimedb = load_emerge_config(trees=trees) - portdb = trees[settings["ROOT"]]["porttree"].dbapi - - if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg: - action_metadata(settings, portdb, myopts) - - if portage._global_updates(trees, mtimedb["updates"]): - mtimedb.commit() - # Reload the whole config from scratch. - settings, trees, mtimedb = load_emerge_config(trees=trees) - portdb = trees[settings["ROOT"]]["porttree"].dbapi - - mybestpv = portdb.xmatch("bestmatch-visible", "sys-apps/portage") - mypvs = portage.best( - trees[settings["ROOT"]]["vartree"].dbapi.match("sys-apps/portage")) - - chk_updated_cfg_files("/", settings.get("CONFIG_PROTECT","").split()) - - if myaction != "metadata": - if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK): - retval = portage.process.spawn( - [os.path.join(portage.USER_CONFIG_PATH, "bin", "post_sync"), - dosyncuri], env=settings.environ()) - if retval != os.EX_OK: - print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync") - - if(mybestpv != mypvs) and not "--quiet" in myopts: - 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 - print red(" * ")+"To update portage, run 'emerge portage' now." - print - - display_news_notification(trees) - -def action_metadata(settings, portdb, myopts): - portage.writemsg_stdout("\n>>> Updating Portage cache: ") - old_umask = os.umask(0002) - cachedir = os.path.normpath(settings.depcachedir) - if cachedir in ["/", "/bin", "/dev", "/etc", "/home", - "/lib", "/opt", "/proc", "/root", "/sbin", - "/sys", "/tmp", "/usr", "/var"]: - print >> sys.stderr, "!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \ - "ROOT DIRECTORY ON YOUR SYSTEM." - print >> sys.stderr, \ - "!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir - sys.exit(73) - if not os.path.exists(cachedir): - os.mkdir(cachedir) - - ec = portage.eclass_cache.cache(portdb.porttree_root) - myportdir = os.path.realpath(settings["PORTDIR"]) - cm = settings.load_best_module("portdbapi.metadbmodule")( - myportdir, "metadata/cache", portage.auxdbkeys[:]) - - from portage.cache import util - - class percentage_noise_maker(util.quiet_mirroring): - def __init__(self, dbapi): - self.dbapi = dbapi - self.cp_all = dbapi.cp_all() - l = len(self.cp_all) - self.call_update_min = 100000000 - self.min_cp_all = l/100.0 - self.count = 1 - self.pstr = '' - - def __iter__(self): - for x in self.cp_all: - self.count += 1 - if self.count > self.min_cp_all: - self.call_update_min = 0 - self.count = 0 - for y in self.dbapi.cp_list(x): - yield y - self.call_update_mine = 0 - - def update(self, *arg): - try: self.pstr = int(self.pstr) + 1 - except ValueError: self.pstr = 1 - sys.stdout.write("%s%i%%" % \ - ("\b" * (len(str(self.pstr))+1), self.pstr)) - sys.stdout.flush() - self.call_update_min = 10000000 - - def finish(self, *arg): - sys.stdout.write("\b\b\b\b100%\n") - sys.stdout.flush() - - if "--quiet" in myopts: - def quicky_cpv_generator(cp_all_list): - for x in cp_all_list: - for y in portdb.cp_list(x): - yield y - source = quicky_cpv_generator(portdb.cp_all()) - noise_maker = portage.cache.util.quiet_mirroring() - else: - noise_maker = source = percentage_noise_maker(portdb) - portage.cache.util.mirror_cache(source, cm, portdb.auxdb[myportdir], - eclass_cache=ec, verbose_instance=noise_maker) - - sys.stdout.flush() - os.umask(old_umask) - -def action_regen(settings, portdb): - xterm_titles = "notitles" not in settings.features - emergelog(xterm_titles, " === regen") - #regenerate cache entries - print "Regenerating cache entries... " - try: - os.close(sys.stdin.fileno()) - except SystemExit, e: - raise # Needed else can't exit - except: - pass - sys.stdout.flush() - mynodes = portdb.cp_all() - from portage.cache.cache_errors import CacheError - dead_nodes = {} - for mytree in portdb.porttrees: - try: - dead_nodes[mytree] = set(portdb.auxdb[mytree].iterkeys()) - except CacheError, e: - print "\n error listing cache entries for " + \ - "'%s': %s, continuing..." % (mytree, e) - del e - dead_nodes = None - break - for x in mynodes: - mymatches = portdb.cp_list(x) - portage.writemsg_stdout("processing %s\n" % x) - for y in mymatches: - try: - foo = portdb.aux_get(y,["DEPEND"]) - except SystemExit, e: - # sys.exit is an exception... And consequently, we can't catch it. - raise - except Exception, e: - print "\n error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)} - if dead_nodes: - for mytree in portdb.porttrees: - if portdb.findname2(y, mytree=mytree)[0]: - dead_nodes[mytree].discard(y) - if dead_nodes: - for mytree, nodes in dead_nodes.iteritems(): - auxdb = portdb.auxdb[mytree] - for y in nodes: - try: - del auxdb[y] - except (KeyError, CacheError): - pass - print "done!" - -def action_config(settings, trees, myopts, myfiles): - if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles: - print red("!!! config can only take a single package atom at this time\n") - sys.exit(1) - if not is_valid_package_atom(myfiles[0]): - portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0], - noiselevel=-1) - portage.writemsg("!!! Please check ebuild(5) for full details.\n") - portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") - sys.exit(1) - print - try: - pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0]) - except ValueError, e: - # Multiple matches thrown from cpv_expand - pkgs = e.args[0] - if len(pkgs) == 0: - print "No packages found.\n" - sys.exit(0) - elif len(pkgs) > 1: - if "--ask" in myopts: - options = [] - print "Please select a package to configure:" - idx = 0 - for pkg in pkgs: - idx += 1 - options.append(str(idx)) - print options[-1]+") "+pkg - print "X) Cancel" - options.append("X") - idx = userquery("Selection?", options) - if idx == "X": - sys.exit(0) - pkg = pkgs[int(idx)-1] - else: - print "The following packages available:" - for pkg in pkgs: - print "* "+pkg - print "\nPlease use a specific atom or the --ask option." - sys.exit(1) - else: - pkg = pkgs[0] - - print - if "--ask" in myopts: - if userquery("Ready to configure "+pkg+"?") == "No": - sys.exit(0) - else: - print "Configuring pkg..." - print - ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg) - mysettings = portage.config(clone=settings) - portage.doebuild(ebuildpath, "config", settings["ROOT"], mysettings, - debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True, - mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree") - print - -def action_info(settings, trees, myopts, myfiles): - unameout=commands.getstatusoutput("uname -mrp")[1] - print getportageversion(settings["PORTDIR"], settings["ROOT"], - settings.profile_path, settings["CHOST"], - trees[settings["ROOT"]]["vartree"].dbapi) - header_width = 65 - header_title = "System Settings" - if myfiles: - print header_width * "=" - print header_title.rjust(int(header_width/2 + len(header_title)/2)) - print header_width * "=" - print "System uname: "+unameout - - lastSync = portage.grabfile(os.path.join( - settings["PORTDIR"], "metadata", "timestamp.chk")) - print "Timestamp of tree:", - if lastSync: - print lastSync[0] - else: - print "Unknown" - - output=commands.getstatusoutput("distcc --version") - if not output[0]: - print str(output[1].split("\n",1)[0]), - if "distcc" in settings.features: - print "[enabled]" - else: - print "[disabled]" - - output=commands.getstatusoutput("ccache -V") - if not output[0]: - print str(output[1].split("\n",1)[0]), - if "ccache" in settings.features: - print "[enabled]" - else: - print "[disabled]" - - myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers", - "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] - myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs") - myvars = portage.util.unique_array(myvars) - myvars.sort() - - for x in myvars: - if portage.isvalidatom(x): - pkg_matches = trees["/"]["vartree"].dbapi.match(x) - pkg_matches = [portage.catpkgsplit(cpv)[1:] for cpv in pkg_matches] - pkg_matches.sort(portage.pkgcmp) - pkgs = [] - for pn, ver, rev in pkg_matches: - if rev != "r0": - pkgs.append(ver + "-" + rev) - else: - pkgs.append(ver) - if pkgs: - pkgs = ", ".join(pkgs) - print "%-20s %s" % (x+":", pkgs) - else: - print "%-20s %s" % (x+":", "[NOT VALID]") - - libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool")) - - if "--verbose" in myopts: - myvars=settings.keys() - else: - myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK', - 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR', - 'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS', - 'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS'] - - myvars.extend(portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_vars")) - - myvars = portage.util.unique_array(myvars) - unset_vars = [] - myvars.sort() - for x in myvars: - if x in settings: - if x != "USE": - print '%s="%s"' % (x, settings[x]) - else: - use = set(settings["USE"].split()) - use_expand = settings["USE_EXPAND"].split() - use_expand.sort() - for varname in use_expand: - flag_prefix = varname.lower() + "_" - for f in list(use): - if f.startswith(flag_prefix): - use.remove(f) - use = list(use) - use.sort() - print 'USE="%s"' % " ".join(use), - for varname in use_expand: - myval = settings.get(varname) - if myval: - print '%s="%s"' % (varname, myval), - print - else: - unset_vars.append(x) - if unset_vars: - print "Unset: "+", ".join(unset_vars) - print - - if "--debug" in myopts: - for x in dir(portage): - module = getattr(portage, x) - if "cvs_id_string" in dir(module): - print "%s: %s" % (str(x), str(module.cvs_id_string)) - - # See if we can find any packages installed matching the strings - # passed on the command line - mypkgs = [] - vardb = trees[settings["ROOT"]]["vartree"].dbapi - portdb = trees[settings["ROOT"]]["porttree"].dbapi - for x in myfiles: - mypkgs.extend(vardb.match(x)) - - # If some packages were found... - if mypkgs: - # Get our global settings (we only print stuff if it varies from - # the current config) - mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS' ] - auxkeys = mydesiredvars + [ "USE", "IUSE"] - global_vals = {} - pkgsettings = portage.config(clone=settings) - - for myvar in mydesiredvars: - global_vals[myvar] = set(settings.get(myvar, "").split()) - - # Loop through each package - # Only print settings if they differ from global settings - header_title = "Package Settings" - print header_width * "=" - print header_title.rjust(int(header_width/2 + len(header_title)/2)) - print header_width * "=" - from portage.output import EOutput - out = EOutput() - for pkg in mypkgs: - # Get all package specific variables - auxvalues = vardb.aux_get(pkg, auxkeys) - valuesmap = {} - for i in xrange(len(auxkeys)): - valuesmap[auxkeys[i]] = set(auxvalues[i].split()) - diff_values = {} - for myvar in mydesiredvars: - # If the package variable doesn't match the - # current global variable, something has changed - # so set diff_found so we know to print - if valuesmap[myvar] != global_vals[myvar]: - diff_values[myvar] = valuesmap[myvar] - valuesmap["IUSE"] = set(filter_iuse_defaults(valuesmap["IUSE"])) - valuesmap["USE"] = valuesmap["USE"].intersection(valuesmap["IUSE"]) - pkgsettings.reset() - # If a matching ebuild is no longer available in the tree, maybe it - # would make sense to compare against the flags for the best - # available version with the same slot? - mydb = None - if portdb.cpv_exists(pkg): - mydb = portdb - pkgsettings.setcpv(pkg, mydb=mydb) - if valuesmap["IUSE"].intersection(pkgsettings["USE"].split()) != \ - valuesmap["USE"]: - diff_values["USE"] = valuesmap["USE"] - # If a difference was found, print the info for - # this package. - if diff_values: - # Print package info - print "%s was built with the following:" % pkg - for myvar in mydesiredvars + ["USE"]: - if myvar in diff_values: - mylist = list(diff_values[myvar]) - mylist.sort() - print "%s=\"%s\"" % (myvar, " ".join(mylist)) - print - print ">>> Attempting to run pkg_info() for '%s'" % pkg - ebuildpath = vardb.findname(pkg) - if not ebuildpath or not os.path.exists(ebuildpath): - out.ewarn("No ebuild found for '%s'" % pkg) - continue - portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"], - pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1), - mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, - tree="vartree") - -def action_search(settings, portdb, vartree, myopts, myfiles, spinner, setconfig): - if not myfiles: - print "emerge: no search terms provided." - else: - searchinstance = search(settings, portdb, - vartree, spinner, "--searchdesc" in myopts, - "--quiet" not in myopts, setconfig) - 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() - -def action_depclean(settings, trees, ldpath_mtimes, - myopts, action, myfiles, spinner): - # Kill packages that aren't explicitly merged or are required as a - # dependency of another package. World file is explicit. - - msg = [] - msg.append("Depclean may break link level dependencies. Thus, it is\n") - msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n") - msg.append("app-portage/gentoolkit) in order to detect such breakage.\n") - msg.append("\n") - msg.append("Also study the list of packages to be cleaned for any obvious\n") - msg.append("mistakes. Packages that are part of the world set will always\n") - msg.append("be kept. They can be manually added to this set with\n") - msg.append(good("`emerge --noreplace `") + ". Packages that are listed in\n") - msg.append("package.provided (see portage(5)) will be removed by\n") - msg.append("depclean, even if they are part of the world set.\n") - msg.append("\n") - msg.append("As a safety measure, depclean will not remove any packages\n") - msg.append("unless *all* required dependencies have been resolved. As a\n") - msg.append("consequence, it is often necessary to run\n") - msg.append(good("`emerge --update --newuse --deep world`") + " prior to depclean.\n") - - if action == "depclean" and "--quiet" not in myopts and not myfiles: - portage.writemsg_stdout("\n") - for x in msg: - portage.writemsg_stdout(colorize("BAD", "*** WARNING *** ") + x) - - xterm_titles = "notitles" not in settings.features - myroot = settings["ROOT"] - portdb = trees[myroot]["porttree"].dbapi - dep_check_trees = {} - dep_check_trees[myroot] = {} - dep_check_trees[myroot]["vartree"] = \ - FakeVartree(trees[myroot]["vartree"], - trees[myroot]["porttree"].dbapi, - depgraph._mydbapi_keys) - vardb = dep_check_trees[myroot]["vartree"].dbapi - # Constrain dependency selection to the installed packages. - dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"] - system_set = SystemSet(settings.profiles) - syslist = list(system_set) - world_set = WorldSet(myroot) - worldlist = list(world_set) - args_set = InternalPackageSet() - fakedb = portage.fakedbapi(settings=settings) - myvarlist = vardb.cpv_all() - - if not syslist: - print "\n!!! You have no system list.", - if not worldlist: - print "\n!!! You have no world file.", - if not myvarlist: - print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH, - - if not (syslist and worldlist and myvarlist): - print "\n!!! Proceeding "+(syslist and myvarlist and "may" or "will") - print " break your installation.\n" - if "--pretend" not in myopts: - countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean") - - if action == "depclean": - emergelog(xterm_titles, " >>> depclean") - if myfiles: - for x in myfiles: - if not is_valid_package_atom(x): - portage.writemsg("!!! '%s' is not a valid package atom.\n" % x, - noiselevel=-1) - portage.writemsg("!!! Please check ebuild(5) for full details.\n") - return - try: - atom = portage.dep_expand(x, mydb=vardb, settings=settings) - except ValueError, e: - print "!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" - print "!!! one of the following fully-qualified ebuild names instead:\n" - for i in e[0]: - print " " + colorize("INFORM", i) - print - return - args_set.add(atom) - matched_packages = False - for x in args_set: - if vardb.match(x): - matched_packages = True - break - if not matched_packages: - portage.writemsg_stdout( - ">>> No packages selected for removal by %s\n" % action) - return - - if "--quiet" not in myopts: - print "\nCalculating dependencies ", - - soft = 0 - hard = 1 - remaining_atoms = [] - if action == "depclean": - for atom in worldlist: - if vardb.match(atom): - remaining_atoms.append((atom, 'world', hard)) - for atom in syslist: - if vardb.match(atom): - remaining_atoms.append((atom, 'system', hard)) - elif action == "prune": - for atom in syslist: - if vardb.match(atom): - remaining_atoms.append((atom, 'system', hard)) - # Pull in everything that's installed since we don't want to prune a - # package if something depends on it. - remaining_atoms.extend((atom, 'world', hard) for atom in vardb.cp_all()) - if not myfiles: - # Try to prune everything that's slotted. - for cp in vardb.cp_all(): - if len(vardb.cp_list(cp)) > 1: - args_set.add(cp) - - unresolveable = {} - aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"] - metadata_keys = ["PROVIDE", "SLOT", "USE"] - graph = digraph() - - while remaining_atoms: - atom, parent, priority = remaining_atoms.pop() - pkgs = vardb.match(atom) - if not pkgs: - if not atom.startswith("!") and priority == hard: - unresolveable.setdefault(atom, []).append(parent) - continue - if action == "depclean" and parent == "world" and myfiles: - # Filter out packages given as arguments since the user wants - # to remove those. - filtered_pkgs = [] - for pkg in pkgs: - metadata = dict(izip(metadata_keys, - vardb.aux_get(pkg, metadata_keys))) - arg_atom = None - try: - arg_atom = args_set.findAtomForPackage(pkg, metadata) - except portage.exception.InvalidDependString, e: - file_path = os.path.join(myroot, VDB_PATH, pkg, "PROVIDE") - portage.writemsg("\n\nInvalid PROVIDE: %s\n" % str(s), - noiselevel=-1) - portage.writemsg("See '%s'\n" % file_path, - noiselevel=-1) - del e - if not arg_atom: - filtered_pkgs.append(pkg) - pkgs = filtered_pkgs - prune_this = False - if action == "prune": - for pkg in pkgs: - metadata = dict(izip(metadata_keys, - vardb.aux_get(pkg, metadata_keys))) - try: - arg_atom = args_set.findAtomForPackage(pkg, metadata) - except portage.exception.InvalidDependString, e: - file_path = os.path.join(myroot, VDB_PATH, pkg, "PROVIDE") - portage.writemsg("\n\nInvalid PROVIDE: %s\n" % str(s), - noiselevel=-1) - portage.writemsg("See '%s'\n" % file_path, - noiselevel=-1) - del e - continue - if arg_atom: - prune_this = True - break - if len(pkgs) > 1 and (parent != "world" or prune_this): - # Prune all but the best matching slot, since that's all that a - # deep world update would pull in. Don't prune if this atom comes - # directly from world though, since world atoms are greedy when - # they don't specify a slot. - visible_in_portdb = [cpv for cpv in pkgs if portdb.match("="+cpv)] - if visible_in_portdb: - # For consistency with the update algorithm, keep the highest - # visible version and prune any versions that are either masked - # or no longer exist in the portage tree. - pkgs = visible_in_portdb - pkgs = [portage.best(pkgs)] - for pkg in pkgs: - graph.add(pkg, parent) - if fakedb.cpv_exists(pkg): - continue - spinner.update() - fakedb.cpv_inject(pkg) - myaux = dict(izip(aux_keys, vardb.aux_get(pkg, aux_keys))) - mydeps = [] - if myopts.get("--with-bdeps", "y") == "y": - mydeps.append((myaux["DEPEND"], soft)) - del myaux["DEPEND"] - mydeps.append((" ".join(myaux.values()), hard)) - usedef = vardb.aux_get(pkg, ["USE"])[0].split() - for depstr, priority in mydeps: - - if not depstr: - continue - - if "--debug" in myopts: - print - print "Parent: ", pkg - print "Depstring:", depstr - print "Priority:", - if priority == soft: - print "soft" - else: - print "hard" - - try: - portage.dep._dep_check_strict = False - success, atoms = portage.dep_check(depstr, None, settings, - myuse=usedef, trees=dep_check_trees, myroot=myroot) - finally: - portage.dep._dep_check_strict = True - if not success: - show_invalid_depstring_notice( - ("installed", myroot, pkg, "nomerge"), - depstr, atoms) - return - - if "--debug" in myopts: - print "Candidates:", atoms - - for atom in atoms: - remaining_atoms.append((atom, pkg, priority)) - - if "--quiet" not in myopts: - print "\b\b... done!\n" - - if unresolveable: - print "Dependencies could not be completely resolved due to" - print "the following required packages not being installed:" - print - for atom in unresolveable: - print atom, "required by", " ".join(unresolveable[atom]) - if unresolveable: - print - print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to" - print "%s? It may be necessary to manually uninstall packages that no longer" % action - print "exist in the portage tree since it may not be possible to satisfy their" - print "dependencies. Also, be aware of the --with-bdeps option that is documented" - print "in " + good("`man emerge`") + "." - print - if action == "prune": - print "If you would like to ignore dependencies then use %s." % \ - good("--nodeps") - return - - def show_parents(child_node): - parent_nodes = graph.parent_nodes(child_node) - if not parent_nodes: - # With --prune, the highest version can be pulled in without any - # real parent since all installed packages are pulled in. In that - # case there's nothing to show here. - return - parent_nodes.sort() - msg = [] - msg.append(" %s pulled in by:\n" % str(child_node)) - for parent_node in parent_nodes: - msg.append(" %s\n" % str(parent_node)) - msg.append("\n") - portage.writemsg_stdout("".join(msg), noiselevel=-1) - - cleanlist = [] - if action == "depclean": - if myfiles: - for pkg in vardb.cpv_all(): - metadata = dict(izip(metadata_keys, - vardb.aux_get(pkg, metadata_keys))) - arg_atom = None - try: - arg_atom = args_set.findAtomForPackage(pkg, metadata) - except portage.exception.InvalidDependString: - # this error has already been displayed by now - continue - if arg_atom: - if not fakedb.cpv_exists(pkg): - cleanlist.append(pkg) - elif "--verbose" in myopts: - show_parents(pkg) - else: - for pkg in vardb.cpv_all(): - if not fakedb.cpv_exists(pkg): - cleanlist.append(pkg) - elif "--verbose" in myopts: - show_parents(pkg) - elif action == "prune": - # Prune really uses all installed instead of world. It's not a real - # reverse dependency so don't display it as such. - if graph.contains("world"): - graph.remove("world") - for atom in args_set: - for pkg in vardb.match(atom): - if not fakedb.cpv_exists(pkg): - cleanlist.append(pkg) - elif "--verbose" in myopts: - show_parents(pkg) - - if not cleanlist: - portage.writemsg_stdout( - ">>> No packages selected for removal by %s\n" % action) - if "--verbose" not in myopts: - portage.writemsg_stdout( - ">>> To see reverse dependencies, use %s\n" % \ - good("--verbose")) - if action == "prune": - portage.writemsg_stdout( - ">>> To ignore dependencies, use %s\n" % \ - good("--nodeps")) - - if len(cleanlist): - unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"], - "unmerge", cleanlist, ldpath_mtimes) - - if action == "prune": - return - - if not cleanlist and "--quiet" in myopts: - return - - 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(myvarlist)) - print "Required packages: "+str(len(fakedb.cpv_all())) - if "--pretend" in myopts: - print "Number to remove: "+str(len(cleanlist)) - else: - print "Number removed: "+str(len(cleanlist)) - -def action_build(settings, trees, mtimedb, - myopts, myaction, myfiles, spinner): - ldpath_mtimes = mtimedb["ldpath"] - favorites=[] - merge_count = 0 - pretend = "--pretend" in myopts - fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts - if pretend or fetchonly: - # make the mtimedb readonly - mtimedb.filename = None - if "--quiet" not in myopts and \ - ("--pretend" in myopts or "--ask" in myopts or \ - "--tree" in myopts or "--verbose" in myopts): - action = "" - if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: - action = "fetched" - elif "--buildpkgonly" in myopts: - action = "built" - else: - action = "merged" - if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching - print - print darkgreen("These are the packages that would be %s, in reverse order:") % action - print - else: - print - print darkgreen("These are the packages that would be %s, in order:") % action - print - - # validate the state of the resume data - # so that we can make assumptions later. - for k in ("resume", "resume_backup"): - if k in mtimedb: - if "mergelist" in mtimedb[k]: - if not mtimedb[k]["mergelist"]: - del mtimedb[k] - else: - del mtimedb[k] - - if "--resume" in myopts and \ - ("resume" in mtimedb or - "resume_backup" in mtimedb): - if "resume" not in mtimedb: - mtimedb["resume"] = mtimedb["resume_backup"] - del mtimedb["resume_backup"] - mtimedb.commit() - - # Adjust config according to options of the command being resumed. - for myroot in trees: - mysettings = trees[myroot]["vartree"].settings - mysettings.unlock() - adjust_config(myopts, mysettings) - mysettings.lock() - del myroot, mysettings - - # "myopts" is a list for backward compatibility. - resume_opts = mtimedb["resume"].get("myopts", []) - if isinstance(resume_opts, list): - resume_opts = dict((k,True) for k in resume_opts) - for opt in ("--skipfirst", "--ask", "--tree"): - resume_opts.pop(opt, None) - myopts.update(resume_opts) - show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts - if not show_spinner: - spinner.update = spinner.update_quiet - if show_spinner: - print "Calculating dependencies ", - myparams = create_depgraph_params(myopts, myaction) - mydepgraph = depgraph(settings, trees, - myopts, myparams, spinner) - try: - mydepgraph.loadResumeCommand(mtimedb["resume"]) - except portage.exception.PackageNotFound: - if show_spinner: - print - from portage.output import EOutput - out = EOutput() - out.eerror("Error: The resume list contains packages that are no longer") - out.eerror(" available to be emerged. Please restart/continue") - out.eerror(" the merge operation manually.") - return 1 - if show_spinner: - print "\b\b... done!" - else: - if ("--resume" in myopts): - print darkgreen("emerge: It seems we have nothing to resume...") - return os.EX_OK - - myparams = create_depgraph_params(myopts, myaction) - if myaction in ["system","world"]: - if "--quiet" not in myopts and "--nodeps" not in myopts: - print "Calculating",myaction,"dependencies ", - sys.stdout.flush() - mydepgraph = depgraph(settings, trees, myopts, myparams, spinner) - if not mydepgraph.xcreate(myaction): - print "!!! Depgraph creation failed." - return 1 - if "--quiet" not in myopts and "--nodeps" not in myopts: - print "\b\b... done!" - else: - if "--quiet" not in myopts and "--nodeps" not in myopts: - print "Calculating dependencies ", - sys.stdout.flush() - mydepgraph = depgraph(settings, trees, myopts, myparams, spinner) - try: - retval, favorites = mydepgraph.select_files(myfiles) - except portage.exception.PackageNotFound, e: - portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1) - return 1 - if not retval: - return 1 - if "--quiet" not in myopts and "--nodeps" not in myopts: - print "\b\b... done!" - - if ("--usepkgonly" in myopts) and mydepgraph.missingbins: - sys.stderr.write(red("The following binaries are not available for merging...\n")) - - if mydepgraph.missingbins: - for x in mydepgraph.missingbins: - sys.stderr.write(" "+str(x)+"\n") - sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") - return 1 - - if "--pretend" not in myopts and \ - ("--ask" in myopts or "--tree" in myopts or \ - "--verbose" in myopts) and \ - not ("--quiet" in myopts and "--ask" not in myopts): - if "--resume" in myopts: - mymergelist = mtimedb["resume"]["mergelist"] - if "--skipfirst" in myopts: - mymergelist = mymergelist[1:] - if len(mymergelist) == 0: - print colorize("INFORM", "emerge: It seems we have nothing to resume...") - return os.EX_OK - favorites = mtimedb["resume"]["favorites"] - retval = mydepgraph.display(mymergelist, favorites=favorites) - if retval != os.EX_OK: - return retval - prompt="Would you like to resume merging these packages?" - else: - retval = mydepgraph.display( - mydepgraph.altlist(reversed=("--tree" in myopts)), - favorites=favorites) - if retval != os.EX_OK: - return retval - mergecount=0 - for x in mydepgraph.altlist(): - if x[0] != "blocks" and x[3] != "nomerge": - mergecount+=1 - #check for blocking dependencies - if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts: - print "\n!!! Error: The above package list contains packages which cannot be installed" - print "!!! at the same time on the same system." - if "--quiet" not in myopts: - show_blocker_docs_link() - return 1 - if mergecount==0: - if "--noreplace" in myopts and favorites: - print - for x in favorites: - print " %s %s" % (good("*"), x) - prompt="Would you like to add these packages to your world favorites?" - elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]: - prompt="Nothing to merge; would you like to auto-clean packages?" - else: - print - print "Nothing to merge; quitting." - print - return os.EX_OK - elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts: - prompt="Would you like to fetch the source files for these packages?" - else: - prompt="Would you like to merge these packages?" - print - if "--ask" in myopts and userquery(prompt) == "No": - print - print "Quitting." - print - return os.EX_OK - # Don't ask again (e.g. when auto-cleaning packages after merge) - myopts.pop("--ask", None) - - if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): - if ("--resume" in myopts): - mymergelist = mtimedb["resume"]["mergelist"] - if "--skipfirst" in myopts: - mymergelist = mymergelist[1:] - if len(mymergelist) == 0: - print colorize("INFORM", "emerge: It seems we have nothing to resume...") - return os.EX_OK - favorites = mtimedb["resume"]["favorites"] - retval = mydepgraph.display(mymergelist, favorites=favorites) - if retval != os.EX_OK: - return retval - else: - retval = mydepgraph.display( - mydepgraph.altlist(reversed=("--tree" in myopts)), - favorites=favorites) - if retval != os.EX_OK: - return retval - if "--buildpkgonly" in myopts and \ - not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM): - print "\n!!! --buildpkgonly requires all dependencies to be merged." - print "!!! You have to merge the dependencies before you can build this package.\n" - return 1 - else: - if ("--buildpkgonly" in myopts): - if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM): - print "\n!!! --buildpkgonly requires all dependencies to be merged." - print "!!! Cannot merge requested packages. Merge deps and try again.\n" - return 1 - - if ("--resume" in myopts): - favorites=mtimedb["resume"]["favorites"] - mergetask = MergeTask(settings, trees, myopts) - if "--fetchonly" in myopts: - """ parallel-fetch uses --resume --fetchonly and we don't want - it to write the mtimedb""" - mtimedb.filename = None - time.sleep(3) # allow the parent to have first fetch - del mydepgraph - retval = mergetask.merge( - mtimedb["resume"]["mergelist"], favorites, mtimedb) - merge_count = mergetask.curval - else: - if "resume" in mtimedb and \ - "mergelist" in mtimedb["resume"] and \ - len(mtimedb["resume"]["mergelist"]) > 1: - mtimedb["resume_backup"] = mtimedb["resume"] - del mtimedb["resume"] - mtimedb.commit() - mtimedb["resume"]={} - # XXX: Stored as a list for backward compatibility. - mtimedb["resume"]["myopts"] = \ - [k for k in myopts if myopts[k] is True] - mtimedb["resume"]["favorites"]=favorites - if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): - for pkgline in mydepgraph.altlist(): - if pkgline[0]=="ebuild" and pkgline[3]=="merge": - y = trees[pkgline[1]]["porttree"].dbapi.findname(pkgline[2]) - tmpsettings = portage.config(clone=settings) - edebug = 0 - if settings.get("PORTAGE_DEBUG", "") == "1": - edebug = 1 - retval = portage.doebuild( - y, "digest", settings["ROOT"], tmpsettings, edebug, - ("--pretend" in myopts), - mydbapi=trees[pkgline[1]]["porttree"].dbapi, - tree="porttree") - if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: - pkglist = [] - for pkg in mydepgraph.altlist(): - if pkg[0] != "blocks": - pkglist.append(pkg) - else: - pkglist = mydepgraph.altlist() - if favorites: - mydepgraph.saveNomergeFavorites() - del mydepgraph - mergetask = MergeTask(settings, trees, myopts) - retval = mergetask.merge(pkglist, favorites, mtimedb) - merge_count = mergetask.curval - - if retval == os.EX_OK and not (pretend or fetchonly): - mtimedb.pop("resume", None) - if "yes" == settings.get("AUTOCLEAN"): - portage.writemsg_stdout(">>> Auto-cleaning packages...\n") - vartree = trees[settings["ROOT"]]["vartree"] - unmerge(settings, myopts, vartree, "clean", ["world"], - ldpath_mtimes, autoclean=1) - else: - portage.writemsg_stdout(colorize("WARN", "WARNING:") - + " AUTOCLEAN is disabled. This can cause serious" - + " problems due to overlapping packages.\n") - - if merge_count and not (pretend or fetchonly): - post_emerge(trees, mtimedb, retval) - return retval - -def multiple_actions(action1, action2): - sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n") - sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2)) - sys.exit(1) - -def parse_opts(tmpcmdline, silent=False): - myaction=None - myopts = {} - myfiles=[] - - global actions, options, shortmapping - - longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"} - argument_options = { - "--config-root": { - "help":"specify the location for portage configuration files", - "action":"store" - }, - "--color": { - "help":"enable or disable color output", - "type":"choice", - "choices":("y", "n") - }, - "--with-bdeps": { - "help":"include unnecessary build time dependencies", - "type":"choice", - "choices":("y", "n") - }, - "--reinstall": { - "help":"specify conditions to trigger package reinstallation", - "type":"choice", - "choices":["changed-use"] - } - } - - from optparse import OptionParser - parser = OptionParser() - if parser.has_option("--help"): - parser.remove_option("--help") - - for action_opt in actions: - parser.add_option("--" + action_opt, action="store_true", - dest=action_opt.replace("-", "_"), default=False) - for myopt in options: - parser.add_option(myopt, action="store_true", - dest=myopt.lstrip("--").replace("-", "_"), default=False) - for shortopt, longopt in shortmapping.iteritems(): - parser.add_option("-" + shortopt, action="store_true", - dest=longopt.lstrip("--").replace("-", "_"), default=False) - for myalias, myopt in longopt_aliases.iteritems(): - parser.add_option(myalias, action="store_true", - dest=myopt.lstrip("--").replace("-", "_"), default=False) - - for myopt, kwargs in argument_options.iteritems(): - parser.add_option(myopt, - dest=myopt.lstrip("--").replace("-", "_"), **kwargs) - - myoptions, myargs = parser.parse_args(args=tmpcmdline) - - for myopt in options: - v = getattr(myoptions, myopt.lstrip("--").replace("-", "_")) - if v: - myopts[myopt] = True - - for myopt in argument_options: - v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None) - if v is not None: - myopts[myopt] = v - - for action_opt in actions: - v = getattr(myoptions, action_opt.replace("-", "_")) - if v: - if myaction: - multiple_actions(myaction, action_opt) - sys.exit(1) - myaction = action_opt - - for x in myargs: - if x in actions and myaction != "search": - if not silent and x not in ["system", "world"]: - print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x)) - # special case "search" so people can search for action terms, e.g. emerge -s sync - if myaction: - multiple_actions(myaction, x) - sys.exit(1) - myaction = x - else: - myfiles.append(x) - - if "--nocolor" in myopts: - if not silent: - sys.stderr.write("*** Deprecated use of '--nocolor', " + \ - "use '--color=n' instead.\n") - del myopts["--nocolor"] - myopts["--color"] = "n" - - return myaction, myopts, myfiles - -def validate_ebuild_environment(trees): - for myroot in trees: - mysettings = trees[myroot]["vartree"].settings - for var in "ARCH", "USERLAND": - if mysettings.get(var): - continue - print >> sys.stderr, bad(("\a!!! %s is not set... " % var) + \ - "Are you missing the '%setc/make.profile' symlink?" % \ - mysettings["PORTAGE_CONFIGROOT"]) - print >> sys.stderr, bad("\a!!! Is the symlink correct? " + \ - "Is your portage tree complete?\n") - sys.exit(9) - del myroot, mysettings - -def load_emerge_config(trees=None): - kwargs = {} - for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")): - kwargs[k] = os.environ.get(envvar, None) - trees = portage.create_trees(trees=trees, **kwargs) - - settings = trees["/"]["vartree"].settings - - for myroot in trees: - if myroot != "/": - settings = trees[myroot]["vartree"].settings - break - - mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb") - mtimedb = portage.MtimeDB(mtimedbfile) - return settings, trees, mtimedb - -def adjust_config(myopts, settings): - """Make emerge specific adjustments to the config.""" - - # To enhance usability, make some vars case insensitive by forcing them to - # lower case. - for myvar in ("AUTOCLEAN", "NOCOLOR"): - if myvar in settings: - settings[myvar] = settings[myvar].lower() - settings.backup_changes(myvar) - del myvar - - # Kill noauto as it will break merges otherwise. - if "noauto" in settings.features: - while "noauto" in settings.features: - settings.features.remove("noauto") - settings["FEATURES"] = " ".join(settings.features) - settings.backup_changes("FEATURES") - - CLEAN_DELAY = 5 - try: - CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY))) - except ValueError, e: - portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) - portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \ - settings["CLEAN_DELAY"], noiselevel=-1) - settings["CLEAN_DELAY"] = str(CLEAN_DELAY) - settings.backup_changes("CLEAN_DELAY") - - EMERGE_WARNING_DELAY = 10 - try: - EMERGE_WARNING_DELAY = int(settings.get( - "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY))) - except ValueError, e: - portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) - portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \ - settings["EMERGE_WARNING_DELAY"], noiselevel=-1) - settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY) - settings.backup_changes("EMERGE_WARNING_DELAY") - - if "--quiet" in myopts: - settings["PORTAGE_QUIET"]="1" - settings.backup_changes("PORTAGE_QUIET") - - # Set so that configs will be merged regardless of remembered status - if ("--noconfmem" in myopts): - settings["NOCONFMEM"]="1" - settings.backup_changes("NOCONFMEM") - - # Set various debug markers... They should be merged somehow. - PORTAGE_DEBUG = 0 - try: - PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG))) - if PORTAGE_DEBUG not in (0, 1): - portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \ - PORTAGE_DEBUG, noiselevel=-1) - portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n", - noiselevel=-1) - PORTAGE_DEBUG = 0 - except ValueError, e: - portage.writemsg("!!! %s\n" % str(e), noiselevel=-1) - portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\ - settings["PORTAGE_DEBUG"], noiselevel=-1) - del e - if "--debug" in myopts: - PORTAGE_DEBUG = 1 - settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG) - settings.backup_changes("PORTAGE_DEBUG") - - if settings.get("NOCOLOR") not in ("yes","true"): - portage.output.havecolor = 1 - - """The explicit --color < y | n > option overrides the NOCOLOR environment - variable and stdout auto-detection.""" - if "--color" in myopts: - if "y" == myopts["--color"]: - portage.output.havecolor = 1 - settings["NOCOLOR"] = "false" - else: - portage.output.havecolor = 0 - settings["NOCOLOR"] = "true" - settings.backup_changes("NOCOLOR") - elif not sys.stdout.isatty() and settings.get("NOCOLOR") != "no": - portage.output.havecolor = 0 - settings["NOCOLOR"] = "true" - settings.backup_changes("NOCOLOR") - -def emerge_main(): - global portage # NFC why this is necessary now - genone - # Disable color until we're sure that it should be enabled (after - # EMERGE_DEFAULT_OPTS has been parsed). - portage.output.havecolor = 0 - # This first pass is just for options that need to be known as early as - # possible, such as --config-root. They will be parsed again later, - # together with EMERGE_DEFAULT_OPTS (which may vary depending on the - # the value of --config-root). - myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True) - if "--debug" in myopts: - os.environ["PORTAGE_DEBUG"] = "1" - if "--config-root" in myopts: - os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"] - - # Portage needs to ensure a sane umask for the files it creates. - os.umask(022) - settings, trees, mtimedb = load_emerge_config() - portdb = trees[settings["ROOT"]]["porttree"].dbapi - - try: - os.nice(int(settings.get("PORTAGE_NICENESS", "0"))) - except (OSError, ValueError), e: - portage.writemsg("!!! Failed to change nice value to '%s'\n" % \ - settings["PORTAGE_NICENESS"]) - portage.writemsg("!!! %s\n" % str(e)) - del e - - if portage._global_updates(trees, mtimedb["updates"]): - mtimedb.commit() - # Reload the whole config from scratch. - settings, trees, mtimedb = load_emerge_config(trees=trees) - portdb = trees[settings["ROOT"]]["porttree"].dbapi - - xterm_titles = "notitles" not in settings.features - - tmpcmdline = [] - if "--ignore-default-opts" not in myopts: - tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split()) - tmpcmdline.extend(sys.argv[1:]) - myaction, myopts, myfiles = parse_opts(tmpcmdline) - - if "--digest" in myopts: - os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest" - # Reload the whole config from scratch so that the portdbapi internal - # config is updated with new FEATURES. - settings, trees, mtimedb = load_emerge_config(trees=trees) - portdb = trees[settings["ROOT"]]["porttree"].dbapi - - for myroot in trees: - mysettings = trees[myroot]["vartree"].settings - mysettings.unlock() - adjust_config(myopts, mysettings) - mysettings.lock() - del myroot, mysettings - - spinner = stdout_spinner() - if "candy" in settings.features: - spinner.update = spinner.update_scroll - - if "--quiet" not in myopts: - portage.deprecated_profile_check() - - #Freeze the portdbapi for enhanced performance: - for myroot in trees: - trees[myroot]["porttree"].dbapi.freeze() - del myroot - - if "moo" in myfiles: - print """ - - Larry loves Gentoo (""" + os.uname()[0] + """) - - _______________________ -< Have you mooed today? > - ----------------------- - \ ^__^ - \ (oo)\_______ - (__)\ )\/\ - ||----w | - || || - -""" - - if (myaction in ["world", "system"]) and myfiles: - print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both." - sys.exit(1) - - for x in myfiles: - ext = os.path.splitext(x)[1] - if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): - print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n") - break - - setconfigpaths = [os.path.join(GLOBAL_CONFIG_PATH, "sets.conf")] - setconfigpaths.append(os.path.join(settings["PORTDIR"], "sets.conf")) - setconfigpaths += [os.path.join(x, "sets.conf") for x in settings["PORDIR_OVERLAY"].split()] - setconfigpaths.append(os.path.join(settings["PORTAGE_CONFIGROOT"], - USER_CONFIG_PATH.lstrip(os.path.sep), "sets.conf")) - #setconfig = SetConfig(setconfigpaths, settings, trees[settings["ROOT"]]) - setconfig = make_default_config(settings, trees[settings["ROOT"]]) - del setconfigpaths - if myaction not in ["search", "metadata", "sync"]: - oldargs = myfiles[:] - packagesets, setconfig_errors = setconfig.getSetsWithAliases() - for s in packagesets: - if s in myfiles: - # TODO: check if the current setname also resolves to a package name - if myaction in ["unmerge", "prune", "clean", "depclean"] and not packagesets[s].supportsOperation("unmerge"): - print "emerge: the given set %s does not support unmerge operations" % s - sys.exit(1) - if not packagesets[s].getAtoms(): - print "emerge: '%s' is an empty set" % s - else: - myfiles.extend(packagesets[s].getAtoms()) - for e in packagesets[s].errors: - print e - myfiles.remove(s) - # Need to handle empty sets specially, otherwise emerge will react - # with the help message for empty argument lists - if oldargs and not myfiles: - print "emerge: no targets left after set expansion" - sys.exit(0) - del oldargs - - if ("--tree" in myopts) and ("--columns" in myopts): - print "emerge: can't specify both of \"--tree\" and \"--columns\"." - sys.exit(1) - - if ("--quiet" in myopts): - spinner.update = spinner.update_quiet - portage.util.noiselimit = -1 - - # Always create packages if FEATURES=buildpkg - # Imply --buildpkg if --buildpkgonly - if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts): - if "--buildpkg" not in myopts: - myopts["--buildpkg"] = True - - # Also allow -S to invoke search action (-sS) - if ("--searchdesc" in myopts): - if myaction and myaction != "search": - myfiles.append(myaction) - if "--search" not in myopts: - myopts["--search"] = True - myaction = "search" - - # Always try and fetch binary packages if FEATURES=getbinpkg - if ("getbinpkg" in settings.features): - myopts["--getbinpkg"] = True - - if "--skipfirst" in myopts and "--resume" not in myopts: - myopts["--resume"] = True - - if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): - myopts["--usepkgonly"] = True - - if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): - myopts["--getbinpkg"] = True - - if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): - myopts["--usepkg"] = True - - # Also allow -K to apply --usepkg/-k - if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): - myopts["--usepkg"] = True - - # Allow -p to remove --ask - if ("--pretend" in myopts) and ("--ask" in myopts): - print ">>> --pretend disables --ask... removing --ask from options." - del myopts["--ask"] - - # forbid --ask when not in a terminal - # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. - if ("--ask" in myopts) and (not sys.stdin.isatty()): - portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n", - noiselevel=-1) - sys.exit(1) - - if settings.get("PORTAGE_DEBUG", "") == "1": - spinner.update = spinner.update_quiet - portage.debug=1 - if "python-trace" in settings.features: - import portage.debug - portage.debug.set_trace(True) - - if ("--resume" in myopts): - if "--tree" in myopts: - print "* --tree is currently broken with --resume. Disabling..." - del myopts["--tree"] - - if not ("--quiet" in myopts): - if not sys.stdout.isatty() or ("--nospinner" in myopts): - spinner.update = spinner.update_basic - - if "--version" in myopts: - print getportageversion(settings["PORTDIR"], settings["ROOT"], - settings.profile_path, settings["CHOST"], - trees[settings["ROOT"]]["vartree"].dbapi) - sys.exit(0) - elif "--help" in myopts: - emerge.help.help(myaction, myopts, portage.output.havecolor) - sys.exit(0) - - if "--debug" in myopts: - print "myaction", myaction - print "myopts", myopts - - if not myaction and not myfiles and "--resume" not in myopts: - emerge.help.help(myaction, myopts, portage.output.havecolor) - sys.exit(1) - - # check if root user is the current user for the actions where emerge needs this - if portage.secpass < 2: - # We've already allowed "--version" and "--help" above. - if "--pretend" not in myopts and myaction not in ("search","info"): - need_superuser = not \ - ("--fetchonly" in myopts or \ - "--fetch-all-uri" in myopts or \ - myaction in ("metadata", "regen") or \ - (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK))) - if portage.secpass < 1 or \ - need_superuser: - if need_superuser: - access_desc = "superuser" - else: - access_desc = "portage group" - # Always show portage_group_warning() when only portage group - # access is required but the user is not in the portage group. - from portage.data import portage_group_warning - if "--ask" in myopts: - myopts["--pretend"] = True - del myopts["--ask"] - print ("%s access is required... " + \ - "adding --pretend to options.\n") % access_desc - if portage.secpass < 1 and not need_superuser: - portage_group_warning() - else: - sys.stderr.write(("emerge: %s access is " + \ - "required.\n\n") % access_desc) - if portage.secpass < 1 and not need_superuser: - portage_group_warning() - return 1 - - disable_emergelog = False - for x in ("--pretend", "--fetchonly", "--fetch-all-uri"): - if x in myopts: - disable_emergelog = True - break - if myaction in ("search", "info"): - disable_emergelog = True - if disable_emergelog: - """ Disable emergelog for everything except build or unmerge - operations. This helps minimize parallel emerge.log entries that can - confuse log parsers. We especially want it disabled during - parallel-fetch, which uses --resume --fetchonly.""" - global emergelog - def emergelog(*pargs, **kargs): - pass - - if not "--pretend" in myopts: - emergelog(xterm_titles, "Started emerge on: "+\ - time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) - myelogstr="" - if myopts: - myelogstr=" ".join(myopts) - if myaction: - myelogstr+=" "+myaction - if myfiles: - myelogstr+=" "+" ".join(myfiles) - emergelog(xterm_titles, " *** emerge " + myelogstr) - - def emergeexitsig(signum, frame): - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTERM, signal.SIG_IGN) - portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) - sys.exit(100+signum) - signal.signal(signal.SIGINT, emergeexitsig) - signal.signal(signal.SIGTERM, emergeexitsig) - - def emergeexit(): - """This gets out final log message in before we quit.""" - if "--pretend" not in myopts: - emergelog(xterm_titles, " *** terminating.") - if "notitles" not in settings.features: - xtermTitleReset() - portage.atexit_register(emergeexit) - - if myaction in ("config", "metadata", "regen", "sync"): - if "--pretend" in myopts: - sys.stderr.write(("emerge: The '%s' action does " + \ - "not support '--pretend'.\n") % myaction) - return 1 - if "sync" == myaction: - action_sync(settings, trees, mtimedb, myopts, myaction) - elif "metadata" == myaction: - action_metadata(settings, portdb, myopts) - elif myaction=="regen": - validate_ebuild_environment(trees) - action_regen(settings, portdb) - # HELP action - elif "config"==myaction: - validate_ebuild_environment(trees) - action_config(settings, trees, myopts, myfiles) - - # INFO action - elif "info"==myaction: - action_info(settings, trees, myopts, myfiles) - - # SEARCH action - elif "search"==myaction: - validate_ebuild_environment(trees) - action_search(settings, portdb, trees["/"]["vartree"], - myopts, myfiles, spinner, setconfig) - elif myaction in ("clean", "unmerge") or \ - (myaction == "prune" and "--nodeps" in myopts): - validate_ebuild_environment(trees) - vartree = trees[settings["ROOT"]]["vartree"] - if 1 == unmerge(settings, myopts, vartree, myaction, myfiles, - mtimedb["ldpath"]): - if "--pretend" not in myopts: - post_emerge(trees, mtimedb, os.EX_OK) - - elif myaction in ("depclean", "prune"): - validate_ebuild_environment(trees) - action_depclean(settings, trees, mtimedb["ldpath"], - myopts, myaction, myfiles, spinner) - if "--pretend" not in myopts: - post_emerge(trees, mtimedb, os.EX_OK) - # "update", "system", or just process files: - else: - validate_ebuild_environment(trees) - if "--pretend" not in myopts: - display_news_notification(trees) - retval = action_build(settings, trees, mtimedb, - myopts, myaction, myfiles, spinner) - if "--pretend" in myopts: - display_news_notification(trees) - return retval - -if __name__ == "__main__": - retval = emerge_main() - sys.exit(retval) diff --git a/pym/emerge/help.py b/pym/emerge/help.py deleted file mode 100644 index 5bb93a1f4..000000000 --- a/pym/emerge/help.py +++ /dev/null @@ -1,394 +0,0 @@ -# Copyright 1999-2007 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Id$ - - -import os,sys -from portage.output import bold, turquoise, green - -def shorthelp(): - print bold("emerge:")+" the other white meat (command-line interface to the Portage system)" - print bold("Usage:") - print " "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] [ "+turquoise("ebuildfile")+" | "+turquoise("tbz2file")+" | "+turquoise("dependency")+" ] [ ... ]" - print " "+turquoise("emerge")+" [ "+green("options")+" ] [ "+green("action")+" ] < "+turquoise("system")+" | "+turquoise("world")+" >" - print " "+turquoise("emerge")+" < "+turquoise("--sync")+" | "+turquoise("--metadata")+" | "+turquoise("--info")+" >" - print " "+turquoise("emerge")+" "+turquoise("--resume")+" [ "+green("--pretend")+" | "+green("--ask")+" | "+green("--skipfirst")+" ]" - print " "+turquoise("emerge")+" "+turquoise("--help")+" [ "+green("system")+" | "+green("world")+" | "+green("--sync")+" ] " - print bold("Options:")+" "+green("-")+"["+green("abBcCdDefgGhkKlnNoOpqPsStuvV")+"] ["+green("--oneshot")+"] ["+green("--newuse")+"] ["+green("--noconfmem")+"]" - print " [ " + green("--color")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ] [ "+green("--columns")+" ]" - print " [ "+green("--reinstall ")+turquoise("changed-use")+" ] ["+green("--nospinner")+"]" - print " [ "+green("--deep")+" ] [" + green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" > ]" - print bold("Actions:")+" [ "+green("--clean")+" | "+green("--depclean")+" | "+green("--prune")+" | "+green("--regen")+" | "+green("--search")+" | "+green("--unmerge")+" ]" - -def help(myaction,myopts,havecolor=1): - if not myaction and ("--verbose" not in myopts): - shorthelp() - print - print " For more help try 'emerge --help --verbose' or consult the man page." - elif not myaction: - shorthelp() - print - print turquoise("Help (this screen):") - print " "+green("--help")+" ("+green("-h")+" short option)" - print " Displays this help; an additional argument (see above) will tell" - print " emerge to display detailed help." - print - print turquoise("Actions:") - print " "+green("--clean")+" ("+green("-c")+" short option)" - print " Cleans the system by removing outdated packages which will not" - print " remove functionalities or prevent your system from working." - print " The arguments can be in several different formats :" - print " * world " - print " * system or" - print " * 'dependency specification' (in single quotes is best.)" - print " Here are a few examples of the dependency specification format:" - print " "+bold("binutils")+" matches" - print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" - print " "+bold("sys-devel/binutils")+" matches" - print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" - print " "+bold(">sys-devel/binutils-2.11.90.0.7")+" matches" - print " binutils-2.11.92.0.12.3-r1" - print " "+bold(">=sys-devel/binutils-2.11.90.0.7")+" matches" - print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" - print " "+bold("<=sys-devel/binutils-2.11.92.0.12.3-r1")+" matches" - print " binutils-2.11.90.0.7 and binutils-2.11.92.0.12.3-r1" - print - print " "+green("--config") - print " Runs package-specific operations that must be executed after an" - print " emerge process has completed. This usually entails configuration" - print " file setup or other similar setups that the user may wish to run." - print - print " "+green("--depclean") - print " Cleans the system by removing packages that are not associated" - print " with explicitly merged packages. Depclean works by creating the" - print " full dependency tree from the system list and the world file," - print " then comparing it to installed packages. Packages installed, but" - print " not associated with an explicit merge are listed as candidates" - print " for unmerging. Inexperienced users are advised to use --pretend" - print " with this option in order to see a preview of which packages will" - print " be uninstalled. "+turquoise(" WARNING: Removing some packages may cause") - print " "+turquoise("packages which link to the removed package to stop working and") - print " "+turquoise("complain about missing libraries. Rebuild the complaining package") - print " "+turquoise("to fix this issue.")+" Also see --with-bdeps for behavior with" - print " respect to build time dependencies that are not strictly" - print " required. Depclean serves as a dependency aware version of" - print " --unmerge. When given one or more atoms, it will unmerge matched" - print " packages that have no reverse dependencies. Use --depclean" - print " together with --verbose to show reverse dependencies." - print - print " "+green("--info") - print " Displays important portage variables that will be exported to" - print " ebuild.sh when performing merges. This information is useful" - print " for bug reports and verification of settings. All settings in" - print " make.{conf,globals,defaults} and the environment show up if" - print " run with the '--verbose' flag." - print - print " "+green("--metadata") - print " Transfers metadata cache from ${PORTDIR}/metadata/cache/ to" - print " /var/cache/edb/dep/ as is normally done on the tail end of an" - print " rsync update using " + bold("emerge --sync") + ". This process populates the" - print " cache database that portage uses for pre-parsed lookups of" - print " package data. It does not populate cache for the overlays" - print " listed in PORTDIR_OVERLAY. In order to generate cache for" - print " overlays, use " + bold("--regen") + "." - print - print " "+green("--prune")+" ("+green("-P")+" short option)" - print " "+turquoise("WARNING: This action can remove important packages!") - print " Removes all but the highest installed version of a package" - print " from your system. This action doesn't verify the possible binary" - print " compatibility between versions and can thus remove essential" - print " dependencies from your system. Use --prune together with" - print " --verbose to show reverse dependencies or with --nodeps to" - print " ignore all dependencies." - print - print " "+green("--regen") - print " Causes portage to check and update the dependency cache of all" - print " ebuilds in the portage tree. This is not recommended for rsync" - print " users as rsync updates the cache using server-side caches." - print " Rsync users should simply 'emerge --sync' to regenerate." - print - print " "+green("--resume") - print " Resumes the most recent merge list that has been aborted due to an" - print " error. Please note that this operation will only return an error" - print " on failure. If there is nothing for portage to do, then portage" - print " will exit with a message and a success condition. A resume list" - print " will persist until it has been completed in entirety or until" - print " another aborted merge list replaces it. The resume history is" - print " capable of storing two merge lists. After one resume list" - print " completes, it is possible to invoke --resume once again in order" - print " to resume an older list." - print - print " "+green("--search")+" ("+green("-s")+" short option)" - print " Searches for matches of the supplied string in the current local" - print " portage tree. By default emerge uses a case-insensitive simple " - print " search, but you can enable a regular expression search by " - print " prefixing the search string with %." - print " Prepending the expression with a '@' will cause the category to" - print " be included in the search." - print " A few examples:" - print " "+bold("emerge --search libc") - print " list all packages that contain libc in their name" - print " "+bold("emerge --search '%^kde'") - print " list all packages starting with kde" - print " "+bold("emerge --search '%gcc$'") - print " list all packages ending with gcc" - print " "+bold("emerge --search '%@^dev-java.*jdk'") - print " list all available Java JDKs" - print - print " "+green("--searchdesc")+" ("+green("-S")+" short option)" - print " Matches the search string against the description field as well" - print " the package's name. Take caution as the descriptions are also" - print " matched as regular expressions." - print " emerge -S html" - print " emerge -S applet" - print " emerge -S 'perl.*module'" - print - print " "+green("--unmerge")+" ("+green("-C")+" short option)" - print " "+turquoise("WARNING: This action can remove important packages!") - print " Removes all matching packages. This does no checking of" - print " dependencies, so it may remove packages necessary for the proper" - print " operation of your system. Its arguments can be atoms or" - print " ebuilds. For a dependency aware version of --unmerge, use" - print " --depclean or --prune." - print - print " "+green("--update")+" ("+green("-u")+" short option)" - print " Updates packages to the best version available, which may not" - print " always be the highest version number due to masking for testing" - print " and development. This will also update direct dependencies which" - print " may not what you want. Package atoms specified on the command line" - print " are greedy, meaning that unspecific atoms may match multiple" - print " installed versions of slotted packages." - print - print " "+green("--version")+" ("+green("-V")+" short option)" - print " Displays the currently installed version of portage along with" - print " other information useful for quick reference on a system. See" - print " "+bold("emerge info")+" for more advanced information." - print - print turquoise("Options:") - print " "+green("--alphabetical") - print " When displaying USE and other flag output, combines the enabled" - print " and disabled flags into a single list and sorts it alphabetically." - print " With this option, output such as USE=\"dar -bar -foo\" will instead" - print " be displayed as USE=\"-bar dar -foo\"" - print - print " "+green("--ask")+" ("+green("-a")+" short option)" - print " before performing the merge, display what ebuilds and tbz2s will" - print " be installed, in the same format as when using --pretend; then" - print " ask whether to continue with the merge or abort. Using --ask is" - print " more efficient than using --pretend and then executing the same" - print " command without --pretend, as dependencies will only need to be" - print " calculated once. WARNING: If the \"Enter\" key is pressed at the" - print " prompt (with no other input), it is interpreted as acceptance of" - print " the first choice. Note that the input buffer is not cleared prior" - print " to the prompt, so an accidental press of the \"Enter\" key at any" - print " time prior to the prompt will be interpreted as a choice!" - print - print " "+green("--buildpkg")+" ("+green("-b")+" short option)" - print " Tell emerge to build binary packages for all ebuilds processed" - print " (in addition to actually merging the packages. Useful for" - print " maintainers or if you administrate multiple Gentoo Linux" - print " systems (build once, emerge tbz2s everywhere) as well as disaster" - print " recovery." - print - print " "+green("--buildpkgonly")+" ("+green("-B")+" short option)" - print " Creates a binary package, but does not merge it to the" - print " system. This has the restriction that unsatisfied dependencies" - print " must not exist for the desired package as they cannot be used if" - print " they do not exist on the system." - print - print " "+green("--changelog")+" ("+green("-l")+" short option)" - print " When pretending, also display the ChangeLog entries for packages" - print " that will be upgraded." - print - print " "+green("--color") + " < " + turquoise("y") + " | "+ turquoise("n")+" >" - print " Enable or disable color output. This option will override NOCOLOR" - print " (see make.conf(5)) and may also be used to force color output when" - print " stdout is not a tty (by default, color is disabled unless stdout" - print " is a tty)." - print - print " "+green("--columns") - print " Display the pretend output in a tabular form. Versions are" - print " aligned vertically." - print - print " "+green("--debug")+" ("+green("-d")+" short option)" - print " Tell emerge to run the ebuild command in --debug mode. In this" - print " mode, the bash build environment will run with the -x option," - print " causing it to output verbose debug information print to stdout." - print " --debug is great for finding bash syntax errors as providing" - print " very verbose information about the dependency and build process." - print - print " "+green("--deep")+" ("+green("-D")+" short option)" - print " This flag forces emerge to consider the entire dependency tree of" - print " packages, instead of checking only the immediate dependencies of" - print " the packages. As an example, this catches updates in libraries" - print " that are not directly listed in the dependencies of a package." - print " Also see --with-bdeps for behavior with respect to build time" - print " dependencies that are not strictly required." - print - print " "+green("--emptytree")+" ("+green("-e")+" short option)" - print " Virtually tweaks the tree of installed packages to contain" - print " nothing. This is great to use together with --pretend. This makes" - print " it possible for developers to get a complete overview of the" - print " complete dependency tree of a certain package." - print - print " "+green("--fetchonly")+" ("+green("-f")+" short option)" - print " Instead of doing any package building, just perform fetches for" - print " all packages (main package as well as all dependencies.) When" - print " used in combination with --pretend all the SRC_URIs will be" - print " displayed multiple mirrors per line, one line per file." - print - print " "+green("--fetch-all-uri")+" ("+green("-F")+" short option)" - print " Same as --fetchonly except that all package files, including those" - print " not required to build the package, will be processed." - print - print " "+green("--getbinpkg")+" ("+green("-g")+" short option)" - print " Using the server and location defined in PORTAGE_BINHOST, portage" - print " will download the information from each binary file there and it" - print " will use that information to help build the dependency list. This" - print " option implies '-k'. (Use -gK for binary-only merging.)" - print - print " "+green("--getbinpkgonly")+" ("+green("-G")+" short option)" - print " This option is identical to -g, as above, except it will not use" - print " ANY information from the local machine. All binaries will be" - print " downloaded from the remote server without consulting packages" - print " existing in the packages directory." - print - print " "+green("--newuse")+" ("+green("-N")+" short option)" - print " Tells emerge to include installed packages where USE flags have " - print " changed since installation." - print - print " "+green("--noconfmem") - print " Portage keeps track of files that have been placed into" - print " CONFIG_PROTECT directories, and normally it will not merge the" - print " same file more than once, as that would become annoying. This" - print " can lead to problems when the user wants the file in the case" - print " of accidental deletion. With this option, files will always be" - print " merged to the live fs instead of silently dropped." - print - print " "+green("--nodeps")+" ("+green("-O")+" short option)" - print " Merge specified packages, but don't merge any dependencies." - print " Note that the build may fail if deps aren't satisfied." - print - print " "+green("--noreplace")+" ("+green("-n")+" short option)" - print " Skip the packages specified on the command-line that have" - print " already been installed. Without this option, any packages," - print " ebuilds, or deps you specify on the command-line *will* cause" - print " Portage to remerge the package, even if it is already installed." - print " Note that Portage won't remerge dependencies by default." - print - print " "+green("--nospinner") - print " Disables the spinner regardless of terminal type." - print - print " "+green("--oneshot")+" ("+green("-1")+" short option)" - print " Emerge as normal, but don't add packages to the world profile." - print " This package will only be updated if it is depended upon by" - print " another package." - print - print " "+green("--onlydeps")+" ("+green("-o")+" short option)" - print " Only merge (or pretend to merge) the dependencies of the" - print " specified packages, not the packages themselves." - print - print " "+green("--pretend")+" ("+green("-p")+" short option)" - print " Instead of actually performing the merge, simply display what" - print " ebuilds and tbz2s *would* have been installed if --pretend" - print " weren't used. Using --pretend is strongly recommended before" - print " installing an unfamiliar package. In the printout, N = new," - print " U = updating, R = replacing, F = fetch restricted, B = blocked" - print " by an already installed package, D = possible downgrading," - print " S = slotted install. --verbose causes affecting use flags to be" - print " printed out accompanied by a '+' for enabled and a '-' for" - print " disabled USE flags." - print - print " "+green("--quiet")+" ("+green("-q")+" short option)" - print " Effects vary, but the general outcome is a reduced or condensed" - print " output from portage's displays." - print - print " "+green("--reinstall ") + turquoise("changed-use") - print " Tells emerge to include installed packages where USE flags have" - print " changed since installation. Unlike --newuse, this option does" - print " not trigger reinstallation when flags that the user has not" - print " enabled are added or removed." - print - print " "+green("--skipfirst") - print " This option is only valid in a resume situation. It removes the" - print " first package in the resume list so that a merge may continue in" - print " the presence of an uncorrectable or inconsequential error. This" - print " should only be used in cases where skipping the package will not" - print " result in failed dependencies." - print - print " "+green("--tree")+" ("+green("-t")+" short option)" - print " Shows the dependency tree using indentation for dependencies." - print " The packages are also listed in reverse merge order so that" - print " a package's dependencies follow the package. Only really useful" - print " in combination with --emptytree, --update or --deep." - print - print " "+green("--usepkg")+" ("+green("-k")+" short option)" - print " Tell emerge to use binary packages (from $PKGDIR) if they are" - print " available, thus possibly avoiding some time-consuming compiles." - print " This option is useful for CD installs; you can export" - print " PKGDIR=/mnt/cdrom/packages and then use this option to have" - print " emerge \"pull\" binary packages from the CD in order to satisfy" - print " dependencies." - print - print " "+green("--usepkgonly")+" ("+green("-K")+" short option)" - print " Like --usepkg above, except this only allows the use of binary" - print " packages, and it will abort the emerge if the package is not" - print " available at the time of dependency calculation." - print - print " "+green("--verbose")+" ("+green("-v")+" short option)" - print " Effects vary, but the general outcome is an increased or expanded" - print " display of content in portage's displays." - print - print " "+green("--with-bdeps")+" < " + turquoise("y") + " | "+ turquoise("n")+" >" - print " In dependency calculations, pull in build time dependencies that" - print " are not strictly required. This defaults to 'n' for installation" - print " actions and 'y' for the --depclean action. This setting can be" - print " added to EMERGE_DEFAULT_OPTS (see make.conf(5)) and later" - print " overridden via the command line." - print - elif myaction == "sync": - print - print bold("Usage: ")+turquoise("emerge")+" "+turquoise("--sync") - print - print " 'emerge --sync' tells emerge to update the Portage tree as specified in" - print " The SYNC variable found in /etc/make.conf. By default, SYNC instructs" - print " emerge to perform an rsync-style update with rsync.gentoo.org." - print - print " 'emerge-webrsync' exists as a helper app to emerge --sync, providing a" - print " method to receive the entire portage tree as a tarball that can be" - print " extracted and used. First time syncs would benefit greatly from this." - print - print " "+turquoise("WARNING:") - print " If using our rsync server, emerge will clean out all files that do not" - print " exist on it, including ones that you may have created. The exceptions" - print " to this are the distfiles, local and packages directories." - print - elif myaction=="system": - print - print bold("Usage: ")+turquoise("emerge")+" [ "+green("options")+" ] "+turquoise("system") - print - print " \"emerge system\" is the Portage system update command. When run, it" - print " will scan the etc/make.profile/packages file and determine what" - print " packages need to be installed so that your system meets the minimum" - print " requirements of your current system profile. Note that this doesn't" - print " necessarily bring your system up-to-date at all; instead, it just" - print " ensures that you have no missing parts. For example, if your system" - print " profile specifies that you should have sys-apps/iptables installed" - print " and you don't, then \"emerge system\" will install it (the most" - print " recent version that matches the profile spec) for you. It's always a" - print " good idea to do an \"emerge --pretend system\" before an \"emerge" - print " system\", just so you know what emerge is planning to do." - print - elif myaction=="world": - print - print bold("Usage: ")+turquoise("emerge")+" [ "+green("options")+" ] "+turquoise("world") - print - print " 'emerge world' is the Portage command for completely updating your" - print " system. The normal procedure is to first do an 'emerge --sync' and" - print " then an 'emerge --update --deep world'. The first command brings your" - print " local Portage tree up-to-date with the latest version information and" - print " ebuilds. The second command then rebuilds all packages for which newer" - print " versions or newer ebuilds have become available since you last did a" - print " sync and update." - print - -- cgit v1.2.3-1-g7c22