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