Revert PackageSet.containsCPV() calls back to findAtomForPackage() calls so that...
[portage.git] / pym / emerge / __init__.py
1 #!/usr/bin/python -O
2 # Copyright 1999-2006 Gentoo Foundation
3 # Distributed under the terms of the GNU General Public License v2
4 # $Id: emerge 5976 2007-02-17 09:14:53Z genone $
5
6 import sys
7 # This block ensures that ^C interrupts are handled quietly.
8 try:
9         import signal
10
11         def exithandler(signum,frame):
12                 signal.signal(signal.SIGINT, signal.SIG_IGN)
13                 signal.signal(signal.SIGTERM, signal.SIG_IGN)
14                 sys.exit(1)
15         
16         signal.signal(signal.SIGINT, exithandler)
17         signal.signal(signal.SIGTERM, exithandler)
18         signal.signal(signal.SIGPIPE, signal.SIG_DFL)
19
20 except KeyboardInterrupt:
21         sys.exit(1)
22
23 import os, stat
24
25 os.environ["PORTAGE_LEGACY_GLOBALS"] = "false"
26 try:
27         import portage
28 except ImportError:
29         from os import path as osp
30         sys.path.insert(0, osp.join(osp.dirname(osp.dirname(osp.realpath(__file__))), "pym"))
31         import portage
32 del os.environ["PORTAGE_LEGACY_GLOBALS"]
33 from portage import digraph, portdbapi
34 from portage.const import NEWS_LIB_PATH, CACHE_PATH, PRIVATE_PATH
35
36 import emerge.help
37 import portage.xpak, commands, errno, re, socket, time, types
38 from portage.output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \
39         havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \
40         xtermTitleReset, yellow
41 from portage.output import create_color_func
42 good = create_color_func("GOOD")
43 bad = create_color_func("BAD")
44 # white looks bad on terminals with white background
45 from portage.output import bold as white
46
47 import portage.dep
48 portage.dep._dep_check_strict = True
49 import portage.util
50 import portage.locks
51 import portage.exception
52 from portage.data import secpass
53 from portage.util import normalize_path as normpath
54 from portage.util import writemsg
55 from portage.sets import InternalPackageSet
56 from portage.sets.profiles import PackagesSystemSet as SystemSet
57 from portage.sets.files import WorldSet
58
59 from itertools import chain, izip
60 from UserDict import DictMixin
61
62 try:
63         import cPickle
64 except ImportError:
65         import pickle as cPickle
66
67 class stdout_spinner(object):
68         scroll_msgs = [
69                 "Gentoo Rocks ("+os.uname()[0]+")",
70                 "Thank you for using Gentoo. :)",
71                 "Are you actually trying to read this?",
72                 "How many times have you stared at this?",
73                 "We are generating the cache right now",
74                 "You are paying too much attention.",
75                 "A theory is better than its explanation.",
76                 "Phasers locked on target, Captain.",
77                 "Thrashing is just virtual crashing.",
78                 "To be is to program.",
79                 "Real Users hate Real Programmers.",
80                 "When all else fails, read the instructions.",
81                 "Functionality breeds Contempt.",
82                 "The future lies ahead.",
83                 "3.1415926535897932384626433832795028841971694",
84                 "Sometimes insanity is the only alternative.",
85                 "Inaccuracy saves a world of explanation.",
86         ]
87
88         twirl_sequence = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|"
89
90         def __init__(self):
91                 self.spinpos = 0
92                 self.update = self.update_twirl
93                 self.scroll_sequence = self.scroll_msgs[
94                         int(time.time() * 100) % len(self.scroll_msgs)]
95
96         def update_basic(self):
97                 self.spinpos = (self.spinpos + 1) % 500
98                 if (self.spinpos % 100) == 0:
99                         if self.spinpos == 0:
100                                 sys.stdout.write(". ")
101                         else:
102                                 sys.stdout.write(".")
103                 sys.stdout.flush()
104
105         def update_scroll(self):
106                 if(self.spinpos >= len(self.scroll_sequence)):
107                         sys.stdout.write(darkgreen(" \b\b\b" + self.scroll_sequence[
108                                 len(self.scroll_sequence) - 1 - (self.spinpos % len(self.scroll_sequence))]))
109                 else:
110                         sys.stdout.write(green("\b " + self.scroll_sequence[self.spinpos]))
111                 sys.stdout.flush()
112                 self.spinpos = (self.spinpos + 1) % (2 * len(self.scroll_sequence))
113
114         def update_twirl(self):
115                 self.spinpos = (self.spinpos + 1) % len(self.twirl_sequence)
116                 sys.stdout.write("\b\b " + self.twirl_sequence[self.spinpos])
117                 sys.stdout.flush()
118
119         def update_quiet(self):
120                 return
121
122 def userquery(prompt, responses=None, colours=None):
123         """Displays a prompt and a set of responses, then waits for a response
124         which is checked against the responses and the first to match is
125         returned.  An empty response will match the first value in responses.  The
126         input buffer is *not* cleared prior to the prompt!
127
128         prompt: a String.
129         responses: a List of Strings.
130         colours: a List of Functions taking and returning a String, used to
131         process the responses for display. Typically these will be functions
132         like red() but could be e.g. lambda x: "DisplayString".
133         If responses is omitted, defaults to ["Yes", "No"], [green, red].
134         If only colours is omitted, defaults to [bold, ...].
135
136         Returns a member of the List responses. (If called without optional
137         arguments, returns "Yes" or "No".)
138         KeyboardInterrupt is converted to SystemExit to avoid tracebacks being
139         printed."""
140         if responses is None:
141                 responses = ["Yes", "No"]
142                 colours = [
143                         create_color_func("PROMPT_CHOICE_DEFAULT"),
144                         create_color_func("PROMPT_CHOICE_OTHER")
145                 ]
146         elif colours is None:
147                 colours=[bold]
148         colours=(colours*len(responses))[:len(responses)]
149         print bold(prompt),
150         try:
151                 while True:
152                         response=raw_input("["+"/".join([colours[i](responses[i]) for i in range(len(responses))])+"] ")
153                         for key in responses:
154                                 # An empty response will match the first value in responses.
155                                 if response.upper()==key[:len(response)].upper():
156                                         return key
157                         print "Sorry, response '%s' not understood." % response,
158         except (EOFError, KeyboardInterrupt):
159                 print "Interrupted."
160                 sys.exit(1)
161
162 actions=[
163 "clean", "config", "depclean",
164 "info", "metadata",
165 "prune", "regen",  "search",
166 "sync",  "system", "unmerge",  "world",
167 ]
168 options=[
169 "--ask",          "--alphabetical",
170 "--buildpkg",     "--buildpkgonly",
171 "--changelog",    "--columns",
172 "--debug",        "--deep",
173 "--digest",
174 "--emptytree",
175 "--fetchonly",    "--fetch-all-uri",
176 "--getbinpkg",    "--getbinpkgonly",
177 "--help",         "--ignore-default-opts",
178 "--noconfmem",
179 "--newuse",       "--nocolor",
180 "--nodeps",       "--noreplace",
181 "--nospinner",    "--oneshot",
182 "--onlydeps",     "--pretend",
183 "--quiet",        "--resume",
184 "--searchdesc",   "--selective",
185 "--skipfirst",
186 "--tree",
187 "--update",
188 "--usepkg",       "--usepkgonly",
189 "--verbose",      "--version"
190 ]
191
192 shortmapping={
193 "1":"--oneshot",
194 "a":"--ask",
195 "b":"--buildpkg",  "B":"--buildpkgonly",
196 "c":"--clean",     "C":"--unmerge",
197 "d":"--debug",     "D":"--deep",
198 "e":"--emptytree",
199 "f":"--fetchonly", "F":"--fetch-all-uri",
200 "g":"--getbinpkg", "G":"--getbinpkgonly",
201 "h":"--help",
202 "k":"--usepkg",    "K":"--usepkgonly",
203 "l":"--changelog",
204 "n":"--noreplace", "N":"--newuse",
205 "o":"--onlydeps",  "O":"--nodeps",
206 "p":"--pretend",   "P":"--prune",
207 "q":"--quiet",
208 "s":"--search",    "S":"--searchdesc",
209 't':"--tree",
210 "u":"--update",
211 "v":"--verbose",   "V":"--version"
212 }
213
214 def emergelog(xterm_titles, mystr, short_msg=None):
215         if xterm_titles:
216                 if short_msg == None:
217                         short_msg = mystr
218                 if "HOSTNAME" in os.environ:
219                         short_msg = os.environ["HOSTNAME"]+": "+short_msg
220                 xtermTitle(short_msg)
221         try:
222                 file_path = "/var/log/emerge.log"
223                 mylogfile = open(file_path, "a")
224                 portage.util.apply_secpass_permissions(file_path,
225                         uid=portage.portage_uid, gid=portage.portage_gid,
226                         mode=0660)
227                 mylock = None
228                 try:
229                         mylock = portage.locks.lockfile(mylogfile)
230                         # seek because we may have gotten held up by the lock.
231                         # if so, we may not be positioned at the end of the file.
232                         mylogfile.seek(0, 2)
233                         mylogfile.write(str(time.time())[:10]+": "+mystr+"\n")
234                         mylogfile.flush()
235                 finally:
236                         if mylock:
237                                 portage.locks.unlockfile(mylock)
238                         mylogfile.close()
239         except (IOError,OSError,portage.exception.PortageException), e:
240                 if secpass >= 1:
241                         print >> sys.stderr, "emergelog():",e
242
243 def countdown(secs=5, doing="Starting"):
244         if secs:
245                 print ">>> Waiting",secs,"seconds before starting..."
246                 print ">>> (Control-C to abort)...\n"+doing+" in: ",
247                 ticks=range(secs)
248                 ticks.reverse()
249                 for sec in ticks:
250                         sys.stdout.write(colorize("UNMERGE_WARN", str(sec+1)+" "))
251                         sys.stdout.flush()
252                         time.sleep(1)
253                 print
254
255 # formats a size given in bytes nicely
256 def format_size(mysize):
257         if type(mysize) not in [types.IntType,types.LongType]:
258                 return str(mysize)
259         if 0 != mysize % 1024:
260                 # Always round up to the next kB so that it doesn't show 0 kB when
261                 # some small file still needs to be fetched.
262                 mysize += 1024 - mysize % 1024
263         mystr=str(mysize/1024)
264         mycount=len(mystr)
265         while (mycount > 3):
266                 mycount-=3
267                 mystr=mystr[:mycount]+","+mystr[mycount:]
268         return mystr+" kB"
269
270
271 def getgccversion(chost):
272         """
273         rtype: C{str}
274         return:  the current in-use gcc version
275         """
276
277         gcc_ver_command = 'gcc -dumpversion'
278         gcc_ver_prefix = 'gcc-'
279
280         gcc_not_found_error = red(
281         "!!! No gcc found. You probably need to 'source /etc/profile'\n" +
282         "!!! to update the environment of this terminal and possibly\n" +
283         "!!! other terminals also.\n"
284         )
285
286         mystatus, myoutput = commands.getstatusoutput("eselect compiler show")
287         if mystatus == os.EX_OK and len(myoutput.split("/")) == 2:
288                 part1, part2 = myoutput.split("/")
289                 if part1.startswith(chost + "-"):
290                         return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
291
292         mystatus, myoutput = commands.getstatusoutput("gcc-config -c")
293         if mystatus == os.EX_OK and myoutput.startswith(chost + "-"):
294                 return myoutput.replace(chost + "-", gcc_ver_prefix, 1)
295
296         mystatus, myoutput = commands.getstatusoutput(
297                 chost + "-" + gcc_ver_command)
298         if mystatus == os.EX_OK:
299                 return gcc_ver_prefix + myoutput
300
301         mystatus, myoutput = commands.getstatusoutput(gcc_ver_command)
302         if mystatus == os.EX_OK:
303                 return gcc_ver_prefix + myoutput
304
305         portage.writemsg(gcc_not_found_error, noiselevel=-1)
306         return "[unavailable]"
307
308 def getportageversion(portdir, target_root, profile, chost, vardb):
309         profilever = "unavailable"
310         if profile:
311                 realpath = os.path.realpath(profile)
312                 basepath   = os.path.realpath(os.path.join(portdir, "profiles"))
313                 if realpath.startswith(basepath):
314                         profilever = realpath[1 + len(basepath):]
315                 else:
316                         try:
317                                 profilever = "!" + os.readlink(profile)
318                         except (OSError):
319                                 pass
320                 del realpath, basepath
321
322         libcver=[]
323         libclist  = vardb.match("virtual/libc")
324         libclist += vardb.match("virtual/glibc")
325         libclist  = portage.util.unique_array(libclist)
326         for x in libclist:
327                 xs=portage.catpkgsplit(x)
328                 if libcver:
329                         libcver+=","+"-".join(xs[1:])
330                 else:
331                         libcver="-".join(xs[1:])
332         if libcver==[]:
333                 libcver="unavailable"
334
335         gccver = getgccversion(chost)
336         unameout=os.uname()[2]+" "+os.uname()[4]
337
338         return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")"
339
340 def create_depgraph_params(myopts, myaction):
341         #configure emerge engine parameters
342         #
343         # self:      include _this_ package regardless of if it is merged.
344         # selective: exclude the package if it is merged
345         # recurse:   go into the dependencies
346         # deep:      go into the dependencies of already merged packages
347         # empty:     pretend nothing is merged
348         myparams = set(["recurse"])
349         if "--update" in myopts or \
350                 "--newuse" in myopts or \
351                 "--reinstall" in myopts or \
352                 "--noreplace" in myopts or \
353                 myaction in ("system", "world"):
354                 myparams.add("selective")
355         if "--emptytree" in myopts:
356                 myparams.add("empty")
357                 myparams.discard("selective")
358         if "--nodeps" in myopts:
359                 myparams.discard("recurse")
360         if "--deep" in myopts:
361                 myparams.add("deep")
362         return myparams
363
364 # search functionality
365 class search(object):
366
367         #
368         # class constants
369         #
370         VERSION_SHORT=1
371         VERSION_RELEASE=2
372
373         #
374         # public interface
375         #
376         def __init__(self, settings, portdb, vartree, spinner, searchdesc,
377                 verbose):
378                 """Searches the available and installed packages for the supplied search key.
379                 The list of available and installed packages is created at object instantiation.
380                 This makes successive searches faster."""
381                 self.settings = settings
382                 self.portdb = portdb
383                 self.vartree = vartree
384                 self.spinner = spinner
385                 self.verbose = verbose
386                 self.searchdesc = searchdesc
387
388         def execute(self,searchkey):
389                 """Performs the search for the supplied search key"""
390                 match_category = 0
391                 self.searchkey=searchkey
392                 self.packagematches = []
393                 if self.searchdesc:
394                         self.searchdesc=1
395                         self.matches = {"pkg":[], "desc":[]}
396                 else:
397                         self.searchdesc=0
398                         self.matches = {"pkg":[]}
399                 print "Searching...   ",
400
401                 regexsearch = False
402                 if self.searchkey.startswith('%'):
403                         regexsearch = True
404                         self.searchkey = self.searchkey[1:]
405                 if self.searchkey.startswith('@'):
406                         match_category = 1
407                         self.searchkey = self.searchkey[1:]
408                 if regexsearch:
409                         self.searchre=re.compile(self.searchkey,re.I)
410                 else:
411                         self.searchre=re.compile(re.escape(self.searchkey), re.I)
412                 for package in self.portdb.cp_all():
413                         self.spinner.update()
414
415                         if match_category:
416                                 match_string  = package[:]
417                         else:
418                                 match_string  = package.split("/")[-1]
419
420                         masked=0
421                         if self.searchre.search(match_string):
422                                 if not self.portdb.xmatch("match-visible", package):
423                                         masked=1
424                                 self.matches["pkg"].append([package,masked])
425                         elif self.searchdesc: # DESCRIPTION searching
426                                 full_package = self.portdb.xmatch("bestmatch-visible", package)
427                                 if not full_package:
428                                         #no match found; we don't want to query description
429                                         full_package = portage.best(
430                                                 self.portdb.xmatch("match-all", package))
431                                         if not full_package:
432                                                 continue
433                                         else:
434                                                 masked=1
435                                 try:
436                                         full_desc = self.portdb.aux_get(
437                                                 full_package, ["DESCRIPTION"])[0]
438                                 except KeyError:
439                                         print "emerge: search: aux_get() failed, skipping"
440                                         continue
441                                 if self.searchre.search(full_desc):
442                                         self.matches["desc"].append([full_package,masked])
443                 self.mlen=0
444                 for mtype in self.matches:
445                         self.matches[mtype].sort()
446                         self.mlen += len(self.matches[mtype])
447
448         def output(self):
449                 """Outputs the results of the search."""
450                 print "\b\b  \n[ Results for search key : "+white(self.searchkey)+" ]"
451                 print "[ Applications found : "+white(str(self.mlen))+" ]"
452                 print " "
453                 for mtype in self.matches:
454                         for match,masked in self.matches[mtype]:
455                                 if mtype=="pkg":
456                                         catpack=match
457                                         full_package = self.portdb.xmatch(
458                                                 "bestmatch-visible", match)
459                                         if not full_package:
460                                                 #no match found; we don't want to query description
461                                                 masked=1
462                                                 full_package = portage.best(
463                                                         self.portdb.xmatch("match-all",match))
464                                 else:
465                                         full_package = match
466                                         match        = portage.pkgsplit(match)[0]
467
468                                 if full_package:
469                                         try:
470                                                 desc, homepage, license = self.portdb.aux_get(
471                                                         full_package, ["DESCRIPTION","HOMEPAGE","LICENSE"])
472                                         except KeyError:
473                                                 print "emerge: search: aux_get() failed, skipping"
474                                                 continue
475                                         if masked:
476                                                 print green("*")+"  "+white(match)+" "+red("[ Masked ]")
477                                         else:
478                                                 print green("*")+"  "+white(match)
479                                         myversion = self.getVersion(full_package, search.VERSION_RELEASE)
480
481                                         mysum = [0,0]
482                                         mycat = match.split("/")[0]
483                                         mypkg = match.split("/")[1]
484                                         mycpv = match + "-" + myversion
485                                         myebuild = self.portdb.findname(mycpv)
486                                         pkgdir = os.path.dirname(myebuild)
487                                         from portage import manifest
488                                         mf = manifest.Manifest(
489                                                 pkgdir, self.settings["DISTDIR"])
490                                         fetchlist = self.portdb.getfetchlist(mycpv,
491                                                 mysettings=self.settings, all=True)[1]
492                                         try:
493                                                 mysum[0] = mf.getDistfilesSize(fetchlist)
494                                                 mystr = str(mysum[0]/1024)
495                                                 mycount=len(mystr)
496                                                 while (mycount > 3):
497                                                         mycount-=3
498                                                         mystr=mystr[:mycount]+","+mystr[mycount:]
499                                                 mysum[0]=mystr+" kB"
500                                         except KeyError, e:
501                                                 mysum[0] = "Unknown (missing digest for %s)" % str(e)
502
503                                         if self.verbose:
504                                                 print "     ", darkgreen("Latest version available:"),myversion
505                                                 print "     ", self.getInstallationStatus(mycat+'/'+mypkg)
506                                                 print "     ", darkgreen("Size of files:"),mysum[0]
507                                                 print "     ", darkgreen("Homepage:")+"     ",homepage
508                                                 print "     ", darkgreen("Description:")+"  ",desc
509                                                 print "     ", darkgreen("License:")+"      ",license
510                                                 print
511                 print
512         #
513         # private interface
514         #
515         def getInstallationStatus(self,package):
516                 installed_package = self.vartree.dep_bestmatch(package)
517                 result = ""
518                 version = self.getVersion(installed_package,search.VERSION_RELEASE)
519                 if len(version) > 0:
520                         result = darkgreen("Latest version installed:")+" "+version
521                 else:
522                         result = darkgreen("Latest version installed:")+" [ Not Installed ]"
523                 return result
524
525         def getVersion(self,full_package,detail):
526                 if len(full_package) > 1:
527                         package_parts = portage.catpkgsplit(full_package)
528                         if detail == search.VERSION_RELEASE and package_parts[3] != 'r0':
529                                 result = package_parts[2]+ "-" + package_parts[3]
530                         else:
531                                 result = package_parts[2]
532                 else:
533                         result = ""
534                 return result
535
536
537 #build our package digraph
538 def getlist(settings, mode):
539         if mode=="system":
540                 mylines = settings.packages
541         elif mode=="world":
542                 try:
543                         file_path = os.path.join(settings["ROOT"], portage.WORLD_FILE)
544                         myfile = open(file_path, "r")
545                         mylines = myfile.readlines()
546                         myfile.close()
547                 except (OSError, IOError), e:
548                         if e.errno == errno.ENOENT:
549                                 portage.writemsg("\n!!! World file does not exist: '%s'\n" % file_path)
550                                 mylines=[]
551                         else:
552                                 raise
553         mynewlines=[]
554         for x in mylines:
555                 myline=" ".join(x.split())
556                 if not len(myline):
557                         continue
558                 elif myline[0]=="#":
559                         continue
560                 elif mode=="system":
561                         if myline[0]!="*":
562                                 continue
563                         myline=myline[1:]
564                 mynewlines.append(myline.strip())
565
566         return mynewlines
567
568 def clean_world(vardb, cpv):
569         """Remove a package from the world file when unmerged."""
570         world_set = WorldSet("world", vardb.settings["ROOT"])
571         world_set.lock()
572         worldlist = list(world_set) # loads latest from disk
573         mykey = portage.cpv_getkey(cpv)
574         newworldlist = []
575         for x in worldlist:
576                 if portage.dep_getkey(x) == mykey:
577                         matches = vardb.match(x, use_cache=0)
578                         if not matches:
579                                 #zap our world entry
580                                 pass
581                         elif len(matches) == 1 and matches[0] == cpv:
582                                 #zap our world entry
583                                 pass
584                         else:
585                                 #others are around; keep it.
586                                 newworldlist.append(x)
587                 else:
588                         #this doesn't match the package we're unmerging; keep it.
589                         newworldlist.append(x)
590
591         world_set.replace(newworldlist)
592         world_set.unlock()
593
594
595 class RootConfig(object):
596         """This is used internally by depgraph to track information about a
597         particular $ROOT."""
598         def __init__(self, trees):
599                 self.trees = trees
600                 self.settings = trees["vartree"].settings
601                 self.root = self.settings["ROOT"]
602                 self.sets = {}
603                 world_set = WorldSet("world", self.root)
604                 self.sets["world"] = world_set
605                 system_set = SystemSet("system", self.settings.profiles)
606                 self.sets["system"] = system_set
607
608 def create_world_atom(pkg_key, metadata, args_set, root_config):
609         """Create a new atom for the world file if one does not exist.  If the
610         argument atom is precise enough to identify a specific slot then a slot
611         atom will be returned. Atoms that are in the system set may also be stored
612         in world since system atoms can only match one slot while world atoms can
613         be greedy with respect to slots.  Unslotted system packages will not be
614         stored in world."""
615         arg_atom = args_set.findAtomForPackage(pkg_key, metadata)
616         cp = portage.dep_getkey(arg_atom)
617         new_world_atom = cp
618         sets = root_config.sets
619         portdb = root_config.trees["porttree"].dbapi
620         vardb = root_config.trees["vartree"].dbapi
621         available_slots = set(portdb.aux_get(cpv, ["SLOT"])[0] \
622                 for cpv in portdb.match(cp))
623         slotted = len(available_slots) > 1 or \
624                 (len(available_slots) == 1 and "0" not in available_slots)
625         if not slotted:
626                 # check the vdb in case this is multislot
627                 available_slots = set(vardb.aux_get(cpv, ["SLOT"])[0] \
628                         for cpv in vardb.match(cp))
629                 slotted = len(available_slots) > 1 or \
630                         (len(available_slots) == 1 and "0" not in available_slots)
631         if slotted and arg_atom != cp:
632                 # If the user gave a specific atom, store it as a
633                 # slot atom in the world file.
634                 slot_atom = "%s:%s" % (cp, metadata["SLOT"])
635                 # First verify the slot is in the portage tree to avoid
636                 # adding a bogus slot like that produced by multislot.
637                 if portdb.match(slot_atom):
638                         # Now verify that the argument is precise enough to identify a
639                         # specific slot.
640                         matches = portdb.match(arg_atom)
641                         matched_slots = set()
642                         for cpv in matches:
643                                 matched_slots.add(portdb.aux_get(cpv, ["SLOT"])[0])
644                         if len(matched_slots) == 1:
645                                 new_world_atom = slot_atom
646         if new_world_atom == sets["world"].findAtomForPackage(pkg_key, metadata):
647                 # Both atoms would be identical, so there's nothing to add.
648                 return None
649         if not slotted:
650                 # Unlike world atoms, system atoms are not greedy for slots, so they
651                 # can't be safely excluded from world if they are slotted.
652                 system_atom = sets["system"].findAtomForPackage(pkg_key, metadata)
653                 if system_atom:
654                         if not portage.dep_getkey(system_atom).startswith("virtual/"):
655                                 return None
656                         # System virtuals aren't safe to exclude from world since they can
657                         # match multiple old-style virtuals but only one of them will be
658                         # pulled in by update or depclean.
659                         providers = portdb.mysettings.getvirtuals().get(
660                                 portage.dep_getkey(system_atom))
661                         if providers and len(providers) == 1 and providers[0] == cp:
662                                 return None
663         return new_world_atom
664
665 def filter_iuse_defaults(iuse):
666         for flag in iuse:
667                 if flag.startswith("+") or flag.startswith("-"):
668                         yield flag[1:]
669                 else:
670                         yield flag
671
672 class DepPriority(object):
673         """
674                 This class generates an integer priority level based of various
675                 attributes of the dependency relationship.  Attributes can be assigned
676                 at any time and the new integer value will be generated on calls to the
677                 __int__() method.  Rich comparison operators are supported.
678
679                 The boolean attributes that affect the integer value are "satisfied",
680                 "buildtime", "runtime", and "system".  Various combinations of
681                 attributes lead to the following priority levels:
682
683                 Combination of properties    Priority level
684
685                 not satisfied and buildtime     0
686                 not satisfied and runtime      -1
687                 satisfied and buildtime        -2
688                 satisfied and runtime          -3
689                 (none of the above)            -4
690
691                 Several integer constants are defined for categorization of priority
692                 levels:
693
694                 MEDIUM   The upper boundary for medium dependencies.
695                 MEDIUM_SOFT   The upper boundary for medium-soft dependencies.
696                 SOFT     The upper boundary for soft dependencies.
697                 MIN      The lower boundary for soft dependencies.
698         """
699         __slots__ = ("__weakref__", "satisfied", "buildtime", "runtime", "runtime_post")
700         MEDIUM = -1
701         MEDIUM_SOFT = -2
702         SOFT   = -3
703         MIN    = -6
704         def __init__(self, **kwargs):
705                 for myattr in self.__slots__:
706                         if myattr == "__weakref__":
707                                 continue
708                         myvalue = kwargs.get(myattr, False)
709                         setattr(self, myattr, myvalue)
710         def __int__(self):
711                 if not self.satisfied:
712                         if self.buildtime:
713                                 return 0
714                         if self.runtime:
715                                 return -1
716                         if self.runtime_post:
717                                 return -2
718                 if self.buildtime:
719                         return -3
720                 if self.runtime:
721                         return -4
722                 if self.runtime_post:
723                         return -5
724                 return -6
725         def __lt__(self, other):
726                 return self.__int__() < other
727         def __le__(self, other):
728                 return self.__int__() <= other
729         def __eq__(self, other):
730                 return self.__int__() == other
731         def __ne__(self, other):
732                 return self.__int__() != other
733         def __gt__(self, other):
734                 return self.__int__() > other
735         def __ge__(self, other):
736                 return self.__int__() >= other
737         def copy(self):
738                 import copy
739                 return copy.copy(self)
740         def __str__(self):
741                 myvalue = self.__int__()
742                 if myvalue > self.MEDIUM:
743                         return "hard"
744                 if myvalue > self.MEDIUM_SOFT:
745                         return "medium"
746                 if myvalue > self.SOFT:
747                         return "medium-soft"
748                 return "soft"
749
750 class FakeVartree(portage.vartree):
751         """This is implements an in-memory copy of a vartree instance that provides
752         all the interfaces required for use by the depgraph.  The vardb is locked
753         during the constructor call just long enough to read a copy of the
754         installed package information.  This allows the depgraph to do it's
755         dependency calculations without holding a lock on the vardb.  It also
756         allows things like vardb global updates to be done in memory so that the
757         user doesn't necessarily need write access to the vardb in cases where
758         global updates are necessary (updates are performed when necessary if there
759         is not a matching ebuild in the tree)."""
760         def __init__(self, real_vartree, portdb):
761                 self.root = real_vartree.root
762                 self.settings = real_vartree.settings
763                 self.dbapi = portage.fakedbapi(settings=real_vartree.settings)
764                 vdb_path = os.path.join(self.root, portage.VDB_PATH)
765                 try:
766                         # At least the parent needs to exist for the lock file.
767                         portage.util.ensure_dirs(vdb_path)
768                 except portage.exception.PortageException:
769                         pass
770                 vdb_lock = None
771                 try:
772                         if os.access(vdb_path, os.W_OK):
773                                 vdb_lock = portage.locks.lockdir(vdb_path)
774                         mykeys = ["SLOT", "COUNTER", "PROVIDE", "USE", "IUSE",
775                                 "RESTRICT", "DEPEND", "RDEPEND", "PDEPEND", "repository"]
776                         real_dbapi = real_vartree.dbapi
777                         slot_counters = {}
778                         for cpv in real_dbapi.cpv_all():
779                                 metadata = dict(izip(mykeys, real_dbapi.aux_get(cpv, mykeys)))
780                                 myslot = metadata["SLOT"]
781                                 mycp = portage.dep_getkey(cpv)
782                                 myslot_atom = "%s:%s" % (mycp, myslot)
783                                 try:
784                                         mycounter = long(metadata["COUNTER"])
785                                 except ValueError:
786                                         mycounter = 0
787                                         metadata["COUNTER"] = str(mycounter)
788                                 other_counter = slot_counters.get(myslot_atom, None)
789                                 if other_counter is not None:
790                                         if other_counter > mycounter:
791                                                 continue
792                                 slot_counters[myslot_atom] = mycounter
793                                 self.dbapi.cpv_inject(cpv, metadata=metadata)
794                         real_dbapi.flush_cache()
795                 finally:
796                         if vdb_lock:
797                                 portage.locks.unlockdir(vdb_lock)
798                 # Populate the old-style virtuals using the cached values.
799                 if not self.settings.treeVirtuals:
800                         self.settings.treeVirtuals = portage.util.map_dictlist_vals(
801                                 portage.getCPFromCPV, self.get_all_provides())
802
803                 # Intialize variables needed for lazy cache pulls of the live ebuild
804                 # metadata.  This ensures that the vardb lock is released ASAP, without
805                 # being delayed in case cache generation is triggered.
806                 self._aux_get = self.dbapi.aux_get
807                 self.dbapi.aux_get = self._aux_get_wrapper
808                 self._aux_get_history = set()
809                 self._portdb_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
810                 self._portdb = portdb
811                 self._global_updates = None
812
813         def _aux_get_wrapper(self, pkg, wants):
814                 if pkg in self._aux_get_history:
815                         return self._aux_get(pkg, wants)
816                 self._aux_get_history.add(pkg)
817                 try:
818                         # Use the live ebuild metadata if possible.
819                         live_metadata = dict(izip(self._portdb_keys,
820                                 self._portdb.aux_get(pkg, self._portdb_keys)))
821                         self.dbapi.aux_update(pkg, live_metadata)
822                 except (KeyError, portage.exception.PortageException):
823                         if self._global_updates is None:
824                                 self._global_updates = \
825                                         grab_global_updates(self._portdb.porttree_root)
826                         perform_global_updates(
827                                 pkg, self.dbapi, self._global_updates)
828                 return self._aux_get(pkg, wants)
829
830 def grab_global_updates(portdir):
831         from portage.update import grab_updates, parse_updates
832         updpath = os.path.join(portdir, "profiles", "updates")
833         try:
834                 rawupdates = grab_updates(updpath)
835         except portage.exception.DirectoryNotFound:
836                 rawupdates = []
837         upd_commands = []
838         for mykey, mystat, mycontent in rawupdates:
839                 commands, errors = parse_updates(mycontent)
840                 upd_commands.extend(commands)
841         return upd_commands
842
843 def perform_global_updates(mycpv, mydb, mycommands):
844         from portage.update import update_dbentries
845         aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
846         aux_dict = dict(izip(aux_keys, mydb.aux_get(mycpv, aux_keys)))
847         updates = update_dbentries(mycommands, aux_dict)
848         if updates:
849                 mydb.aux_update(mycpv, updates)
850
851 class BlockerCache(DictMixin):
852         """This caches blockers of installed packages so that dep_check does not
853         have to be done for every single installed package on every invocation of
854         emerge.  The cache is invalidated whenever it is detected that something
855         has changed that might alter the results of dep_check() calls:
856                 1) the set of installed packages (including COUNTER) has changed
857                 2) the old-style virtuals have changed
858         """
859         class BlockerData(object):
860                 def __init__(self, counter, atoms):
861                         self.counter = counter
862                         self.atoms = atoms
863
864         def __init__(self, myroot, vardb):
865                 self._vardb = vardb
866                 self._installed_pkgs = set(vardb.cpv_all())
867                 self._virtuals = vardb.settings.getvirtuals()
868                 self._cache_filename = os.path.join(myroot,
869                         portage.CACHE_PATH.lstrip(os.path.sep), "vdb_blockers.pickle")
870                 self._cache_version = "1"
871                 self._cache_data = None
872                 self._modified = False
873                 self._load()
874
875         def _load(self):
876                 try:
877                         f = open(self._cache_filename)
878                         mypickle = cPickle.Unpickler(f)
879                         mypickle.find_global = None
880                         self._cache_data = mypickle.load()
881                         f.close()
882                         del f
883                 except (IOError, OSError, EOFError, cPickle.UnpicklingError):
884                         pass
885                 cache_valid = self._cache_data and \
886                         isinstance(self._cache_data, dict) and \
887                         self._cache_data.get("version") == self._cache_version and \
888                         self._cache_data.get("virtuals") == self._virtuals and \
889                         set(self._cache_data.get("blockers", [])) == self._installed_pkgs
890                 if cache_valid:
891                         for pkg in self._installed_pkgs:
892                                 if long(self._vardb.aux_get(pkg, ["COUNTER"])[0]) != \
893                                         self[pkg].counter:
894                                         cache_valid = False
895                                         break
896                 if not cache_valid:
897                         self._cache_data = {"version":self._cache_version}
898                         self._cache_data["blockers"] = {}
899                         self._cache_data["virtuals"] = self._virtuals
900                 self._modified = False
901
902         def flush(self):
903                 """If the current user has permission and the internal blocker cache
904                 been updated, save it to disk and mark it unmodified.  This is called
905                 by emerge after it has proccessed blockers for all installed packages.
906                 Currently, the cache is only written if the user has superuser
907                 privileges (since that's required to obtain a lock), but all users
908                 have read access and benefit from faster blocker lookups (as long as
909                 the entire cache is still valid).  The cache is stored as a pickled
910                 dict object with the following format:
911
912                 {
913                         version : "1",
914                         "blockers" : {cpv1:(counter,(atom1, atom2...)), cpv2...},
915                         "virtuals" : vardb.settings.getvirtuals()
916                 }
917                 """
918                 if self._modified and \
919                         secpass >= 2:
920                         try:
921                                 f = portage.util.atomic_ofstream(self._cache_filename)
922                                 cPickle.dump(self._cache_data, f, -1)
923                                 f.close()
924                                 portage.util.apply_secpass_permissions(
925                                         self._cache_filename, gid=portage.portage_gid, mode=0644)
926                         except (IOError, OSError), e:
927                                 pass
928                         self._modified = False
929
930         def __setitem__(self, cpv, blocker_data):
931                 """
932                 Update the cache and mark it as modified for a future call to
933                 self.flush().
934
935                 @param cpv: Package for which to cache blockers.
936                 @type cpv: String
937                 @param blocker_data: An object with counter and atoms attributes.
938                 @type blocker_data: BlockerData
939                 """
940                 self._cache_data["blockers"][cpv] = \
941                         (blocker_data.counter, blocker_data.atoms)
942                 self._modified = True
943
944         def __getitem__(self, cpv):
945                 """
946                 @rtype: BlockerData
947                 @returns: An object with counter and atoms attributes.
948                 """
949                 return self.BlockerData(*self._cache_data["blockers"][cpv])
950
951         def keys(self):
952                 """This needs to be implemented so that self.__repr__() doesn't raise
953                 an AttributeError."""
954                 if self._cache_data and "blockers" in self._cache_data:
955                         return self._cache_data["blockers"].keys()
956                 return []
957
958 def show_invalid_depstring_notice(parent_node, depstring, error_msg):
959
960         from formatter import AbstractFormatter, DumbWriter
961         f = AbstractFormatter(DumbWriter(maxcol=72))
962
963         print "\n\n!!! Invalid or corrupt dependency specification: "
964         print
965         print error_msg
966         print
967         print parent_node
968         print
969         print depstring
970         print
971         p_type, p_root, p_key, p_status = parent_node
972         msg = []
973         if p_status == "nomerge":
974                 category, pf = portage.catsplit(p_key)
975                 pkg_location = os.path.join(p_root, portage.VDB_PATH, category, pf)
976                 msg.append("Portage is unable to process the dependencies of the ")
977                 msg.append("'%s' package. " % p_key)
978                 msg.append("In order to correct this problem, the package ")
979                 msg.append("should be uninstalled, reinstalled, or upgraded. ")
980                 msg.append("As a temporary workaround, the --nodeps option can ")
981                 msg.append("be used to ignore all dependencies.  For reference, ")
982                 msg.append("the problematic dependencies can be found in the ")
983                 msg.append("*DEPEND files located in '%s/'." % pkg_location)
984         else:
985                 msg.append("This package can not be installed.  ")
986                 msg.append("Please notify the '%s' package maintainer " % p_key)
987                 msg.append("about this problem.")
988
989         for x in msg:
990                 f.add_flowing_data(x)
991         f.end_paragraph(1)
992
993 class depgraph(object):
994
995         pkg_tree_map = {
996                 "ebuild":"porttree",
997                 "binary":"bintree",
998                 "installed":"vartree"}
999
1000         def __init__(self, settings, trees, myopts, myparams, spinner):
1001                 self.settings = settings
1002                 self.target_root = settings["ROOT"]
1003                 self.myopts = myopts
1004                 self.myparams = myparams
1005                 self.edebug = 0
1006                 if settings.get("PORTAGE_DEBUG", "") == "1":
1007                         self.edebug = 1
1008                 self.spinner = spinner
1009                 self.pkgsettings = {}
1010                 # Maps cpv to digraph node for all nodes added to the graph.
1011                 self.pkg_node_map = {}
1012                 # Maps slot atom to digraph node for all nodes added to the graph.
1013                 self._slot_node_map = {}
1014                 # Maps nodes to the reasons they were selected for reinstallation.
1015                 self._reinstall_nodes = {}
1016                 self.mydbapi = {}
1017                 self._mydbapi_keys = ["SLOT", "DEPEND", "RDEPEND", "PDEPEND",
1018                         "USE", "IUSE", "PROVIDE", "RESTRICT", "repository"]
1019                 self.useFlags = {}
1020                 self.trees = {}
1021                 self.roots = {}
1022                 for myroot in trees:
1023                         self.trees[myroot] = {}
1024                         for tree in ("porttree", "bintree"):
1025                                 self.trees[myroot][tree] = trees[myroot][tree]
1026                         self.trees[myroot]["vartree"] = \
1027                                 FakeVartree(trees[myroot]["vartree"],
1028                                         trees[myroot]["porttree"].dbapi)
1029                         self.pkgsettings[myroot] = portage.config(
1030                                 clone=self.trees[myroot]["vartree"].settings)
1031                         self.pkg_node_map[myroot] = {}
1032                         self._slot_node_map[myroot] = {}
1033                         vardb = self.trees[myroot]["vartree"].dbapi
1034                         self.roots[myroot] = RootConfig(self.trees[myroot])
1035                         # This fakedbapi instance will model the state that the vdb will
1036                         # have after new packages have been installed.
1037                         fakedb = portage.fakedbapi(settings=self.pkgsettings[myroot])
1038                         self.mydbapi[myroot] = fakedb
1039                         if "--nodeps" not in self.myopts and \
1040                                 "--buildpkgonly" not in self.myopts:
1041                                 # --nodeps bypasses this, since it isn't needed in this case
1042                                 # and the cache pulls might trigger (slow) cache generation.
1043                                 for pkg in vardb.cpv_all():
1044                                         self.spinner.update()
1045                                         fakedb.cpv_inject(pkg,
1046                                                 metadata=dict(izip(self._mydbapi_keys,
1047                                                 vardb.aux_get(pkg, self._mydbapi_keys))))
1048                         del vardb, fakedb
1049                         self.useFlags[myroot] = {}
1050                         if "--usepkg" in self.myopts:
1051                                 self.trees[myroot]["bintree"].populate(
1052                                         "--getbinpkg" in self.myopts,
1053                                         "--getbinpkgonly" in self.myopts)
1054                 del trees
1055
1056                 self.missingbins=[]
1057                 self.digraph=portage.digraph()
1058                 # Tracks simple parent/child relationships (PDEPEND relationships are
1059                 # not reversed).
1060                 self._parent_child_digraph = digraph()
1061                 self.orderedkeys=[]
1062                 self.outdatedpackages=[]
1063                 # contains all sets added to the graph
1064                 self._sets = {}
1065                 # contains atoms given as arguments
1066                 self._sets["args"] = InternalPackageSet()
1067                 # contains all atoms from all sets added to the graph, including
1068                 # atoms given as arguments
1069                 self._set_atoms = InternalPackageSet()
1070                 # contains all nodes pulled in by self._set_atoms
1071                 self._set_nodes = set()
1072                 self.blocker_digraph = digraph()
1073                 self.blocker_parents = {}
1074                 self._unresolved_blocker_parents = {}
1075                 self._slot_collision_info = []
1076                 # Slot collision nodes are not allowed to block other packages since
1077                 # blocker validation is only able to account for one package per slot.
1078                 self._slot_collision_nodes = set()
1079                 self._altlist_cache = {}
1080                 self._pprovided_args = []
1081
1082         def _show_slot_collision_notice(self, packages):
1083                 """Show an informational message advising the user to mask one of the
1084                 the packages. In some cases it may be possible to resolve this
1085                 automatically, but support for backtracking (removal nodes that have
1086                 already been selected) will be required in order to handle all possible
1087                 cases."""
1088
1089                 msg = []
1090                 msg.append("\n!!! Multiple versions within a single " + \
1091                         "package slot have been \n")
1092                 msg.append("!!! pulled into the dependency graph:\n\n")
1093                 for node, parents in packages:
1094                         msg.append(str(node))
1095                         if parents:
1096                                 msg.append(" pulled in by\n")
1097                                 for parent in parents:
1098                                         msg.append("  ")
1099                                         msg.append(str(parent))
1100                                         msg.append("\n")
1101                         else:
1102                                 msg.append(" (no parents)\n")
1103                         msg.append("\n")
1104                 sys.stderr.write("".join(msg))
1105                 sys.stderr.flush()
1106
1107                 if "--quiet" in self.myopts:
1108                         return
1109
1110                 msg = []
1111                 msg.append("It may be possible to solve this problem ")
1112                 msg.append("by using package.mask to prevent one of ")
1113                 msg.append("those packages from being selected. ")
1114                 msg.append("However, it is also possible that conflicting ")
1115                 msg.append("dependencies exist such that they are impossible to ")
1116                 msg.append("satisfy simultaneously.  If such a conflict exists in ")
1117                 msg.append("the dependencies of two different packages, then those ")
1118                 msg.append("packages can not be installed simultaneously.")
1119
1120                 from formatter import AbstractFormatter, DumbWriter
1121                 f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72))
1122                 for x in msg:
1123                         f.add_flowing_data(x)
1124                 f.end_paragraph(1)
1125
1126                 msg = []
1127                 msg.append("For more information, see MASKED PACKAGES ")
1128                 msg.append("section in the emerge man page or refer ")
1129                 msg.append("to the Gentoo Handbook.")
1130                 for x in msg:
1131                         f.add_flowing_data(x)
1132                 f.end_paragraph(1)
1133                 f.writer.flush()
1134
1135         def _reinstall_for_flags(self, forced_flags,
1136                 orig_use, orig_iuse, cur_use, cur_iuse):
1137                 """Return a set of flags that trigger reinstallation, or None if there
1138                 are no such flags."""
1139                 if "--newuse" in self.myopts:
1140                         flags = orig_iuse.symmetric_difference(
1141                                 cur_iuse).difference(forced_flags)
1142                         flags.update(orig_iuse.intersection(orig_use).symmetric_difference(
1143                                 cur_iuse.intersection(cur_use)))
1144                         if flags:
1145                                 return flags
1146                 elif "changed-use" == self.myopts.get("--reinstall"):
1147                         flags = orig_iuse.intersection(orig_use).symmetric_difference(
1148                                 cur_iuse.intersection(cur_use))
1149                         if flags:
1150                                 return flags
1151                 return None
1152
1153         def create(self, mybigkey, myparent=None, addme=1, myuse=None,
1154                 priority=DepPriority(), rev_dep=False, arg=None):
1155                 """
1156                 Fills the digraph with nodes comprised of packages to merge.
1157                 mybigkey is the package spec of the package to merge.
1158                 myparent is the package depending on mybigkey ( or None )
1159                 addme = Should we add this package to the digraph or are we just looking at it's deps?
1160                         Think --onlydeps, we need to ignore packages in that case.
1161                 #stuff to add:
1162                 #SLOT-aware emerge
1163                 #IUSE-aware emerge -> USE DEP aware depgraph
1164                 #"no downgrade" emerge
1165                 """
1166                 mytype, myroot, mykey = mybigkey
1167                 existing_node = None
1168                 if addme:
1169                         existing_node = self.pkg_node_map[myroot].get(mykey)
1170                 if existing_node:
1171                         self._parent_child_digraph.add(existing_node, myparent)
1172                         if existing_node != myparent:
1173                                 # Refuse to make a node depend on itself so that the we don't
1174                                 # don't create a bogus circular dependency in self.altlist().
1175                                 if rev_dep and myparent:
1176                                         self.digraph.addnode(myparent, existing_node,
1177                                                 priority=priority)
1178                                 else:
1179                                         self.digraph.addnode(existing_node, myparent,
1180                                                 priority=priority)
1181                         return 1
1182                 
1183                 if "--nodeps" not in self.myopts:
1184                         self.spinner.update()
1185                 if mytype == "blocks":
1186                         if myparent and \
1187                                 "--buildpkgonly" not in self.myopts and \
1188                                 "--nodeps" not in self.myopts and \
1189                                 myparent not in self._slot_collision_nodes:
1190                                 mybigkey[1] = myparent[1]
1191                                 self.blocker_parents.setdefault(
1192                                         tuple(mybigkey), set()).add(myparent)
1193                         return 1
1194
1195                 # select the correct /var database that we'll be checking against
1196                 vardbapi = self.trees[myroot]["vartree"].dbapi
1197                 portdb = self.trees[myroot]["porttree"].dbapi
1198                 bindb = self.trees[myroot]["bintree"].dbapi
1199                 pkgsettings = self.pkgsettings[myroot]
1200
1201                 # if the package is already on the system, we add a "nomerge"
1202                 # directive, otherwise we add a "merge" directive.
1203
1204                 mydbapi = self.trees[myroot][self.pkg_tree_map[mytype]].dbapi
1205                 metadata = dict(izip(self._mydbapi_keys,
1206                         mydbapi.aux_get(mykey, self._mydbapi_keys)))
1207                 if mytype == "ebuild":
1208                         pkgsettings.setcpv(mykey, mydb=portdb)
1209                         metadata["USE"] = pkgsettings["USE"]
1210                         myuse = pkgsettings["USE"].split()
1211
1212                 if not arg and myroot == self.target_root:
1213                         try:
1214                                 arg = self._set_atoms.findAtomForPackage(mykey, metadata)
1215                         except portage.exception.InvalidDependString, e:
1216                                 if mytype != "installed":
1217                                         show_invalid_depstring_notice(tuple(mybigkey+["merge"]),
1218                                                 metadata["PROVIDE"], str(e))
1219                                         return 0
1220                                 del e
1221
1222                 reinstall_for_flags = None
1223                 merging=1
1224                 if mytype == "installed":
1225                         merging = 0
1226                 if addme and mytype != "installed":
1227                 # this is where we add the node to the list of packages to merge
1228                         if "selective" in self.myparams or not arg:
1229                                 if "empty" not in self.myparams and vardbapi.cpv_exists(mykey):
1230                                         merging=0
1231
1232                         """ If we aren't merging, perform the --newuse check.
1233                             If the package has new iuse flags or different use flags then if
1234                             --newuse is specified, we need to merge the package. """
1235                         if merging == 0 and \
1236                                 myroot == self.target_root and \
1237                                 ("--newuse" in self.myopts or
1238                                 "--reinstall" in self.myopts) and \
1239                                 vardbapi.cpv_exists(mykey):
1240                                 pkgsettings.setcpv(mykey, mydb=mydbapi)
1241                                 forced_flags = set()
1242                                 forced_flags.update(pkgsettings.useforce)
1243                                 forced_flags.update(pkgsettings.usemask)
1244                                 old_use = vardbapi.aux_get(mykey, ["USE"])[0].split()
1245                                 iuses = set(filter_iuse_defaults(metadata["IUSE"].split()))
1246                                 old_iuse = set(filter_iuse_defaults(
1247                                         vardbapi.aux_get(mykey, ["IUSE"])[0].split()))
1248                                 reinstall_for_flags = self._reinstall_for_flags(
1249                                         forced_flags, old_use, old_iuse, myuse, iuses)
1250                                 if reinstall_for_flags:
1251                                         merging = 1
1252
1253                 if addme and merging == 1:
1254                         mybigkey.append("merge")
1255                 else:
1256                         mybigkey.append("nomerge")
1257                 jbigkey = tuple(mybigkey)
1258
1259                 if addme:
1260                         if merging == 0 and vardbapi.cpv_exists(mykey) and \
1261                                 mytype != "installed":
1262                                 mytype = "installed"
1263                                 mybigkey[0] = "installed"
1264                                 mydbapi = vardbapi
1265                                 jbigkey = tuple(mybigkey)
1266                                 metadata = dict(izip(self._mydbapi_keys,
1267                                         mydbapi.aux_get(mykey, self._mydbapi_keys)))
1268                                 myuse = metadata["USE"].split()
1269                         slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
1270                         existing_node = self._slot_node_map[myroot].get(
1271                                 slot_atom, None)
1272                         slot_collision = False
1273                         if existing_node:
1274                                 e_type, myroot, e_cpv, e_status = existing_node
1275                                 if mykey == e_cpv:
1276                                         # The existing node can be reused.
1277                                         self._parent_child_digraph.add(existing_node, myparent)
1278                                         if rev_dep and myparent:
1279                                                 ptype, proot, pkey, pstatus = myparent
1280                                                 self.digraph.addnode(myparent, existing_node,
1281                                                         priority=priority)
1282                                         else:
1283                                                 self.digraph.addnode(existing_node, myparent,
1284                                                         priority=priority)
1285                                         return 1
1286                                 else:
1287                                         # A slot collision has occurred.  Sometimes this coincides
1288                                         # with unresolvable blockers, so the slot collision will be
1289                                         # shown later if there are no unresolvable blockers.
1290                                         e_parents = self._parent_child_digraph.parent_nodes(
1291                                                 existing_node)
1292                                         myparents = []
1293                                         if myparent:
1294                                                 myparents.append(myparent)
1295                                         self._slot_collision_info.append(
1296                                                 ((jbigkey, myparents), (existing_node, e_parents)))
1297                                         self._slot_collision_nodes.add(jbigkey)
1298                                         slot_collision = True
1299
1300                         if slot_collision:
1301                                 # Now add this node to the graph so that self.display()
1302                                 # can show use flags and --tree portage.output.  This node is
1303                                 # only being partially added to the graph.  It must not be
1304                                 # allowed to interfere with the other nodes that have been
1305                                 # added.  Do not overwrite data for existing nodes in
1306                                 # self.pkg_node_map and self.mydbapi since that data will
1307                                 # be used for blocker validation.
1308                                 self.pkg_node_map[myroot].setdefault(mykey, jbigkey)
1309                                 self.useFlags[myroot].setdefault(mykey, myuse)
1310                                 # Even though the graph is now invalid, continue to process
1311                                 # dependencies so that things like --fetchonly can still
1312                                 # function despite collisions.
1313                         else:
1314                                 self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata)
1315                                 self._slot_node_map[myroot][slot_atom] = jbigkey
1316                                 self.pkg_node_map[myroot][mykey] = jbigkey
1317                                 self.useFlags[myroot][mykey] = myuse
1318                                 if reinstall_for_flags:
1319                                         self._reinstall_nodes[jbigkey] = reinstall_for_flags
1320
1321                         if rev_dep and myparent:
1322                                 self.digraph.addnode(myparent, jbigkey,
1323                                         priority=priority)
1324                         else:
1325                                 self.digraph.addnode(jbigkey, myparent,
1326                                         priority=priority)
1327
1328                 if arg:
1329                         self._set_nodes.add(jbigkey)
1330
1331                 # Do this even when addme is False (--onlydeps) so that the
1332                 # parent/child relationship is always known in case
1333                 # self._show_slot_collision_notice() needs to be called later.
1334                 self._parent_child_digraph.add(jbigkey, myparent)
1335
1336                 """ This section determines whether we go deeper into dependencies or not.
1337                     We want to go deeper on a few occasions:
1338                     Installing package A, we need to make sure package A's deps are met.
1339                     emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
1340                     If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
1341                 """
1342                 if "deep" not in self.myparams and not merging and \
1343                         not ("--update" in self.myopts and arg and merging):
1344                         return 1
1345                 elif "recurse" not in self.myparams:
1346                         return 1
1347
1348                 """ Check DEPEND/RDEPEND/PDEPEND/SLOT
1349                 Pull from bintree if it's binary package, porttree if it's ebuild.
1350                 Binpkg's can be either remote or local. """
1351
1352                 edepend={}
1353                 depkeys = ["DEPEND","RDEPEND","PDEPEND"]
1354                 for k in depkeys:
1355                         edepend[k] = metadata[k]
1356
1357                 if mytype == "ebuild":
1358                         if "--buildpkgonly" in self.myopts:
1359                                 edepend["RDEPEND"] = ""
1360                                 edepend["PDEPEND"] = ""
1361                 if not (arg and "--onlydeps" in self.myopts and \
1362                         mytype == "ebuild") and \
1363                         self.myopts.get("--with-bdeps", "n") == "n" and \
1364                         (mytype == "binary" or mybigkey[3] == "nomerge"):
1365                         edepend["DEPEND"] = ""
1366
1367                 """ We have retrieve the dependency information, now we need to recursively
1368                     process them.  DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """
1369                 
1370                 mp = tuple(mybigkey)
1371
1372                 try:
1373                         if not self.select_dep("/", edepend["DEPEND"], myparent=mp,
1374                                 myuse=myuse, priority=DepPriority(buildtime=True),
1375                                 parent_arg=arg):
1376                                 return 0
1377                         """RDEPEND is soft by definition.  However, in order to ensure
1378                         correct merge order, we make it a hard dependency.  Otherwise, a
1379                         build time dependency might not be usable due to it's run time
1380                         dependencies not being installed yet.
1381                         """
1382                         if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp,
1383                                 myuse=myuse, priority=DepPriority(runtime=True),
1384                                 parent_arg=arg):
1385                                 return 0
1386                         if edepend.has_key("PDEPEND") and edepend["PDEPEND"]:
1387                                 # Post Depend -- Add to the list without a parent, as it depends
1388                                 # on a package being present AND must be built after that package.
1389                                 if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp,
1390                                         myuse=myuse, priority=DepPriority(runtime_post=True),
1391                                         parent_arg=arg):
1392                                         return 0
1393                 except ValueError, e:
1394                         pkgs = e.args[0]
1395                         portage.writemsg("\n\n!!! An atom in the dependencies " + \
1396                                 "is not fully-qualified. Multiple matches:\n\n", noiselevel=-1)
1397                         for cpv in pkgs:
1398                                 portage.writemsg("    %s\n" % cpv, noiselevel=-1)
1399                         portage.writemsg("\n", noiselevel=-1)
1400                         if mytype == "binary":
1401                                 portage.writemsg(
1402                                         "!!! This binary package cannot be installed: '%s'\n" % \
1403                                         mykey, noiselevel=-1)
1404                         elif mytype == "ebuild":
1405                                 myebuild, mylocation = portdb.findname2(mykey)
1406                                 portage.writemsg("!!! This ebuild cannot be installed: " + \
1407                                         "'%s'\n" % myebuild, noiselevel=-1)
1408                         portage.writemsg("!!! Please notify the package maintainer " + \
1409                                 "that atoms must be fully-qualified.\n", noiselevel=-1)
1410                         return 0
1411                 return 1
1412
1413         def select_files(self,myfiles):
1414                 "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list"
1415                 myfavorites=[]
1416                 myroot = self.target_root
1417                 portdb = self.trees[myroot]["porttree"].dbapi
1418                 bindb = self.trees[myroot]["bintree"].dbapi
1419                 pkgsettings = self.pkgsettings[myroot]
1420                 arg_atoms = []
1421                 def visible(mylist):
1422                         matches = portdb.gvisible(portdb.visible(mylist))
1423                         return [x for x in mylist \
1424                                 if x in matches or not portdb.cpv_exists(x)]
1425                 for x in myfiles:
1426                         ext = os.path.splitext(x)[1]
1427                         if ext==".tbz2":
1428                                 if not os.path.exists(x):
1429                                         if os.path.exists(
1430                                                 os.path.join(pkgsettings["PKGDIR"], "All", x)):
1431                                                 x = os.path.join(pkgsettings["PKGDIR"], "All", x)
1432                                         elif os.path.exists(
1433                                                 os.path.join(pkgsettings["PKGDIR"], x)):
1434                                                 x = os.path.join(pkgsettings["PKGDIR"], x)
1435                                         else:
1436                                                 print "\n\n!!! Binary package '"+str(x)+"' does not exist."
1437                                                 print "!!! Please ensure the tbz2 exists as specified.\n"
1438                                                 return 0, myfavorites
1439                                 mytbz2=portage.xpak.tbz2(x)
1440                                 mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
1441                                 if os.path.realpath(x) != \
1442                                         os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)):
1443                                         print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n")
1444                                         return 0, myfavorites
1445                                 if not self.create(["binary", myroot, mykey],
1446                                         None, "--onlydeps" not in self.myopts,
1447                                         myuse=mytbz2.getelements("USE"), arg=x):
1448                                         return (0,myfavorites)
1449                                 arg_atoms.append((x, "="+mykey))
1450                         elif ext==".ebuild":
1451                                 ebuild_path = portage.util.normalize_path(os.path.abspath(x))
1452                                 pkgdir = os.path.dirname(ebuild_path)
1453                                 tree_root = os.path.dirname(os.path.dirname(pkgdir))
1454                                 cp = pkgdir[len(tree_root)+1:]
1455                                 e = portage.exception.PackageNotFound(
1456                                         ("%s is not in a valid portage tree " + \
1457                                         "hierarchy or does not exist") % x)
1458                                 if not portage.isvalidatom(cp):
1459                                         raise e
1460                                 cat = portage.catsplit(cp)[0]
1461                                 mykey = cat + "/" + os.path.basename(ebuild_path[:-7])
1462                                 if not portage.isvalidatom("="+mykey):
1463                                         raise e
1464                                 ebuild_path = portdb.findname(mykey)
1465                                 if ebuild_path:
1466                                         if ebuild_path != os.path.join(os.path.realpath(tree_root),
1467                                                 cp, os.path.basename(ebuild_path)):
1468                                                 print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
1469                                                 return 0, myfavorites
1470                                         if mykey not in portdb.xmatch(
1471                                                 "match-visible", portage.dep_getkey(mykey)):
1472                                                 print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use")
1473                                                 print colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man")
1474                                                 print colorize("BAD", "*** page for details.")
1475                                                 countdown(int(self.settings["EMERGE_WARNING_DELAY"]),
1476                                                         "Continuing...")
1477                                 else:
1478                                         raise portage.exception.PackageNotFound(
1479                                                 "%s is not in a valid portage tree hierarchy or does not exist" % x)
1480                                 if not self.create(["ebuild", myroot, mykey],
1481                                         None, "--onlydeps" not in self.myopts, arg=x):
1482                                         return (0,myfavorites)
1483                                 arg_atoms.append((x, "="+mykey))
1484                         else:
1485                                 if not is_valid_package_atom(x):
1486                                         portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
1487                                                 noiselevel=-1)
1488                                         portage.writemsg("!!! Please check ebuild(5) for full details.\n")
1489                                         portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
1490                                         return (0,[])
1491                                 try:
1492                                         mykey = None
1493                                         if "--usepkg" in self.myopts:
1494                                                 mykey = portage.dep_expand(x, mydb=bindb,
1495                                                         settings=pkgsettings)
1496                                         if (mykey and not mykey.startswith("null/")) or \
1497                                                 "--usepkgonly" in self.myopts:
1498                                                 arg_atoms.append((x, mykey))
1499                                                 continue
1500
1501                                         mykey = portage.dep_expand(x,
1502                                                 mydb=portdb, settings=pkgsettings)
1503                                         arg_atoms.append((x, mykey))
1504                                 except ValueError, errpkgs:
1505                                         print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous.  Please specify"
1506                                         print "!!! one of the following fully-qualified ebuild names instead:\n"
1507                                         for i in errpkgs[0]:
1508                                                 print "    " + green(i)
1509                                         print
1510                                         sys.exit(1)
1511
1512                 if "--update" in self.myopts:
1513                         """Make sure all installed slots are updated when possible. Do this
1514                         with --emptytree also, to ensure that all slots are remerged."""
1515                         vardb = self.trees[self.target_root]["vartree"].dbapi
1516                         greedy_atoms = []
1517                         for myarg, myatom in arg_atoms:
1518                                 greedy_atoms.append((myarg, myatom))
1519                                 myslots = set()
1520                                 for cpv in vardb.match(myatom):
1521                                         myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
1522                                 if myslots:
1523                                         best_pkgs = []
1524                                         if "--usepkg" in self.myopts:
1525                                                 mymatches = bindb.match(myatom)
1526                                                 if "--usepkgonly" not in self.myopts:
1527                                                         mymatches = visible(mymatches)
1528                                                 best_pkg = portage.best(mymatches)
1529                                                 if best_pkg:
1530                                                         best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
1531                                                         best_pkgs.append(("binary", best_pkg, best_slot))
1532                                         if "--usepkgonly" not in self.myopts:
1533                                                 best_pkg = portage.best(portdb.match(myatom))
1534                                                 if best_pkg:
1535                                                         best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
1536                                                         best_pkgs.append(("ebuild", best_pkg, best_slot))
1537                                         if best_pkgs:
1538                                                 best_pkg = portage.best([x[1] for x in best_pkgs])
1539                                                 best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
1540                                                 best_slot = best_pkgs[0][2]
1541                                                 myslots.add(best_slot)
1542                                 if len(myslots) > 1:
1543                                         for myslot in myslots:
1544                                                 myslot_atom = "%s:%s" % \
1545                                                         (portage.dep_getkey(myatom), myslot)
1546                                                 available = False
1547                                                 if "--usepkgonly" not in self.myopts and \
1548                                                         self.trees[self.target_root][
1549                                                         "porttree"].dbapi.match(myslot_atom):
1550                                                         available = True
1551                                                 elif "--usepkg" in self.myopts:
1552                                                         mymatches = bindb.match(myslot_atom)
1553                                                         if "--usepkgonly" not in self.myopts:
1554                                                                 mymatches = visible(mymatches)
1555                                                         if mymatches:
1556                                                                 available = True
1557                                                 if available:
1558                                                         greedy_atoms.append((myarg, myslot_atom))
1559                         arg_atoms = greedy_atoms
1560
1561                 oneshot = "--oneshot" in self.myopts or "--onlydeps" in self.myopts
1562                 """ These are used inside self.create() in order to ensure packages
1563                 that happen to match arguments are not incorrectly marked as nomerge."""
1564                 args_set = self._sets["args"]
1565                 for myarg, myatom in arg_atoms:
1566                         if myatom in args_set:
1567                                 continue
1568                         args_set.add(myatom)
1569                         self._set_atoms.add(myatom)
1570                         if not oneshot:
1571                                 myfavorites.append(myatom)
1572                 for myarg, myatom in arg_atoms:
1573                                 try:
1574                                         self.mysd = self.select_dep(myroot, myatom, arg=myarg)
1575                                 except portage.exception.MissingSignature, e:
1576                                         portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n")
1577                                         portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
1578                                         portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
1579                                         portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
1580                                         portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
1581                                         sys.exit(1)
1582                                 except portage.exception.InvalidSignature, e:
1583                                         portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n")
1584                                         portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
1585                                         portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
1586                                         portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
1587                                         portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
1588                                         sys.exit(1)
1589                                 except SystemExit, e:
1590                                         raise # Needed else can't exit
1591                                 except Exception, e:
1592                                         print >> sys.stderr, "\n\n!!! Problem in '%s' dependencies." % mykey
1593                                         print >> sys.stderr, "!!!", str(e), getattr(e, "__module__", None)
1594                                         raise
1595
1596                                 if not self.mysd:
1597                                         return (0,myfavorites)
1598
1599                 missing=0
1600                 if "--usepkgonly" in self.myopts:
1601                         for xs in self.digraph.all_nodes():
1602                                 if len(xs) >= 4 and xs[0] != "binary" and xs[3] == "merge":
1603                                         if missing == 0:
1604                                                 print
1605                                         missing += 1
1606                                         print "Missing binary for:",xs[2]
1607
1608                 if not self.validate_blockers():
1609                         return False, myfavorites
1610                 
1611                 # We're true here unless we are missing binaries.
1612                 return (not missing,myfavorites)
1613
1614         def select_dep(self, myroot, depstring, myparent=None, arg=None,
1615                 myuse=None, raise_on_missing=False, priority=DepPriority(),
1616                 rev_deps=False, parent_arg=None):
1617                 """ Given a depstring, create the depgraph such that all dependencies are satisfied.
1618                     myroot = $ROOT from environment, where {R,P}DEPENDs are merged to.
1619                     myparent = the node whose depstring is being passed in
1620                     arg = package was specified on the command line, merge even if it's already installed
1621                     myuse = USE flags at present
1622                     raise_on_missing = Given that the depgraph is not proper, raise an exception if true
1623                     else continue trying.
1624                     return 1 on success, 0 for failure
1625                 """
1626
1627                 portdb = self.trees[myroot]["porttree"].dbapi
1628                 bindb  = self.trees[myroot]["bintree"].dbapi
1629                 vardb  = self.trees[myroot]["vartree"].dbapi
1630                 pkgsettings = self.pkgsettings[myroot]
1631                 if myparent:
1632                         p_type, p_root, p_key, p_status = myparent
1633
1634                 if "--debug" in self.myopts:
1635                         print
1636                         print "Parent:   ",myparent
1637                         print "Depstring:",depstring
1638                         if rev_deps:
1639                                 print "Reverse:", rev_deps
1640                         print "Priority:", priority
1641
1642                 #processing dependencies
1643                 """ Call portage.dep_check to evaluate the use? conditionals and make sure all
1644                 dependencies are satisfiable. """
1645                 if arg:
1646                         mymerge = [depstring]
1647                         pprovided = pkgsettings.pprovideddict.get(
1648                                 portage.dep_getkey(depstring))
1649                         if pprovided and portage.match_from_list(depstring, pprovided):
1650                                 mymerge = []
1651                 else:
1652                         try:
1653                                 if myparent and p_status == "nomerge":
1654                                         portage.dep._dep_check_strict = False
1655                                 mycheck = portage.dep_check(depstring, None,
1656                                         pkgsettings, myuse=myuse,
1657                                         use_binaries=("--usepkgonly" in self.myopts),
1658                                         myroot=myroot, trees=self.trees)
1659                         finally:
1660                                 portage.dep._dep_check_strict = True
1661         
1662                         if not mycheck[0]:
1663                                 if myparent:
1664                                         show_invalid_depstring_notice(
1665                                                 myparent, depstring, mycheck[1])
1666                                 else:
1667                                         sys.stderr.write("\n%s\n%s\n" % (depstring, mycheck[1]))
1668                                 return 0
1669                         mymerge = mycheck[1]
1670
1671                 if not mymerge and arg:
1672                         # A provided package has been specified on the command line.  The
1673                         # package will not be merged and a warning will be displayed.
1674                         if depstring in self._set_atoms:
1675                                 self._pprovided_args.append((arg, depstring))
1676
1677                 if myparent:
1678                         # The parent is added after it's own dep_check call so that it
1679                         # isn't allowed to satisfy a direct bootstrap dependency on itself
1680                         # via an old-style virtual.  This isn't a problem with new-style
1681                         # virtuals, which are preferenced in dep_zapdeps by looking only at
1682                         # the depstring, vdb, and available packages.
1683
1684                         p_type, p_root, p_key, p_status = myparent
1685                         if p_status == "merge":
1686                                 # Update old-style virtuals if this package provides any.
1687                                 # These are needed for dep_virtual calls inside dep_check.
1688                                 p_db = self.mydbapi[p_root] # contains cached metadata
1689                                 if myparent in self._slot_collision_nodes:
1690                                         # The metadata isn't cached due to the slot collision.
1691                                         p_db = self.trees[p_root][self.pkg_tree_map[p_type]].dbapi
1692                                 try:
1693                                         self.pkgsettings[p_root].setinst(p_key, p_db)
1694                                         # For consistency, also update the global virtuals.
1695                                         settings = self.roots[p_root].settings
1696                                         settings.unlock()
1697                                         settings.setinst(p_key, p_db)
1698                                         settings.lock()
1699                                 except portage.exception.InvalidDependString, e:
1700                                         provide = p_db.aux_get(p_key, ["PROVIDE"])[0]
1701                                         show_invalid_depstring_notice(myparent, provide, str(e))
1702                                         del e
1703                                         return 0
1704
1705                 if "--debug" in self.myopts:
1706                         print "Candidates:",mymerge
1707                 for x in mymerge:
1708                         selected_pkg = None
1709                         if x[0]=="!":
1710                                 selected_pkg = ["blocks", myroot, x[1:], None]
1711                         else:
1712                                 #We are not processing a blocker but a normal dependency
1713                                 if myparent:
1714                                         """In some cases, dep_check will return deps that shouldn't
1715                                         be proccessed any further, so they are identified and
1716                                         discarded here."""
1717                                         if "empty" not in self.myparams and \
1718                                                 "deep" not in self.myparams and \
1719                                                 not ("--update" in self.myopts and parent_arg) and \
1720                                                 vardb.match(x):
1721                                                 continue
1722
1723                                 # List of acceptable packages, ordered by type preference.
1724                                 matched_packages = []
1725                                 myeb_matches = portdb.xmatch("match-visible", x)
1726                                 myeb = None
1727                                 if "--usepkgonly" not in self.myopts:
1728                                         myeb = portage.best(myeb_matches)
1729
1730                                 myeb_pkg=None
1731                                 if "--usepkg" in self.myopts:
1732                                         # The next line assumes the binarytree has been populated.
1733                                         # XXX: Need to work out how we use the binary tree with roots.
1734                                         myeb_pkg_matches = bindb.match(x)
1735                                         if "--usepkgonly" not in self.myopts:
1736                                                 # Remove any binary package entries that are masked in the portage tree (#55871)
1737                                                 myeb_pkg_matches = [pkg for pkg in myeb_pkg_matches \
1738                                                         if pkg in myeb_matches or  \
1739                                                         not portdb.cpv_exists(pkg)]
1740                                         if myeb_pkg_matches:
1741                                                 myeb_pkg = portage.best(myeb_pkg_matches)
1742
1743                                 if myeb_pkg and \
1744                                         ("--newuse" in self.myopts or \
1745                                         "--reinstall" in self.myopts):
1746                                         iuses = set(filter_iuse_defaults(
1747                                                 bindb.aux_get(myeb_pkg, ["IUSE"])[0].split()))
1748                                         old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split()
1749                                         mydb = None
1750                                         if "--usepkgonly" not in self.myopts and myeb:
1751                                                 mydb = portdb
1752                                         if myeb:
1753                                                 pkgsettings.setcpv(myeb, mydb=mydb)
1754                                         else:
1755                                                 pkgsettings.setcpv(myeb_pkg, mydb=mydb)
1756                                         now_use = pkgsettings["USE"].split()
1757                                         forced_flags = set()
1758                                         forced_flags.update(pkgsettings.useforce)
1759                                         forced_flags.update(pkgsettings.usemask)
1760                                         cur_iuse = iuses
1761                                         if "--usepkgonly" not in self.myopts and myeb:
1762                                                 cur_iuse = set(filter_iuse_defaults(
1763                                                         portdb.aux_get(myeb, ["IUSE"])[0].split()))
1764                                         if self._reinstall_for_flags(
1765                                                 forced_flags, old_use, iuses, now_use, cur_iuse):
1766                                                 myeb_pkg = None
1767                                 if myeb_pkg:
1768                                         binpkguseflags = \
1769                                                 self.trees[myroot]["bintree"].dbapi.aux_get(
1770                                                         myeb_pkg, ["USE"])[0].split()
1771                                         matched_packages.append(
1772                                                 ["binary", myroot, myeb_pkg, binpkguseflags])
1773
1774                                 if "--usepkgonly" not in self.myopts and myeb_matches:
1775                                         matched_packages.append(
1776                                                 ["ebuild", myroot, myeb, None])
1777
1778                                 if not matched_packages and \
1779                                         not (arg and "selective" not in self.myparams):
1780                                         """Fall back to the installed package database.  This is a
1781                                         last resort because the metadata tends to diverge from that
1782                                         of the ebuild in the tree."""
1783                                         myeb_inst_matches = vardb.match(x)
1784                                         if "--usepkgonly" not in self.myopts:
1785                                                 """ TODO: Improve masking check for installed and
1786                                                 binary packages. bug #149816"""
1787                                                 myeb_inst_matches = [pkg for pkg in myeb_inst_matches \
1788                                                         if not portdb.cpv_exists(pkg)]
1789                                         myeb_inst = None
1790                                         if myeb_inst_matches:
1791                                                 myeb_inst = portage.best(myeb_inst_matches)
1792                                         if myeb_inst:
1793                                                 binpkguseflags = vardb.aux_get(
1794                                                         myeb_inst, ["USE"])[0].split()
1795                                                 matched_packages.append(
1796                                                         ["installed", myroot, myeb_inst, binpkguseflags])
1797
1798                                 if not matched_packages:
1799                                         if raise_on_missing:
1800                                                 raise ValueError
1801                                         if not arg:
1802                                                 xinfo='"'+x+'"'
1803                                         else:
1804                                                 xinfo='"'+arg+'"'
1805                                         if myparent:
1806                                                 xfrom = '(dependency required by '+ \
1807                                                         green('"%s"' % myparent[2]) + \
1808                                                         red(' [%s]' % myparent[0]) + ')'
1809                                         alleb = portdb.xmatch("match-all", x)
1810                                         if alleb:
1811                                                 if "--usepkgonly" not in self.myopts:
1812                                                         print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.")
1813                                                         print "!!! One of the following masked packages is required to complete your request:"
1814                                                         oldcomment = ""
1815                                                         shown_licenses = []
1816                                                         for p in alleb:
1817                                                                 mreasons = portage.getmaskingstatus(p,
1818                                                                         settings=pkgsettings, portdb=portdb)
1819                                                                 print "- "+p+" (masked by: "+", ".join(mreasons)+")"
1820                                                                 if "package.mask" in mreasons:
1821                                                                         comment, filename = \
1822                                                                                 portage.getmaskingreason(p,
1823                                                                                 settings=pkgsettings, portdb=portdb,
1824                                                                                 return_location=True)
1825                                                                         if comment and comment != oldcomment:
1826                                                                                 print filename+":"
1827                                                                                 print comment
1828                                                                                 oldcomment = comment
1829                                                                 try:
1830                                                                         licenses = portdb.aux_get(p, ["LICENSE"])[0]
1831                                                                 except KeyError:
1832                                                                         # Corruption will have been reported above.
1833                                                                         continue
1834                                                                 uselist = []
1835                                                                 if "?" in licenses:
1836                                                                         pkgsettings.setcpv(p, mydb=portdb)
1837                                                                         uselist = pkgsettings.get("USE", "").split()
1838                                                                 missing_licenses = []
1839                                                                 try:
1840                                                                         missing_licenses = \
1841                                                                                 pkgsettings.getMissingLicenses(
1842                                                                                         licenses, p, uselist)
1843                                                                 except portage.exception.InvalidDependString:
1844                                                                         # This will have already been reported
1845                                                                         # above via mreasons.
1846                                                                         pass
1847                                                                 for l in missing_licenses:
1848                                                                         l_path = portdb.findLicensePath(l)
1849                                                                         if l in shown_licenses:
1850                                                                                 continue
1851                                                                         msg = ("A copy of the '%s' license" + \
1852                                                                         " is located at '%s'.") % (l, l_path)
1853                                                                         print msg
1854                                                                         print
1855                                                                         shown_licenses.append(l)
1856                                                         print
1857                                                         print "For more information, see MASKED PACKAGES section in the emerge man page or "
1858                                                         print "refer to the Gentoo Handbook."
1859                                                 else:
1860                                                         print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo)
1861                                                         print "!!! Either add a suitable binary package or compile from an ebuild."
1862                                         else:
1863                                                 print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"."
1864                                         if myparent:
1865                                                 print xfrom
1866                                         print
1867                                         return 0
1868
1869                                 if "--debug" in self.myopts:
1870                                         for pkg in matched_packages:
1871                                                 print (pkg[0] + ":").rjust(10), pkg[2]
1872
1873                                 if len(matched_packages) > 1:
1874                                         bestmatch = portage.best(
1875                                                 [pkg[2] for pkg in matched_packages])
1876                                         matched_packages = [pkg for pkg in matched_packages \
1877                                                 if pkg[2] == bestmatch]
1878
1879                                 # ordered by type preference ("ebuild" type is the last resort)
1880                                 selected_pkg =  matched_packages[0]
1881                                 pkgtype, myroot, mycpv, myuse = selected_pkg
1882                                 mydbapi = self.trees[myroot][self.pkg_tree_map[pkgtype]].dbapi
1883                                 slot_atom = "%s:%s" % (portage.dep_getkey(mycpv),
1884                                         mydbapi.aux_get(mycpv, ["SLOT"])[0])
1885                                 existing_node = self._slot_node_map[myroot].get(
1886                                         slot_atom, None)
1887                                 if existing_node:
1888                                         e_type, myroot, e_cpv, e_status = existing_node
1889                                         if portage.match_from_list(x, [e_cpv]):
1890                                                 # The existing node can be reused.
1891                                                 selected_pkg = [e_type, myroot, e_cpv,
1892                                                         self.useFlags[myroot][e_cpv]]
1893
1894                         if myparent:
1895                                 #we are a dependency, so we want to be unconditionally added
1896                                 mypriority = priority.copy()
1897                                 if vardb.match(x):
1898                                         mypriority.satisfied = True
1899                                 if not self.create(selected_pkg[0:3], myparent,
1900                                         myuse=selected_pkg[-1], priority=mypriority,
1901                                         rev_dep=rev_deps, arg=arg):
1902                                         return 0
1903                         else:
1904                                 #if mysource is not set, then we are a command-line dependency and should not be added
1905                                 #if --onlydeps is specified.
1906                                 if not self.create(selected_pkg[0:3], myparent,
1907                                         addme=("--onlydeps" not in self.myopts),
1908                                         myuse=selected_pkg[-1], rev_dep=rev_deps, arg=arg):
1909                                         return 0
1910
1911                 if "--debug" in self.myopts:
1912                         print "Exiting...",myparent
1913                 return 1
1914
1915         def validate_blockers(self):
1916                 """Remove any blockers from the digraph that do not match any of the
1917                 packages within the graph.  If necessary, create hard deps to ensure
1918                 correct merge order such that mutually blocking packages are never
1919                 installed simultaneously."""
1920
1921                 if "--buildpkgonly" in self.myopts or \
1922                         "--nodeps" in self.myopts:
1923                         return True
1924
1925                 modified_slots = {}
1926                 for myroot in self.trees:
1927                         myslots = {}
1928                         modified_slots[myroot] = myslots
1929                         final_db = self.mydbapi[myroot]
1930                         slot_node_map = self._slot_node_map[myroot]
1931                         for slot_atom, mynode in slot_node_map.iteritems():
1932                                 mytype, myroot, mycpv, mystatus = mynode
1933                                 if mystatus == "merge":
1934                                         myslots[slot_atom] = mycpv
1935
1936                 #if "deep" in self.myparams:
1937                 if True:
1938                         # Pull in blockers from all installed packages that haven't already
1939                         # been pulled into the depgraph.  This is not enabled by default
1940                         # due to the performance penalty that is incurred by all the
1941                         # additional dep_check calls that are required.
1942
1943                         # Optimization hack for dep_check calls that minimizes the
1944                         # available matches by replacing the portdb with a fakedbapi
1945                         # instance.
1946                         class FakePortageTree(object):
1947                                 def __init__(self, mydb):
1948                                         self.dbapi = mydb
1949                         dep_check_trees = {}
1950                         for myroot in self.trees:
1951                                 dep_check_trees[myroot] = self.trees[myroot].copy()
1952                                 dep_check_trees[myroot]["porttree"] = \
1953                                         FakePortageTree(self.mydbapi[myroot])
1954
1955                         dep_keys = ["DEPEND","RDEPEND","PDEPEND"]
1956                         for myroot in self.trees:
1957                                 pkg_node_map = self.pkg_node_map[myroot]
1958                                 vardb = self.trees[myroot]["vartree"].dbapi
1959                                 portdb = self.trees[myroot]["porttree"].dbapi
1960                                 pkgsettings = self.pkgsettings[myroot]
1961                                 final_db = self.mydbapi[myroot]
1962                                 cpv_all_installed = self.trees[myroot]["vartree"].dbapi.cpv_all()
1963                                 blocker_cache = BlockerCache(myroot, vardb)
1964                                 for pkg in cpv_all_installed:
1965                                         blocker_atoms = None
1966                                         matching_node = pkg_node_map.get(pkg, None)
1967                                         if matching_node and \
1968                                                 matching_node[3] == "nomerge":
1969                                                 continue
1970                                         # If this node has any blockers, create a "nomerge"
1971                                         # node for it so that they can be enforced.
1972                                         self.spinner.update()
1973                                         blocker_data = blocker_cache.get(pkg)
1974                                         if blocker_data:
1975                                                 blocker_atoms = blocker_data.atoms
1976                                         else:
1977                                                 dep_vals = vardb.aux_get(pkg, dep_keys)
1978                                                 myuse = vardb.aux_get(pkg, ["USE"])[0].split()
1979                                                 depstr = " ".join(dep_vals)
1980                                                 # It is crucial to pass in final_db here in order to
1981                                                 # optimize dep_check calls by eliminating atoms via
1982                                                 # dep_wordreduce and dep_eval calls.
1983                                                 try:
1984                                                         portage.dep._dep_check_strict = False
1985                                                         try:
1986                                                                 success, atoms = portage.dep_check(depstr,
1987                                                                         final_db, pkgsettings, myuse=myuse,
1988                                                                         trees=dep_check_trees, myroot=myroot)
1989                                                         except Exception, e:
1990                                                                 if isinstance(e, SystemExit):
1991                                                                         raise
1992                                                                 # This is helpful, for example, if a ValueError
1993                                                                 # is thrown from cpv_expand due to multiple
1994                                                                 # matches (this can happen if an atom lacks a
1995                                                                 # category).
1996                                                                 show_invalid_depstring_notice(
1997                                                                         ("installed", myroot, pkg, "nomerge"),
1998                                                                         depstr, str(e))
1999                                                                 del e
2000                                                                 raise
2001                                                 finally:
2002                                                         portage.dep._dep_check_strict = True
2003                                                 if not success:
2004                                                         slot_atom = "%s:%s" % (portage.dep_getkey(pkg),
2005                                                                 vardb.aux_get(pkg, ["SLOT"])[0])
2006                                                         if slot_atom in modified_slots[myroot]:
2007                                                                 # This package is being replaced anyway, so
2008                                                                 # ignore invalid dependencies so as not to
2009                                                                 # annoy the user too much (otherwise they'd be
2010                                                                 # forced to manually unmerge it first).
2011                                                                 continue
2012                                                         show_invalid_depstring_notice(
2013                                                                 ("installed", myroot, pkg, "nomerge"),
2014                                                                 depstr, atoms)
2015                                                         return False
2016                                                 blocker_atoms = [myatom for myatom in atoms \
2017                                                         if myatom.startswith("!")]
2018                                                 counter = long(vardb.aux_get(pkg, ["COUNTER"])[0])
2019                                                 blocker_cache[pkg] = \
2020                                                         blocker_cache.BlockerData(counter, blocker_atoms)
2021                                         if blocker_atoms:
2022                                                 # Don't store this parent in pkg_node_map, because it's
2023                                                 # not needed there and it might overwrite a "merge"
2024                                                 # node with the same cpv.
2025                                                 myparent = ("installed", myroot, pkg, "nomerge")
2026                                                 for myatom in blocker_atoms:
2027                                                         blocker = ("blocks", myroot, myatom[1:])
2028                                                         myparents = \
2029                                                                 self.blocker_parents.get(blocker, None)
2030                                                         if not myparents:
2031                                                                 myparents = set()
2032                                                                 self.blocker_parents[blocker] = myparents
2033                                                         myparents.add(myparent)
2034                                 blocker_cache.flush()
2035                                 del blocker_cache
2036
2037                 for blocker in self.blocker_parents.keys():
2038                         mytype, myroot, mydep = blocker
2039                         initial_db = self.trees[myroot]["vartree"].dbapi
2040                         final_db = self.mydbapi[myroot]
2041                         blocked_initial = initial_db.match(mydep)
2042                         blocked_final = final_db.match(mydep)
2043                         if not blocked_initial and not blocked_final:
2044                                 del self.blocker_parents[blocker]
2045                                 continue
2046                         blocked_slots_initial = {}
2047                         blocked_slots_final = {}
2048                         for cpv in blocked_initial:
2049                                 blocked_slots_initial[cpv] = \
2050                                         "%s:%s" % (portage.dep_getkey(cpv),
2051                                                 initial_db.aux_get(cpv, ["SLOT"])[0])
2052                         for cpv in blocked_final:
2053                                 blocked_slots_final[cpv] = \
2054                                         "%s:%s" % (portage.dep_getkey(cpv),
2055                                                 final_db.aux_get(cpv, ["SLOT"])[0])
2056                         for parent in list(self.blocker_parents[blocker]):
2057                                 ptype, proot, pcpv, pstatus = parent
2058                                 pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi
2059                                 pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0]
2060                                 pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot)
2061                                 parent_static = pslot_atom not in modified_slots[proot]
2062                                 unresolved_blocks = False
2063                                 depends_on_order = set()
2064                                 for cpv in blocked_initial:
2065                                         slot_atom = blocked_slots_initial[cpv]
2066                                         if slot_atom == pslot_atom:
2067                                                 # TODO: Support blocks within slots in cases where it
2068                                                 # might make sense.  For example, a new version might
2069                                                 # require that the old version be uninstalled at build
2070                                                 # time.
2071                                                 continue
2072                                         if parent_static and \
2073                                                 slot_atom not in modified_slots[myroot]:
2074                                                 # This blocker will be handled the next time that a
2075                                                 # merge of either package is triggered.
2076                                                 continue
2077                                         if pstatus == "merge" and \
2078                                                 slot_atom in modified_slots[myroot]:
2079                                                 replacement = final_db.match(slot_atom)
2080                                                 if replacement:
2081                                                         if not portage.match_from_list(mydep, replacement):
2082                                                                 # Apparently a replacement may be able to
2083                                                                 # invalidate this block.
2084                                                                 replacement_node = \
2085                                                                         self.pkg_node_map[proot][replacement[0]]
2086                                                                 depends_on_order.add((replacement_node, parent))
2087                                                                 continue
2088                                         # None of the above blocker resolutions techniques apply,
2089                                         # so apparently this one is unresolvable.
2090                                         unresolved_blocks = True
2091                                 for cpv in blocked_final:
2092                                         slot_atom = blocked_slots_final[cpv]
2093                                         if slot_atom == pslot_atom:
2094                                                 # TODO: Support blocks within slots.
2095                                                 continue
2096                                         if parent_static and \
2097                                                 slot_atom not in modified_slots[myroot]:
2098                                                 # This blocker will be handled the next time that a
2099                                                 # merge of either package is triggered.
2100                                                 continue
2101                                         if not parent_static and pstatus == "nomerge" and \
2102                                                 slot_atom in modified_slots[myroot]:
2103                                                 replacement = final_db.match(pslot_atom)
2104                                                 if replacement:
2105                                                         replacement_node = \
2106                                                                 self.pkg_node_map[proot][replacement[0]]
2107                                                         if replacement_node not in \
2108                                                                 self.blocker_parents[blocker]:
2109                                                                 # Apparently a replacement may be able to
2110                                                                 # invalidate this block.
2111                                                                 blocked_node = self.pkg_node_map[proot][cpv]
2112                                                                 depends_on_order.add(
2113                                                                         (replacement_node, blocked_node))
2114                                                                 continue
2115                                         # None of the above blocker resolutions techniques apply,
2116                                         # so apparently this one is unresolvable.
2117                                         unresolved_blocks = True
2118                                 if not unresolved_blocks and depends_on_order:
2119                                         for node, pnode in depends_on_order:
2120                                                 # Enforce correct merge order with a hard dep.
2121                                                 self.digraph.addnode(node, pnode,
2122                                                         priority=DepPriority(buildtime=True))
2123                                                 # Count references to this blocker so that it can be
2124                                                 # invalidated after nodes referencing it have been
2125                                                 # merged.
2126                                                 self.blocker_digraph.addnode(node, blocker)
2127                                 if not unresolved_blocks and not depends_on_order:
2128                                         self.blocker_parents[blocker].remove(parent)
2129                                 if unresolved_blocks:
2130                                         self._unresolved_blocker_parents.setdefault(
2131                                                 blocker, set()).add(parent)
2132                         if not self.blocker_parents[blocker]:
2133                                 del self.blocker_parents[blocker]
2134                 # Validate blockers that depend on merge order.
2135                 if not self.blocker_digraph.empty():
2136                         self.altlist()
2137                 if self._slot_collision_info:
2138                         # The user is only notified of a slot collision if there are no
2139                         # unresolvable blocks.
2140                         for x in self.altlist():
2141                                 if x[0] == "blocks":
2142                                         return True
2143                         self._show_slot_collision_notice(self._slot_collision_info[0])
2144                         if not self._accept_collisions():
2145                                 return False
2146                 return True
2147
2148         def _accept_collisions(self):
2149                 acceptable = False
2150                 for x in ("--nodeps", "--pretend", "--fetchonly", "--fetch-all-uri"):
2151                         if x in self.myopts:
2152                                 acceptable = True
2153                                 break
2154                 return acceptable
2155
2156         def _merge_order_bias(self, mygraph):
2157                 """Order nodes from highest to lowest overall reference count for
2158                 optimal leaf node selection."""
2159                 node_info = {}
2160                 for node in mygraph.order:
2161                         node_info[node] = len(mygraph.parent_nodes(node))
2162                 def cmp_merge_preference(node1, node2):
2163                         return node_info[node2] - node_info[node1]
2164                 mygraph.order.sort(cmp_merge_preference)
2165
2166         def altlist(self, reversed=False):
2167                 if reversed in self._altlist_cache:
2168                         return self._altlist_cache[reversed][:]
2169                 if reversed:
2170                         retlist = self.altlist()
2171                         retlist.reverse()
2172                         self._altlist_cache[reversed] = retlist[:]
2173                         return retlist
2174                 mygraph=self.digraph.copy()
2175                 for node in mygraph.order[:]:
2176                         if node[-1] == "nomerge":
2177                                 mygraph.remove(node)
2178                 self._merge_order_bias(mygraph)
2179                 myblockers = self.blocker_digraph.copy()
2180                 retlist=[]
2181                 circular_blocks = False
2182                 blocker_deps = None
2183                 asap_nodes = []
2184                 if reversed:
2185                         get_nodes = mygraph.root_nodes
2186                 else:
2187                         get_nodes = mygraph.leaf_nodes
2188                         for cpv, node in self.pkg_node_map["/"].iteritems():
2189                                 if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]:
2190                                         asap_nodes.append(node)
2191                                         break
2192                 ignore_priority_soft_range = [None]
2193                 ignore_priority_soft_range.extend(
2194                         xrange(DepPriority.MIN, DepPriority.SOFT + 1))
2195                 tree_mode = "--tree" in self.myopts
2196                 # Tracks whether or not the current iteration should prefer asap_nodes
2197                 # if available.  This is set to False when the previous iteration
2198                 # failed to select any nodes.  It is reset whenever nodes are
2199                 # successfully selected.
2200                 prefer_asap = True
2201                 while not mygraph.empty():
2202                         selected_nodes = None
2203                         if prefer_asap and asap_nodes:
2204                                 """ASAP nodes are merged before their soft deps."""
2205                                 asap_nodes = [node for node in asap_nodes \
2206                                         if mygraph.contains(node)]
2207                                 for node in asap_nodes:
2208                                         if not mygraph.child_nodes(node,
2209                                                 ignore_priority=DepPriority.SOFT):
2210                                                 selected_nodes = [node]
2211                                                 asap_nodes.remove(node)
2212                                                 break
2213                         if not selected_nodes and \
2214                                 not (prefer_asap and asap_nodes):
2215                                 for ignore_priority in ignore_priority_soft_range:
2216                                         nodes = get_nodes(ignore_priority=ignore_priority)
2217                                         if nodes:
2218                                                 break
2219                                 if nodes:
2220                                         if ignore_priority is None and not tree_mode:
2221                                                 # Greedily pop all of these nodes since no relationship
2222                                                 # has been ignored.  This optimization destroys --tree
2223                                                 # output, so it's disabled in reversed mode.
2224                                                 selected_nodes = nodes
2225                                         else:
2226                                                 # For optimal merge order:
2227                                                 #  * Only pop one node.
2228                                                 #  * Removing a root node (node without a parent)
2229                                                 #    will not produce a leaf node, so avoid it.
2230                                                 for node in nodes:
2231                                                         if mygraph.parent_nodes(node):
2232                                                                 # found a non-root node
2233                                                                 selected_nodes = [node]
2234                                                                 break
2235                                                 if not selected_nodes:
2236                                                         # settle for a root node
2237                                                         selected_nodes = [nodes[0]]
2238                         if not selected_nodes:
2239                                 nodes = get_nodes(ignore_priority=DepPriority.MEDIUM)
2240                                 if nodes:
2241                                         """Recursively gather a group of nodes that RDEPEND on
2242                                         eachother.  This ensures that they are merged as a group
2243                                         and get their RDEPENDs satisfied as soon as possible."""
2244                                         def gather_deps(ignore_priority,
2245                                                 mergeable_nodes, selected_nodes, node):
2246                                                 if node in selected_nodes:
2247                                                         return True
2248                                                 if node not in mergeable_nodes:
2249                                                         return False
2250                                                 selected_nodes.add(node)
2251                                                 for child in mygraph.child_nodes(node,
2252                                                         ignore_priority=ignore_priority):
2253                                                         if not gather_deps(ignore_priority,
2254                                                                 mergeable_nodes, selected_nodes, child):
2255                                                                 return False
2256                                                 return True
2257                                         mergeable_nodes = set(nodes)
2258                                         if prefer_asap and asap_nodes:
2259                                                 nodes = asap_nodes
2260                                         for ignore_priority in xrange(DepPriority.SOFT,
2261                                                 DepPriority.MEDIUM_SOFT + 1):
2262                                                 for node in nodes:
2263                                                         selected_nodes = set()
2264                                                         if gather_deps(ignore_priority,
2265                                                                 mergeable_nodes, selected_nodes, node):
2266                                                                 break
2267                                                         else:
2268                                                                 selected_nodes = None
2269                                                 if selected_nodes:
2270                                                         break
2271
2272                                         if prefer_asap and asap_nodes and not selected_nodes:
2273                                                 # We failed to find any asap nodes to merge, so ignore
2274                                                 # them for the next iteration.
2275                                                 prefer_asap = False
2276                                                 continue
2277
2278                                         if selected_nodes and ignore_priority > DepPriority.SOFT:
2279                                                 # Try to merge ignored medium deps as soon as possible.
2280                                                 for node in selected_nodes:
2281                                                         children = set(mygraph.child_nodes(node))
2282                                                         soft = children.difference(
2283                                                                 mygraph.child_nodes(node,
2284                                                                 ignore_priority=DepPriority.SOFT))
2285                                                         medium_soft = children.difference(
2286                                                                 mygraph.child_nodes(node,
2287                                                                 ignore_priority=DepPriority.MEDIUM_SOFT))
2288                                                         medium_soft.difference_update(soft)
2289                                                         for child in medium_soft:
2290                                                                 if child in selected_nodes:
2291                                                                         continue
2292                                                                 if child in asap_nodes:
2293                                                                         continue
2294                                                                 # TODO: Try harder to make these nodes get
2295                                                                 # merged absolutely as soon as possible.
2296                                                                 asap_nodes.append(child)
2297
2298                         if not selected_nodes:
2299                                 if not myblockers.is_empty():
2300                                         """A blocker couldn't be circumnavigated while keeping all
2301                                         dependencies satisfied.  The user will have to resolve this
2302                                         manually.  This is a panic condition and thus the order
2303                                         doesn't really matter, so just pop a random node in order
2304                                         to avoid a circular dependency panic if possible."""
2305                                         if not circular_blocks:
2306                                                 circular_blocks = True
2307                                                 blocker_deps = myblockers.leaf_nodes()
2308                                         while blocker_deps:
2309                                                 # Some of these nodes might have already been selected
2310                                                 # by the normal node selection process after the
2311                                                 # circular_blocks flag has been set.  Therefore, we
2312                                                 # have to verify that they're still in the graph so
2313                                                 # that they're not selected more than once.
2314                                                 node = blocker_deps.pop()
2315                                                 if mygraph.contains(node):
2316                                                         selected_nodes = [node]
2317                                                         break
2318
2319                         if not selected_nodes:
2320                                 # No leaf nodes are available, so we have a circular
2321                                 # dependency panic situation.  Reduce the noise level to a
2322                                 # minimum via repeated elimination of root nodes since they
2323                                 # have no parents and thus can not be part of a cycle.
2324                                 while True:
2325                                         root_nodes = mygraph.root_nodes(
2326                                                 ignore_priority=DepPriority.SOFT)
2327                                         if not root_nodes:
2328                                                 break
2329                                         for node in root_nodes:
2330                                                 mygraph.remove(node)
2331                                 # Display the USE flags that are enabled on nodes that are part
2332                                 # of dependency cycles in case that helps the user decide to
2333                                 # disable some of them.
2334                                 display_order = []
2335                                 tempgraph = mygraph.copy()
2336                                 while not tempgraph.empty():
2337                                         nodes = tempgraph.leaf_nodes()
2338                                         if not nodes:
2339                                                 node = tempgraph.order[0]
2340                                         else:
2341                                                 node = nodes[0]
2342                                         display_order.append(list(node))
2343                                         tempgraph.remove(node)
2344                                 display_order.reverse()
2345                                 self.myopts.pop("--quiet", None)
2346                                 self.myopts.pop("--verbose", None)
2347                                 self.myopts["--tree"] = True
2348                                 self.display(display_order)
2349                                 print "!!! Error: circular dependencies:"
2350                                 print
2351                                 mygraph.debug_print()
2352                                 print
2353                                 print "!!! Note that circular dependencies can often be avoided by temporarily"
2354                                 print "!!! disabling USE flags that trigger optional dependencies."
2355                                 sys.exit(1)
2356
2357                         # At this point, we've succeeded in selecting one or more nodes, so
2358                         # it's now safe to reset the prefer_asap to it's default state.
2359                         prefer_asap = True
2360
2361                         for node in selected_nodes:
2362                                 retlist.append(list(node))
2363                                 mygraph.remove(node)
2364                                 if not reversed and not circular_blocks and myblockers.contains(node):
2365                                         """This node may have invalidated one or more blockers."""
2366                                         myblockers.remove(node)
2367                                         for blocker in myblockers.root_nodes():
2368                                                 if not myblockers.child_nodes(blocker):
2369                                                         myblockers.remove(blocker)
2370                                                         unresolved = \
2371                                                                 self._unresolved_blocker_parents.get(blocker)
2372                                                         if unresolved:
2373                                                                 self.blocker_parents[blocker] = unresolved
2374                                                         else:
2375                                                                 del self.blocker_parents[blocker]
2376
2377                 if not reversed:
2378                         """Blocker validation does not work with reverse mode,
2379                         so self.altlist() should first be called with reverse disabled
2380                         so that blockers are properly validated."""
2381                         self.blocker_digraph = myblockers
2382
2383                 """ Add any unresolved blocks so that they can be displayed."""
2384                 for blocker in self.blocker_parents:
2385                         retlist.append(list(blocker))
2386                 self._altlist_cache[reversed] = retlist[:]
2387                 return retlist
2388
2389         def xcreate(self,mode="system"):
2390                 vardb = self.trees[self.target_root]["vartree"].dbapi
2391                 portdb = self.trees[self.target_root]["porttree"].dbapi
2392                 bindb = self.trees[self.target_root]["bintree"].dbapi
2393                 def visible(mylist):
2394                         matches = portdb.gvisible(portdb.visible(mylist))
2395                         return [x for x in mylist \
2396                                 if x in matches or not portdb.cpv_exists(x)]
2397                 world_problems = False
2398
2399                 root_config = self.roots[self.target_root]
2400                 world_set = root_config.sets["world"]
2401                 system_set = root_config.sets["system"]
2402                 mylist = list(system_set)
2403                 self._sets["system"] = system_set
2404                 if mode == "world":
2405                         self._sets["world"] = world_set
2406                         for x in world_set:
2407                                 if not portage.isvalidatom(x):
2408                                         world_problems = True
2409                                         continue
2410                                 elif not vardb.match(x):
2411                                         world_problems = True
2412                                         available = False
2413                                         if "--usepkgonly" not in self.myopts and \
2414                                                 portdb.match(x):
2415                                                 available = True
2416                                         elif "--usepkg" in self.myopts:
2417                                                 mymatches = bindb.match(x)
2418                                                 if "--usepkgonly" not in self.myopts:
2419                                                         mymatches = visible(mymatches)
2420                                                 if mymatches:
2421                                                         available = True
2422                                         if not available:
2423                                                 continue
2424                                 mylist.append(x)
2425
2426                 newlist = []
2427                 for atom in mylist:
2428                         mykey = portage.dep_getkey(atom)
2429                         if True:
2430                                 newlist.append(atom)
2431                                 if mode == "system" or atom not in world_set:
2432                                         # only world is greedy for slots, not system
2433                                         continue
2434                                 # Make sure all installed slots are updated when possible.
2435                                 # Do this with --emptytree also, to ensure that all slots are
2436                                 # remerged.
2437                                 myslots = set()
2438                                 for cpv in vardb.match(mykey):
2439                                         myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
2440                                 if myslots:
2441                                         best_pkgs = []
2442                                         if "--usepkg" in self.myopts:
2443                                                 mymatches = bindb.match(atom)
2444                                                 if "--usepkgonly" not in self.myopts:
2445                                                         mymatches = visible(mymatches)
2446                                                 best_pkg = portage.best(mymatches)
2447                                                 if best_pkg:
2448                                                         best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
2449                                                         best_pkgs.append(("binary", best_pkg, best_slot))
2450                                         if "--usepkgonly" not in self.myopts:
2451                                                 best_pkg = portage.best(portdb.match(atom))
2452                                                 if best_pkg:
2453                                                         best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
2454                                                         best_pkgs.append(("ebuild", best_pkg, best_slot))
2455                                         if best_pkgs:
2456                                                 best_pkg = portage.best([x[1] for x in best_pkgs])
2457                                                 best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
2458                                                 best_slot = best_pkgs[0][2]
2459                                                 myslots.add(best_slot)
2460                                 if len(myslots) > 1:
2461                                         for myslot in myslots:
2462                                                 myslot_atom = "%s:%s" % (mykey, myslot)
2463                                                 available = False
2464                                                 if "--usepkgonly" not in self.myopts and \
2465                                                         self.trees[self.target_root][
2466                                                         "porttree"].dbapi.match(myslot_atom):
2467                                                         available = True
2468                                                 elif "--usepkg" in self.myopts:
2469                                                         mymatches = bindb.match(myslot_atom)
2470                                                         if "--usepkgonly" not in self.myopts:
2471                                                                 mymatches = visible(mymatches)
2472                                                         if mymatches:
2473                                                                 available = True
2474                                                 if available:
2475                                                         newlist.append(myslot_atom)
2476                 mylist = newlist
2477
2478                 for myatom in mylist:
2479                         self._set_atoms.add(myatom)
2480
2481                 missing_atoms = []
2482                 for mydep in mylist:
2483                         try:
2484                                 if not self.select_dep(
2485                                         self.target_root, mydep, raise_on_missing=True, arg=mydep):
2486                                         print >> sys.stderr, "\n\n!!! Problem resolving dependencies for", mydep
2487                                         return 0
2488                         except ValueError:
2489                                 missing_atoms.append(mydep)
2490
2491                 if not self.validate_blockers():
2492                         return False
2493
2494                 if world_problems:
2495                         print >> sys.stderr, "\n!!! Problems have been detected with your world file"
2496                         print >> sys.stderr, "!!! Please run "+green("emaint --check world")+"\n"
2497
2498                 if missing_atoms:
2499                         print >> sys.stderr, "\n" + colorize("BAD", "!!!") + \
2500                                 " Ebuilds for the following packages are either all"
2501                         print >> sys.stderr, colorize("BAD", "!!!") + " masked or don't exist:"
2502                         print >> sys.stderr, " ".join(missing_atoms) + "\n"
2503
2504                 return 1
2505
2506         def display(self, mylist, favorites=[], verbosity=None):
2507                 if verbosity is None:
2508                         verbosity = ("--quiet" in self.myopts and 1 or \
2509                                 "--verbose" in self.myopts and 3 or 2)
2510                 favorites_set = InternalPackageSet(favorites)
2511                 changelogs=[]
2512                 p=[]
2513                 blockers = []
2514
2515                 counters = PackageCounters()
2516
2517                 if verbosity == 1 and "--verbose" not in self.myopts:
2518                         def create_use_string(*args):
2519                                 return ""
2520                 else:
2521                         def create_use_string(name, cur_iuse, iuse_forced, cur_use,
2522                                 old_iuse, old_use,
2523                                 is_new, all_flags=(verbosity == 3 or "--quiet" in self.myopts),
2524                                 alphabetical=("--alphabetical" in self.myopts)):
2525                                 enabled = []
2526                                 if alphabetical:
2527                                         disabled = enabled
2528                                         removed = enabled
2529                                 else:
2530                                         disabled = []
2531                                         removed = []
2532                                 cur_iuse = set(cur_iuse)
2533                                 enabled_flags = cur_iuse.intersection(cur_use)
2534                                 removed_iuse = set(old_iuse).difference(cur_iuse)
2535                                 any_iuse = cur_iuse.union(old_iuse)
2536                                 any_iuse = list(any_iuse)
2537                                 any_iuse.sort()
2538                                 for flag in any_iuse:
2539                                         flag_str = None
2540                                         isEnabled = False
2541                                         if flag in enabled_flags:
2542                                                 isEnabled = True
2543                                                 if is_new or flag in old_use and all_flags:
2544                                                         flag_str = red(flag)
2545                                                 elif flag not in old_iuse:
2546                                                         flag_str = yellow(flag) + "%*"
2547                                                 elif flag not in old_use:
2548                                                         flag_str = green(flag) + "*"
2549                                         elif flag in removed_iuse:
2550                                                 if all_flags:
2551                                                         flag_str = yellow("-" + flag) + "%"
2552                                                         if flag in old_use:
2553                                                                 flag_str += "*"
2554                                                         flag_str = "(" + flag_str + ")"
2555                                                         removed.append(flag_str)
2556                                                 continue
2557                                         else:
2558                                                 if is_new or flag in old_iuse and flag not in old_use and all_flags:
2559                                                         flag_str = blue("-" + flag)
2560                                                 elif flag not in old_iuse:
2561                                                         flag_str = yellow("-" + flag)
2562                                                         if flag not in iuse_forced:
2563                                                                 flag_str += "%"
2564                                                 elif flag in old_use:
2565                                                         flag_str = green("-" + flag) + "*"
2566                                         if flag_str:
2567                                                 if flag in iuse_forced:
2568                                                         flag_str = "(" + flag_str + ")"
2569                                                 if isEnabled:
2570                                                         enabled.append(flag_str)
2571                                                 else:
2572                                                         disabled.append(flag_str)
2573
2574                                 if alphabetical:
2575                                         ret = " ".join(enabled)
2576                                 else:
2577                                         ret = " ".join(enabled + disabled + removed)
2578                                 if ret:
2579                                         ret = '%s="%s" ' % (name, ret)
2580                                 return ret
2581
2582                 repo_display = RepoDisplay(self.roots)
2583
2584                 tree_nodes = []
2585                 display_list = []
2586                 mygraph = self._parent_child_digraph
2587                 i = 0
2588                 depth = 0
2589                 shown_edges = set()
2590                 for x in mylist:
2591                         if "blocks" == x[0]:
2592                                 display_list.append((x, 0, True))
2593                                 continue
2594                         graph_key = tuple(x)
2595                         if "--tree" in self.myopts:
2596                                 depth = len(tree_nodes)
2597                                 while depth and graph_key not in \
2598                                         mygraph.child_nodes(tree_nodes[depth-1]):
2599                                                 depth -= 1
2600                                 if depth:
2601                                         tree_nodes = tree_nodes[:depth]
2602                                         tree_nodes.append(graph_key)
2603                                         display_list.append((x, depth, True))
2604                                         shown_edges.add((graph_key, tree_nodes[depth-1]))
2605                                 else:
2606                                         traversed_nodes = set() # prevent endless circles
2607                                         traversed_nodes.add(graph_key)
2608                                         def add_parents(current_node, ordered):
2609                                                 parent_nodes = None
2610                                                 # Do not traverse to parents if this node is an
2611                                                 # an argument or a direct member of a set that has
2612                                                 # been specified as an argument (system or world).
2613                                                 if current_node not in self._set_nodes:
2614                                                         parent_nodes = mygraph.parent_nodes(current_node)
2615                                                 if parent_nodes:
2616                                                         child_nodes = set(mygraph.child_nodes(current_node))
2617                                                         selected_parent = None
2618                                                         # First, try to avoid a direct cycle.
2619                                                         for node in parent_nodes:
2620                                                                 if node not in traversed_nodes and \
2621                                                                         node not in child_nodes:
2622                                                                         edge = (current_node, node)
2623                                                                         if edge in shown_edges:
2624                                                                                 continue
2625                                                                         selected_parent = node
2626                                                                         break
2627                                                         if not selected_parent:
2628                                                                 # A direct cycle is unavoidable.
2629                                                                 for node in parent_nodes:
2630                                                                         if node not in traversed_nodes:
2631                                                                                 edge = (current_node, node)
2632                                                                                 if edge in shown_edges:
2633                                                                                         continue
2634                                                                                 selected_parent = node
2635                                                                                 break
2636                                                         if selected_parent:
2637                                                                 shown_edges.add((current_node, selected_parent))
2638                                                                 traversed_nodes.add(selected_parent)
2639                                                                 add_parents(selected_parent, False)
2640                                                 display_list.append((list(current_node),
2641                                                         len(tree_nodes), ordered))
2642                                                 tree_nodes.append(current_node)
2643                                         tree_nodes = []
2644                                         add_parents(graph_key, True)
2645                         else:
2646                                 display_list.append((x, depth, True))
2647                 mylist = display_list
2648
2649                 last_merge_depth = 0
2650                 for i in xrange(len(mylist)-1,-1,-1):
2651                         graph_key, depth, ordered = mylist[i]
2652                         if not ordered and depth == 0 and i > 0 \
2653                                 and graph_key == mylist[i-1][0] and \
2654                                 mylist[i-1][1] == 0:
2655                                 # An ordered node got a consecutive duplicate when the tree was
2656                                 # being filled in.
2657                                 del mylist[i]
2658                                 continue
2659                         if "blocks" == graph_key[0]:
2660                                 continue
2661                         if ordered and graph_key[-1] != "nomerge":
2662                                 last_merge_depth = depth
2663                                 continue
2664                         if depth >= last_merge_depth or \
2665                                 i < len(mylist) - 1 and \
2666                                 depth >= mylist[i+1][1]:
2667                                         del mylist[i]
2668
2669                 from portage import flatten
2670                 from portage.dep import use_reduce, paren_reduce
2671                 # files to fetch list - avoids counting a same file twice
2672                 # in size display (verbose mode)
2673                 myfetchlist=[]
2674
2675                 for mylist_index in xrange(len(mylist)):
2676                         x, depth, ordered = mylist[mylist_index]
2677                         pkg_node = tuple(x)
2678                         pkg_type = x[0]
2679                         myroot = x[1]
2680                         pkg_key = x[2]
2681                         portdb = self.trees[myroot]["porttree"].dbapi
2682                         bindb  = self.trees[myroot]["bintree"].dbapi
2683                         vardb = self.trees[myroot]["vartree"].dbapi
2684                         vartree = self.trees[myroot]["vartree"]
2685                         pkgsettings = self.pkgsettings[myroot]
2686
2687                         fetch=" "
2688
2689                         if x[0]=="blocks":
2690                                 addl=""+red("B")+"  "+fetch+"  "
2691                                 if ordered:
2692                                         counters.blocks += 1
2693                                 resolved = portage.key_expand(
2694                                         pkg_key, mydb=vardb, settings=pkgsettings)
2695                                 if "--columns" in self.myopts and "--quiet" in self.myopts:
2696                                         addl = addl + " " + red(resolved)
2697                                 else:
2698                                         addl = "[blocks " + addl + "] " + red(resolved)
2699                                 block_parents = self.blocker_parents[tuple(x)]
2700                                 block_parents = set([pnode[2] for pnode in block_parents])
2701                                 block_parents = ", ".join(block_parents)
2702                                 if resolved!=x[2]:
2703                                         addl += bad(" (\"%s\" is blocking %s)") % \
2704                                                 (pkg_key, block_parents)
2705                                 else:
2706                                         addl += bad(" (is blocking %s)") % block_parents
2707                                 blockers.append(addl)
2708                         else:
2709                                 pkg_status = x[3]
2710                                 pkg_merge = ordered and pkg_status != "nomerge"
2711                                 if pkg_node in self._slot_collision_nodes or \
2712                                         (pkg_status == "nomerge" and pkg_type != "installed"):
2713                                         # The metadata isn't cached due to a slot collision or
2714                                         # --onlydeps.
2715                                         mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
2716                                 else:
2717                                         mydbapi = self.mydbapi[myroot] # contains cached metadata
2718                                 metadata = dict(izip(self._mydbapi_keys,
2719                                         mydbapi.aux_get(pkg_key, self._mydbapi_keys)))
2720                                 ebuild_path = None
2721                                 repo_name = metadata["repository"]
2722                                 if pkg_type == "ebuild":
2723                                         ebuild_path = portdb.findname(pkg_key)
2724                                         if not ebuild_path: # shouldn't happen
2725                                                 raise portage.exception.PackageNotFound(pkg_key)
2726                                         repo_path_real = os.path.dirname(os.path.dirname(
2727                                                 os.path.dirname(ebuild_path)))
2728                                 else:
2729                                         repo_path_real = portdb.getRepositoryPath(repo_name)
2730                                 if pkg_key not in self.useFlags[myroot]:
2731                                         """If this is a --resume then the USE flags need to be
2732                                         fetched from the appropriate locations here."""
2733                                         self.useFlags[myroot][pkg_key] = mydbapi.aux_get(
2734                                                 pkg_key, ["USE"])[0].split()
2735
2736                                 try:
2737                                         restrict = flatten(use_reduce(paren_reduce(
2738                                                 mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]),
2739                                                 uselist=self.useFlags[myroot][pkg_key]))
2740                                 except portage.exception.InvalidDependString, e:
2741                                         if pkg_status != "nomerge":
2742                                                 restrict = mydbapi.aux_get(pkg_key, ["RESTRICT"])[0]
2743                                                 show_invalid_depstring_notice(x, restrict, str(e))
2744                                                 del e
2745                                                 return 1
2746                                         restrict = []
2747                                 if "ebuild" == pkg_type and x[3] != "nomerge" and \
2748                                         "fetch" in restrict:
2749                                         fetch = red("F")
2750                                         if ordered:
2751                                                 counters.restrict_fetch += 1
2752                                         if portdb.fetch_check(
2753                                                 pkg_key, self.useFlags[myroot][pkg_key]):
2754                                                 fetch = green("f")
2755                                                 if ordered:
2756                                                         counters.restrict_fetch_satisfied += 1
2757
2758                                 #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty"
2759                                 #param is used for -u, where you still *do* want to see when something is being upgraded.
2760                                 myoldbest=""
2761                                 if vardb.cpv_exists(pkg_key):
2762                                         addl="  "+yellow("R")+fetch+"  "
2763                                         if x[3] != "nomerge":
2764                                                 if ordered:
2765                                                         counters.reinst += 1
2766                                 elif vardb.match(portage.dep_getkey(pkg_key)):
2767                                         mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0]
2768                                         myoldlist = self.trees[x[1]]["vartree"].dbapi.match(
2769                                                 portage.pkgsplit(x[2])[0])
2770                                         myinslotlist = [inst_pkg for inst_pkg in myoldlist
2771                                                 if mynewslot == vardb.aux_get(inst_pkg, ["SLOT"])[0]]
2772                                         if myinslotlist:
2773                                                 myoldbest=portage.best(myinslotlist)
2774                                                 addl="   "+fetch
2775                                                 if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0:
2776                                                         # Downgrade in slot
2777                                                         addl+=turquoise("U")+blue("D")
2778                                                         if ordered:
2779                                                                 counters.downgrades += 1
2780                                                 else:
2781                                                         # Update in slot
2782                                                         addl+=turquoise("U")+" "
2783                                                         if ordered:
2784                                                                 counters.upgrades += 1
2785                                         else:
2786                                                 # New slot, mark it new.
2787                                                 addl=" "+green("NS")+fetch+"  "
2788                                                 if ordered:
2789                                                         counters.newslot += 1
2790
2791                                         if "--changelog" in self.myopts:
2792                                                 slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key),
2793                                                         mydbapi.aux_get(pkg_key, ["SLOT"])[0])
2794                                                 inst_matches = vardb.match(slot_atom)
2795                                                 if inst_matches:
2796                                                         changelogs.extend(self.calc_changelog(
2797                                                                 portdb.findname(pkg_key),
2798                                                                 inst_matches[0], pkg_key))
2799                                 else:
2800                                         addl=" "+green("N")+" "+fetch+"  "
2801                                         if ordered:
2802                                                 counters.new += 1
2803
2804                                 verboseadd=""
2805                                 
2806                                 if pkg_key in self.useFlags[myroot]:
2807                                         # USE flag display
2808                                         cur_iuse = list(filter_iuse_defaults(
2809                                                 mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()))
2810
2811                                         forced_flags = set()
2812                                         forced_flags.update(pkgsettings.useforce)
2813                                         forced_flags.update(pkgsettings.usemask)
2814
2815                                         cur_iuse = portage.unique_array(cur_iuse)
2816                                         cur_iuse.sort()
2817                                         cur_use = self.useFlags[myroot][pkg_key]
2818                                         cur_use = [flag for flag in cur_use if flag in cur_iuse]
2819
2820                                         if myoldbest:
2821                                                 pkg = myoldbest
2822                                         else:
2823                                                 pkg = x[2]
2824                                         if self.trees[x[1]]["vartree"].dbapi.cpv_exists(pkg):
2825                                                 old_iuse, old_use = \
2826                                                         self.trees[x[1]]["vartree"].dbapi.aux_get(
2827                                                                 pkg, ["IUSE", "USE"])
2828                                                 old_iuse = list(set(
2829                                                         filter_iuse_defaults(old_iuse.split())))
2830                                                 old_iuse.sort()
2831                                                 old_use = old_use.split()
2832                                                 is_new = False
2833                                         else:
2834                                                 old_iuse = []
2835                                                 old_use = []
2836                                                 is_new = True
2837
2838                                         old_use = [flag for flag in old_use if flag in old_iuse]
2839
2840                                         use_expand = pkgsettings["USE_EXPAND"].lower().split()
2841                                         use_expand.sort()
2842                                         use_expand.reverse()
2843                                         use_expand_hidden = \
2844                                                 pkgsettings["USE_EXPAND_HIDDEN"].lower().split()
2845
2846                                         def map_to_use_expand(myvals, forcedFlags=False,
2847                                                 removeHidden=True):
2848                                                 ret = {}
2849                                                 forced = {}
2850                                                 for exp in use_expand:
2851                                                         ret[exp] = []
2852                                                         forced[exp] = set()
2853                                                         for val in myvals[:]:
2854                                                                 if val.startswith(exp.lower()+"_"):
2855                                                                         if val in forced_flags:
2856                                                                                 forced[exp].add(val[len(exp)+1:])
2857                                                                         ret[exp].append(val[len(exp)+1:])
2858                                                                         myvals.remove(val)
2859                                                 ret["USE"] = myvals
2860                                                 forced["USE"] = [val for val in myvals \
2861                                                         if val in forced_flags]
2862                                                 if removeHidden:
2863                                                         for exp in use_expand_hidden:
2864                                                                 ret.pop(exp, None)
2865                                                 if forcedFlags:
2866                                                         return ret, forced
2867                                                 return ret
2868
2869                                         # Prevent USE_EXPAND_HIDDEN flags from being hidden if they
2870                                         # are the only thing that triggered reinstallation.
2871                                         reinst_flags_map = None
2872                                         reinstall_for_flags = self._reinstall_nodes.get(pkg_node)
2873                                         if reinstall_for_flags:
2874                                                 reinst_flags_map = map_to_use_expand(
2875                                                         list(reinstall_for_flags), removeHidden=False)
2876                                                 if reinst_flags_map["USE"]:
2877                                                         reinst_flags_map = None
2878                                                 else:
2879                                                         for k in reinst_flags_map.keys():
2880                                                                 if not reinst_flags_map[k]:
2881                                                                         del reinst_flags_map[k]
2882                                         if reinst_flags_map and \
2883                                                 not set(reinst_flags_map).difference(
2884                                                 use_expand_hidden):
2885                                                 use_expand_hidden = set(use_expand_hidden).difference(
2886                                                         reinst_flags_map)
2887
2888                                         cur_iuse_map, iuse_forced = \
2889                                                 map_to_use_expand(cur_iuse, forcedFlags=True)
2890                                         cur_use_map = map_to_use_expand(cur_use)
2891                                         old_iuse_map = map_to_use_expand(old_iuse)
2892                                         old_use_map = map_to_use_expand(old_use)
2893
2894                                         use_expand.sort()
2895                                         use_expand.insert(0, "USE")
2896                                         
2897                                         for key in use_expand:
2898                                                 if key in use_expand_hidden:
2899                                                         continue
2900                                                 verboseadd += create_use_string(key.upper(),
2901                                                         cur_iuse_map[key], iuse_forced[key],
2902                                                         cur_use_map[key], old_iuse_map[key],
2903                                                         old_use_map[key], is_new)
2904
2905                                 if verbosity == 3:
2906                                         # size verbose
2907                                         mysize=0
2908                                         if pkg_type == "ebuild" and pkg_merge:
2909                                                 try:
2910                                                         myfilesdict = portdb.getfetchsizes(pkg_key,
2911                                                                 useflags=self.useFlags[myroot][pkg_key],
2912                                                                 debug=self.edebug)
2913                                                 except portage.exception.InvalidDependString, e:
2914                                                         src_uri = portdb.aux_get(pkg_key, ["SRC_URI"])[0]
2915                                                         show_invalid_depstring_notice(x, src_uri, str(e))
2916                                                         del e
2917                                                         return 1
2918                                                 if myfilesdict is None:
2919                                                         myfilesdict="[empty/missing/bad digest]"
2920                                                 else:
2921                                                         for myfetchfile in myfilesdict:
2922                                                                 if myfetchfile not in myfetchlist:
2923                                                                         mysize+=myfilesdict[myfetchfile]
2924                                                                         myfetchlist.append(myfetchfile)
2925                                                         counters.totalsize += mysize
2926                                                 verboseadd+=format_size(mysize)+" "
2927
2928                                         # overlay verbose
2929                                         # assign index for a previous version in the same slot
2930                                         has_previous = False
2931                                         repo_name_prev = None
2932                                         slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key),
2933                                                 metadata["SLOT"])
2934                                         slot_matches = vardb.match(slot_atom)
2935                                         if slot_matches:
2936                                                 has_previous = True
2937                                                 repo_name_prev = vardb.aux_get(slot_matches[0],
2938                                                         ["repository"])[0]
2939
2940                                         # now use the data to generate output
2941                                         repoadd = None
2942                                         if pkg_status == "nomerge" or not has_previous:
2943                                                 repoadd = repo_display.repoStr(repo_path_real)
2944                                         else:
2945                                                 repo_path_prev = None
2946                                                 if repo_name_prev:
2947                                                         repo_path_prev = portdb.getRepositoryPath(
2948                                                                 repo_name_prev)
2949                                                 repoadd = "%s=>%s" % (
2950                                                         repo_display.repoStr(repo_path_prev),
2951                                                         repo_display.repoStr(repo_path_real))
2952                                         if repoadd:
2953                                                 verboseadd += teal("[%s]" % repoadd)
2954
2955                                 xs = list(portage.pkgsplit(x[2]))
2956                                 if xs[2]=="r0":
2957                                         xs[2]=""
2958                                 else:
2959                                         xs[2]="-"+xs[2]
2960
2961                                 mywidth = 130
2962                                 if "COLUMNWIDTH" in self.settings:
2963                                         try:
2964                                                 mywidth = int(self.settings["COLUMNWIDTH"])
2965                                         except ValueError, e:
2966                                                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
2967                                                 portage.writemsg(
2968                                                         "!!! Unable to parse COLUMNWIDTH='%s'\n" % \
2969                                                         self.settings["COLUMNWIDTH"], noiselevel=-1)
2970                                                 del e
2971                                 oldlp=mywidth-30
2972                                 newlp=oldlp-30
2973
2974                                 indent = " " * depth
2975
2976                                 if myoldbest:
2977                                         myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2]
2978                                         if myoldbest[-3:]=="-r0":
2979                                                 myoldbest=myoldbest[:-3]
2980                                         myoldbest=blue("["+myoldbest+"]")
2981
2982                                 pkg_cp = xs[0]
2983                                 root_config = self.roots[myroot]
2984                                 system_set = root_config.sets["system"]
2985                                 world_set  = root_config.sets["world"]
2986
2987                                 pkg_system = False
2988                                 pkg_world = False
2989                                 try:
2990                                         pkg_system = system_set.findAtomForPackage(pkg_key, metadata)
2991                                         pkg_world  = world_set.findAtomForPackage(pkg_key, metadata)
2992                                         if not pkg_world and myroot == self.target_root and \
2993                                                 favorites_set.findAtomForPackage(pkg_key, metadata):
2994                                                 # Maybe it will be added to world now.
2995                                                 if create_world_atom(pkg_key, metadata,
2996                                                         favorites_set, root_config):
2997                                                         pkg_world = True
2998                                 except portage.exception.InvalidDependString:
2999                                         # This is reported elsewhere if relevant.
3000                                         pass
3001
3002                                 def pkgprint(pkg):
3003                                         if pkg_merge:
3004                                                 if pkg_system:
3005                                                         return colorize("PKG_MERGE_SYSTEM", pkg)
3006                                                 elif pkg_world:
3007                                                         return colorize("PKG_MERGE_WORLD", pkg)
3008                                                 else:
3009                                                         return colorize("PKG_MERGE", pkg)
3010                                         else:
3011                                                 if pkg_system:
3012                                                         return colorize("PKG_NOMERGE_SYSTEM", pkg)
3013                                                 elif pkg_world:
3014                                                         return colorize("PKG_NOMERGE_WORLD", pkg)
3015                                                 else:
3016                                                         return colorize("PKG_NOMERGE", pkg)
3017
3018                                 if x[1]!="/":
3019                                         if myoldbest:
3020                                                 myoldbest +=" "
3021                                         if "--columns" in self.myopts:
3022                                                 if "--quiet" in self.myopts:
3023                                                         myprint=addl+" "+indent+pkgprint(pkg_cp)
3024                                                         myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
3025                                                         myprint=myprint+myoldbest
3026                                                         myprint=myprint+darkgreen("to "+x[1])
3027                                                 else:
3028                                                         myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp)
3029                                                         if (newlp-nc_len(myprint)) > 0:
3030                                                                 myprint=myprint+(" "*(newlp-nc_len(myprint)))
3031                                                         myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] "
3032                                                         if (oldlp-nc_len(myprint)) > 0:
3033                                                                 myprint=myprint+" "*(oldlp-nc_len(myprint))
3034                                                         myprint=myprint+myoldbest
3035                                                         myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
3036                                         else:
3037                                                 if not pkg_merge:
3038                                                         myprint = "[%s      ] " % pkgprint("nomerge")
3039                                                 else:
3040                                                         myprint = "[" + pkg_type + " " + addl + "] "
3041                                                 myprint += indent + pkgprint(pkg_key) + " " + \
3042                                                         myoldbest + darkgreen("to " + myroot) + " " + \
3043                                                         verboseadd
3044                                 else:
3045                                         if "--columns" in self.myopts:
3046                                                 if "--quiet" in self.myopts:
3047                                                         myprint=addl+" "+indent+pkgprint(pkg_cp)
3048                                                         myprint=myprint+" "+green(xs[1]+xs[2])+" "
3049                                                         myprint=myprint+myoldbest
3050                                                 else:
3051                                                         myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_cp)
3052                                                         if (newlp-nc_len(myprint)) > 0:
3053                                                                 myprint=myprint+(" "*(newlp-nc_len(myprint)))
3054                                                         myprint=myprint+green(" ["+xs[1]+xs[2]+"] ")
3055                                                         if (oldlp-nc_len(myprint)) > 0:
3056                                                                 myprint=myprint+(" "*(oldlp-nc_len(myprint)))
3057                                                         myprint=myprint+myoldbest+"  "+verboseadd
3058                                         else:
3059                                                 if not pkg_merge:
3060                                                         myprint="["+pkgprint("nomerge")+"      ] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd
3061                                                 else:
3062                                                         myprint="["+pkgprint(pkg_type)+" "+addl+"] "+indent+pkgprint(pkg_key)+" "+myoldbest+" "+verboseadd
3063                                 p.append(myprint)
3064
3065                         mysplit = portage.pkgsplit(x[2])
3066                         if "--tree" not in self.myopts and mysplit and \
3067                                 len(mysplit) == 3 and mysplit[0] == "sys-apps/portage" and \
3068                                 x[1] == "/":
3069
3070                                 if mysplit[2] == "r0":
3071                                         myversion = mysplit[1]
3072                                 else:
3073                                         myversion = "%s-%s" % (mysplit[1], mysplit[2])
3074
3075                                 if myversion != portage.VERSION and "--quiet" not in self.myopts:
3076                                         if mylist_index < len(mylist) - 1 and \
3077                                                 "livecvsportage" not in self.settings.features:
3078                                                 p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,"))
3079                                                 p.append(colorize("WARN", "    then resume the merge."))
3080                                                 print
3081                         del mysplit
3082
3083                 for x in p:
3084                         print x
3085                 for x in blockers:
3086                         print x
3087
3088                 if verbosity == 3:
3089                         print
3090                         print counters
3091                         sys.stdout.write(str(repo_display))
3092
3093                 if "--changelog" in self.myopts:
3094                         print
3095                         for revision,text in changelogs:
3096                                 print bold('*'+revision)
3097                                 sys.stdout.write(text)
3098
3099                 if self._pprovided_args:
3100                         arg_refs = {}
3101                         for arg_atom in self._pprovided_args:
3102                                 arg, atom = arg_atom
3103                                 arg_refs[arg_atom] = []
3104                                 cp = portage.dep_getkey(atom)
3105                                 for set_name, atom_set in self._sets.iteritems():
3106                                         if atom in atom_set:
3107                                                 arg_refs[arg_atom].append(set_name)
3108                         msg = []
3109                         msg.append(bad("\nWARNING: "))
3110                         if len(self._pprovided_args) > 1:
3111                                 msg.append("Requested packages will not be " + \
3112                                         "merged because they are listed in\n")
3113                         else:
3114                                 msg.append("A requested package will not be " + \
3115                                         "merged because it is listed in\n")
3116                         msg.append("package.provided:\n\n")
3117                         problems_sets = set()
3118                         for (arg, atom), refs in arg_refs.iteritems():
3119                                 ref_string = ""
3120                                 if refs:
3121                                         problems_sets.update(refs)
3122                                         refs.sort()
3123                                         ref_string = ", ".join(["'%s'" % name for name in refs])
3124                                         ref_string = " pulled in by " + ref_string
3125                                 msg.append("  %s%s\n" % (colorize("INFORM", arg), ref_string))
3126                         msg.append("\n")
3127                         if "world" in problems_sets:
3128                                 msg.append("This problem can be solved in one of the following ways:\n\n")
3129                                 msg.append("  A) Use emaint to clean offending packages from world (if not installed).\n")
3130                                 msg.append("  B) Uninstall offending packages (cleans them from world).\n")
3131                                 msg.append("  C) Remove offending entries from package.provided.\n\n")
3132                                 msg.append("The best course of action depends on the reason that an offending\n")
3133                                 msg.append("package.provided entry exists.\n\n")
3134                         sys.stderr.write("".join(msg))
3135                 return os.EX_OK
3136
3137         def calc_changelog(self,ebuildpath,current,next):
3138                 if ebuildpath == None or not os.path.exists(ebuildpath):
3139                         return []
3140                 current = '-'.join(portage.catpkgsplit(current)[1:])
3141                 if current.endswith('-r0'):
3142                         current = current[:-3]
3143                 next = '-'.join(portage.catpkgsplit(next)[1:])
3144                 if next.endswith('-r0'):
3145                         next = next[:-3]
3146                 changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog')
3147                 try:
3148                         changelog = open(changelogpath).read()
3149                 except SystemExit, e:
3150                         raise # Needed else can't exit
3151                 except:
3152                         return []
3153                 divisions = self.find_changelog_tags(changelog)
3154                 #print 'XX from',current,'to',next
3155                 #for div,text in divisions: print 'XX',div
3156                 # skip entries for all revisions above the one we are about to emerge
3157                 for i in range(len(divisions)):
3158                         if divisions[i][0]==next:
3159                                 divisions = divisions[i:]
3160                                 break
3161                 # find out how many entries we are going to display
3162                 for i in range(len(divisions)):
3163                         if divisions[i][0]==current:
3164                                 divisions = divisions[:i]
3165                                 break
3166                 else:
3167                     # couldnt find the current revision in the list. display nothing
3168                         return []
3169                 return divisions
3170
3171         def find_changelog_tags(self,changelog):
3172                 divs = []
3173                 release = None
3174                 while 1:
3175                         match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M)
3176                         if match is None:
3177                                 if release is not None:
3178                                         divs.append((release,changelog))
3179                                 return divs
3180                         if release is not None:
3181                                 divs.append((release,changelog[:match.start()]))
3182                         changelog = changelog[match.end():]
3183                         release = match.group(1)
3184                         if release.endswith('.ebuild'):
3185                                 release = release[:-7]
3186                         if release.endswith('-r0'):
3187                                 release = release[:-3]
3188
3189         def saveNomergeFavorites(self):
3190                 """Find atoms in favorites that are not in the mergelist and add them
3191                 to the world file if necessary."""
3192                 for x in ("--fetchonly", "--fetch-all-uri",
3193                         "--oneshot", "--onlydeps", "--pretend"):
3194                         if x in self.myopts:
3195                                 return
3196                 root_config = self.roots[self.target_root]
3197                 world_set = root_config.sets["world"]
3198                 world_set.lock()
3199                 world_set.load() # maybe it's changed on disk
3200                 args_set = self._sets["args"]
3201                 portdb = self.trees[self.target_root]["porttree"].dbapi
3202                 added_favorites = set()
3203                 for x in self._set_nodes:
3204                         pkg_type, root, pkg_key, pkg_status = x
3205                         if pkg_status != "nomerge":
3206                                 continue
3207                         metadata = dict(izip(self._mydbapi_keys,
3208                                 self.mydbapi[root].aux_get(pkg_key, self._mydbapi_keys)))
3209                         try:
3210                                 myfavkey = create_world_atom(pkg_key, metadata,
3211                                         args_set, root_config)
3212                                 if myfavkey:
3213                                         if myfavkey in added_favorites:
3214                                                 continue
3215                                         added_favorites.add(myfavkey)
3216                                         world_set.add(myfavkey)
3217                                         print ">>> Recording",myfavkey,"in \"world\" favorites file..."
3218                         except portage.exception.InvalidDependString, e:
3219                                 writemsg("\n\n!!! '%s' has invalid PROVIDE: %s\n" % \
3220                                         (pkg_key, str(e)), noiselevel=-1)
3221                                 writemsg("!!! see '%s'\n\n" % os.path.join(
3222                                         root, portage.VDB_PATH, pkg_key, "PROVIDE"), noiselevel=-1)
3223                                 del e
3224                 world_set.unlock()
3225
3226         def loadResumeCommand(self, resume_data):
3227                 """
3228                 Add a resume command to the graph and validate it in the process.  This
3229                 will raise a PackageNotFound exception if a package is not available.
3230                 """
3231                 self._sets["args"].update(resume_data.get("favorites", []))
3232                 mergelist = resume_data.get("mergelist", [])
3233                 fakedb = self.mydbapi
3234                 trees = self.trees
3235                 for x in mergelist:
3236                         if len(x) != 4:
3237                                 continue
3238                         pkg_type, myroot, pkg_key, action = x
3239                         if pkg_type not in self.pkg_tree_map:
3240                                 continue
3241                         if action != "merge":
3242                                 continue
3243                         mydb = trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
3244                         try:
3245                                 metadata = dict(izip(self._mydbapi_keys,
3246                                         mydb.aux_get(pkg_key, self._mydbapi_keys)))
3247                         except KeyError:
3248                                 # It does no exist or it is corrupt.
3249                                 raise portage.exception.PackageNotFound(pkg_key)
3250                         fakedb[myroot].cpv_inject(pkg_key, metadata=metadata)
3251                         if pkg_type == "ebuild":
3252                                 pkgsettings = self.pkgsettings[myroot]
3253                                 pkgsettings.setcpv(pkg_key, mydb=fakedb[myroot])
3254                                 fakedb[myroot].aux_update(pkg_key, {"USE":pkgsettings["USE"]})
3255                         self.spinner.update()
3256
3257 class RepoDisplay(object):
3258         def __init__(self, roots):
3259                 self._shown_repos = {}
3260                 self._unknown_repo = False
3261                 repo_paths = set()
3262                 for root_config in roots.itervalues():
3263                         portdir = root_config.settings.get("PORTDIR")
3264                         if portdir:
3265                                 repo_paths.add(portdir)
3266                         overlays = root_config.settings.get("PORTDIR_OVERLAY")
3267                         if overlays:
3268                                 repo_paths.update(overlays.split())
3269                 repo_paths = list(repo_paths)
3270                 self._repo_paths = repo_paths
3271                 self._repo_paths_real = [ os.path.realpath(repo_path) \
3272                         for repo_path in repo_paths ]
3273
3274                 # pre-allocate index for PORTDIR so that it always has index 0.
3275                 for root_config in roots.itervalues():
3276                         portdb = root_config.trees["porttree"].dbapi
3277                         portdir = portdb.porttree_root
3278                         if portdir:
3279                                 self.repoStr(portdir)
3280
3281         def repoStr(self, repo_path_real):
3282                 real_index = -1
3283                 if repo_path_real:
3284                         real_index = self._repo_paths_real.index(repo_path_real)
3285                 if real_index == -1:
3286                         s = "?"
3287                         self._unknown_repo = True
3288                 else:
3289                         shown_repos = self._shown_repos
3290                         repo_paths = self._repo_paths
3291                         repo_path = repo_paths[real_index]
3292                         index = shown_repos.get(repo_path)
3293                         if index is None:
3294                                 index = len(shown_repos)
3295                                 shown_repos[repo_path] = index
3296                         s = str(index)
3297                 return s
3298
3299         def __str__(self):
3300                 output = []
3301                 shown_repos = self._shown_repos
3302                 unknown_repo = self._unknown_repo
3303                 if shown_repos or self._unknown_repo:
3304                         output.append("Portage tree and overlays:\n")
3305                 show_repo_paths = list(shown_repos)
3306                 for repo_path, repo_index in shown_repos.iteritems():
3307                         show_repo_paths[repo_index] = repo_path
3308                 if show_repo_paths:
3309                         for index, repo_path in enumerate(show_repo_paths):
3310                                 output.append(" "+teal("["+str(index)+"]")+" %s\n" % repo_path)
3311                 if unknown_repo:
3312                         output.append(" "+teal("[?]") + \
3313                                 " indicates that the source repository could not be determined\n")
3314                 return "".join(output)
3315
3316 class PackageCounters(object):
3317
3318         def __init__(self):
3319                 self.upgrades   = 0
3320                 self.downgrades = 0
3321                 self.new        = 0
3322                 self.newslot    = 0
3323                 self.reinst     = 0
3324                 self.blocks     = 0
3325                 self.totalsize  = 0
3326                 self.restrict_fetch           = 0
3327                 self.restrict_fetch_satisfied = 0
3328
3329         def __str__(self):
3330                 total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst
3331                 myoutput = []
3332                 details = []
3333                 myoutput.append("Total: %s package" % total_installs)
3334                 if total_installs != 1:
3335                         myoutput.append("s")
3336                 if total_installs != 0:
3337                         myoutput.append(" (")
3338                 if self.upgrades > 0:
3339                         details.append("%s upgrade" % self.upgrades)
3340                         if self.upgrades > 1:
3341                                 details[-1] += "s"
3342                 if self.downgrades > 0:
3343                         details.append("%s downgrade" % self.downgrades)
3344                         if self.downgrades > 1:
3345                                 details[-1] += "s"
3346                 if self.new > 0:
3347                         details.append("%s new" % self.new)
3348                 if self.newslot > 0:
3349                         details.append("%s in new slot" % self.newslot)
3350                         if self.newslot > 1:
3351                                 details[-1] += "s"
3352                 if self.reinst > 0:
3353                         details.append("%s reinstall" % self.reinst)
3354                         if self.reinst > 1:
3355                                 details[-1] += "s"
3356                 if self.blocks > 0:
3357                         details.append("%s block" % self.blocks)
3358                         if self.blocks > 1:
3359                                 details[-1] += "s"
3360                 myoutput.append(", ".join(details))
3361                 if total_installs != 0:
3362                         myoutput.append(")")
3363                 myoutput.append(", Size of downloads: %s" % format_size(self.totalsize))
3364                 if self.restrict_fetch:
3365                         myoutput.append("\nFetch Restriction: %s package" % \
3366                                 self.restrict_fetch)
3367                         if self.restrict_fetch > 1:
3368                                 myoutput.append("s")
3369                 if self.restrict_fetch_satisfied < self.restrict_fetch:
3370                         myoutput.append(bad(" (%s unsatisfied)") % \
3371                                 (self.restrict_fetch - self.restrict_fetch_satisfied))
3372                 return "".join(myoutput)
3373
3374 class MergeTask(object):
3375
3376         def __init__(self, settings, trees, myopts):
3377                 self.settings = settings
3378                 self.target_root = settings["ROOT"]
3379                 self.trees = trees
3380                 self.myopts = myopts
3381                 self.edebug = 0
3382                 if settings.get("PORTAGE_DEBUG", "") == "1":
3383                         self.edebug = 1
3384                 self.pkgsettings = {}
3385                 self.pkgsettings[self.target_root] = portage.config(clone=settings)
3386                 if self.target_root != "/":
3387                         self.pkgsettings["/"] = \
3388                                 portage.config(clone=trees["/"]["vartree"].settings)
3389                 self.curval = 0
3390
3391         def merge(self, mylist, favorites, mtimedb):
3392                 from portage.elog import elog_process
3393                 from portage.elog.filtering import filter_mergephases
3394                 failed_fetches = []
3395                 fetchonly = "--fetchonly" in self.myopts or \
3396                         "--fetch-all-uri" in self.myopts
3397                 pretend = "--pretend" in self.myopts
3398                 mymergelist=[]
3399                 ldpath_mtimes = mtimedb["ldpath"]
3400                 xterm_titles = "notitles" not in self.settings.features
3401
3402                 #check for blocking dependencies
3403                 if "--fetchonly" not in self.myopts and \
3404                         "--fetch-all-uri" not in self.myopts and \
3405                         "--buildpkgonly" not in self.myopts:
3406                         for x in mylist:
3407                                 if x[0]=="blocks":
3408                                         print "\n!!! Error: the "+x[2]+" package conflicts with another package;"
3409                                         print   "!!!        the two packages cannot be installed on the same system together."
3410                                         print   "!!!        Please use 'emerge --pretend' to determine blockers."
3411                                         if "--quiet" not in self.myopts:
3412                                                 show_blocker_docs_link()
3413                                         return 1
3414
3415                 if "--resume" in self.myopts:
3416                         # We're resuming.
3417                         print colorize("GOOD", "*** Resuming merge...")
3418                         emergelog(xterm_titles, " *** Resuming merge...")
3419                         mylist = mtimedb["resume"]["mergelist"][:]
3420                         if "--skipfirst" in self.myopts and mylist:
3421                                 del mtimedb["resume"]["mergelist"][0]
3422                                 del mylist[0]
3423                                 mtimedb.commit()
3424                         mymergelist = mylist
3425
3426                 # Verify all the manifests now so that the user is notified of failure
3427                 # as soon as possible.
3428                 if "--fetchonly" not in self.myopts and \
3429                         "--fetch-all-uri" not in self.myopts and \
3430                         "strict" in self.settings.features:
3431                         shown_verifying_msg = False
3432                         quiet_settings = {}
3433                         for myroot, pkgsettings in self.pkgsettings.iteritems():
3434                                 quiet_config = portage.config(clone=pkgsettings)
3435                                 quiet_config["PORTAGE_QUIET"] = "1"
3436                                 quiet_config.backup_changes("PORTAGE_QUIET")
3437                                 quiet_settings[myroot] = quiet_config
3438                                 del quiet_config
3439                         for x in mylist:
3440                                 if x[0] != "ebuild" or x[-1] == "nomerge":
3441                                         continue
3442                                 if not shown_verifying_msg:
3443                                         shown_verifying_msg = True
3444                                         print ">>> Verifying ebuild Manifests..."
3445                                 mytype, myroot, mycpv, mystatus = x
3446                                 portdb = self.trees[myroot]["porttree"].dbapi
3447                                 quiet_config = quiet_settings[myroot]
3448                                 quiet_config["O"] = os.path.dirname(portdb.findname(mycpv))
3449                                 if not portage.digestcheck([], quiet_config, strict=True):
3450                                         return 1
3451                                 del x, mytype, myroot, mycpv, mystatus, quiet_config
3452                         del shown_verifying_msg, quiet_settings
3453
3454                 root_config = RootConfig(self.trees[self.target_root])
3455                 system_set = root_config.sets["system"]
3456                 args_set = InternalPackageSet(favorites)
3457                 world_set = root_config.sets["world"]
3458                 if "--resume" not in self.myopts:
3459                         mymergelist = mylist
3460                         mtimedb["resume"]["mergelist"]=mymergelist[:]
3461                         mtimedb.commit()
3462
3463                 myfeat = self.settings.features[:]
3464                 bad_resume_opts = set(["--ask", "--tree", "--changelog", "--skipfirst",
3465                         "--resume"])
3466                 if "parallel-fetch" in myfeat and \
3467                         not ("--pretend" in self.myopts or \
3468                         "--fetch-all-uri" in self.myopts or \
3469                         "--fetchonly" in self.myopts):
3470                         if "distlocks" not in myfeat:
3471                                 print red("!!!")
3472                                 print red("!!!")+" parallel-fetching requires the distlocks feature enabled"
3473                                 print red("!!!")+" you have it disabled, thus parallel-fetching is being disabled"
3474                                 print red("!!!")
3475                         elif len(mymergelist) > 1:
3476                                 print ">>> starting parallel fetching"
3477                                 fetch_log = "/var/log/emerge-fetch.log"
3478                                 logfile = open(fetch_log, "w")
3479                                 fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()}
3480                                 portage.util.apply_secpass_permissions(fetch_log,
3481                                         uid=portage.portage_uid, gid=portage.portage_gid,
3482                                         mode=0660)
3483                                 fetch_env = os.environ.copy()
3484                                 fetch_env["FEATURES"] = fetch_env.get("FEATURES", "") + " -cvs"
3485                                 fetch_env["PORTAGE_NICENESS"] = "0"
3486                                 fetch_args = [sys.argv[0], "--resume", "--fetchonly"]
3487                                 resume_opts = self.myopts.copy()
3488                                 # For automatic resume, we need to prevent
3489                                 # any of bad_resume_opts from leaking in
3490                                 # via EMERGE_DEFAULT_OPTS.
3491                                 resume_opts["--ignore-default-opts"] = True
3492                                 for myopt, myarg in resume_opts.iteritems():
3493                                         if myopt not in bad_resume_opts:
3494                                                 if myarg is True:
3495                                                         fetch_args.append(myopt)
3496                                                 else:
3497                                                         fetch_args.append(myopt +"="+ myarg)
3498                                 portage.process.spawn(fetch_args, env=fetch_env,
3499                                         fd_pipes=fd_pipes, returnpid=True)
3500                                 logfile.close() # belongs to the spawned process
3501                                 del fetch_log, logfile, fd_pipes, fetch_env, fetch_args, \
3502                                         resume_opts
3503
3504                 metadata_keys = [k for k in portage.auxdbkeys \
3505                         if not k.startswith("UNUSED_")] + ["USE"]
3506
3507                 mergecount=0
3508                 for x in mymergelist:
3509                         mergecount+=1
3510                         pkg_type = x[0]
3511                         myroot=x[1]
3512                         pkg_key = x[2]
3513                         pkgindex=2
3514                         portdb = self.trees[myroot]["porttree"].dbapi
3515                         bindb  = self.trees[myroot]["bintree"].dbapi
3516                         vartree = self.trees[myroot]["vartree"]
3517                         pkgsettings = self.pkgsettings[myroot]
3518                         metadata = {}
3519                         if pkg_type == "blocks":
3520                                 pass
3521                         elif pkg_type == "ebuild":
3522                                 mydbapi = portdb
3523                                 metadata.update(izip(metadata_keys,
3524                                         mydbapi.aux_get(pkg_key, metadata_keys)))
3525                                 pkgsettings.setcpv(pkg_key, mydb=mydbapi)
3526                                 metadata["USE"] = pkgsettings["USE"]
3527                         else:
3528                                 if pkg_type == "binary":
3529                                         mydbapi = bindb
3530                                 else:
3531                                         raise AssertionError("Package type: '%s'" % pkg_type)
3532                                 metadata.update(izip(metadata_keys,
3533                                         mydbapi.aux_get(pkg_key, metadata_keys)))
3534                         if x[0]=="blocks":
3535                                 pkgindex=3
3536                         y = portdb.findname(pkg_key)
3537                         if "--pretend" not in self.myopts:
3538                                 print "\n>>> Emerging (" + \
3539                                         colorize("MERGE_LIST_PROGRESS", str(mergecount)) + " of " + \
3540                                         colorize("MERGE_LIST_PROGRESS", str(len(mymergelist))) + ") " + \
3541                                         colorize("GOOD", x[pkgindex]) + " to " + x[1]
3542                                 emergelog(xterm_titles, " >>> emerge ("+\
3543                                         str(mergecount)+" of "+str(len(mymergelist))+\
3544                                         ") "+x[pkgindex]+" to "+x[1])
3545
3546                         pkgsettings["EMERGE_FROM"] = x[0]
3547                         pkgsettings.backup_changes("EMERGE_FROM")
3548                         pkgsettings.reset()
3549
3550                         #buildsyspkg: Check if we need to _force_ binary package creation
3551                         issyspkg = ("buildsyspkg" in myfeat) \
3552                                         and x[0] != "blocks" \
3553                                         and system_set.findAtomForPackage(pkg_key, metadata) \
3554                                         and "--buildpkg" not in self.myopts
3555                         if x[0] in ["ebuild","blocks"]:
3556                                 if x[0] == "blocks" and "--fetchonly" not in self.myopts:
3557                                         raise Exception, "Merging a blocker"
3558                                 elif "--fetchonly" in self.myopts or \
3559                                         "--fetch-all-uri" in self.myopts:
3560                                         if "--fetch-all-uri" in self.myopts:
3561                                                 retval = portage.doebuild(y, "fetch", myroot,
3562                                                         pkgsettings, self.edebug,
3563                                                         "--pretend" in self.myopts, fetchonly=1,
3564                                                         fetchall=1, mydbapi=portdb, tree="porttree")
3565                                         else:
3566                                                 retval = portage.doebuild(y, "fetch", myroot,
3567                                                         pkgsettings, self.edebug,
3568                                                         "--pretend" in self.myopts, fetchonly=1,
3569                                                         mydbapi=portdb, tree="porttree")
3570                                         if (retval is None) or retval:
3571                                                 print
3572                                                 print "!!! Fetch for",y,"failed, continuing..."
3573                                                 print
3574                                                 failed_fetches.append(pkg_key)
3575                                         self.curval += 1
3576                                         continue
3577
3578                                 portage.doebuild_environment(y, "setup", myroot,
3579                                         pkgsettings, self.edebug, 1, portdb)
3580                                 catdir = os.path.dirname(pkgsettings["PORTAGE_BUILDDIR"])
3581                                 portage.util.ensure_dirs(os.path.dirname(catdir),
3582                                         uid=portage.portage_uid, gid=portage.portage_gid,
3583                                         mode=070, mask=0)
3584                                 builddir_lock = None
3585                                 catdir_lock = None
3586                                 try:
3587                                         catdir_lock = portage.locks.lockdir(catdir)
3588                                         portage.util.ensure_dirs(catdir,
3589                                                 uid=portage.portage_uid, gid=portage.portage_gid,
3590                                                 mode=070, mask=0)
3591                                         builddir_lock = portage.locks.lockdir(
3592                                                 pkgsettings["PORTAGE_BUILDDIR"])
3593                                         try:
3594                                                 portage.locks.unlockdir(catdir_lock)
3595                                         finally:
3596                                                 catdir_lock = None
3597                                         msg = " === (%s of %s) Cleaning (%s::%s)" % \
3598                                                 (mergecount, len(mymergelist), pkg_key, y)
3599                                         short_msg = "emerge: (%s of %s) %s Clean" % \
3600                                                 (mergecount, len(mymergelist), pkg_key)
3601                                         emergelog(xterm_titles, msg, short_msg=short_msg)
3602                                         retval = portage.doebuild(y, "clean", myroot,
3603                                                 pkgsettings, self.edebug, cleanup=1,
3604                                                 mydbapi=portdb, tree="porttree")
3605                                         if retval != os.EX_OK:
3606                                                 return retval
3607                                         if "--buildpkg" in self.myopts or issyspkg:
3608                                                 if issyspkg:
3609                                                         print ">>> This is a system package, " + \
3610                                                                 "let's pack a rescue tarball."
3611                                                 msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
3612                                                         (mergecount, len(mymergelist), pkg_key, y)
3613                                                 short_msg = "emerge: (%s of %s) %s Compile" % \
3614                                                         (mergecount, len(mymergelist), pkg_key)
3615                                                 emergelog(xterm_titles, msg, short_msg=short_msg)
3616                                                 self.trees[myroot]["bintree"].prevent_collision(pkg_key)
3617                                                 binpkg_tmpfile = os.path.join(pkgsettings["PKGDIR"],
3618                                                         pkg_key + ".tbz2." + str(os.getpid()))
3619                                                 pkgsettings["PORTAGE_BINPKG_TMPFILE"] = binpkg_tmpfile
3620                                                 pkgsettings.backup_changes("PORTAGE_BINPKG_TMPFILE")
3621                                                 retval = portage.doebuild(y, "package", myroot,
3622                                                         pkgsettings, self.edebug, mydbapi=portdb,
3623                                                         tree="porttree")
3624                                                 del pkgsettings["PORTAGE_BINPKG_TMPFILE"]
3625                                                 if retval != os.EX_OK or \
3626                                                         "--buildpkgonly" in self.myopts:
3627                                                         elog_process(pkg_key, pkgsettings, phasefilter=filter_mergephases)
3628                                                 if retval != os.EX_OK:
3629                                                         return retval
3630                                                 bintree = self.trees[myroot]["bintree"]
3631                                                 bintree.inject(pkg_key, filename=binpkg_tmpfile)
3632                                                 if "--buildpkgonly" not in self.myopts:
3633                                                         msg = " === (%s of %s) Merging (%s::%s)" % \
3634                                                                 (mergecount, len(mymergelist), pkg_key, y)
3635                                                         short_msg = "emerge: (%s of %s) %s Merge" % \
3636                                                                 (mergecount, len(mymergelist), pkg_key)
3637                                                         emergelog(xterm_titles, msg, short_msg=short_msg)
3638                                                         retval = portage.merge(pkgsettings["CATEGORY"],
3639                                                                 pkgsettings["PF"], pkgsettings["D"],
3640                                                                 os.path.join(pkgsettings["PORTAGE_BUILDDIR"],
3641                                                                 "build-info"), myroot, pkgsettings,
3642                                                                 myebuild=pkgsettings["EBUILD"],
3643                                                                 mytree="porttree", mydbapi=portdb,
3644                                                                 vartree=vartree, prev_mtimes=ldpath_mtimes)
3645                                                         if retval != os.EX_OK:
3646                                                                 return retval
3647                                                 elif "noclean" not in pkgsettings.features:
3648                                                         portage.doebuild(y, "clean", myroot,
3649                                                                 pkgsettings, self.edebug, mydbapi=portdb,
3650                                                                 tree="porttree")
3651                                         else:
3652                                                 msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
3653                                                         (mergecount, len(mymergelist), pkg_key, y)
3654                                                 short_msg = "emerge: (%s of %s) %s Compile" % \
3655                                                         (mergecount, len(mymergelist), pkg_key)
3656                                                 emergelog(xterm_titles, msg, short_msg=short_msg)
3657                                                 retval = portage.doebuild(y, "merge", myroot,
3658                                                         pkgsettings, self.edebug, vartree=vartree,
3659                                                         mydbapi=portdb, tree="porttree",
3660                                                         prev_mtimes=ldpath_mtimes)
3661                                                 if retval != os.EX_OK:
3662                                                         return retval
3663                                 finally:
3664                                         if builddir_lock:
3665                                                 portage.locks.unlockdir(builddir_lock)
3666                                         try:
3667                                                 if not catdir_lock:
3668                                                         # Lock catdir for removal if empty.
3669                                                         catdir_lock = portage.locks.lockdir(catdir)
3670                                         finally:
3671                                                 if catdir_lock:
3672                                                         try:
3673                                                                 os.rmdir(catdir)
3674                                                         except OSError, e:
3675                                                                 if e.errno not in (errno.ENOENT,
3676                                                                         errno.ENOTEMPTY, errno.EEXIST):
3677                                                                         raise
3678                                                                 del e
3679                                                         portage.locks.unlockdir(catdir_lock)
3680
3681                         elif x[0]=="binary":
3682                                 #merge the tbz2
3683                                 mytbz2 = self.trees[myroot]["bintree"].getname(pkg_key)
3684                                 if "--getbinpkg" in self.myopts:
3685                                         tbz2_lock = None
3686                                         try:
3687                                                 if "distlocks" in pkgsettings.features and \
3688                                                         os.access(pkgsettings["PKGDIR"], os.W_OK):
3689                                                         portage.util.ensure_dirs(os.path.dirname(mytbz2))
3690                                                         tbz2_lock = portage.locks.lockfile(mytbz2,
3691                                                                 wantnewlockfile=1)
3692                                                 if self.trees[myroot]["bintree"].isremote(pkg_key):
3693                                                         msg = " --- (%s of %s) Fetching Binary (%s::%s)" %\
3694                                                                 (mergecount, len(mymergelist), pkg_key, mytbz2)
3695                                                         short_msg = "emerge: (%s of %s) %s Fetch" % \
3696                                                                 (mergecount, len(mymergelist), pkg_key)
3697                                                         emergelog(xterm_titles, msg, short_msg=short_msg)
3698                                                         try:
3699                                                                 self.trees[myroot]["bintree"].gettbz2(pkg_key)
3700                                                         except portage.exception.FileNotFound:
3701                                                                 writemsg("!!! Fetching Binary failed " + \
3702                                                                         "for '%s'\n" % pkg_key, noiselevel=-1)
3703                                                                 if not fetchonly:
3704                                                                         return 1
3705                                                                 failed_fetches.append(pkg_key)
3706                                                         except portage.exception.DigestException, e:
3707                                                                 writemsg("\n!!! Digest verification failed:\n",
3708                                                                         noiselevel=-1)
3709                                                                 writemsg("!!! %s\n" % e.value[0],
3710                                                                         noiselevel=-1)
3711                                                                 writemsg("!!! Reason: %s\n" % e.value[1],
3712                                                                         noiselevel=-1)
3713                                                                 writemsg("!!! Got: %s\n" % e.value[2],
3714                                                                         noiselevel=-1)
3715                                                                 writemsg("!!! Expected: %s\n" % e.value[3],
3716                                                                         noiselevel=-1)
3717                                                                 os.unlink(mytbz2)
3718                                                                 if not fetchonly:
3719                                                                         return 1
3720                                                                 failed_fetches.append(pkg_key)
3721                                         finally:
3722                                                 if tbz2_lock:
3723                                                         portage.locks.unlockfile(tbz2_lock)
3724
3725                                 if "--fetchonly" in self.myopts or \
3726                                         "--fetch-all-uri" in self.myopts:
3727                                         self.curval += 1
3728                                         continue
3729
3730                                 short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary"
3731                                 emergelog(xterm_titles, " === ("+str(mergecount)+\
3732                                         " of "+str(len(mymergelist))+") Merging Binary ("+\
3733                                         x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg)
3734                                 retval = portage.pkgmerge(mytbz2, x[1], pkgsettings,
3735                                         mydbapi=bindb,
3736                                         vartree=self.trees[myroot]["vartree"],
3737                                         prev_mtimes=ldpath_mtimes)
3738                                 if retval != os.EX_OK:
3739                                         return retval
3740                                 #need to check for errors
3741                         if "--buildpkgonly" not in self.myopts:
3742                                 self.trees[x[1]]["vartree"].inject(x[2])
3743                                 myfavkey = portage.cpv_getkey(x[2])
3744                                 if not fetchonly and not pretend and \
3745                                         args_set.findAtomForPackage(pkg_key, metadata):
3746                                         world_set.lock()
3747                                         world_set.load() # maybe it's changed on disk
3748                                         myfavkey = create_world_atom(pkg_key, metadata,
3749                                                 args_set, root_config)
3750                                         if myfavkey:
3751                                                 print ">>> Recording",myfavkey,"in \"world\" favorites file..."
3752                                                 emergelog(xterm_titles, " === ("+\
3753                                                         str(mergecount)+" of "+\
3754                                                         str(len(mymergelist))+\
3755                                                         ") Updating world file ("+x[pkgindex]+")")
3756                                                 world_set.add(myfavkey)
3757                                         world_set.unlock()
3758
3759                                 if "--pretend" not in self.myopts and \
3760                                         "--fetchonly" not in self.myopts and \
3761                                         "--fetch-all-uri" not in self.myopts:
3762                                         # Clean the old package that we have merged over top of it.
3763                                         if pkgsettings.get("AUTOCLEAN", "yes") == "yes":
3764                                                 xsplit=portage.pkgsplit(x[2])
3765                                                 emergelog(xterm_titles, " >>> AUTOCLEAN: " + xsplit[0])
3766                                                 retval = unmerge(pkgsettings, self.myopts, vartree,
3767                                                         "clean", [xsplit[0]], ldpath_mtimes, autoclean=1)
3768                                                 if not retval:
3769                                                         emergelog(xterm_titles,
3770                                                                 " --- AUTOCLEAN: Nothing unmerged.")
3771                                         else:
3772                                                 portage.writemsg_stdout(colorize("WARN", "WARNING:")
3773                                                         + " AUTOCLEAN is disabled.  This can cause serious"
3774                                                         + " problems due to overlapping packages.\n")
3775
3776                                         # Figure out if we need a restart.
3777                                         mysplit=portage.pkgsplit(x[2])
3778                                         if mysplit[0] == "sys-apps/portage" and x[1] == "/":
3779                                                 myver=mysplit[1]+"-"+mysplit[2]
3780                                                 if myver[-3:]=='-r0':
3781                                                         myver=myver[:-3]
3782                                                 if (myver != portage.VERSION) and \
3783                                                    "livecvsportage" not in self.settings.features:
3784                                                         if len(mymergelist) > mergecount:
3785                                                                 emergelog(xterm_titles,
3786                                                                         " ::: completed emerge ("+ \
3787                                                                         str(mergecount)+" of "+ \
3788                                                                         str(len(mymergelist))+") "+ \
3789                                                                         x[2]+" to "+x[1])
3790                                                                 emergelog(xterm_titles, " *** RESTARTING " + \
3791                                                                         "emerge via exec() after change of " + \
3792                                                                         "portage version.")
3793                                                                 del mtimedb["resume"]["mergelist"][0]
3794                                                                 mtimedb.commit()
3795                                                                 portage.run_exitfuncs()
3796                                                                 mynewargv=[sys.argv[0],"--resume"]
3797                                                                 resume_opts = self.myopts.copy()
3798                                                                 # For automatic resume, we need to prevent
3799                                                                 # any of bad_resume_opts from leaking in
3800                                                                 # via EMERGE_DEFAULT_OPTS.
3801                                                                 resume_opts["--ignore-default-opts"] = True
3802                                                                 for myopt, myarg in resume_opts.iteritems():
3803                                                                         if myopt not in bad_resume_opts:
3804                                                                                 if myarg is True:
3805                                                                                         mynewargv.append(myopt)
3806                                                                                 else:
3807                                                                                         mynewargv.append(myopt +"="+ myarg)
3808                                                                 # priority only needs to be adjusted on the first run
3809                                                                 os.environ["PORTAGE_NICENESS"] = "0"
3810                                                                 os.execv(mynewargv[0], mynewargv)
3811
3812                         if "--pretend" not in self.myopts and \
3813                                 "--fetchonly" not in self.myopts and \
3814                                 "--fetch-all-uri" not in self.myopts:
3815                                 if "noclean" not in self.settings.features:
3816                                         short_msg = "emerge: (%s of %s) %s Clean Post" % \
3817                                                 (mergecount, len(mymergelist), x[pkgindex])
3818                                         emergelog(xterm_titles, (" === (%s of %s) " + \
3819                                                 "Post-Build Cleaning (%s::%s)") % \
3820                                                 (mergecount, len(mymergelist), x[pkgindex], y),
3821                                                 short_msg=short_msg)
3822                                 emergelog(xterm_titles, " ::: completed emerge ("+\
3823                                         str(mergecount)+" of "+str(len(mymergelist))+") "+\
3824                                         x[2]+" to "+x[1])
3825
3826                         # Unsafe for parallel merges
3827                         del mtimedb["resume"]["mergelist"][0]
3828                         # Commit after each merge so that --resume may still work in
3829                         # in the event that portage is not allowed to exit normally
3830                         # due to power failure, SIGKILL, etc...
3831                         mtimedb.commit()
3832                         self.curval += 1
3833
3834                 if "--pretend" not in self.myopts:
3835                         emergelog(xterm_titles, " *** Finished. Cleaning up...")
3836
3837                 # We're out of the loop... We're done. Delete the resume data.
3838                 if mtimedb.has_key("resume"):
3839                         del mtimedb["resume"]
3840                 mtimedb.commit()
3841
3842                 #by doing an exit this way, --fetchonly can continue to try to
3843                 #fetch everything even if a particular download fails.
3844                 if "--fetchonly" in self.myopts or "--fetch-all-uri" in self.myopts:
3845                         if failed_fetches:
3846                                 sys.stderr.write("\n\n!!! Some fetch errors were " + \
3847                                         "encountered.  Please see above for details.\n\n")
3848                                 for cpv in failed_fetches:
3849                                         sys.stderr.write("   ")
3850                                         sys.stderr.write(cpv)
3851                                         sys.stderr.write("\n")
3852                                 sys.stderr.write("\n")
3853                                 sys.exit(1)
3854                         else:
3855                                 sys.exit(0)
3856                 return os.EX_OK
3857
3858 def unmerge(settings, myopts, vartree, unmerge_action, unmerge_files,
3859         ldpath_mtimes, autoclean=0):
3860         candidate_catpkgs=[]
3861         global_unmerge=0
3862         xterm_titles = "notitles" not in settings.features
3863
3864         vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH)
3865         try:
3866                 # At least the parent needs to exist for the lock file.
3867                 portage.util.ensure_dirs(vdb_path)
3868         except portage.exception.PortageException:
3869                 pass
3870         vdb_lock = None
3871         try:
3872                 if os.access(vdb_path, os.W_OK):
3873                         vdb_lock = portage.locks.lockdir(vdb_path)
3874                 realsyslist = getlist(settings, "system")
3875                 syslist = []
3876                 for x in realsyslist:
3877                         mycp = portage.dep_getkey(x)
3878                         if mycp in settings.getvirtuals():
3879                                 providers = []
3880                                 for provider in settings.getvirtuals()[mycp]:
3881                                         if vartree.dbapi.match(provider):
3882                                                 providers.append(provider)
3883                                 if len(providers) == 1:
3884                                         syslist.extend(providers)
3885                         else:
3886                                 syslist.append(mycp)
3887         
3888                 mysettings = portage.config(clone=settings)
3889         
3890                 if not unmerge_files or "world" in unmerge_files or \
3891                         "system" in unmerge_files:
3892                         if "unmerge"==unmerge_action:
3893                                 print
3894                                 print bold("emerge unmerge") + " can only be used with " + \
3895                                         "specific package names, not with "+bold("world")+" or"
3896                                 print bold("system")+" targets."
3897                                 print
3898                                 return 0
3899                         else:
3900                                 global_unmerge = 1
3901         
3902                 localtree = vartree
3903                 # process all arguments and add all
3904                 # valid db entries to candidate_catpkgs
3905                 if global_unmerge:
3906                         if not unmerge_files or "world" in unmerge_files:
3907                                 candidate_catpkgs.extend(vartree.dbapi.cp_all())
3908                         elif "system" in unmerge_files:
3909                                 candidate_catpkgs.extend(getlist(settings, "system"))
3910                 else:
3911                         #we've got command-line arguments
3912                         if not unmerge_files:
3913                                 print "\nNo packages to unmerge have been provided.\n"
3914                                 return 0
3915                         for x in unmerge_files:
3916                                 arg_parts = x.split('/')
3917                                 if x[0] not in [".","/"] and \
3918                                         arg_parts[-1][-7:] != ".ebuild":
3919                                         #possible cat/pkg or dep; treat as such
3920                                         candidate_catpkgs.append(x)
3921                                 elif unmerge_action in ["prune","clean"]:
3922                                         print "\n!!! Prune and clean do not accept individual" + \
3923                                                 " ebuilds as arguments;\n    skipping.\n"
3924                                         continue
3925                                 else:
3926                                         # it appears that the user is specifying an installed
3927                                         # ebuild and we're in "unmerge" mode, so it's ok.
3928                                         if not os.path.exists(x):
3929                                                 print "\n!!! The path '"+x+"' doesn't exist.\n"
3930                                                 return 0
3931         
3932                                         absx   = os.path.abspath(x)
3933                                         sp_absx = absx.split("/")
3934                                         if sp_absx[-1][-7:] == ".ebuild":
3935                                                 del sp_absx[-1]
3936                                                 absx = "/".join(sp_absx)
3937         
3938                                         sp_absx_len = len(sp_absx)
3939         
3940                                         vdb_path = os.path.join(settings["ROOT"], portage.VDB_PATH)
3941                                         vdb_len  = len(vdb_path)
3942         
3943                                         sp_vdb     = vdb_path.split("/")
3944                                         sp_vdb_len = len(sp_vdb)
3945         
3946                                         if not os.path.exists(absx+"/CONTENTS"):
3947                                                 print "!!! Not a valid db dir: "+str(absx)
3948                                                 return 0
3949         
3950                                         if sp_absx_len <= sp_vdb_len:
3951                                                 # The Path is shorter... so it can't be inside the vdb.
3952                                                 print sp_absx
3953                                                 print absx
3954                                                 print "\n!!!",x,"cannot be inside "+ \
3955                                                         vdb_path+"; aborting.\n"
3956                                                 return 0
3957         
3958                                         for idx in range(0,sp_vdb_len):
3959                                                 if idx >= sp_absx_len or sp_vdb[idx] != sp_absx[idx]:
3960                                                         print sp_absx
3961                                                         print absx
3962                                                         print "\n!!!", x, "is not inside "+\
3963                                                                 vdb_path+"; aborting.\n"
3964                                                         return 0
3965         
3966                                         print "="+"/".join(sp_absx[sp_vdb_len:])
3967                                         candidate_catpkgs.append(
3968                                                 "="+"/".join(sp_absx[sp_vdb_len:]))
3969         
3970                 newline=""
3971                 if (not "--quiet" in myopts):
3972                         newline="\n"
3973                 if settings["ROOT"] != "/":
3974                         print darkgreen(newline+ \
3975                                 ">>> Using system located in ROOT tree "+settings["ROOT"])
3976                 if (("--pretend" in myopts) or ("--ask" in myopts)) and \
3977                         not ("--quiet" in myopts):
3978                         print darkgreen(newline+\
3979                                 ">>> These are the packages that would be unmerged:")
3980         
3981                 pkgmap={}
3982                 numselected=0
3983                 for x in candidate_catpkgs:
3984                         # cycle through all our candidate deps and determine
3985                         # what will and will not get unmerged
3986                         try:
3987                                 mymatch=localtree.dep_match(x)
3988                         except KeyError:
3989                                 mymatch=None
3990                         except ValueError, errpkgs:
3991                                 print "\n\n!!! The short ebuild name \"" + \
3992                                         x + "\" is ambiguous.  Please specify"
3993                                 print "!!! one of the following fully-qualified " + \
3994                                         "ebuild names instead:\n"
3995                                 for i in errpkgs[0]:
3996                                         print "    " + green(i)
3997                                 print
3998                                 sys.exit(1)
3999         
4000                         if not mymatch and x[0] not in "<>=~":
4001                                 #add a "=" if missing
4002                                 mymatch=localtree.dep_match("="+x)
4003                         if not mymatch:
4004                                 portage.writemsg("\n--- Couldn't find '%s' to %s.\n" % \
4005                                         (x, unmerge_action), noiselevel=-1)
4006                                 continue
4007                         mykey = portage.key_expand(
4008                                 portage.dep_getkey(
4009                                         mymatch[0]), mydb=vartree.dbapi, settings=settings)
4010                         if not pkgmap.has_key(mykey):
4011                                 pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] }
4012                         if unmerge_action=="unmerge":
4013                                         for y in mymatch:
4014                                                 if y not in pkgmap[mykey]["selected"]:
4015                                                         pkgmap[mykey]["selected"].append(y)
4016                                                         numselected=numselected+len(mymatch)
4017         
4018                         else:
4019                                 #unmerge_action in ["prune", clean"]
4020                                 slotmap={}
4021                                 for mypkg in mymatch:
4022                                         if unmerge_action=="clean":
4023                                                 myslot=localtree.getslot(mypkg)
4024                                         else:
4025                                                 # since we're pruning, we don't care about slots
4026                                                 # and put all the pkgs in together
4027                                                 myslot=0
4028                                         if not slotmap.has_key(myslot):
4029                                                 slotmap[myslot]={}
4030                                         slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg
4031                                 for myslot in slotmap:
4032                                         counterkeys=slotmap[myslot].keys()
4033                                         counterkeys.sort()
4034                                         if not counterkeys:
4035                                                 continue
4036                                         counterkeys.sort()
4037                                         pkgmap[mykey]["protected"].append(
4038                                                 slotmap[myslot][counterkeys[-1]])
4039                                         del counterkeys[-1]
4040                                         #be pretty and get them in order of merge:
4041                                         for ckey in counterkeys:
4042                                                 pkgmap[mykey]["selected"].append(slotmap[myslot][ckey])
4043                                                 numselected=numselected+1
4044                                         # ok, now the last-merged package
4045                                         # is protected, and the rest are selected
4046                 if global_unmerge and not numselected:
4047                         portage.writemsg_stdout("\n>>> No outdated packages were found on your system.\n")
4048                         return 0
4049         
4050                 if not numselected:
4051                         portage.writemsg_stdout(
4052                                 "\n>>> No packages selected for removal by " + \
4053                                 unmerge_action + "\n")
4054                         return 0
4055         finally:
4056                 if vdb_lock:
4057                         portage.locks.unlockdir(vdb_lock)
4058         for x in pkgmap:
4059                 for y in localtree.dep_match(x):
4060                         if y not in pkgmap[x]["omitted"] and \
4061                            y not in pkgmap[x]["selected"] and \
4062                            y not in pkgmap[x]["protected"]:
4063                                 pkgmap[x]["omitted"].append(y)
4064                 if global_unmerge and not pkgmap[x]["selected"]:
4065                         #avoid cluttering the preview printout with stuff that isn't getting unmerged
4066                         continue
4067                 if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist):
4068                         print colorize("BAD","\a\n\n!!! '%s' is part of your system profile." % x)
4069                         print colorize("WARN","\a!!! Unmerging it may be damaging to your system.\n")
4070                         if "--pretend" not in myopts and "--ask" not in myopts:
4071                                 countdown(int(settings["EMERGE_WARNING_DELAY"]),
4072                                         colorize("UNMERGE_WARN", "Press Ctrl-C to Stop"))
4073                 if "--quiet" not in myopts:
4074                         print "\n "+white(x)
4075                 else:
4076                         print white(x)+": ",
4077                 for mytype in ["selected","protected","omitted"]:
4078                         if "--quiet" not in myopts:
4079                                 portage.writemsg_stdout((mytype + ": ").rjust(14), noiselevel=-1)
4080                         if pkgmap[x][mytype]:
4081                                 for mypkg in pkgmap[x][mytype]:
4082                                         mysplit=portage.catpkgsplit(mypkg)
4083                                         if mysplit[3]=="r0":
4084                                                 myversion=mysplit[2]
4085                                         else:
4086                                                 myversion=mysplit[2]+"-"+mysplit[3]
4087                                         if mytype=="selected":
4088                                                 portage.writemsg_stdout(
4089                                                         colorize("UNMERGE_WARN", myversion + " "), noiselevel=-1)
4090                                         else:
4091                                                 portage.writemsg_stdout(
4092                                                         colorize("GOOD", myversion + " "), noiselevel=-1)
4093                         else:
4094                                 portage.writemsg_stdout("none ", noiselevel=-1)
4095                         if "--quiet" not in myopts:
4096                                 portage.writemsg_stdout("\n", noiselevel=-1)
4097                 if "--quiet" in myopts:
4098                         portage.writemsg_stdout("\n", noiselevel=-1)
4099
4100         portage.writemsg_stdout("\n>>> " + colorize("UNMERGE_WARN", "'Selected'") + \
4101                 " packages are slated for removal.\n")
4102         portage.writemsg_stdout(">>> " + colorize("GOOD", "'Protected'") + \
4103                         " and " + colorize("GOOD", "'omitted'") + \
4104                         " packages will not be removed.\n\n")
4105
4106         if "--pretend" in myopts:
4107                 #we're done... return
4108                 return 0
4109         if "--ask" in myopts:
4110                 if userquery("Would you like to unmerge these packages?")=="No":
4111                         # enter pretend mode for correct formatting of results
4112                         myopts["--pretend"] = True
4113                         print
4114                         print "Quitting."
4115                         print
4116                         return 0
4117         #the real unmerging begins, after a short delay....
4118         if not autoclean:
4119                 countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging")
4120
4121         for x in pkgmap:
4122                 for y in pkgmap[x]["selected"]:
4123                         print ">>> Unmerging "+y+"..."
4124                         emergelog(xterm_titles, "=== Unmerging... ("+y+")")
4125                         mysplit=y.split("/")
4126                         #unmerge...
4127                         retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"],
4128                                 mysettings, unmerge_action not in ["clean","prune"],
4129                                 vartree=vartree, ldpath_mtimes=ldpath_mtimes)
4130                         if retval != os.EX_OK:
4131                                 emergelog(xterm_titles, " !!! unmerge FAILURE: "+y)
4132                                 ebuild = vartree.dbapi.findname(y)
4133                                 show_unmerge_failure_message(y, ebuild, retval)
4134                                 sys.exit(retval)
4135                         else:
4136                                 clean_world(vartree.dbapi, y)
4137                                 emergelog(xterm_titles, " >>> unmerge success: "+y)
4138         return 1
4139
4140 def show_unmerge_failure_message(pkg, ebuild, retval):
4141
4142         from formatter import AbstractFormatter, DumbWriter
4143         f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72))
4144
4145         msg = []
4146         msg.append("A removal phase of the '%s' package " % pkg)
4147         msg.append("has failed with exit value %s.  " % retval)
4148         msg.append("The problem occurred while executing ")
4149         msg.append("the ebuild located at '%s'.  " % ebuild)
4150         msg.append("If necessary, manually remove the ebuild " )
4151         msg.append("in order to skip the execution of removal phases.")
4152
4153         f.end_paragraph(1)
4154         for x in msg:
4155                 f.add_flowing_data(x)
4156         f.end_paragraph(1)
4157         f.writer.flush()
4158
4159 def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
4160
4161         if os.path.exists("/usr/bin/install-info"):
4162                 regen_infodirs=[]
4163                 for z in infodirs:
4164                         if z=='':
4165                                 continue
4166                         inforoot=normpath(root+z)
4167                         if os.path.isdir(inforoot):
4168                                 infomtime = long(os.stat(inforoot).st_mtime)
4169                                 if inforoot not in prev_mtimes or \
4170                                         prev_mtimes[inforoot] != infomtime:
4171                                                 regen_infodirs.append(inforoot)
4172
4173                 if not regen_infodirs:
4174                         portage.writemsg_stdout(" "+green("*")+" GNU info directory index is up-to-date.\n")
4175                 else:
4176                         portage.writemsg_stdout(" "+green("*")+" Regenerating GNU info directory index...\n")
4177
4178                         icount=0
4179                         badcount=0
4180                         for inforoot in regen_infodirs:
4181                                 if inforoot=='':
4182                                         continue
4183                                 for filename in ("dir", "dir.gz", "dir.bz2"):
4184                                         file_path = os.path.join(inforoot, filename)
4185                                         try:
4186                                                 os.rename(file_path, file_path + ".old")
4187                                         except OSError, e:
4188                                                 if e.errno != errno.ENOENT:
4189                                                         raise
4190                                                 del e
4191
4192                                 if not os.path.isdir(inforoot):
4193                                         continue
4194                                 errmsg = ""
4195                                 file_list = os.listdir(inforoot)
4196                                 file_list.sort()
4197                                 for x in file_list:
4198                                         if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)):
4199                                                 continue
4200                                         myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
4201                                         existsstr="already exists, for file `"
4202                                         if myso!="":
4203                                                 if re.search(existsstr,myso):
4204                                                         # Already exists... Don't increment the count for this.
4205                                                         pass
4206                                                 elif myso[:44]=="install-info: warning: no info dir entry in ":
4207                                                         # This info file doesn't contain a DIR-header: install-info produces this
4208                                                         # (harmless) warning (the --quiet switch doesn't seem to work).
4209                                                         # Don't increment the count for this.
4210                                                         pass
4211                                                 else:
4212                                                         badcount=badcount+1
4213                                                         errmsg += myso + "\n"
4214                                         icount=icount+1
4215
4216                                 #update mtime so we can potentially avoid regenerating.
4217                                 prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime)
4218
4219                         if badcount:
4220                                 print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors."
4221                                 print errmsg
4222                         else:
4223                                 print " "+green("*")+" Processed",icount,"info files."
4224
4225
4226 def display_news_notification(trees):
4227         for target_root in trees:
4228                 if len(trees) > 1 and target_root != "/":
4229                         break
4230         settings = trees[target_root]["vartree"].settings
4231         portdb = trees[target_root]["porttree"].dbapi
4232         vardb = trees[target_root]["vartree"].dbapi
4233         NEWS_PATH = os.path.join("metadata", "news")
4234         UNREAD_PATH = os.path.join(target_root, NEWS_LIB_PATH, "news")
4235         newsReaderDisplay = False
4236
4237         for repo in portdb.getRepositories():
4238                 unreadItems = checkUpdatedNewsItems(
4239                         portdb, vardb, NEWS_PATH, UNREAD_PATH, repo)
4240                 if unreadItems:
4241                         if not newsReaderDisplay:
4242                                 newsReaderDisplay = True
4243                                 print
4244                         print colorize("WARN", " * IMPORTANT:"),
4245                         print "%s news items need reading for repository '%s'." % (unreadItems, repo)
4246                         
4247         
4248         if newsReaderDisplay:
4249                 print colorize("WARN", " *"),
4250                 print "Use " + colorize("GOOD", "eselect news") + " to read news items."
4251                 print
4252
4253 def post_emerge(trees, mtimedb, retval):
4254         """
4255         Misc. things to run at the end of a merge session.
4256         
4257         Update Info Files
4258         Update Config Files
4259         Update News Items
4260         Commit mtimeDB
4261         Display preserved libs warnings
4262         Exit Emerge
4263
4264         @param trees: A dictionary mapping each ROOT to it's package databases
4265         @type trees: dict
4266         @param mtimedb: The mtimeDB to store data needed across merge invocations
4267         @type mtimedb: MtimeDB class instance
4268         @param retval: Emerge's return value
4269         @type retval: Int
4270         @rype: None
4271         @returns:
4272         1.  Calls sys.exit(retval)
4273         """
4274         for target_root in trees:
4275                 if len(trees) > 1 and target_root != "/":
4276                         break
4277         vardbapi = trees[target_root]["vartree"].dbapi
4278         settings = vardbapi.settings
4279         info_mtimes = mtimedb["info"]
4280
4281         # Load the most current variables from ${ROOT}/etc/profile.env
4282         settings.unlock()
4283         settings.regenerate()
4284         settings.lock()
4285
4286         config_protect = settings.get("CONFIG_PROTECT","").split()
4287         infodirs = settings.get("INFOPATH","").split(":") + \
4288                 settings.get("INFODIR","").split(":")
4289
4290         os.chdir("/")
4291
4292         emergelog("notitles" not in settings.features,
4293                 " *** exiting successfully.")
4294
4295         # Dump the mod_echo output now so that our other notifications are shown
4296         # last.
4297         from portage.elog import mod_echo
4298         mod_echo.finalize()
4299
4300         if "noinfo" not in settings.features:
4301                 chk_updated_info_files(target_root, infodirs, info_mtimes, retval)
4302
4303         chk_updated_cfg_files(target_root, config_protect)
4304         
4305         display_news_notification(trees)
4306         
4307         if vardbapi.plib_registry.hasEntries():
4308                 print colorize("WARN", "!!!") + " existing preserved libs:"
4309                 plibdata = vardbapi.plib_registry.getPreservedLibs()
4310                 for cpv in plibdata:
4311                         print colorize("WARN", ">>>") + " package: %s" % cpv
4312                         for f in plibdata[cpv]:
4313                                 print colorize("WARN", " * ") + " - %s" % f
4314                 print "Use " + colorize("GOOD", "revdep-rebuild") + " to rebuild packages using these libraries"
4315                 print "and then remerge the packages listed above."
4316         
4317         mtimedb.commit()
4318         sys.exit(retval)
4319
4320
4321 def chk_updated_cfg_files(target_root, config_protect):
4322         if config_protect:
4323                 #number of directories with some protect files in them
4324                 procount=0
4325                 for x in config_protect:
4326                         x = os.path.join(target_root, x.lstrip(os.path.sep))
4327                         try:
4328                                 mymode = os.lstat(x).st_mode
4329                         except OSError:
4330                                 continue
4331                         if stat.S_ISDIR(mymode):
4332                                 mycommand = "cd '%s'; find . -iname '._cfg????_*'" % x
4333                         else:
4334                                 mycommand = "cd '%s'; find . -maxdepth 1 -iname '._cfg????_%s'" % \
4335                                         os.path.split(x.rstrip(os.path.sep))
4336                         a = commands.getstatusoutput(mycommand + \
4337                                 " ! -iname '.*~' ! -iname '.*.bak'")
4338                         if a[0] != 0:
4339                                 print >> sys.stderr, " " + bad("*")+ " error scanning '%s'" % x
4340                         else:
4341                                 files = a[1].split()
4342                                 if files:
4343                                         procount += 1
4344                                         print colorize("WARN", " * IMPORTANT:"),
4345                                         if stat.S_ISDIR(mymode):
4346                                                  print "%d config files in '%s' need updating." % \
4347                                                         (len(files), x)
4348                                         else:
4349                                                  print "config file '%s' needs updating." % x
4350
4351                 if procount:
4352                         #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
4353                         print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
4354
4355 def checkUpdatedNewsItems(portdb, vardb, NEWS_PATH, UNREAD_PATH, repo_id):
4356         """
4357         Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items
4358         Returns the number of unread (yet relevent) items.
4359         
4360         @param portdb: a portage tree database
4361         @type portdb: pordbapi
4362         @param vardb: an installed package database
4363         @type vardb: vardbapi
4364         @param NEWS_PATH:
4365         @type NEWS_PATH:
4366         @param UNREAD_PATH:
4367         @type UNREAD_PATH:
4368         @param repo_id:
4369         @type repo_id:
4370         @rtype: Integer
4371         @returns:
4372         1.  The number of unread but relevant news items.
4373         
4374         """
4375         from portage.news import NewsManager
4376         manager = NewsManager(portdb, vardb, NEWS_PATH, UNREAD_PATH)
4377         return manager.getUnreadItems( repo_id, update=True )
4378
4379 def is_valid_package_atom(x):
4380         try:
4381                 testkey = portage.dep_getkey(x)
4382         except portage.exception.InvalidData:
4383                 return False
4384         if testkey.startswith("null/"):
4385                 testatom = x.replace(testkey[5:], "cat/"+testkey[5:])
4386         elif "/" not in x:
4387                 testatom = "cat/"+x
4388         else:
4389                 testatom = x
4390         return portage.isvalidatom(testatom)
4391
4392 def show_blocker_docs_link():
4393         print
4394         print "For more information about " + bad("Blocked Packages") + ", please refer to the following"
4395         print "section of the Gentoo Linux x86 Handbook (architecture is irrelevant):"
4396         print
4397         print "http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked"
4398         print
4399
4400 def action_sync(settings, trees, mtimedb, myopts, myaction):
4401         xterm_titles = "notitles" not in settings.features
4402         emergelog(xterm_titles, " === sync")
4403         myportdir = settings.get("PORTDIR", None)
4404         if not myportdir:
4405                 sys.stderr.write("!!! PORTDIR is undefined.  Is /etc/make.globals missing?\n")
4406                 sys.exit(1)
4407         if myportdir[-1]=="/":
4408                 myportdir=myportdir[:-1]
4409         if not os.path.exists(myportdir):
4410                 print ">>>",myportdir,"not found, creating it."
4411                 os.makedirs(myportdir,0755)
4412         syncuri=settings["SYNC"].rstrip()
4413         os.umask(0022)
4414         updatecache_flg = False
4415         if myaction == "metadata":
4416                 print "skipping sync"
4417                 updatecache_flg = True
4418                 tmpservertimestampfile = None
4419         elif syncuri[:8]=="rsync://":
4420                 if not os.path.exists("/usr/bin/rsync"):
4421                         print "!!! /usr/bin/rsync does not exist, so rsync support is disabled."
4422                         print "!!! Type \"emerge net-misc/rsync\" to enable rsync support."
4423                         sys.exit(1)
4424                 mytimeout=180
4425
4426                 rsync_opts = []
4427                 import shlex, StringIO
4428                 if settings["PORTAGE_RSYNC_OPTS"] == "":
4429                         portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n")
4430                         rsync_opts.extend([
4431                                 "--recursive",    # Recurse directories
4432                                 "--links",        # Consider symlinks
4433                                 "--safe-links",   # Ignore links outside of tree
4434                                 "--perms",        # Preserve permissions
4435                                 "--times",        # Preserive mod times
4436                                 "--compress",     # Compress the data transmitted
4437                                 "--force",        # Force deletion on non-empty dirs
4438                                 "--whole-file",   # Don't do block transfers, only entire files
4439                                 "--delete",       # Delete files that aren't in the master tree
4440                                 "--delete-after", # Delete only after everything else is done
4441                                 "--stats",        # Show final statistics about what was transfered
4442                                 "--timeout="+str(mytimeout), # IO timeout if not done in X seconds
4443                                 "--exclude=/distfiles",   # Exclude distfiles from consideration
4444                                 "--exclude=/local",       # Exclude local     from consideration
4445                                 "--exclude=/packages",    # Exclude packages  from consideration
4446                                 "--filter=H_**/files/digest-*", # Exclude manifest1 digests and delete on the receiving side
4447                         ])
4448
4449                 else:
4450                         # The below validation is not needed when using the above hardcoded
4451                         # defaults.
4452
4453                         portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1)
4454                         lexer = shlex.shlex(StringIO.StringIO(
4455                                 settings.get("PORTAGE_RSYNC_OPTS","")), posix=True)
4456                         lexer.whitespace_split = True
4457                         rsync_opts.extend(lexer)
4458                         del lexer
4459
4460                         for opt in ("--recursive", "--times"):
4461                                 if opt not in rsync_opts:
4462                                         portage.writemsg(yellow("WARNING:") + " adding required option " + \
4463                                         "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
4464                                         rsync_opts.append(opt)
4465         
4466                         for exclude in ("distfiles", "local", "packages"):
4467                                 opt = "--exclude=/%s" % exclude
4468                                 if opt not in rsync_opts:
4469                                         portage.writemsg(yellow("WARNING:") + \
4470                                         " adding required option %s not included in "  % opt + \
4471                                         "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n")
4472                                         rsync_opts.append(opt)
4473         
4474                         if settings["RSYNC_TIMEOUT"] != "":
4475                                 portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \
4476                                 "use PORTAGE_RSYNC_EXTRA_OPTS instead\n")
4477                                 try:
4478                                         mytimeout = int(settings["RSYNC_TIMEOUT"])
4479                                         rsync_opts.append("--timeout=%d" % mytimeout)
4480                                 except ValueError, e:
4481                                         portage.writemsg("!!! %s\n" % str(e))
4482         
4483                         # TODO: determine options required for official servers
4484                         if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"):
4485
4486                                 def rsync_opt_startswith(opt_prefix):
4487                                         for x in rsync_opts:
4488                                                 if x.startswith(opt_prefix):
4489                                                         return True
4490                                         return False
4491
4492                                 if not rsync_opt_startswith("--timeout="):
4493                                         rsync_opts.append("--timeout=%d" % mytimeout)
4494
4495                                 for opt in ("--compress", "--whole-file"):
4496                                         if opt not in rsync_opts:
4497                                                 portage.writemsg(yellow("WARNING:") + " adding required option " + \
4498                                                 "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
4499                                                 rsync_opts.append(opt)
4500
4501                 if "--quiet" in myopts:
4502                         rsync_opts.append("--quiet")    # Shut up a lot
4503                 else:
4504                         rsync_opts.append("--verbose")  # Print filelist
4505
4506                 if "--verbose" in myopts:
4507                         rsync_opts.append("--progress")  # Progress meter for each file
4508
4509                 if "--debug" in myopts:
4510                         rsync_opts.append("--checksum") # Force checksum on all files
4511
4512                 if settings["RSYNC_EXCLUDEFROM"] != "":
4513                         portage.writemsg(yellow("WARNING:") + \
4514                         " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \
4515                         "PORTAGE_RSYNC_EXTRA_OPTS instead\n")
4516                         if os.path.exists(settings["RSYNC_EXCLUDEFROM"]):
4517                                 rsync_opts.append("--exclude-from=%s" % \
4518                                 settings["RSYNC_EXCLUDEFROM"])
4519                         else:
4520                                 portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \
4521                                 " but file does not exist.\n")
4522
4523                 if settings["RSYNC_RATELIMIT"] != "":
4524                         portage.writemsg(yellow("WARNING:") + \
4525                         " usage of RSYNC_RATELIMIT is deprecated, use " + \
4526                         "PORTAGE_RSYNC_EXTRA_OPTS instead")
4527                         rsync_opts.append("--bwlimit=%s" % \
4528                         settings["RSYNC_RATELIMIT"])
4529
4530                 # Real local timestamp file.
4531                 servertimestampfile = os.path.join(
4532                         myportdir, "metadata", "timestamp.chk")
4533                 # Temporary file for remote server timestamp comparison.
4534                 tmpservertimestampfile = os.path.join(
4535                         settings["PORTAGE_TMPDIR"], "timestamp.chk")
4536
4537                 content = portage.util.grabfile(servertimestampfile)
4538                 mytimestamp = 0
4539                 if content:
4540                         try:
4541                                 mytimestamp = time.mktime(time.strptime(content[0],
4542                                         "%a, %d %b %Y %H:%M:%S +0000"))
4543                         except (OverflowError, ValueError):
4544                                 pass
4545                 del content
4546
4547                 try:
4548                         rsync_initial_timeout = \
4549                                 int(settings.get("PORTAGE_RSYNC_INITIAL_TIMEOUT", "15"))
4550                 except ValueError:
4551                         rsync_initial_timeout = 15
4552
4553                 try:
4554                         if settings.has_key("RSYNC_RETRIES"):
4555                                 print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead"
4556                                 maxretries=int(settings["RSYNC_RETRIES"])                               
4557                         else:
4558                                 maxretries=int(settings["PORTAGE_RSYNC_RETRIES"])
4559                 except SystemExit, e:
4560                         raise # Needed else can't exit
4561                 except:
4562                         maxretries=3 #default number of retries
4563
4564                 retries=0
4565                 user_name, hostname, port = re.split(
4566                         "rsync://([^:/]+@)?([^:/]*)(:[0-9]+)?", syncuri, maxsplit=3)[1:4]
4567                 if port is None:
4568                         port=""
4569                 if user_name is None:
4570                         user_name=""
4571                 updatecache_flg=True
4572                 all_rsync_opts = set(rsync_opts)
4573                 lexer = shlex.shlex(StringIO.StringIO(
4574                         settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")), posix=True)
4575                 lexer.whitespace_split = True
4576                 extra_rsync_opts = list(lexer)
4577                 del lexer
4578                 all_rsync_opts.update(extra_rsync_opts)
4579                 family = socket.AF_INET
4580                 if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts:
4581                         family = socket.AF_INET
4582                 elif socket.has_ipv6 and \
4583                         ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
4584                         family = socket.AF_INET6
4585                 ips=[]
4586                 while (1):
4587                         if ips:
4588                                 del ips[0]
4589                         if ips==[]:
4590                                 try:
4591                                         for addrinfo in socket.getaddrinfo(
4592                                                 hostname, None, family, socket.SOCK_STREAM):
4593                                                 if addrinfo[0] == socket.AF_INET6:
4594                                                         # IPv6 addresses need to be enclosed in square brackets
4595                                                         ips.append("[%s]" % addrinfo[4][0])
4596                                                 else:
4597                                                         ips.append(addrinfo[4][0])
4598                                         from random import shuffle
4599                                         shuffle(ips)
4600                                 except SystemExit, e:
4601                                         raise # Needed else can't exit
4602                                 except Exception, e:
4603                                         print "Notice:",str(e)
4604                                         dosyncuri=syncuri
4605
4606                         if ips:
4607                                 try:
4608                                         dosyncuri = syncuri.replace(
4609                                                 "//" + user_name + hostname + port + "/",
4610                                                 "//" + user_name + ips[0] + port + "/", 1)
4611                                 except SystemExit, e:
4612                                         raise # Needed else can't exit
4613                                 except Exception, e:
4614                                         print "Notice:",str(e)
4615                                         dosyncuri=syncuri
4616
4617                         if (retries==0):
4618                                 if "--ask" in myopts:
4619                                         if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No":
4620                                                 print
4621                                                 print "Quitting."
4622                                                 print
4623                                                 sys.exit(0)
4624                                 emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri)
4625                                 if "--quiet" not in myopts:
4626                                         print ">>> Starting rsync with "+dosyncuri+"..."
4627                         else:
4628                                 emergelog(xterm_titles,
4629                                         ">>> Starting retry %d of %d with %s" % \
4630                                                 (retries,maxretries,dosyncuri))
4631                                 print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)
4632
4633                         if mytimestamp != 0 and "--quiet" not in myopts:
4634                                 print ">>> Checking server timestamp ..."
4635
4636                         rsynccommand = ["/usr/bin/rsync"] + rsync_opts + extra_rsync_opts
4637
4638                         if "--debug" in myopts:
4639                                 print rsynccommand
4640
4641                         exitcode = os.EX_OK
4642                         servertimestamp = 0
4643                         # Even if there's no timestamp available locally, fetch the
4644                         # timestamp anyway as an initial probe to verify that the server is
4645                         # responsive.  This protects us from hanging indefinitely on a
4646                         # connection attempt to an unresponsive server which rsync's
4647                         # --timeout option does not prevent.
4648                         if True:
4649                                 mycommand = rsynccommand[:]
4650                                 mycommand.append(dosyncuri.rstrip("/") + \
4651                                         "/metadata/timestamp.chk")
4652                                 mycommand.append(tmpservertimestampfile)
4653                                 content = None
4654                                 mypids = []
4655                                 try:
4656                                         def timeout_handler(signum, frame):
4657                                                 raise portage.exception.PortageException("timed out")
4658                                         signal.signal(signal.SIGALRM, timeout_handler)
4659                                         # Timeout here in case the server is unresponsive.  The
4660                                         # --timeout rsync option doesn't apply to the initial
4661                                         # connection attempt.
4662                                         if rsync_initial_timeout:
4663                                                 signal.alarm(rsync_initial_timeout)
4664                                         try:
4665                                                 mypids.extend(portage.process.spawn(
4666                                                         mycommand, env=settings.environ(), returnpid=True))
4667                                                 exitcode = os.waitpid(mypids[0], 0)[1]
4668                                                 content = portage.grabfile(tmpservertimestampfile)
4669                                         finally:
4670                                                 if rsync_initial_timeout:
4671                                                         signal.alarm(0)
4672                                                 try:
4673                                                         os.unlink(tmpservertimestampfile)
4674                                                 except OSError:
4675                                                         pass
4676                                 except portage.exception.PortageException, e:
4677                                         # timed out
4678                                         print e
4679                                         del e
4680                                         if mypids and os.waitpid(mypids[0], os.WNOHANG) == (0,0):
4681                                                 os.kill(mypids[0], signal.SIGTERM)
4682                                                 os.waitpid(mypids[0], 0)
4683                                         # This is the same code rsync uses for timeout.
4684                                         exitcode = 30
4685                                 else:
4686                                         if exitcode != os.EX_OK:
4687                                                 if exitcode & 0xff:
4688                                                         exitcode = (exitcode & 0xff) << 8
4689                                                 else:
4690                                                         exitcode = exitcode >> 8
4691                                 if mypids:
4692                                         portage.process.spawned_pids.remove(mypids[0])
4693                                 if content:
4694                                         try:
4695                                                 servertimestamp = time.mktime(time.strptime(
4696                                                         content[0], "%a, %d %b %Y %H:%M:%S +0000"))
4697                                         except (OverflowError, ValueError):
4698                                                 pass
4699                                 del mycommand, mypids, content
4700                         if exitcode == os.EX_OK:
4701                                 if (servertimestamp != 0) and (servertimestamp == mytimestamp):
4702                                         emergelog(xterm_titles,
4703                                                 ">>> Cancelling sync -- Already current.")
4704                                         print
4705                                         print ">>>"
4706                                         print ">>> Timestamps on the server and in the local repository are the same."
4707                                         print ">>> Cancelling all further sync action. You are already up to date."
4708                                         print ">>>"
4709                                         print ">>> In order to force sync, remove '%s'." % servertimestampfile
4710                                         print ">>>"
4711                                         print
4712                                         sys.exit(0)
4713                                 elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
4714                                         emergelog(xterm_titles,
4715                                                 ">>> Server out of date: %s" % dosyncuri)
4716                                         print
4717                                         print ">>>"
4718                                         print ">>> SERVER OUT OF DATE: %s" % dosyncuri
4719                                         print ">>>"
4720                                         print ">>> In order to force sync, remove '%s'." % servertimestampfile
4721                                         print ">>>"
4722                                         print
4723                                 elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
4724                                         # actual sync
4725                                         mycommand = rsynccommand + [dosyncuri+"/", myportdir]
4726                                         exitcode = portage.process.spawn(mycommand,
4727                                                 env=settings.environ())
4728                                         if exitcode in [0,1,3,4,11,14,20,21]:
4729                                                 break
4730                         elif exitcode in [1,3,4,11,14,20,21]:
4731                                 break
4732                         else:
4733                                 # Code 2 indicates protocol incompatibility, which is expected
4734                                 # for servers with protocol < 29 that don't support
4735                                 # --prune-empty-directories.  Retry for a server that supports
4736                                 # at least rsync protocol version 29 (>=rsync-2.6.4).
4737                                 pass
4738
4739                         retries=retries+1
4740
4741                         if retries<=maxretries:
4742                                 print ">>> Retrying..."
4743                                 time.sleep(11)
4744                         else:
4745                                 # over retries
4746                                 # exit loop
4747                                 updatecache_flg=False
4748                                 break
4749
4750                 if (exitcode==0):
4751                         emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri)
4752                 elif (exitcode>0):
4753                         print
4754                         if exitcode==1:
4755                                 print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure")
4756                                 print darkred("!!!")+green(" that your SYNC statement is proper.")
4757                                 print darkred("!!!")+green(" SYNC="+settings["SYNC"])
4758                         elif exitcode==11:
4759                                 print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally")
4760                                 print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption")
4761                                 print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate")
4762                                 print darkred("!!!")+green(" and try again after the problem has been fixed.")
4763                                 print darkred("!!!")+green(" PORTDIR="+settings["PORTDIR"])
4764                         elif exitcode==20:
4765                                 print darkred("!!!")+green(" Rsync was killed before it finished.")
4766                         else:
4767                                 print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep")
4768                                 print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable")
4769                                 print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a")
4770                                 print darkred("!!!")+green(" temporary problem unless complications exist with your network")
4771                                 print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.")
4772                         print
4773                         sys.exit(exitcode)
4774         elif syncuri[:6]=="cvs://":
4775                 if not os.path.exists("/usr/bin/cvs"):
4776                         print "!!! /usr/bin/cvs does not exist, so CVS support is disabled."
4777                         print "!!! Type \"emerge dev-util/cvs\" to enable CVS support."
4778                         sys.exit(1)
4779                 cvsroot=syncuri[6:]
4780                 cvsdir=os.path.dirname(myportdir)
4781                 if not os.path.exists(myportdir+"/CVS"):
4782                         #initial checkout
4783                         print ">>> Starting initial cvs checkout with "+syncuri+"..."
4784                         if os.path.exists(cvsdir+"/gentoo-x86"):
4785                                 print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting."
4786                                 sys.exit(1)
4787                         try:
4788                                 os.rmdir(myportdir)
4789                         except OSError, e:
4790                                 if e.errno != errno.ENOENT:
4791                                         sys.stderr.write(
4792                                                 "!!! existing '%s' directory; exiting.\n" % myportdir)
4793                                         sys.exit(1)
4794                                 del e
4795                         if portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",settings,free=1):
4796                                 print "!!! cvs checkout error; exiting."
4797                                 sys.exit(1)
4798                         os.rename(os.path.join(cvsdir, "gentoo-x86"), myportdir)
4799                 else:
4800                         #cvs update
4801                         print ">>> Starting cvs update with "+syncuri+"..."
4802                         retval = portage.spawn("cd '%s'; cvs -z0 -q update -dP" % \
4803                                 myportdir, settings, free=1)
4804                         if retval != os.EX_OK:
4805                                 sys.exit(retval)
4806                 dosyncuri = syncuri
4807         else:
4808                 print "!!! rsync setting: ",syncuri,"not recognized; exiting."
4809                 sys.exit(1)
4810
4811         if updatecache_flg and  \
4812                 myaction != "metadata" and \
4813                 "metadata-transfer" not in settings.features:
4814                 updatecache_flg = False
4815
4816         # Reload the whole config from scratch.
4817         settings, trees, mtimedb = load_emerge_config(trees=trees)
4818         portdb = trees[settings["ROOT"]]["porttree"].dbapi
4819
4820         if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
4821                 action_metadata(settings, portdb, myopts)
4822
4823         if portage._global_updates(trees, mtimedb["updates"]):
4824                 mtimedb.commit()
4825                 # Reload the whole config from scratch.
4826                 settings, trees, mtimedb = load_emerge_config(trees=trees)
4827                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
4828
4829         mybestpv = portdb.xmatch("bestmatch-visible", "sys-apps/portage")
4830         mypvs = portage.best(
4831                 trees[settings["ROOT"]]["vartree"].dbapi.match("sys-apps/portage"))
4832
4833         chk_updated_cfg_files("/", settings.get("CONFIG_PROTECT","").split())
4834
4835         if myaction != "metadata":
4836                 if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK):
4837                         retval = portage.process.spawn(
4838                                 [os.path.join(portage.USER_CONFIG_PATH, "bin", "post_sync"),
4839                                 dosyncuri], env=settings.environ())
4840                         if retval != os.EX_OK:
4841                                 print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync")
4842
4843         if(mybestpv != mypvs) and not "--quiet" in myopts:
4844                 print
4845                 print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
4846                 print red(" * ")+"that you update portage now, before any other packages are updated."
4847                 print
4848                 print red(" * ")+"To update portage, run 'emerge portage' now."
4849                 print
4850         
4851         display_news_notification(trees)
4852
4853 def action_metadata(settings, portdb, myopts):
4854         portage.writemsg_stdout("\n>>> Updating Portage cache:      ")
4855         old_umask = os.umask(0002)
4856         cachedir = os.path.normpath(settings.depcachedir)
4857         if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
4858                                         "/lib", "/opt", "/proc", "/root", "/sbin",
4859                                         "/sys", "/tmp", "/usr",  "/var"]:
4860                 print >> sys.stderr, "!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \
4861                         "ROOT DIRECTORY ON YOUR SYSTEM."
4862                 print >> sys.stderr, \
4863                         "!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir
4864                 sys.exit(73)
4865         if not os.path.exists(cachedir):
4866                 os.mkdir(cachedir)
4867
4868         ec = portage.eclass_cache.cache(portdb.porttree_root)
4869         myportdir = os.path.realpath(settings["PORTDIR"])
4870         cm = settings.load_best_module("portdbapi.metadbmodule")(
4871                 myportdir, "metadata/cache", portage.auxdbkeys[:])
4872
4873         from portage.cache import util
4874
4875         class percentage_noise_maker(util.quiet_mirroring):
4876                 def __init__(self, dbapi):
4877                         self.dbapi = dbapi
4878                         self.cp_all = dbapi.cp_all()
4879                         l = len(self.cp_all)
4880                         self.call_update_min = 100000000
4881                         self.min_cp_all = l/100.0
4882                         self.count = 1
4883                         self.pstr = ''
4884
4885                 def __iter__(self):
4886                         for x in self.cp_all:
4887                                 self.count += 1
4888                                 if self.count > self.min_cp_all:
4889                                         self.call_update_min = 0
4890                                         self.count = 0
4891                                 for y in self.dbapi.cp_list(x):
4892                                         yield y
4893                         self.call_update_mine = 0
4894
4895                 def update(self, *arg):
4896                         try:                            self.pstr = int(self.pstr) + 1
4897                         except ValueError:      self.pstr = 1
4898                         sys.stdout.write("%s%i%%" % \
4899                                 ("\b" * (len(str(self.pstr))+1), self.pstr))
4900                         sys.stdout.flush()
4901                         self.call_update_min = 10000000
4902
4903                 def finish(self, *arg):
4904                         sys.stdout.write("\b\b\b\b100%\n")
4905                         sys.stdout.flush()
4906
4907         if "--quiet" in myopts:
4908                 def quicky_cpv_generator(cp_all_list):
4909                         for x in cp_all_list:
4910                                 for y in portdb.cp_list(x):
4911                                         yield y
4912                 source = quicky_cpv_generator(portdb.cp_all())
4913                 noise_maker = portage.cache.util.quiet_mirroring()
4914         else:
4915                 noise_maker = source = percentage_noise_maker(portdb)
4916         portage.cache.util.mirror_cache(source, cm, portdb.auxdb[myportdir],
4917                 eclass_cache=ec, verbose_instance=noise_maker)
4918
4919         sys.stdout.flush()
4920         os.umask(old_umask)
4921
4922 def action_regen(settings, portdb):
4923         xterm_titles = "notitles" not in settings.features
4924         emergelog(xterm_titles, " === regen")
4925         #regenerate cache entries
4926         print "Regenerating cache entries... "
4927         try:
4928                 os.close(sys.stdin.fileno())
4929         except SystemExit, e:
4930                 raise # Needed else can't exit
4931         except:
4932                 pass
4933         sys.stdout.flush()
4934         mynodes = portdb.cp_all()
4935         from portage.cache.cache_errors import CacheError
4936         dead_nodes = {}
4937         for mytree in portdb.porttrees:
4938                 try:
4939                         dead_nodes[mytree] = set(portdb.auxdb[mytree].iterkeys())
4940                 except CacheError, e:
4941                         print "\n  error listing cache entries for " + \
4942                                 "'%s': %s, continuing..." % (mytree, e)
4943                         del e
4944                         dead_nodes = None
4945                         break
4946         for x in mynodes:
4947                 mymatches = portdb.cp_list(x)
4948                 portage.writemsg_stdout("processing %s\n" % x)
4949                 for y in mymatches:
4950                         try:
4951                                 foo = portdb.aux_get(y,["DEPEND"])
4952                         except SystemExit, e:
4953                                 # sys.exit is an exception... And consequently, we can't catch it.
4954                                 raise
4955                         except Exception, e:
4956                                 print "\n  error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)}
4957                         if dead_nodes:
4958                                 for mytree in portdb.porttrees:
4959                                         if portdb.findname2(y, mytree=mytree)[0]:
4960                                                 dead_nodes[mytree].discard(y)
4961         if dead_nodes:
4962                 for mytree, nodes in dead_nodes.iteritems():
4963                         auxdb = portdb.auxdb[mytree]
4964                         for y in nodes:
4965                                 try:
4966                                         del auxdb[y]
4967                                 except (KeyError, CacheError):
4968                                         pass
4969         print "done!"
4970
4971 def action_config(settings, trees, myopts, myfiles):
4972         if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles:
4973                 print red("!!! config can only take a single package atom at this time\n")
4974                 sys.exit(1)
4975         if not is_valid_package_atom(myfiles[0]):
4976                 portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0],
4977                         noiselevel=-1)
4978                 portage.writemsg("!!! Please check ebuild(5) for full details.\n")
4979                 portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
4980                 sys.exit(1)
4981         print
4982         try:
4983                 pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0])
4984         except ValueError, e:
4985                 # Multiple matches thrown from cpv_expand
4986                 pkgs = e.args[0]
4987         if len(pkgs) == 0:
4988                 print "No packages found.\n"
4989                 sys.exit(0)
4990         elif len(pkgs) > 1:
4991                 if "--ask" in myopts:
4992                         options = []
4993                         print "Please select a package to configure:"
4994                         idx = 0
4995                         for pkg in pkgs:
4996                                 idx += 1
4997                                 options.append(str(idx))
4998                                 print options[-1]+") "+pkg
4999                         print "X) Cancel"
5000                         options.append("X")
5001                         idx = userquery("Selection?", options)
5002                         if idx == "X":
5003                                 sys.exit(0)
5004                         pkg = pkgs[int(idx)-1]
5005                 else:
5006                         print "The following packages available:"
5007                         for pkg in pkgs:
5008                                 print "* "+pkg
5009                         print "\nPlease use a specific atom or the --ask option."
5010                         sys.exit(1)
5011         else:
5012                 pkg = pkgs[0]
5013
5014         print
5015         if "--ask" in myopts:
5016                 if userquery("Ready to configure "+pkg+"?") == "No":
5017                         sys.exit(0)
5018         else:
5019                 print "Configuring pkg..."
5020         print
5021         ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg)
5022         mysettings = portage.config(clone=settings)
5023         portage.doebuild(ebuildpath, "config", settings["ROOT"], mysettings,
5024                 debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True,
5025                 mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree")
5026         print
5027
5028 def action_info(settings, trees, myopts, myfiles):
5029         unameout=commands.getstatusoutput("uname -mrp")[1]
5030         print getportageversion(settings["PORTDIR"], settings["ROOT"],
5031                 settings.profile_path, settings["CHOST"],
5032                 trees[settings["ROOT"]]["vartree"].dbapi)
5033         header_width = 65
5034         header_title = "System Settings"
5035         if myfiles:
5036                 print header_width * "="
5037                 print header_title.rjust(int(header_width/2 + len(header_title)/2))
5038         print header_width * "="
5039         print "System uname: "+unameout
5040         gentoo_release = portage.grabfile(os.path.join(
5041                 settings["PORTAGE_CONFIGROOT"], "etc", "gentoo-release"))
5042         if gentoo_release:
5043                 print gentoo_release[0]
5044         else:
5045                 print "Unknown Host Operating System"
5046         lastSync = portage.grabfile(os.path.join(
5047                 settings["PORTDIR"], "metadata", "timestamp.chk"))
5048         print "Timestamp of tree:",
5049         if lastSync:
5050                 print lastSync[0]
5051         else:
5052                 print "Unknown"
5053
5054         output=commands.getstatusoutput("distcc --version")
5055         if not output[0]:
5056                 print str(output[1].split("\n",1)[0]),
5057                 if "distcc" in settings.features:
5058                         print "[enabled]"
5059                 else:
5060                         print "[disabled]"
5061
5062         output=commands.getstatusoutput("ccache -V")
5063         if not output[0]:
5064                 print str(output[1].split("\n",1)[0]),
5065                 if "ccache" in settings.features:
5066                         print "[enabled]"
5067                 else:
5068                         print "[disabled]"
5069
5070         myvars  = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
5071                    "sys-devel/binutils", "sys-devel/libtool",  "dev-lang/python"]
5072         myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs")
5073         myvars  = portage.util.unique_array(myvars)
5074         myvars.sort()
5075
5076         for x in myvars:
5077                 if portage.isvalidatom(x):
5078                         pkg_matches = trees["/"]["vartree"].dbapi.match(x)
5079                         pkg_matches = [portage.catpkgsplit(cpv)[1:] for cpv in pkg_matches]
5080                         pkg_matches.sort(portage.pkgcmp)
5081                         pkgs = []
5082                         for pn, ver, rev in pkg_matches:
5083                                 if rev != "r0":
5084                                         pkgs.append(ver + "-" + rev)
5085                                 else:
5086                                         pkgs.append(ver)
5087                         if pkgs:
5088                                 pkgs = ", ".join(pkgs)
5089                                 print "%-20s %s" % (x+":", pkgs)
5090                 else:
5091                         print "%-20s %s" % (x+":", "[NOT VALID]")
5092
5093         libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool"))
5094
5095         if "--verbose" in myopts:
5096                 myvars=settings.keys()
5097         else:
5098                 myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
5099                           'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
5100                           'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
5101                           'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS']
5102
5103                 myvars.extend(portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_vars"))
5104
5105         myvars = portage.util.unique_array(myvars)
5106         unset_vars = []
5107         myvars.sort()
5108         for x in myvars:
5109                 if x in settings:
5110                         if x != "USE":
5111                                 print '%s="%s"' % (x, settings[x])
5112                         else:
5113                                 use = set(settings["USE"].split())
5114                                 use_expand = settings["USE_EXPAND"].split()
5115                                 use_expand.sort()
5116                                 for varname in use_expand:
5117                                         flag_prefix = varname.lower() + "_"
5118                                         for f in list(use):
5119                                                 if f.startswith(flag_prefix):
5120                                                         use.remove(f)
5121                                 use = list(use)
5122                                 use.sort()
5123                                 print 'USE="%s"' % " ".join(use),
5124                                 for varname in use_expand:
5125                                         myval = settings.get(varname)
5126                                         if myval:
5127                                                 print '%s="%s"' % (varname, myval),
5128                                 print
5129                 else:
5130                         unset_vars.append(x)
5131         if unset_vars:
5132                 print "Unset:  "+", ".join(unset_vars)
5133         print
5134
5135         if "--debug" in myopts:
5136                 for x in dir(portage):
5137                         module = getattr(portage, x)
5138                         if "cvs_id_string" in dir(module):
5139                                 print "%s: %s" % (str(x), str(module.cvs_id_string))
5140
5141         # See if we can find any packages installed matching the strings
5142         # passed on the command line
5143         mypkgs = []
5144         vardb = trees[settings["ROOT"]]["vartree"].dbapi
5145         portdb = trees[settings["ROOT"]]["porttree"].dbapi
5146         for x in myfiles:
5147                 mypkgs.extend(vardb.match(x))
5148
5149         # If some packages were found...
5150         if mypkgs:
5151                 # Get our global settings (we only print stuff if it varies from
5152                 # the current config)
5153                 mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS' ]
5154                 auxkeys = mydesiredvars + [ "USE", "IUSE"]
5155                 global_vals = {}
5156                 pkgsettings = portage.config(clone=settings)
5157
5158                 for myvar in mydesiredvars:
5159                         global_vals[myvar] = set(settings.get(myvar, "").split())
5160
5161                 # Loop through each package
5162                 # Only print settings if they differ from global settings
5163                 header_title = "Package Settings"
5164                 print header_width * "="
5165                 print header_title.rjust(int(header_width/2 + len(header_title)/2))
5166                 print header_width * "="
5167                 from portage.output import EOutput
5168                 out = EOutput()
5169                 for pkg in mypkgs:
5170                         # Get all package specific variables
5171                         auxvalues = vardb.aux_get(pkg, auxkeys)
5172                         valuesmap = {}
5173                         for i in xrange(len(auxkeys)):
5174                                 valuesmap[auxkeys[i]] = set(auxvalues[i].split())
5175                         diff_values = {}
5176                         for myvar in mydesiredvars:
5177                                 # If the package variable doesn't match the
5178                                 # current global variable, something has changed
5179                                 # so set diff_found so we know to print
5180                                 if valuesmap[myvar] != global_vals[myvar]:
5181                                         diff_values[myvar] = valuesmap[myvar]
5182                         valuesmap["IUSE"] = set(filter_iuse_defaults(valuesmap["IUSE"]))
5183                         valuesmap["USE"] = valuesmap["USE"].intersection(valuesmap["IUSE"])
5184                         pkgsettings.reset()
5185                         # If a matching ebuild is no longer available in the tree, maybe it
5186                         # would make sense to compare against the flags for the best
5187                         # available version with the same slot?
5188                         mydb = None
5189                         if portdb.cpv_exists(pkg):
5190                                 mydb = portdb
5191                         pkgsettings.setcpv(pkg, mydb=mydb)
5192                         if valuesmap["IUSE"].intersection(pkgsettings["USE"].split()) != \
5193                                 valuesmap["USE"]:
5194                                 diff_values["USE"] = valuesmap["USE"]
5195                         # If a difference was found, print the info for
5196                         # this package.
5197                         if diff_values:
5198                                 # Print package info
5199                                 print "%s was built with the following:" % pkg
5200                                 for myvar in mydesiredvars + ["USE"]:
5201                                         if myvar in diff_values:
5202                                                 mylist = list(diff_values[myvar])
5203                                                 mylist.sort()
5204                                                 print "%s=\"%s\"" % (myvar, " ".join(mylist))
5205                                 print
5206                         print ">>> Attempting to run pkg_info() for '%s'" % pkg
5207                         ebuildpath = vardb.findname(pkg)
5208                         if not ebuildpath or not os.path.exists(ebuildpath):
5209                                 out.ewarn("No ebuild found for '%s'" % pkg)
5210                                 continue
5211                         portage.doebuild(ebuildpath, "info", pkgsettings["ROOT"],
5212                                 pkgsettings, debug=(settings.get("PORTAGE_DEBUG", "") == 1),
5213                                 mydbapi=trees[settings["ROOT"]]["vartree"].dbapi,
5214                                 tree="vartree")
5215
5216 def action_search(settings, portdb, vartree, myopts, myfiles, spinner):
5217         if not myfiles:
5218                 print "emerge: no search terms provided."
5219         else:
5220                 searchinstance = search(settings, portdb,
5221                         vartree, spinner, "--searchdesc" in myopts,
5222                         "--quiet" not in myopts)
5223                 for mysearch in myfiles:
5224                         try:
5225                                 searchinstance.execute(mysearch)
5226                         except re.error, comment:
5227                                 print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment )
5228                                 sys.exit(1)
5229                         searchinstance.output()
5230
5231 def action_depclean(settings, trees, ldpath_mtimes,
5232         myopts, spinner):
5233         # Kill packages that aren't explicitly merged or are required as a
5234         # dependency of another package. World file is explicit.
5235
5236         msg = []
5237         msg.append("Depclean may break link level dependencies.  Thus, it is\n")
5238         msg.append("recommended to use a tool such as " + good("`revdep-rebuild`") + " (from\n")
5239         msg.append("app-portage/gentoolkit) in order to detect such breakage.\n")
5240         msg.append("\n")
5241         msg.append("Also study the list of packages to be cleaned for any obvious\n")
5242         msg.append("mistakes. Packages that are part of the world set will always\n")
5243         msg.append("be kept.  They can be manually added to this set with\n")
5244         msg.append(good("`emerge --noreplace <atom>`") + ".  Packages that are listed in\n")
5245         msg.append("package.provided (see portage(5)) will be removed by\n")
5246         msg.append("depclean, even if they are part of the world set.\n")
5247         msg.append("\n")
5248         msg.append("As a safety measure, depclean will not remove any packages\n")
5249         msg.append("unless *all* required dependencies have been resolved.  As a\n")
5250         msg.append("consequence, it is often necessary to run\n")
5251         msg.append(good("`emerge --update --newuse --deep world`") + " prior to depclean.\n")
5252
5253         portage.writemsg_stdout("\n")
5254         for x in msg:
5255                 portage.writemsg_stdout(colorize("BAD", "*** WARNING ***  ") + x)
5256
5257         xterm_titles = "notitles" not in settings.features
5258         myroot = settings["ROOT"]
5259         portdb = trees[myroot]["porttree"].dbapi
5260         dep_check_trees = {}
5261         dep_check_trees[myroot] = {}
5262         dep_check_trees[myroot]["vartree"] = \
5263                 FakeVartree(trees[myroot]["vartree"], trees[myroot]["porttree"].dbapi)
5264         vardb = dep_check_trees[myroot]["vartree"].dbapi
5265         # Constrain dependency selection to the installed packages.
5266         dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"]
5267         system_set = SystemSet("system", settings.profiles)
5268         syslist = list(system_set)
5269         world_set = WorldSet("world", myroot)
5270         worldlist = list(world_set)
5271         fakedb = portage.fakedbapi(settings=settings)
5272         myvarlist = vardb.cpv_all()
5273
5274         if not syslist:
5275                 print "\n!!! You have no system list.",
5276         if not worldlist:
5277                 print "\n!!! You have no world file.",
5278         if not myvarlist:
5279                 print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH,
5280
5281         if not (syslist and worldlist and myvarlist):
5282                 print "\n!!! Proceeding "+(syslist and myvarlist and "may" or "will")
5283                 print " break your installation.\n"
5284                 if "--pretend" not in myopts:
5285                         countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean")
5286
5287         if not "--pretend" in myopts: #just check pretend, since --ask implies pretend
5288                 emergelog(xterm_titles, " >>> depclean")
5289
5290         if "--quiet" not in myopts:
5291                 print "\nCalculating dependencies  ",
5292
5293         soft = 0
5294         hard = 1
5295         remaining_atoms = [(atom, 'world', hard) for atom in worldlist if vardb.match(atom)]
5296         remaining_atoms += [(atom, 'system', hard) for atom in syslist if vardb.match(atom)]
5297         unresolveable = {}
5298         aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
5299         metadata_keys = ["PROVIDE", "SLOT", "USE"]
5300
5301         while remaining_atoms:
5302                 atom, parent, priority = remaining_atoms.pop()
5303                 pkgs = vardb.match(atom)
5304                 if not pkgs:
5305                         if not atom.startswith("!") and priority == hard:
5306                                 unresolveable.setdefault(atom, []).append(parent)
5307                         continue
5308                 if len(pkgs) > 1 and parent != "world":
5309                         # Prune all but the best matching slot, since that's all that a
5310                         # deep world update would pull in.  Don't prune if this atom comes
5311                         # directly from world though, since world atoms are greedy when
5312                         # they don't specify a slot.
5313                         visible_in_portdb = [cpv for cpv in pkgs if portdb.match("="+cpv)]
5314                         if visible_in_portdb:
5315                                 # For consistency with the update algorithm, keep the highest
5316                                 # visible version and prune any versions that are either masked
5317                                 # or no longer exist in the portage tree.
5318                                 pkgs = visible_in_portdb
5319                         pkgs = [portage.best(pkgs)]
5320                 for pkg in pkgs:
5321                         if fakedb.cpv_exists(pkg):
5322                                 continue
5323                         spinner.update()
5324                         fakedb.cpv_inject(pkg)
5325                         myaux = dict(izip(aux_keys, vardb.aux_get(pkg, aux_keys)))
5326                         mydeps = []
5327                         if myopts.get("--with-bdeps", "y") == "y":
5328                                 mydeps.append((myaux["DEPEND"], soft))
5329                         del myaux["DEPEND"]
5330                         mydeps.append((" ".join(myaux.values()), hard))
5331                         usedef = vardb.aux_get(pkg, ["USE"])[0].split()
5332                         for depstr, priority in mydeps:
5333
5334                                 if not depstr:
5335                                         continue
5336
5337                                 if "--debug" in myopts:
5338                                         print
5339                                         print "Parent:   ", pkg
5340                                         print "Depstring:", depstr
5341                                         print "Priority:",
5342                                         if priority == soft:
5343                                                 print "soft"
5344                                         else:
5345                                                 print "hard"
5346
5347                                 try:
5348                                         portage.dep._dep_check_strict = False
5349                                         success, atoms = portage.dep_check(depstr, None, settings,
5350                                                 myuse=usedef, trees=dep_check_trees, myroot=myroot)
5351                                 finally:
5352                                         portage.dep._dep_check_strict = True
5353                                 if not success:
5354                                         show_invalid_depstring_notice(
5355                                                 ("installed", myroot, pkg, "nomerge"),
5356                                                 depstr, atoms)
5357                                         return
5358
5359                                 if "--debug" in myopts:
5360                                         print "Candidates:", atoms
5361
5362                                 for atom in atoms:
5363                                         remaining_atoms.append((atom, pkg, priority))
5364
5365         if "--quiet" not in myopts:
5366                 print "\b\b... done!\n"
5367
5368         if unresolveable:
5369                 print "Dependencies could not be completely resolved due to"
5370                 print "the following required packages not being installed:"
5371                 print
5372                 for atom in unresolveable:
5373                         print atom, "required by", " ".join(unresolveable[atom])
5374                 print
5375                 print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to"
5376                 print "depclean?  It may be necessary to manually uninstall packages that no longer"
5377                 print "exist in the portage tree since it may not be possible to satisfy their"
5378                 print "dependencies.  Also, be aware of the --with-bdeps option that is documented"
5379                 print "in " + good("`man emerge`") + "."
5380                 print
5381                 return
5382
5383         cleanlist = [pkg for pkg in vardb.cpv_all() if not fakedb.cpv_exists(pkg)]
5384
5385         if len(cleanlist):
5386                 unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"],
5387                         "unmerge", cleanlist, ldpath_mtimes)
5388
5389         print "Packages installed:   "+str(len(myvarlist))
5390         print "Packages in world:    "+str(len(worldlist))
5391         print "Packages in system:   "+str(len(syslist))
5392         print "Unique package names: "+str(len(myvarlist))
5393         print "Required packages:    "+str(len(fakedb.cpv_all()))
5394         if "--pretend" in myopts:
5395                 print "Number to remove:     "+str(len(cleanlist))
5396         else:
5397                 print "Number removed:       "+str(len(cleanlist))
5398
5399 def action_build(settings, trees, mtimedb,
5400         myopts, myaction, myfiles, spinner):
5401         ldpath_mtimes = mtimedb["ldpath"]
5402         favorites=[]
5403         merge_count = 0
5404         pretend = "--pretend" in myopts
5405         fetchonly = "--fetchonly" in myopts or "--fetch-all-uri" in myopts
5406         if pretend or fetchonly:
5407                 # make the mtimedb readonly
5408                 mtimedb.filename = None
5409         if "--quiet" not in myopts and \
5410                 ("--pretend" in myopts or "--ask" in myopts or \
5411                 "--tree" in myopts or "--verbose" in myopts):
5412                 action = ""
5413                 if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
5414                         action = "fetched"
5415                 else:
5416                         action = "merged"
5417                 if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching
5418                         print
5419                         print darkgreen("These are the packages that would be %s, in reverse order:") % action
5420                         print
5421                 else:
5422                         print
5423                         print darkgreen("These are the packages that would be %s, in order:") % action
5424                         print
5425
5426         # validate the state of the resume data
5427         # so that we can make assumptions later.
5428         for k in ("resume", "resume_backup"):
5429                 if k in mtimedb:
5430                         if "mergelist" in mtimedb[k]:
5431                                 if not mtimedb[k]["mergelist"]:
5432                                         del mtimedb[k]
5433                         else:
5434                                 del mtimedb[k]
5435
5436         if "--resume" in myopts and \
5437                 ("resume" in mtimedb or
5438                 "resume_backup" in mtimedb):
5439                 if "resume" not in mtimedb:
5440                         mtimedb["resume"] = mtimedb["resume_backup"]
5441                         del mtimedb["resume_backup"]
5442                         mtimedb.commit()
5443
5444                 # Adjust config according to options of the command being resumed.
5445                 for myroot in trees:
5446                         mysettings =  trees[myroot]["vartree"].settings
5447                         mysettings.unlock()
5448                         adjust_config(myopts, mysettings)
5449                         mysettings.lock()
5450                         del myroot, mysettings
5451
5452                 # "myopts" is a list for backward compatibility.
5453                 resume_opts = mtimedb["resume"].get("myopts", [])
5454                 if isinstance(resume_opts, list):
5455                         resume_opts = dict((k,True) for k in resume_opts)
5456                 for opt in ("--skipfirst", "--ask", "--tree"):
5457                         resume_opts.pop(opt, None)
5458                 myopts.update(resume_opts)
5459                 show_spinner = "--quiet" not in myopts and "--nodeps" not in myopts
5460                 if not show_spinner:
5461                         spinner.update = spinner.update_quiet
5462                 if show_spinner:
5463                         print "Calculating dependencies  ",
5464                 myparams = create_depgraph_params(myopts, myaction)
5465                 mydepgraph = depgraph(settings, trees,
5466                         myopts, myparams, spinner)
5467                 try:
5468                         mydepgraph.loadResumeCommand(mtimedb["resume"])
5469                 except portage.exception.PackageNotFound:
5470                         if show_spinner:
5471                                 print
5472                         from portage.output import EOutput
5473                         out = EOutput()
5474                         out.eerror("Error: The resume list contains packages that are no longer")
5475                         out.eerror("       available to be emerged. Please restart/continue")
5476                         out.eerror("       the merge operation manually.")
5477                         return 1
5478                 if show_spinner:
5479                         print "\b\b... done!"
5480         else:
5481                 if ("--resume" in myopts):
5482                         print darkgreen("emerge: It seems we have nothing to resume...")
5483                         return os.EX_OK
5484
5485                 myparams = create_depgraph_params(myopts, myaction)
5486                 if myaction in ["system","world"]:
5487                         if "--quiet" not in myopts and "--nodeps" not in myopts:
5488                                 print "Calculating",myaction,"dependencies  ",
5489                                 sys.stdout.flush()
5490                         mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
5491                         if not mydepgraph.xcreate(myaction):
5492                                 print "!!! Depgraph creation failed."
5493                                 return 1
5494                         if "--quiet" not in myopts and "--nodeps" not in myopts:
5495                                 print "\b\b... done!"
5496                 else:
5497                         if "--quiet" not in myopts and "--nodeps" not in myopts:
5498                                 print "Calculating dependencies  ",
5499                                 sys.stdout.flush()
5500                         mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
5501                         try:
5502                                 retval, favorites = mydepgraph.select_files(myfiles)
5503                         except portage.exception.PackageNotFound, e:
5504                                 portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
5505                                 return 1
5506                         if not retval:
5507                                 return 1
5508                         if "--quiet" not in myopts and "--nodeps" not in myopts:
5509                                 print "\b\b... done!"
5510
5511                         if ("--usepkgonly" in myopts) and mydepgraph.missingbins:
5512                                 sys.stderr.write(red("The following binaries are not available for merging...\n"))
5513
5514                 if mydepgraph.missingbins:
5515                         for x in mydepgraph.missingbins:
5516                                 sys.stderr.write("   "+str(x)+"\n")
5517                         sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
5518                         return 1
5519
5520         if "--pretend" not in myopts and \
5521                 ("--ask" in myopts or "--tree" in myopts or \
5522                 "--verbose" in myopts) and \
5523                 not ("--quiet" in myopts and "--ask" not in myopts):
5524                 if "--resume" in myopts:
5525                         mymergelist = mtimedb["resume"]["mergelist"]
5526                         if "--skipfirst" in myopts:
5527                                 mymergelist = mymergelist[1:]
5528                         if len(mymergelist) == 0:
5529                                 print colorize("INFORM", "emerge: It seems we have nothing to resume...")
5530                                 return os.EX_OK
5531                         favorites = mtimedb["resume"]["favorites"]
5532                         retval = mydepgraph.display(mymergelist, favorites=favorites)
5533                         if retval != os.EX_OK:
5534                                 return retval
5535                         prompt="Would you like to resume merging these packages?"
5536                 else:
5537                         retval = mydepgraph.display(
5538                                 mydepgraph.altlist(reversed=("--tree" in myopts)),
5539                                 favorites=favorites)
5540                         if retval != os.EX_OK:
5541                                 return retval
5542                         mergecount=0
5543                         for x in mydepgraph.altlist():
5544                                 if x[0] != "blocks" and x[3] != "nomerge":
5545                                         mergecount+=1
5546                                 #check for blocking dependencies
5547                                 if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts:
5548                                         print "\n!!! Error: The above package list contains packages which cannot be installed"
5549                                         print   "!!!        at the same time on the same system."
5550                                         if "--quiet" not in myopts:
5551                                                 show_blocker_docs_link()
5552                                         return 1
5553                         if mergecount==0:
5554                                 if "--noreplace" in myopts and favorites:
5555                                         print
5556                                         for x in favorites:
5557                                                 print " %s %s" % (good("*"), x)
5558                                         prompt="Would you like to add these packages to your world favorites?"
5559                                 elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
5560                                         prompt="Nothing to merge; would you like to auto-clean packages?"
5561                                 else:
5562                                         print
5563                                         print "Nothing to merge; quitting."
5564                                         print
5565                                         return os.EX_OK
5566                         elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
5567                                 prompt="Would you like to fetch the source files for these packages?"
5568                         else:
5569                                 prompt="Would you like to merge these packages?"
5570                 print
5571                 if "--ask" in myopts and userquery(prompt) == "No":
5572                         print
5573                         print "Quitting."
5574                         print
5575                         return os.EX_OK
5576                 # Don't ask again (e.g. when auto-cleaning packages after merge)
5577                 myopts.pop("--ask", None)
5578
5579         if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
5580                 if ("--resume" in myopts):
5581                         mymergelist = mtimedb["resume"]["mergelist"]
5582                         if "--skipfirst" in myopts:
5583                                 mymergelist = mymergelist[1:]
5584                         if len(mymergelist) == 0:
5585                                 print colorize("INFORM", "emerge: It seems we have nothing to resume...")
5586                                 return os.EX_OK
5587                         favorites = mtimedb["resume"]["favorites"]
5588                         retval = mydepgraph.display(mymergelist, favorites=favorites)
5589                         if retval != os.EX_OK:
5590                                 return retval
5591                 else:
5592                         retval = mydepgraph.display(
5593                                 mydepgraph.altlist(reversed=("--tree" in myopts)),
5594                                 favorites=favorites)
5595                         if retval != os.EX_OK:
5596                                 return retval
5597                         if "--buildpkgonly" in myopts and \
5598                                 not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
5599                                         print "\n!!! --buildpkgonly requires all dependencies to be merged."
5600                                         print "!!! You have to merge the dependencies before you can build this package.\n"
5601                                         return 1
5602         else:
5603                 if ("--buildpkgonly" in myopts):
5604                         if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
5605                                 print "\n!!! --buildpkgonly requires all dependencies to be merged."
5606                                 print "!!! Cannot merge requested packages. Merge deps and try again.\n"
5607                                 return 1
5608
5609                 if ("--resume" in myopts):
5610                         favorites=mtimedb["resume"]["favorites"]
5611                         mergetask = MergeTask(settings, trees, myopts)
5612                         if "--fetchonly" in myopts:
5613                                 """ parallel-fetch uses --resume --fetchonly and we don't want
5614                                 it to write the mtimedb"""
5615                                 mtimedb.filename = None
5616                                 time.sleep(3) # allow the parent to have first fetch
5617                         del mydepgraph
5618                         retval = mergetask.merge(
5619                                 mtimedb["resume"]["mergelist"], favorites, mtimedb)
5620                         merge_count = mergetask.curval
5621                 else:
5622                         if "resume" in mtimedb and \
5623                         "mergelist" in mtimedb["resume"] and \
5624                         len(mtimedb["resume"]["mergelist"]) > 1:
5625                                 mtimedb["resume_backup"] = mtimedb["resume"]
5626                                 del mtimedb["resume"]
5627                                 mtimedb.commit()
5628                         mtimedb["resume"]={}
5629                         # XXX: Stored as a list for backward compatibility.
5630                         mtimedb["resume"]["myopts"] = \
5631                                 [k for k in myopts if myopts[k] is True]
5632                         mtimedb["resume"]["favorites"]=favorites
5633                         if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
5634                                 for pkgline in mydepgraph.altlist():
5635                                         if pkgline[0]=="ebuild" and pkgline[3]=="merge":
5636                                                 y = trees[pkgline[1]]["porttree"].dbapi.findname(pkgline[2])
5637                                                 tmpsettings = portage.config(clone=settings)
5638                                                 edebug = 0
5639                                                 if settings.get("PORTAGE_DEBUG", "") == "1":
5640                                                         edebug = 1
5641                                                 retval = portage.doebuild(
5642                                                         y, "digest", settings["ROOT"], tmpsettings, edebug,
5643                                                         ("--pretend" in myopts),
5644                                                         mydbapi=trees[pkgline[1]]["porttree"].dbapi,
5645                                                         tree="porttree")
5646                         if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
5647                                 pkglist = []
5648                                 for pkg in mydepgraph.altlist():
5649                                         if pkg[0] != "blocks":
5650                                                 pkglist.append(pkg)
5651                         else:
5652                                 pkglist = mydepgraph.altlist()
5653                         if favorites:
5654                                 mydepgraph.saveNomergeFavorites()
5655                         del mydepgraph
5656                         mergetask = MergeTask(settings, trees, myopts)
5657                         retval = mergetask.merge(pkglist, favorites, mtimedb)
5658                         merge_count = mergetask.curval
5659
5660                 if retval == os.EX_OK and not (pretend or fetchonly):
5661                         mtimedb.pop("resume", None)
5662                         if "yes" == settings.get("AUTOCLEAN"):
5663                                 portage.writemsg_stdout(">>> Auto-cleaning packages...\n")
5664                                 vartree = trees[settings["ROOT"]]["vartree"]
5665                                 unmerge(settings, myopts, vartree, "clean", ["world"],
5666                                         ldpath_mtimes, autoclean=1)
5667                         else:
5668                                 portage.writemsg_stdout(colorize("WARN", "WARNING:")
5669                                         + " AUTOCLEAN is disabled.  This can cause serious"
5670                                         + " problems due to overlapping packages.\n")
5671
5672                 if merge_count and not (pretend or fetchonly):
5673                         post_emerge(trees, mtimedb, retval)
5674                 return retval
5675
5676 def multiple_actions(action1, action2):
5677         sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
5678         sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
5679         sys.exit(1)
5680
5681 def parse_opts(tmpcmdline, silent=False):
5682         myaction=None
5683         myopts = {}
5684         myfiles=[]
5685
5686         global actions, options, shortmapping
5687
5688         longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
5689         argument_options = {
5690                 "--config-root": {
5691                         "help":"specify the location for portage configuration files",
5692                         "action":"store"
5693                 },
5694                 "--color": {
5695                         "help":"enable or disable color output",
5696                         "type":"choice",
5697                         "choices":("y", "n")
5698                 },
5699                 "--with-bdeps": {
5700                         "help":"include unnecessary build time dependencies",
5701                         "type":"choice",
5702                         "choices":("y", "n")
5703                 },
5704                 "--reinstall": {
5705                         "help":"specify conditions to trigger package reinstallation",
5706                         "type":"choice",
5707                         "choices":["changed-use"]
5708                 }
5709         }
5710
5711         from optparse import OptionParser
5712         parser = OptionParser()
5713         if parser.has_option("--help"):
5714                 parser.remove_option("--help")
5715
5716         for action_opt in actions:
5717                 parser.add_option("--" + action_opt, action="store_true",
5718                         dest=action_opt.replace("-", "_"), default=False)
5719         for myopt in options:
5720                 parser.add_option(myopt, action="store_true",
5721                         dest=myopt.lstrip("--").replace("-", "_"), default=False)
5722         for shortopt, longopt in shortmapping.iteritems():
5723                 parser.add_option("-" + shortopt, action="store_true",
5724                         dest=longopt.lstrip("--").replace("-", "_"), default=False)
5725         for myalias, myopt in longopt_aliases.iteritems():
5726                 parser.add_option(myalias, action="store_true",
5727                         dest=myopt.lstrip("--").replace("-", "_"), default=False)
5728
5729         for myopt, kwargs in argument_options.iteritems():
5730                 parser.add_option(myopt,
5731                         dest=myopt.lstrip("--").replace("-", "_"), **kwargs)
5732
5733         myoptions, myargs = parser.parse_args(args=tmpcmdline)
5734
5735         for myopt in options:
5736                 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"))
5737                 if v:
5738                         myopts[myopt] = True
5739
5740         for myopt in argument_options:
5741                 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None)
5742                 if v is not None:
5743                         myopts[myopt] = v
5744
5745         for action_opt in actions:
5746                 v = getattr(myoptions, action_opt.replace("-", "_"))
5747                 if v:
5748                         if myaction:
5749                                 multiple_actions(myaction, action_opt)
5750                                 sys.exit(1)
5751                         myaction = action_opt
5752
5753         for x in myargs:
5754                 if x in actions and myaction != "search":
5755                         if not silent and x not in ["system", "world"]:
5756                                 print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x))
5757                         # special case "search" so people can search for action terms, e.g. emerge -s sync
5758                         if myaction:
5759                                 multiple_actions(myaction, x)
5760                                 sys.exit(1)
5761                         myaction = x
5762                 else:
5763                         myfiles.append(x)
5764
5765         if "--nocolor" in myopts:
5766                 if not silent:
5767                         sys.stderr.write("*** Deprecated use of '--nocolor', " + \
5768                                 "use '--color=n' instead.\n")
5769                 del myopts["--nocolor"]
5770                 myopts["--color"] = "n"
5771
5772         return myaction, myopts, myfiles
5773
5774 def validate_ebuild_environment(trees):
5775         for myroot in trees:
5776                 mysettings = trees[myroot]["vartree"].settings
5777                 for var in "ARCH", "USERLAND":
5778                         if mysettings.get(var):
5779                                 continue
5780                         print >> sys.stderr, bad(("\a!!! %s is not set... " % var) + \
5781                                 "Are you missing the '%setc/make.profile' symlink?" % \
5782                                 mysettings["PORTAGE_CONFIGROOT"])
5783                         print >> sys.stderr, bad("\a!!! Is the symlink correct? " + \
5784                                 "Is your portage tree complete?\n")
5785                         sys.exit(9)
5786                 del myroot, mysettings
5787
5788 def load_emerge_config(trees=None):
5789         kwargs = {}
5790         for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")):
5791                 kwargs[k] = os.environ.get(envvar, None)
5792         trees = portage.create_trees(trees=trees, **kwargs)
5793
5794         settings = trees["/"]["vartree"].settings
5795
5796         for myroot in trees:
5797                 if myroot != "/":
5798                         settings = trees[myroot]["vartree"].settings
5799                         break
5800
5801         mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb")
5802         mtimedb = portage.MtimeDB(mtimedbfile)
5803         return settings, trees, mtimedb
5804
5805 def adjust_config(myopts, settings):
5806         """Make emerge specific adjustments to the config."""
5807
5808         # To enhance usability, make some vars case insensitive by forcing them to
5809         # lower case.
5810         for myvar in ("AUTOCLEAN", "NOCOLOR"):
5811                 if myvar in settings:
5812                         settings[myvar] = settings[myvar].lower()
5813                         settings.backup_changes(myvar)
5814         del myvar
5815
5816         # Kill noauto as it will break merges otherwise.
5817         if "noauto" in settings.features:
5818                 while "noauto" in settings.features:
5819                         settings.features.remove("noauto")
5820                 settings["FEATURES"] = " ".join(settings.features)
5821                 settings.backup_changes("FEATURES")
5822
5823         CLEAN_DELAY = 5
5824         try:
5825                 CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY)))
5826         except ValueError, e:
5827                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
5828                 portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \
5829                         settings["CLEAN_DELAY"], noiselevel=-1)
5830         settings["CLEAN_DELAY"] = str(CLEAN_DELAY)
5831         settings.backup_changes("CLEAN_DELAY")
5832
5833         EMERGE_WARNING_DELAY = 10
5834         try:
5835                 EMERGE_WARNING_DELAY = int(settings.get(
5836                         "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY)))
5837         except ValueError, e:
5838                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
5839                 portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \
5840                         settings["EMERGE_WARNING_DELAY"], noiselevel=-1)
5841         settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY)
5842         settings.backup_changes("EMERGE_WARNING_DELAY")
5843
5844         if "--quiet" in myopts:
5845                 settings["PORTAGE_QUIET"]="1"
5846                 settings.backup_changes("PORTAGE_QUIET")
5847
5848         # Set so that configs will be merged regardless of remembered status
5849         if ("--noconfmem" in myopts):
5850                 settings["NOCONFMEM"]="1"
5851                 settings.backup_changes("NOCONFMEM")
5852
5853         # Set various debug markers... They should be merged somehow.
5854         PORTAGE_DEBUG = 0
5855         try:
5856                 PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG)))
5857                 if PORTAGE_DEBUG not in (0, 1):
5858                         portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \
5859                                 PORTAGE_DEBUG, noiselevel=-1)
5860                         portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n",
5861                                 noiselevel=-1)
5862                         PORTAGE_DEBUG = 0
5863         except ValueError, e:
5864                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
5865                 portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\
5866                         settings["PORTAGE_DEBUG"], noiselevel=-1)
5867                 del e
5868         if "--debug" in myopts:
5869                 PORTAGE_DEBUG = 1
5870         settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG)
5871         settings.backup_changes("PORTAGE_DEBUG")
5872
5873         if settings.get("NOCOLOR") not in ("yes","true"):
5874                 portage.output.havecolor = 1
5875
5876         """The explicit --color < y | n > option overrides the NOCOLOR environment
5877         variable and stdout auto-detection."""
5878         if "--color" in myopts:
5879                 if "y" == myopts["--color"]:
5880                         portage.output.havecolor = 1
5881                         settings["NOCOLOR"] = "false"
5882                 else:
5883                         portage.output.havecolor = 0
5884                         settings["NOCOLOR"] = "true"
5885                 settings.backup_changes("NOCOLOR")
5886         elif not sys.stdout.isatty() and settings.get("NOCOLOR") != "no":
5887                 portage.output.havecolor = 0
5888                 settings["NOCOLOR"] = "true"
5889                 settings.backup_changes("NOCOLOR")
5890
5891 def emerge_main():
5892         global portage  # NFC why this is necessary now - genone
5893         # Disable color until we're sure that it should be enabled (after
5894         # EMERGE_DEFAULT_OPTS has been parsed).
5895         portage.output.havecolor = 0
5896         # This first pass is just for options that need to be known as early as
5897         # possible, such as --config-root.  They will be parsed again later,
5898         # together with EMERGE_DEFAULT_OPTS (which may vary depending on the
5899         # the value of --config-root).
5900         myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True)
5901         if "--debug" in myopts:
5902                 os.environ["PORTAGE_DEBUG"] = "1"
5903         if "--config-root" in myopts:
5904                 os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"]
5905
5906         # Portage needs to ensure a sane umask for the files it creates.
5907         os.umask(022)
5908         settings, trees, mtimedb = load_emerge_config()
5909         portdb = trees[settings["ROOT"]]["porttree"].dbapi
5910
5911         try:
5912                 os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
5913         except (OSError, ValueError), e:
5914                 portage.writemsg("!!! Failed to change nice value to '%s'\n" % \
5915                         settings["PORTAGE_NICENESS"])
5916                 portage.writemsg("!!! %s\n" % str(e))
5917                 del e
5918
5919         if portage._global_updates(trees, mtimedb["updates"]):
5920                 mtimedb.commit()
5921                 # Reload the whole config from scratch.
5922                 settings, trees, mtimedb = load_emerge_config(trees=trees)
5923                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
5924
5925         xterm_titles = "notitles" not in settings.features
5926
5927         tmpcmdline = []
5928         if "--ignore-default-opts" not in myopts:
5929                 tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split())
5930         tmpcmdline.extend(sys.argv[1:])
5931         myaction, myopts, myfiles = parse_opts(tmpcmdline)
5932
5933         if "--digest" in myopts:
5934                 os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest"
5935                 # Reload the whole config from scratch so that the portdbapi internal
5936                 # config is updated with new FEATURES.
5937                 settings, trees, mtimedb = load_emerge_config(trees=trees)
5938                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
5939
5940         for myroot in trees:
5941                 mysettings =  trees[myroot]["vartree"].settings
5942                 mysettings.unlock()
5943                 adjust_config(myopts, mysettings)
5944                 mysettings.lock()
5945                 del myroot, mysettings
5946
5947         spinner = stdout_spinner()
5948         if "candy" in settings.features:
5949                 spinner.update = spinner.update_scroll
5950
5951         if "--quiet" not in myopts:
5952                 portage.deprecated_profile_check()
5953
5954         #Freeze the portdbapi for enhanced performance:
5955         for myroot in trees:
5956                 trees[myroot]["porttree"].dbapi.freeze()
5957                 del myroot
5958
5959         if "moo" in myfiles:
5960                 print """
5961
5962   Larry loves Gentoo (""" + os.uname()[0] + """)
5963
5964  _______________________
5965 < Have you mooed today? >
5966  -----------------------
5967         \   ^__^
5968          \  (oo)\_______
5969             (__)\       )\/\ 
5970                 ||----w |
5971                 ||     ||
5972
5973 """
5974
5975         if (myaction in ["world", "system"]) and myfiles:
5976                 print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
5977                 sys.exit(1)
5978
5979         for x in myfiles:
5980                 ext = os.path.splitext(x)[1]
5981                 if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
5982                         print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")
5983                         break
5984
5985         if ("--tree" in myopts) and ("--columns" in myopts):
5986                 print "emerge: can't specify both of \"--tree\" and \"--columns\"."
5987                 sys.exit(1)
5988
5989         if ("--quiet" in myopts):
5990                 spinner.update = spinner.update_quiet
5991                 portage.util.noiselimit = -1
5992
5993         # Always create packages if FEATURES=buildpkg
5994         # Imply --buildpkg if --buildpkgonly
5995         if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts):
5996                 if "--buildpkg" not in myopts:
5997                         myopts["--buildpkg"] = True
5998
5999         # Also allow -S to invoke search action (-sS)
6000         if ("--searchdesc" in myopts):
6001                 if myaction and myaction != "search":
6002                         myfiles.append(myaction)
6003                 if "--search" not in myopts:
6004                         myopts["--search"] = True
6005                 myaction = "search"
6006
6007         # Always try and fetch binary packages if FEATURES=getbinpkg
6008         if ("getbinpkg" in settings.features):
6009                 myopts["--getbinpkg"] = True
6010
6011         if "--skipfirst" in myopts and "--resume" not in myopts:
6012                 myopts["--resume"] = True
6013
6014         if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts):
6015                 myopts["--usepkgonly"] = True
6016
6017         if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts):
6018                 myopts["--getbinpkg"] = True
6019
6020         if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts):
6021                 myopts["--usepkg"] = True
6022
6023         # Also allow -K to apply --usepkg/-k
6024         if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts):
6025                 myopts["--usepkg"] = True
6026
6027         # Allow -p to remove --ask
6028         if ("--pretend" in myopts) and ("--ask" in myopts):
6029                 print ">>> --pretend disables --ask... removing --ask from options."
6030                 del myopts["--ask"]
6031
6032         # forbid --ask when not in a terminal
6033         # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
6034         if ("--ask" in myopts) and (not sys.stdin.isatty()):
6035                 portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n",
6036                         noiselevel=-1)
6037                 sys.exit(1)
6038
6039         if settings.get("PORTAGE_DEBUG", "") == "1":
6040                 spinner.update = spinner.update_quiet
6041                 portage.debug=1
6042                 if "python-trace" in settings.features:
6043                         import portage.debug
6044                         portage.debug.set_trace(True)
6045
6046         if ("--resume" in myopts):
6047                 if "--tree" in myopts:
6048                         print "* --tree is currently broken with --resume. Disabling..."
6049                         del myopts["--tree"]
6050
6051         if not ("--quiet" in myopts):
6052                 if not sys.stdout.isatty() or ("--nospinner" in myopts):
6053                         spinner.update = spinner.update_basic
6054
6055         if "--version" in myopts:
6056                 print getportageversion(settings["PORTDIR"], settings["ROOT"],
6057                         settings.profile_path, settings["CHOST"],
6058                         trees[settings["ROOT"]]["vartree"].dbapi)
6059                 sys.exit(0)
6060         elif "--help" in myopts:
6061                 emerge.help.help(myaction, myopts, portage.output.havecolor)
6062                 sys.exit(0)
6063
6064         if "--debug" in myopts:
6065                 print "myaction", myaction
6066                 print "myopts", myopts
6067
6068         if not myaction and not myfiles and "--resume" not in myopts:
6069                 emerge.help.help(myaction, myopts, portage.output.havecolor)
6070                 sys.exit(1)
6071
6072         # check if root user is the current user for the actions where emerge needs this
6073         if portage.secpass < 2:
6074                 # We've already allowed "--version" and "--help" above.
6075                 if "--pretend" not in myopts and myaction not in ("search","info"):
6076                         need_superuser = not \
6077                                 ("--fetchonly" in myopts or \
6078                                 "--fetch-all-uri" in myopts or \
6079                                 myaction in ("metadata", "regen") or \
6080                                 (myaction == "sync" and os.access(settings["PORTDIR"], os.W_OK)))
6081                         if portage.secpass < 1 or \
6082                                 need_superuser:
6083                                 if need_superuser:
6084                                         access_desc = "superuser"
6085                                 else:
6086                                         access_desc = "portage group"
6087                                 # Always show portage_group_warning() when only portage group
6088                                 # access is required but the user is not in the portage group.
6089                                 from portage.data import portage_group_warning
6090                                 if "--ask" in myopts:
6091                                         myopts["--pretend"] = True
6092                                         del myopts["--ask"]
6093                                         print ("%s access is required... " + \
6094                                                 "adding --pretend to options.\n") % access_desc
6095                                         if portage.secpass < 1 and not need_superuser:
6096                                                 portage_group_warning()
6097                                 else:
6098                                         sys.stderr.write(("emerge: %s access is " + \
6099                                                 "required.\n\n") % access_desc)
6100                                         if portage.secpass < 1 and not need_superuser:
6101                                                 portage_group_warning()
6102                                         return 1
6103
6104         disable_emergelog = False
6105         for x in ("--pretend", "--fetchonly", "--fetch-all-uri"):
6106                 if x in myopts:
6107                         disable_emergelog = True
6108                         break
6109         if myaction in ("search", "info"):
6110                 disable_emergelog = True
6111         if disable_emergelog:
6112                 """ Disable emergelog for everything except build or unmerge
6113                 operations.  This helps minimize parallel emerge.log entries that can
6114                 confuse log parsers.  We especially want it disabled during
6115                 parallel-fetch, which uses --resume --fetchonly."""
6116                 global emergelog
6117                 def emergelog(*pargs, **kargs):
6118                         pass
6119
6120         if not "--pretend" in myopts:
6121                 emergelog(xterm_titles, "Started emerge on: "+\
6122                         time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
6123                 myelogstr=""
6124                 if myopts:
6125                         myelogstr=" ".join(myopts)
6126                 if myaction:
6127                         myelogstr+=" "+myaction
6128                 if myfiles:
6129                         myelogstr+=" "+" ".join(myfiles)
6130                 emergelog(xterm_titles, " *** emerge " + myelogstr)
6131
6132         def emergeexitsig(signum, frame):
6133                 signal.signal(signal.SIGINT, signal.SIG_IGN)
6134                 signal.signal(signal.SIGTERM, signal.SIG_IGN)
6135                 portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
6136                 sys.exit(100+signum)
6137         signal.signal(signal.SIGINT, emergeexitsig)
6138         signal.signal(signal.SIGTERM, emergeexitsig)
6139
6140         def emergeexit():
6141                 """This gets out final log message in before we quit."""
6142                 if "--pretend" not in myopts:
6143                         emergelog(xterm_titles, " *** terminating.")
6144                 if "notitles" not in settings.features:
6145                         xtermTitleReset()
6146         portage.atexit_register(emergeexit)
6147
6148         if myaction in ("config", "metadata", "regen", "sync"):
6149                 if "--pretend" in myopts:
6150                         sys.stderr.write(("emerge: The '%s' action does " + \
6151                                 "not support '--pretend'.\n") % myaction)
6152                         return 1
6153         if "sync" == myaction:
6154                 action_sync(settings, trees, mtimedb, myopts, myaction)
6155         elif "metadata" == myaction:
6156                 action_metadata(settings, portdb, myopts)
6157         elif myaction=="regen":
6158                 validate_ebuild_environment(trees)
6159                 action_regen(settings, portdb)
6160         # HELP action
6161         elif "config"==myaction:
6162                 validate_ebuild_environment(trees)
6163                 action_config(settings, trees, myopts, myfiles)
6164         
6165         # INFO action
6166         elif "info"==myaction:
6167                 action_info(settings, trees, myopts, myfiles)
6168
6169         # SEARCH action
6170         elif "search"==myaction:
6171                 validate_ebuild_environment(trees)
6172                 action_search(settings, portdb, trees["/"]["vartree"],
6173                         myopts, myfiles, spinner)
6174         elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
6175                 validate_ebuild_environment(trees)
6176                 vartree = trees[settings["ROOT"]]["vartree"]
6177                 if 1 == unmerge(settings, myopts, vartree, myaction, myfiles,
6178                         mtimedb["ldpath"]):
6179                         if "--pretend" not in myopts:
6180                                 post_emerge(trees, mtimedb, os.EX_OK)
6181
6182         elif "depclean"==myaction:
6183                 validate_ebuild_environment(trees)
6184                 action_depclean(settings, trees, mtimedb["ldpath"],
6185                         myopts, spinner)
6186                 if "--pretend" not in myopts:
6187                         post_emerge(trees, mtimedb, os.EX_OK)
6188         # "update", "system", or just process files:
6189         else:
6190                 validate_ebuild_environment(trees)
6191                 if "--pretend" not in myopts:
6192                         display_news_notification(trees)
6193                 retval = action_build(settings, trees, mtimedb,
6194                         myopts, myaction, myfiles, spinner)
6195                 if "--pretend" in myopts:
6196                         display_news_notification(trees)
6197                 return retval
6198
6199 if __name__ == "__main__":
6200         retval = emerge_main()
6201         sys.exit(retval)