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