-except KeyboardInterrupt:
- sys.exit(1)
-
-import os, stat
-
-os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
-try:
- import portage
-except ImportError:
- sys.path.insert(0, "/usr/lib/portage/pym")
- import portage
-del os.environ["PORTAGE_LEGACY_GLOBALS"]
-from portage import digraph
-
-import emergehelp, xpak, commands, errno, re, socket, string, time, types
-import output
-from output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \
- havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \
- xtermTitleReset, yellow
-from output import create_color_func
-good = create_color_func("GOOD")
-bad = create_color_func("BAD")
-
-import portage_dep
-import portage_util
-import portage_locks
-import portage_exception
-from portage_data import secpass
-
-if not hasattr(__builtins__, "set"):
- from sets import Set as set
-from itertools import chain, izip
-
-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 normpath(mystr):
- """
- os.path.normpath("//foo") returns "//foo" instead of "/foo"
- We dislike this behavior so we create our own normpath func
- to fix it.
- """
- if mystr and (mystr[0]=='/'):
- return os.path.normpath("///"+mystr)
- else:
- return os.path.normpath(mystr)
-
-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, colours = ["Yes", "No"], [green, red]
- elif colours is None:
- colours=[bold]
- colours=(colours*len(responses))[:len(responses)]
- print bold(prompt),
- try:
- while True:
- response=raw_input("["+string.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)
-
-def sorted_versions(verlist):
- ret = []
- for ver in verlist:
- verparts = ver.split("-")
- if len(verparts) == 2:
- verrev = int(verparts[1][1:])
- else:
- verrev = 0
- x = 0
- while x < len(ret):
- retparts = ret[x].split("-")
- verdiff = portage.vercmp(retparts[0], verparts[0])
- if verdiff > 0:
- break
- elif verdiff == 0:
- if len(retparts) == 2:
- retrev = int(retparts[1][1:])
- else:
- retrev = 0
- if retrev >= verrev:
- break
- x += 1
- ret.insert(x, ver)
- return ret
-
-
-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:
- xtermTitle(short_msg)
- else:
- xtermTitle(mystr)
- 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+=","+string.join(xs[1:], "-")
- else:
- libcver=string.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 = ["recurse"]
- add=[]
- sub=[]
- if "--update" in myopts or \
- "--newuse" in myopts or \
- "--noreplace" in myopts or \
- myaction in ("system", "world"):
- add.extend(["selective"])
- if "--emptytree" in myopts:
- add.extend(["empty"])
- sub.extend(["selective"])
- if "--nodeps" in myopts:
- sub.extend(["recurse"])
- if "--deep" in myopts:
- add.extend(["deep"])
- for x in add:
- if (x not in myparams) and (x not in sub):
- myparams.append(x)
- for x in sub:
- if x in myparams:
- myparams.remove(x)
- return myparams
-
-# search functionality
-class search:
-
- #
- # class constants
- #
- VERSION_SHORT=1
- VERSION_RELEASE=2
-
- #
- # public interface
- #
- def __init__(self, settings, portdb, vartree, spinner, searchdesc,
- verbose):
- """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
-
- 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":[]}
- else:
- self.searchdesc=0
- self.matches = {"pkg":[]}
- print "Searching... ",
-
- regexsearch = False
- if self.searchkey[0] == '%':
- regexsearch = True
- self.searchkey = self.searchkey[1:]
- if self.searchkey[0] == '@':
- 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.mlen=0
- for mtype in self.matches.keys():
- self.matches[mtype].sort()
- self.mlen += len(self.matches[mtype])
-
- def output(self):
- """Outputs the results of the search."""
- print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]"
- print "[ Applications found : "+white(str(self.mlen))+" ]"
- print " "
- for mtype in self.matches.keys():
- for match,masked in self.matches[mtype]:
- if mtype=="pkg":
- catpack=match
- full_package = 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))
- else:
- full_package = match
- match = portage.pkgsplit(match)[0]
-
- 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)
- import portage_manifest
- mf = portage_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=string.join(string.split(x))
- if not len(myline):
- continue
- elif myline[0]=="#":
- continue
- elif mode=="system":
- if myline[0]!="*":
- continue
- myline=myline[1:]
- mynewlines.append(myline.strip())
-
- return mynewlines
-
-def clean_world(vardb, cpv):
- """Remove a package from the world file when unmerged."""
- world_filename = os.path.join(vardb.root, portage.WORLD_FILE)
- worldlist = portage_util.grabfile(world_filename)
- 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)
-
- portage_util.ensure_dirs(os.path.join(vardb.root, portage.PRIVATE_PATH),
- gid=portage.portage_gid, mode=02770)
- portage_util.write_atomic(world_filename, "\n".join(newworldlist))
-
-def genericdict(mylist):
- mynewdict={}
- for x in mylist:
- mynewdict[portage.dep_getkey(x)]=x
- return mynewdict
-
-def filter_iuse_defaults(iuse):
- for flag in iuse:
- if 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.
- SOFT The upper boundary for soft dependencies.
- MIN The lower boundary for soft dependencies.
- """
- __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime")
- MEDIUM = -1
- SOFT = -2
- MIN = -4
- 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.buildtime:
- return -2
- if self.runtime:
- return -3
- return -4
- 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.SOFT:
- return "medium"
- 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):
- self.root = real_vartree.root
- self.settings = real_vartree.settings
- 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)
- mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
- "DEPEND", "RDEPEND", "PDEPEND"]
- 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
- 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)
- 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 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:
-
- pkg_tree_map = {
- "ebuild":"porttree",
- "binary":"bintree",
- "installed":"vartree"}
-
- 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 = {}
- self.mydbapi = {}
- self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND"]
- self.useFlags = {}
- self.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.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
- # 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.useFlags[myroot] = {}
- 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=[]
- self.args_keys = []
- self.blocker_digraph = digraph()
- self.blocker_parents = {}
- 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."""
-
- from formatter import AbstractFormatter, DumbWriter
- f = AbstractFormatter(DumbWriter(maxcol=72))
-
- print "\n!!! Multiple versions within a single " + \
- "package slot have been "
- print "!!! pulled into the dependency graph:"
- print
- for node, parents in packages:
- print node,
- if parents:
- print "pulled in by"
- for parent in parents:
- print " ", parent
- else:
- print "(no parents)"
- print
-
- 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.")
-
- 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)
-
- def create(self, mybigkey, myparent=None, addme=1, myuse=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
- """
- mytype, myroot, mykey = mybigkey
- existing_node = None
- if addme:
- existing_node = self.pkg_node_map[myroot].get(mykey)
- if existing_node:
- self._parent_child_digraph.add(existing_node, myparent)
- if existing_node != myparent:
- # Refuse to make a node depend on itself so that the we don't
- # don't create a bogus circular dependency in self.altlist().
- if rev_dep and myparent:
- self.digraph.addnode(myparent, existing_node,
- priority=priority)
- else:
- self.digraph.addnode(existing_node, myparent,
- priority=priority)
- return 1
-
- self.spinner.update()
- if mytype == "blocks":
- if myparent and \
- "--buildpkgonly" not in self.myopts and \
- "--nodeps" not in self.myopts:
- mybigkey[1] = myparent[1]
- self.blocker_parents.setdefault(
- tuple(mybigkey), set()).add(myparent)
- return 1
- if not arg and myroot == self.target_root:
- arg = portage.best_match_to_list(mykey, self.args_keys)
- # 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 myuse is None:
- self.pkgsettings[myroot].setcpv(mykey, mydb=portdb)
- myuse = self.pkgsettings[myroot]["USE"].split()
-
- merging=1
- if mytype == "installed":
- merging = 0
- if addme and mytype != "installed":
- # this is where we add the node to the list of packages to merge
- if "selective" in self.myparams or not arg:
- if "empty" not in self.myparams and vardbapi.cpv_exists(mykey):
- merging=0
-
- """ If we aren't merging, perform the --newuse check.
- If the package has new iuse flags or different use flags then if
- --newuse is specified, we need to merge the package. """
- if merging==0 and "--newuse" in self.myopts and \
- mytype == "ebuild" and \
- vardbapi.cpv_exists(mykey):
- pkgsettings.setcpv(mykey, mydb=portdb)
- forced_flags = set()
- forced_flags.update(pkgsettings.useforce)
- forced_flags.update(pkgsettings.usemask)
- old_use = vardbapi.aux_get(mykey, ["USE"])[0].split()
- iuses = set(filter_iuse_defaults(
- mydbapi.aux_get(mykey, ["IUSE"])[0].split()))
- old_iuse = set(filter_iuse_defaults(
- vardbapi.aux_get(mykey, ["IUSE"])[0].split()))
- if iuses.symmetric_difference(
- old_iuse).difference(forced_flags):
- merging = 1
- elif old_iuse.intersection(old_use) != \
- iuses.intersection(myuse):
- merging=1
-
- if addme and merging == 1:
- mybigkey.append("merge")
- else:
- mybigkey.append("nomerge")
- jbigkey = tuple(mybigkey)
-
- if addme:
- metadata = dict(izip(self._mydbapi_keys,
- mydbapi.aux_get(mykey, self._mydbapi_keys)))
- if merging == 0 and vardbapi.cpv_exists(mykey):
- metadata["USE"] = vardbapi.aux_get(mykey, ["USE"])[0]
- myuse = metadata["USE"].split()
- metadata["SLOT"] = vardbapi.aux_get(mykey, ["SLOT"])[0]
- slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
- existing_node = self._slot_node_map[myroot].get(
- slot_atom, None)
- if existing_node:
- e_type, myroot, e_cpv, e_status = existing_node
- if mykey == e_cpv:
- # The existing node can be reused.
- self._parent_child_digraph.add(existing_node, myparent)
- if rev_dep and myparent:
- ptype, proot, pkey, pstatus = myparent
- self.digraph.addnode(myparent, existing_node,
- priority=priority)
- else:
- self.digraph.addnode(existing_node, myparent,
- priority=priority)
- return 1
- else:
- e_parents = self._parent_child_digraph.parent_nodes(
- existing_node)
- myparents = []
- if myparent:
- myparents.append(myparent)
- self._show_slot_collision_notice(
- ((jbigkey, myparents),
- (existing_node, e_parents)))
- return 0
-
- self._slot_node_map[myroot][slot_atom] = jbigkey
- self.pkg_node_map[myroot][mykey] = jbigkey
- self.useFlags[myroot][mykey] = myuse
- self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata)
-
- if rev_dep and myparent:
- self.digraph.addnode(myparent, jbigkey,
- priority=priority)
- else:
- self.digraph.addnode(jbigkey, myparent,
- priority=priority)
-
- # 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 <pkgspec>; 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"]
- depvalues = mydbapi.aux_get(mykey, depkeys)
- for i in xrange(len(depkeys)):
- edepend[depkeys[i]] = depvalues[i]
-
- if mytype == "ebuild":
- if "--buildpkgonly" in self.myopts:
- edepend["RDEPEND"] = ""
- edepend["PDEPEND"] = ""
- if not (arg and "--onlydeps" in self.myopts and \
- mytype == "ebuild") and \
- self.myopts.get("--with-bdeps", "n") == "n" and \
- (mytype == "binary" or mybigkey[3] == "nomerge"):
- 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),
- 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(), rev_deps=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
- portdb = self.trees[myroot]["porttree"].dbapi
- bindb = self.trees[myroot]["bintree"].dbapi
- pkgsettings = self.pkgsettings[myroot]
- arg_atoms = []
- def visible(mylist):
- matches = portdb.gvisible(portdb.visible(mylist))
- return [x for x in mylist \
- if x in matches or not portdb.cpv_exists(x)]
- 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"
- sys.exit(1)
- mytbz2=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")
- sys.exit(1)
- if not self.create(["binary", myroot, mykey],
- None, "--onlydeps" not in self.myopts):
- return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(mykey)
- elif ext==".ebuild":
- x = os.path.realpath(x)
- mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
- ebuild_path = portdb.findname(mykey)
- if ebuild_path:
- if os.path.realpath(ebuild_path) != x:
- print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
- sys.exit(1)
- 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):
- return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- myfavorites.append(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:
- mykey = None
- if "--usepkg" in self.myopts:
- mykey = portage.dep_expand(x, mydb=bindb,
- settings=pkgsettings)
- if (mykey and not mykey.startswith("null/")) or \
- "--usepkgonly" in self.myopts:
- arg_atoms.append((x, mykey))
- continue
-
- mykey = portage.dep_expand(x,
- mydb=portdb, settings=pkgsettings)
- arg_atoms.append((x, mykey))
- 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 "--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."""
- vardb = self.trees[self.target_root]["vartree"].dbapi
- greedy_atoms = []
- for myarg, myatom in arg_atoms:
- greedy_atoms.append((myarg, myatom))
- myslots = set()
- for cpv in vardb.match(myatom):
- myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
- if myslots:
- best_pkgs = []
- if "--usepkg" in self.myopts:
- mymatches = bindb.match(myatom)
- if "--usepkgonly" not in self.myopts:
- mymatches = visible(mymatches)
- best_pkg = portage.best(mymatches)
- if best_pkg:
- best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
- best_pkgs.append(("binary", best_pkg, best_slot))
- if "--usepkgonly" not in self.myopts:
- best_pkg = portage.best(portdb.match(myatom))
- if best_pkg:
- best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
- best_pkgs.append(("ebuild", best_pkg, best_slot))
- if best_pkgs:
- best_pkg = portage.best([x[1] for x in best_pkgs])
- best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
- best_slot = best_pkgs[0][2]
- myslots.add(best_slot)
- if len(myslots) > 1:
- for myslot in myslots:
- myslot_atom = "%s:%s" % \
- (portage.dep_getkey(myatom), myslot)
- available = False
- if "--usepkgonly" not in self.myopts and \
- self.trees[self.target_root][
- "porttree"].dbapi.match(myslot_atom):
- available = True
- elif "--usepkg" in self.myopts:
- mymatches = bindb.match(myslot_atom)
- if "--usepkgonly" not in self.myopts:
- mymatches = visible(mymatches)
- if mymatches:
- available = True
- if available:
- greedy_atoms.append((myarg, myslot_atom))
- arg_atoms = greedy_atoms
-
- """ These are used inside self.create() in order to ensure packages
- that happen to match arguments are not incorrectly marked as nomerge."""
- self.args_keys = [x[1] for x in arg_atoms]
- 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), e.__module__
- raise
-
- if not self.mysd:
- return (0,myfavorites)
- elif not "--oneshot" in self.myopts:
- mykey = portage.dep_getkey(myatom)
- if mykey not in myfavorites:
- myfavorites.append(mykey)
-
- 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 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
- """
-
- 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
-
- #processing dependencies
- """ Call portage.dep_check to evaluate the use? conditionals and make sure all
- dependencies are satisfiable. """
- try:
- if myparent and p_status == "nomerge":
- portage_dep._dep_check_strict = False
- mycheck = portage.dep_check(depstring, None,
- pkgsettings, myuse=myuse,
- use_binaries=("--usepkgonly" in self.myopts),
- myroot=myroot, trees=self.trees)
- finally:
- portage_dep._dep_check_strict = True
-
- if not mycheck[0]:
- show_invalid_depstring_notice(myparent, depstring, mycheck[1])
- return 0
- mymerge = mycheck[1]
-
- if not mymerge and arg and \
- portage.best_match_to_list(depstring, self.args_keys):
- # A provided package has been specified on the command line. The
- # package will not be merged and a warning will be displayed.
- self._pprovided_args.append(arg)
-
- 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.
- self.pkgsettings[p_root].setinst(p_key,
- self.trees[p_root][self.pkg_tree_map[p_type]].dbapi)
-
- if "--debug" in self.myopts:
- print "Candidates:",mymerge
- for x in mymerge:
- selected_pkg = None
- if x[0]=="!":
- selected_pkg = ["blocks", myroot, x[1:], None]
- else:
- #We are not processing a blocker but a normal dependency
- if myparent:
- """In some cases, dep_check will return deps that shouldn't
- be proccessed any further, so they are identified and
- discarded here."""
- if "empty" not in self.myparams and \
- "deep" not in self.myparams and \
- not ("--update" in self.myopts and parent_arg) and \
- vardb.match(x):
- continue
-
- # List of acceptable packages, ordered by type preference.
- matched_packages = []
- myeb_matches = portdb.xmatch("match-visible", x)
- myeb = None
- if "--usepkgonly" not in self.myopts:
- myeb = portage.best(myeb_matches)
-
- myeb_pkg=None
- if "--usepkg" in self.myopts:
- # The next line assumes the binarytree has been populated.
- # XXX: Need to work out how we use the binary tree with roots.
- myeb_pkg_matches = bindb.match(x)
- if "--usepkgonly" not in self.myopts:
- # Remove any binary package entries that are masked in the portage tree (#55871)
- myeb_pkg_matches = [pkg for pkg in myeb_pkg_matches \
- if pkg in myeb_matches or \
- not portdb.cpv_exists(pkg)]
- if myeb_pkg_matches:
- myeb_pkg = portage.best(myeb_pkg_matches)
-
- if myeb_pkg and "--newuse" in self.myopts:
- iuses = set(filter_iuse_defaults(
- bindb.aux_get(myeb_pkg, ["IUSE"])[0].split()))
- old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split()
- mydb = None
- if "--usepkgonly" not in self.myopts and myeb:
- mydb = portdb
- if myeb:
- pkgsettings.setcpv(myeb, mydb=mydb)
- else:
- pkgsettings.setcpv(myeb_pkg, mydb=mydb)
- now_use = pkgsettings["USE"].split()
- forced_flags = set()
- forced_flags.update(pkgsettings.useforce)
- forced_flags.update(pkgsettings.usemask)
- cur_iuse = iuses
- if "--usepkgonly" not in self.myopts and myeb:
- cur_iuse = set(filter_iuse_defaults(
- portdb.aux_get(myeb, ["IUSE"])[0].split()))
- if iuses.symmetric_difference(
- cur_iuse).difference(forced_flags):
- myeb_pkg = None
- elif iuses.intersection(old_use) != \
- cur_iuse.intersection(now_use):
- myeb_pkg = None
- if myeb_pkg:
- binpkguseflags = \
- self.trees[myroot]["bintree"].dbapi.aux_get(
- myeb_pkg, ["USE"])[0].split()
- matched_packages.append(
- ["binary", myroot, myeb_pkg, binpkguseflags])
-
- if "--usepkgonly" not in self.myopts and myeb_matches:
- matched_packages.append(
- ["ebuild", myroot, myeb, None])
-
- if not matched_packages and \
- not (arg and "selective" not in self.myparams):
- """Fall back to the installed package database. This is a
- last resort because the metadata tends to diverge from that
- of the ebuild in the tree."""
- myeb_inst_matches = vardb.match(x)
- if "--usepkgonly" not in self.myopts:
- """ TODO: Improve masking check for installed and
- binary packages. bug #149816"""
- myeb_inst_matches = [pkg for pkg in myeb_inst_matches \
- if not portdb.cpv_exists(pkg)]
- myeb_inst = None
- if myeb_inst_matches:
- myeb_inst = portage.best(myeb_inst_matches)
- if myeb_inst:
- binpkguseflags = vardb.aux_get(
- myeb_inst, ["USE"])[0].split()
- matched_packages.append(
- ["installed", myroot, myeb_inst, binpkguseflags])
-
- if not matched_packages:
- if raise_on_missing:
- raise ValueError
- if not arg:
- xinfo='"'+x+'"'
- else:
- xinfo='"'+arg+'"'
- if myparent:
- xfrom = '(dependency required by '+ \
- green('"%s"' % myparent[2]) + \
- red(' [%s]' % myparent[0]) + ')'
- alleb = portdb.xmatch("match-all", x)
- if alleb:
- if "--usepkgonly" not in self.myopts:
- print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.")
- print "!!! One of the following masked packages is required to complete your request:"
- oldcomment = ""
- for p in alleb:
- mreasons = portage.getmaskingstatus(p,
- settings=pkgsettings, portdb=portdb)
- print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")"
- comment = portage.getmaskingreason(p,
- settings=pkgsettings, portdb=portdb)
- if comment and comment != oldcomment:
- print comment
- oldcomment = comment
- print
- print "For more information, see MASKED PACKAGES section in the emerge man page or "
- print "refer to the Gentoo Handbook."
- else:
- print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo)
- print "!!! Either add a suitable binary package or compile from an ebuild."
- else:
- print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"."
- if myparent:
- print xfrom
- print
- return 0
-
- if "--debug" in self.myopts:
- for pkg in matched_packages:
- print (pkg[0] + ":").rjust(10), pkg[2]
-
- if len(matched_packages) > 1:
- bestmatch = portage.best(
- [pkg[2] for pkg in matched_packages])
- matched_packages = [pkg for pkg in matched_packages \
- if pkg[2] == bestmatch]
-
- # ordered by type preference ("ebuild" type is the last resort)
- selected_pkg = matched_packages[0]
- pkgtype, myroot, mycpv, myuse = selected_pkg
- mydbapi = self.trees[myroot][self.pkg_tree_map[pkgtype]].dbapi
- slot_atom = "%s:%s" % (portage.dep_getkey(mycpv),
- mydbapi.aux_get(mycpv, ["SLOT"])[0])
- existing_node = self._slot_node_map[myroot].get(
- slot_atom, None)
- if existing_node:
- e_type, myroot, e_cpv, e_status = existing_node
- if portage.match_from_list(x, [e_cpv]):
- # The existing node can be reused.
- selected_pkg = [e_type, myroot, e_cpv,
- self.useFlags[myroot][e_cpv]]
-
- 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:3], myparent,
- myuse=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:3], myparent,
- addme=("--onlydeps" not in self.myopts),
- myuse=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]
- for pkg in self.trees[myroot]["vartree"].dbapi.cpv_all():
- blocker_atoms = None
- matching_node = pkg_node_map.get(pkg, None)
- if not matching_node or \
- matching_node[3] == "merge":
- # If this node has any blockers, create a "nomerge"
- # node for it so that they can be enforced.
- self.spinner.update()
- 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
- success, atoms = portage.dep_check(depstr,
- final_db, pkgsettings, myuse=myuse,
- trees=dep_check_trees, myroot=myroot)
- 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("!")]
- 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)
-
- 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])
- blocked_slots_final_values = set(blocked_slots_final.itervalues())
- 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:
- # The parent blocks an initial package in the same
- # slot as itself. The merge/nomerge status of neither
- # node matters. In any case, this particular block is
- # automatically resolved.
- 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 not in blocked_slots_final_values:
- upgrade_matches = final_db.match(slot_atom)
- if upgrade_matches:
- # Apparently an upgrade may be able to invalidate
- # this block.
- upgrade_node = \
- self.pkg_node_map[proot][upgrade_matches[0]]
- depends_on_order.add(upgrade_node)
- 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:
- # The parent blocks itself, so the merge order does not
- # need to be enforced.
- 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
- # 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 in depends_on_order:
- # Enforce correct merge order with a hard dep.
- self.digraph.addnode(node, parent,
- 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 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()
- return True
-
- def altlist(self, reversed=False):
- if reversed in self._altlist_cache:
- return self._altlist_cache[reversed][:]
- mygraph=self.digraph.copy()
- myblockers = self.blocker_digraph.copy()
- retlist=[]
- circular_blocks = False
- blocker_deps = None
- asap_nodes = []
- 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]:
- asap_nodes.append(node)
- break
- ignore_priority_range = [None]
- ignore_priority_range.extend(
- xrange(DepPriority.MIN, DepPriority.MEDIUM + 1))
- while not mygraph.empty():
- ignore_priority = None
- nodes = None
- if asap_nodes:
- """ASAP nodes are merged before their soft deps."""
- for node in asap_nodes:
- if not mygraph.contains(node):
- asap_nodes.remove(node)
- continue
- if not mygraph.child_nodes(node,
- ignore_priority=DepPriority.SOFT):
- nodes = [node]
- asap_nodes.remove(node)
- break
- if not nodes:
- for ignore_priority in ignore_priority_range:
- nodes = get_nodes(ignore_priority=ignore_priority)
- if nodes:
- break
- selected_nodes = None
- if nodes:
- if ignore_priority <= DepPriority.SOFT:
- if ignore_priority is None and not reversed:
- # 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:
- # Only pop one node for optimal merge order.
- selected_nodes = [nodes[0]]
- else:
- """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(mergeable_nodes, selected_nodes, node):
- if node in selected_nodes:
- return True
- if node not in mergeable_nodes:
- return False
- selected_nodes.add(node)
- for child in mygraph.child_nodes(node,
- ignore_priority=DepPriority.SOFT):
- if not gather_deps(
- mergeable_nodes, selected_nodes, child):
- return False
- return True
- mergeable_nodes = set(nodes)
- for node in nodes:
- selected_nodes = set()
- if gather_deps(
- mergeable_nodes, selected_nodes, node):
- break
- else:
- selected_nodes = None
-
- 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()
- if blocker_deps:
- selected_nodes = [blocker_deps.pop()]
-
- if not selected_nodes:
- if reversed:
- """The circular deps ouput should have less noise when
- altlist is not in reversed mode."""
- self.altlist()
- print "!!! Error: circular dependencies:"
- print
- mygraph.debug_print()
- sys.exit(1)
-
- for node in selected_nodes:
- 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)
- 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
- portdb = self.trees[self.target_root]["porttree"].dbapi
- bindb = self.trees[self.target_root]["bintree"].dbapi
- def visible(mylist):
- matches = portdb.gvisible(portdb.visible(mylist))
- return [x for x in mylist \
- if x in matches or not portdb.cpv_exists(x)]
- world_problems = False
- if mode=="system":
- mylist = getlist(self.settings, "system")
- else:
- #world mode
- worldlist = getlist(self.settings, "world")
- sysdict = genericdict(getlist(self.settings, "system"))
- worlddict=genericdict(worldlist)
-
- for x in worlddict.keys():
- if not portage.isvalidatom(x):
- world_problems = True
- elif not self.trees[self.target_root]["vartree"].dbapi.match(x):
- world_problems = True
- else:
- sysdict[x]=worlddict[x]
-
- mylist = sysdict.keys()
-
- newlist = []
- for atom in mylist:
- mykey = portage.dep_getkey(atom)
- if True:
- newlist.append(atom)
- """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:
- best_pkgs = []
- if "--usepkg" in self.myopts:
- mymatches = bindb.match(atom)
- if "--usepkgonly" not in self.myopts:
- mymatches = visible(mymatches)
- best_pkg = portage.best(mymatches)
- if best_pkg:
- best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
- best_pkgs.append(("binary", best_pkg, best_slot))
- if "--usepkgonly" not in self.myopts:
- best_pkg = portage.best(portdb.match(atom))
- if best_pkg:
- best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
- best_pkgs.append(("ebuild", best_pkg, best_slot))
- if best_pkgs:
- best_pkg = portage.best([x[1] for x in best_pkgs])
- best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
- best_slot = best_pkgs[0][2]
- myslots.add(best_slot)
- if len(myslots) > 1:
- for myslot in myslots:
- myslot_atom = "%s:%s" % (mykey, myslot)
- available = False
- if "--usepkgonly" not in self.myopts and \
- self.trees[self.target_root][
- "porttree"].dbapi.match(myslot_atom):
- available = True
- elif "--usepkg" in self.myopts:
- mymatches = bindb.match(myslot_atom)
- if "--usepkgonly" not in self.myopts:
- mymatches = visible(mymatches)
- if mymatches:
- available = True
- if available:
- newlist.append(myslot_atom)
- mylist = newlist
-
- 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 ValueError:
- 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,verbosity=None):
- if verbosity is None:
- verbosity = ("--quiet" in self.myopts and 1 or \
- "--verbose" in self.myopts and 3 or 2)
- changelogs=[]
- p=[]
-
- 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, 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
- if flag in enabled_flags:
- isEnabled = True
- if is_new or flag in old_use and all_flags:
- 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:
- 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:
- 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
-
- if verbosity == 3:
- # FIXME: account for the possibility of different overlays in
- # /etc/make.conf vs. ${PORTAGE_CONFIGROOT}/etc/make.conf
- overlays = self.settings["PORTDIR_OVERLAY"].split()
- overlays_real = [os.path.realpath(t) \
- for t in self.settings["PORTDIR_OVERLAY"].split()]
-
- tree_nodes = []
- node_depth = {}
- i = 0
- depth = 0
- for x in mylist:
- if "blocks" == x[0]:
- continue
- graph_key = tuple(x)
- if "--tree" in self.myopts:
- depth = len(tree_nodes)
- while depth and graph_key not in \
- self.digraph.child_nodes(tree_nodes[depth-1]):
- depth -= 1
- tree_nodes = tree_nodes[:depth]
- tree_nodes.append(graph_key)
- node_depth[graph_key] = depth
-
- last_merge_depth = 0
- for i in xrange(len(mylist)-1,-1,-1):
- if "blocks" == mylist[i][0]:
- continue
- graph_key = tuple(mylist[i])
- if mylist[i][-1] != "nomerge":
- last_merge_depth = node_depth[graph_key]
- continue
- if node_depth[graph_key] >= last_merge_depth or \
- i < len(mylist) - 1 and \
- node_depth[graph_key] >= node_depth[tuple(mylist[i+1])]:
- del mylist[i]
- del node_depth[graph_key]
- del tree_nodes
-
- display_overlays=False
- # files to fetch list - avoids counting a same file twice
- # in size display (verbose mode)
- myfetchlist=[]
- for x in mylist:
- 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+" "
- counters.blocks += 1
- resolved = portage.key_expand(
- pkg_key, mydb=vardb, settings=pkgsettings)
- if "--columns" in self.myopts and "--quiet" in self.myopts:
- print addl,red(resolved),
- else:
- print "["+x[0]+" "+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]:
- print bad("(\"%s\" is blocking %s)") % \
- (pkg_key, block_parents)
- else:
- print bad("(is blocking %s)") % block_parents
- else:
- mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
- binary_package = True
- if "ebuild" == pkg_type:
- if "merge" == x[3] or \
- not vartree.dbapi.cpv_exists(pkg_key):
- """An ebuild "merge" node or a --onlydeps "nomerge"
- node."""
- binary_package = False
- pkgsettings.setcpv(pkg_key, mydb=portdb)
- if pkg_key not in self.useFlags[myroot]:
- self.useFlags[myroot][pkg_key] = \
- pkgsettings["USE"].split()
- else:
- # An ebuild "nomerge" node, so USE come from the vardb.
- mydbapi = vartree.dbapi
- if pkg_key not in self.useFlags[myroot]:
- """If this is a --resume then the USE flags need to be
- fetched from the appropriate locations here."""
- self.useFlags[myroot][pkg_key] = mydbapi.aux_get(
- pkg_key, ["USE"])[0].split()
-
- if "ebuild" == pkg_type and x[3] != "nomerge" and \
- "fetch" in portdb.aux_get(
- x[2], ["RESTRICT"])[0].split():
- fetch = red("F")
- counters.restrict_fetch += 1
- if portdb.fetch_check(
- pkg_key, self.useFlags[myroot][pkg_key]):
- fetch = green("f")
- 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=""
- if vardb.cpv_exists(pkg_key):
- addl=" "+yellow("R")+fetch+" "
- if x[3] != "nomerge":
- counters.reinst += 1
- elif vardb.match(portage.dep_getkey(pkg_key)):
- mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0]
- myoldlist = self.trees[x[1]]["vartree"].dbapi.match(
- portage.pkgsplit(x[2])[0])
- myinslotlist = [inst_pkg for inst_pkg in myoldlist
- if mynewslot == vardb.aux_get(inst_pkg, ["SLOT"])[0]]
- 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")
- counters.downgrades += 1
- else:
- # Update in slot
- addl+=turquoise("U")+" "
- counters.upgrades += 1
- else:
- # New slot, mark it new.
- addl=" "+green("NS")+fetch+" "
- 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+" "
- counters.new += 1
-
- verboseadd=""
-
- if pkg_key in self.useFlags[myroot]:
- # USE flag display
- cur_iuse = list(filter_iuse_defaults(
- mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()))
-
- forced_flags = set()
- if not binary_package:
- forced_flags.update(pkgsettings.useforce)
- forced_flags.update(pkgsettings.usemask)
-
- cur_iuse = portage.unique_array(cur_iuse)
- cur_iuse.sort()
- cur_use = self.useFlags[myroot][pkg_key]
- 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):
- 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]
- for exp in use_expand_hidden:
- if exp in ret:
- del ret[exp]
- if forcedFlags:
- return ret, forced
- return ret
-
- 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)
-
- if verbosity == 3:
- # size verbose
- mysize=0
- if x[0] == "ebuild" and x[-1]!="nomerge":
- myfilesdict = portdb.getfetchsizes(
- pkg_key, useflags=self.useFlags[myroot][pkg_key],
- debug=self.edebug)
- if myfilesdict is None:
- myfilesdict="[empty/missing/bad digest]"
- else:
- for myfetchfile in myfilesdict.keys():
- if myfetchfile not in myfetchlist:
- mysize+=myfilesdict[myfetchfile]
- myfetchlist.append(myfetchfile)
- counters.totalsize += mysize
- verboseadd+=format_size(mysize)+" "
-
- # overlay verbose
- # XXX: Invalid binaries have caused tracebacks here. 'if file_name'
- # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge']
- file_name = portdb.findname(pkg_key)
- if file_name: # It might not exist in the tree
- dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..")
- if (overlays_real.count(dir_name)>0):
- verboseadd+=teal("["+str(overlays_real.index(
- os.path.normpath(dir_name))+1)+"]")+" "
- display_overlays=True
- else:
- verboseadd += "[No ebuild?]"
-
- xs=portage.pkgsplit(x[2])
- if xs[2]=="r0":
- xs[2]=""
- else:
- xs[2]="-"+xs[2]
-
- 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 = " " * node_depth[tuple(x)]
-
- if myoldbest:
- myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2]
- if myoldbest[-3:]=="-r0":
- myoldbest=myoldbest[:-3]
- myoldbest=blue("["+myoldbest+"]")
-
- if x[1]!="/":
- if myoldbest:
- myoldbest +=" "
- if "--columns" in self.myopts:
- if "--quiet" in self.myopts:
- myprint=addl+" "+indent+darkgreen(xs[0])
- myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
- myprint=myprint+myoldbest
- myprint=myprint+darkgreen("to "+x[1])
- else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
- if (newlp-nc_len(myprint)) > 0:
- myprint=myprint+(" "*(newlp-nc_len(myprint)))
- myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] "
- if (oldlp-nc_len(myprint)) > 0:
- myprint=myprint+" "*(oldlp-nc_len(myprint))
- myprint=myprint+myoldbest
- myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
- else:
- if x[3] == "nomerge":
- myprint = darkblue("[nomerge ] ")
- else:
- myprint = "[" + pkg_type + " " + addl + "] "
- myprint += indent + darkgreen(pkg_key) + " " + \
- myoldbest + darkgreen("to " + myroot) + " " + \
- verboseadd
- else:
- if "--columns" in self.myopts:
- if "--quiet" in self.myopts:
- myprint=addl+" "+indent+darkgreen(xs[0])
- myprint=myprint+" "+green(xs[1]+xs[2])+" "
- myprint=myprint+myoldbest
- else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
- if (newlp-nc_len(myprint)) > 0:
- myprint=myprint+(" "*(newlp-nc_len(myprint)))
- myprint=myprint+green(" ["+xs[1]+xs[2]+"] ")
- if (oldlp-nc_len(myprint)) > 0:
- myprint=myprint+(" "*(oldlp-nc_len(myprint)))
- myprint=myprint+myoldbest+" "+verboseadd
- else:
- if x[3]=="nomerge":
- myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd
- else:
- myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd
- p.append(myprint)
-
- 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(x) < 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
-
- if verbosity == 3:
- print
- print counters
- if overlays and display_overlays:
- print "Portage overlays:"
- y=0
- for x in overlays:
- y=y+1
- print " "+teal("["+str(y)+"]"),x
-
- if "--changelog" in self.myopts:
- print
- for revision,text in changelogs:
- print bold('*'+revision)
- sys.stdout.write(text)
-
- if self._pprovided_args:
- 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")
- for arg in self._pprovided_args:
- msg.append(" " + arg + "\n")
- msg.append("\n")
- sys.stderr.write("".join(msg))
-
- def calc_changelog(self,ebuildpath,current,next):
- 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 outdated(self):
- return self.outdatedpackages
-
-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)
-
- def merge(self, mylist, favorites, mtimedb):
- failed_fetches = []
- mymergelist=[]
- ldpath_mtimes = mtimedb["ldpath"]
- xterm_titles = "notitles" not in self.settings.features
-
- #check for blocking dependencies
- if "--fetchonly" not in self.myopts and \
- "--buildpkgonly" not in self.myopts:
- for x in mylist:
- if x[0]=="blocks":
- print "\n!!! Error: the "+x[2]+" package conflicts with another package;"
- print "!!! 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()
- if "--pretend" not in self.myopts:
- try:
- del mtimedb["resume"]
- except KeyError:
- pass
- sys.exit(1)
-
- #buildsyspkg: I need mysysdict also on resume (moved from the else block)
- mysysdict = genericdict(getlist(self.settings, "system"))
- if "--resume" in self.myopts:
- # We're resuming.
- print colorize("GOOD", "*** Resuming merge...")
- emergelog(xterm_titles, " *** Resuming merge...")
- mymergelist=mtimedb["resume"]["mergelist"][:]
- if "--skipfirst" in self.myopts and mymergelist:
- del mtimedb["resume"]["mergelist"][0]
- del mymergelist[0]
- mtimedb.commit()
- validate_merge_list(self.trees, mymergelist)
- else:
- myfavs = portage.grabfile(
- os.path.join(self.target_root, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- for x in range(len(mylist)):
- if mylist[x][3]!="nomerge":
- # Add to the mergelist
- mymergelist.append(mylist[x])
- else:
- myfavkey=portage.cpv_getkey(mylist[x][2])
- if "--onlydeps" in self.myopts:
- continue
- # Add to the world file. Since we won't be able to later.
- if "--fetchonly" not in self.myopts and \
- myfavkey in favorites:
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
- print ">>> Recording",myfavkey,"in \"world\" favorites file..."
- if not ("--fetchonly" in self.myopts or \
- "--fetch-all-uri" in self.myopts or \
- "--pretend" in self.myopts):
- portage.write_atomic(
- os.path.join(self.target_root, portage.WORLD_FILE),
- "\n".join(myfavdict.values()))
-
- 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"]
- for myopt, myarg in self.myopts.iteritems():
- if myopt not in bad_resume_opts:
- if myarg is True:
- fetch_args.append(myopt)
- else:
- fetch_args.append(myopt +"="+ myarg)
- portage.portage_exec.spawn(fetch_args, env=fetch_env,
- fd_pipes=fd_pipes, returnpid=True)
- logfile.close() # belongs to the spawned process
-
- mergecount=0
- for x in mymergelist:
- mergecount+=1
- 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]
- 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 mysysdict.has_key(portage.cpv_getkey(x[2])) \
- 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)
- 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)
- retval = portage.doebuild(y, "package", myroot,
- pkgsettings, self.edebug, mydbapi=portdb,
- tree="porttree")
- if retval != os.EX_OK:
- return retval
- if "--buildpkgonly" not in self.myopts:
- bintree = self.trees[myroot]["bintree"]
- bintree.inject(pkg_key)
- mytbz2 = bintree.getname(pkg_key)
- 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 != errno.ENOTEMPTY:
- raise
- del e
- portage_locks.unlockdir(catdir_lock)
-
- elif x[0]=="binary":
- #merge the tbz2
- mytbz2 = self.trees[myroot]["bintree"].getname(pkg_key)
- if self.trees[myroot]["bintree"].isremote(pkg_key):
- short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch"
- emergelog(xterm_titles, " --- ("+str(mergecount)+\
- " of "+str(len(mymergelist))+\
- ") Fetching Binary ("+x[pkgindex]+\
- "::"+mytbz2+")", short_msg=short_msg)
- if not self.trees[myroot]["bintree"].gettbz2(pkg_key):
- sys.exit(1)
-
- if "--fetchonly" in self.myopts or \
- "--fetch-all-uri" in self.myopts:
- continue
-
- short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary"
- emergelog(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 is None:
- sys.exit(1)
- #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 "--fetchonly" not in self.myopts and \
- "--fetch-all-uri" not in self.myopts and \
- myfavkey in favorites:
- myfavs = portage.grabfile(os.path.join(myroot, portage.WORLD_FILE))
- myfavdict=genericdict(myfavs)
- #don't record if already in system profile or already recorded
- if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
- #we don't have a favorites entry for this package yet; add one
- myfavdict[myfavkey]=myfavkey
- print ">>> Recording",myfavkey,"in \"world\" favorites file..."
- emergelog(xterm_titles, " === ("+\
- str(mergecount)+" of "+\
- str(len(mymergelist))+\
- ") Updating world file ("+x[pkgindex]+")")
- portage.write_atomic(
- os.path.join(myroot, portage.WORLD_FILE),
- "\n".join(myfavdict.values()))
-
- 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)
- 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"]
- for myopt, myarg in self.myopts.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()