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