Fix "UnboundLocalError: local variable 'portage' referenced before assignment" caused...
[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 portage.emergehelp, portage.xpak, commands, errno, re, socket, time, types
36 import output
37 from portage.output import blue, bold, colorize, darkblue, darkgreen, darkred, green, \
38         havecolor, nc_len, nocolor, red, teal, turquoise, white, xtermTitle, \
39         xtermTitleReset, yellow
40 from portage.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                                 vardbapi.cpv_exists(mykey):
1134                                 pkgsettings.setcpv(mykey, mydb=mydbapi)
1135                                 forced_flags = set()
1136                                 forced_flags.update(pkgsettings.useforce)
1137                                 forced_flags.update(pkgsettings.usemask)
1138                                 old_use = vardbapi.aux_get(mykey, ["USE"])[0].split()
1139                                 iuses = set(filter_iuse_defaults(
1140                                         mydbapi.aux_get(mykey, ["IUSE"])[0].split()))
1141                                 old_iuse = set(filter_iuse_defaults(
1142                                         vardbapi.aux_get(mykey, ["IUSE"])[0].split()))
1143                                 if iuses.symmetric_difference(
1144                                         old_iuse).difference(forced_flags):
1145                                         merging = 1
1146                                 elif old_iuse.intersection(old_use) != \
1147                                         iuses.intersection(myuse):
1148                                         merging=1
1149
1150                 if addme and merging == 1:
1151                         mybigkey.append("merge")
1152                 else:
1153                         mybigkey.append("nomerge")
1154                 jbigkey = tuple(mybigkey)
1155
1156                 if addme:
1157                         metadata = dict(izip(self._mydbapi_keys,
1158                                 mydbapi.aux_get(mykey, self._mydbapi_keys)))
1159                         if merging == 0 and vardbapi.cpv_exists(mykey):
1160                                 metadata["USE"] = vardbapi.aux_get(mykey, ["USE"])[0]
1161                                 myuse = metadata["USE"].split()
1162                                 metadata["SLOT"] = vardbapi.aux_get(mykey, ["SLOT"])[0]
1163                         slot_atom = "%s:%s" % (portage.dep_getkey(mykey), metadata["SLOT"])
1164                         existing_node = self._slot_node_map[myroot].get(
1165                                 slot_atom, None)
1166                         slot_collision = False
1167                         if existing_node:
1168                                 e_type, myroot, e_cpv, e_status = existing_node
1169                                 if mykey == e_cpv:
1170                                         # The existing node can be reused.
1171                                         self._parent_child_digraph.add(existing_node, myparent)
1172                                         if rev_dep and myparent:
1173                                                 ptype, proot, pkey, pstatus = myparent
1174                                                 self.digraph.addnode(myparent, existing_node,
1175                                                         priority=priority)
1176                                         else:
1177                                                 self.digraph.addnode(existing_node, myparent,
1178                                                         priority=priority)
1179                                         return 1
1180                                 else:
1181                                         # A slot collision has occurred.  Sometimes this coincides
1182                                         # with unresolvable blockers, so the slot collision will be
1183                                         # shown later if there are no unresolvable blockers.
1184                                         e_parents = self._parent_child_digraph.parent_nodes(
1185                                                 existing_node)
1186                                         myparents = []
1187                                         if myparent:
1188                                                 myparents.append(myparent)
1189                                         self._slot_collision_info.append(
1190                                                 ((jbigkey, myparents), (existing_node, e_parents)))
1191                                         self._slot_collision_nodes.add(jbigkey)
1192                                         slot_collision = True
1193
1194                         if slot_collision:
1195                                 # Now add this node to the graph so that self.display()
1196                                 # can show use flags and --tree portage.output.  This node is
1197                                 # only being partially added to the graph.  It must not be
1198                                 # allowed to interfere with the other nodes that have been
1199                                 # added.  Do not overwrite data for existing nodes in
1200                                 # self.pkg_node_map and self.mydbapi since that data will
1201                                 # be used for blocker validation.
1202                                 self.pkg_node_map[myroot].setdefault(mykey, jbigkey)
1203                                 self.useFlags[myroot].setdefault(mykey, myuse)
1204                                 # Even though the graph is now invalid, continue to process
1205                                 # dependencies so that things like --fetchonly can still
1206                                 # function despite collisions.
1207                         else:
1208                                 self.mydbapi[myroot].cpv_inject(mykey, metadata=metadata)
1209                                 self._slot_node_map[myroot][slot_atom] = jbigkey
1210                                 self.pkg_node_map[myroot][mykey] = jbigkey
1211                                 self.useFlags[myroot][mykey] = myuse
1212
1213                         if rev_dep and myparent:
1214                                 self.digraph.addnode(myparent, jbigkey,
1215                                         priority=priority)
1216                         else:
1217                                 self.digraph.addnode(jbigkey, myparent,
1218                                         priority=priority)
1219
1220                 # Do this even when addme is False (--onlydeps) so that the
1221                 # parent/child relationship is always known in case
1222                 # self._show_slot_collision_notice() needs to be called later.
1223                 self._parent_child_digraph.add(jbigkey, myparent)
1224
1225                 """ This section determines whether we go deeper into dependencies or not.
1226                     We want to go deeper on a few occasions:
1227                     Installing package A, we need to make sure package A's deps are met.
1228                     emerge --deep <pkgspec>; we need to recursively check dependencies of pkgspec
1229                     If we are in --nodeps (no recursion) mode, we obviously only check 1 level of dependencies.
1230                 """
1231                 if "deep" not in self.myparams and not merging and \
1232                         not ("--update" in self.myopts and arg and merging):
1233                         return 1
1234                 elif "recurse" not in self.myparams:
1235                         return 1
1236
1237                 """ Check DEPEND/RDEPEND/PDEPEND/SLOT
1238                 Pull from bintree if it's binary package, porttree if it's ebuild.
1239                 Binpkg's can be either remote or local. """
1240
1241                 edepend={}
1242                 depkeys = ["DEPEND","RDEPEND","PDEPEND"]
1243                 depvalues = mydbapi.aux_get(mykey, depkeys)
1244                 for i in xrange(len(depkeys)):
1245                         edepend[depkeys[i]] = depvalues[i]
1246
1247                 if mytype == "ebuild":
1248                         if "--buildpkgonly" in self.myopts:
1249                                 edepend["RDEPEND"] = ""
1250                                 edepend["PDEPEND"] = ""
1251                 if not (arg and "--onlydeps" in self.myopts and \
1252                         mytype == "ebuild") and \
1253                         self.myopts.get("--with-bdeps", "n") == "n" and \
1254                         (mytype == "binary" or mybigkey[3] == "nomerge"):
1255                         edepend["DEPEND"] = ""
1256
1257                 """ We have retrieve the dependency information, now we need to recursively
1258                     process them.  DEPEND gets processed for root = "/", {R,P}DEPEND in myroot. """
1259                 
1260                 mp = tuple(mybigkey)
1261
1262                 try:
1263                         if not self.select_dep("/", edepend["DEPEND"], myparent=mp,
1264                                 myuse=myuse, priority=DepPriority(buildtime=True),
1265                                 parent_arg=arg):
1266                                 return 0
1267                         """RDEPEND is soft by definition.  However, in order to ensure
1268                         correct merge order, we make it a hard dependency.  Otherwise, a
1269                         build time dependency might not be usable due to it's run time
1270                         dependencies not being installed yet.
1271                         """
1272                         if not self.select_dep(myroot,edepend["RDEPEND"], myparent=mp,
1273                                 myuse=myuse, priority=DepPriority(runtime=True),
1274                                 parent_arg=arg):
1275                                 return 0
1276                         if edepend.has_key("PDEPEND") and edepend["PDEPEND"]:
1277                                 # Post Depend -- Add to the list without a parent, as it depends
1278                                 # on a package being present AND must be built after that package.
1279                                 if not self.select_dep(myroot, edepend["PDEPEND"], myparent=mp,
1280                                         myuse=myuse, priority=DepPriority(), rev_deps=True,
1281                                         parent_arg=arg):
1282                                         return 0
1283                 except ValueError, e:
1284                         pkgs = e.args[0]
1285                         portage.writemsg("\n\n!!! An atom in the dependencies " + \
1286                                 "is not fully-qualified. Multiple matches:\n\n", noiselevel=-1)
1287                         for cpv in pkgs:
1288                                 portage.writemsg("    %s\n" % cpv, noiselevel=-1)
1289                         portage.writemsg("\n", noiselevel=-1)
1290                         if mytype == "binary":
1291                                 portage.writemsg(
1292                                         "!!! This binary package cannot be installed: '%s'\n" % \
1293                                         mykey, noiselevel=-1)
1294                         elif mytype == "ebuild":
1295                                 myebuild, mylocation = portdb.findname2(mykey)
1296                                 portage.writemsg("!!! This ebuild cannot be installed: " + \
1297                                         "'%s'\n" % myebuild, noiselevel=-1)
1298                         portage.writemsg("!!! Please notify the package maintainer " + \
1299                                 "that atoms must be fully-qualified.\n", noiselevel=-1)
1300                         return 0
1301                 return 1
1302
1303         def select_files(self,myfiles):
1304                 "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list"
1305                 myfavorites=[]
1306                 myroot = self.target_root
1307                 portdb = self.trees[myroot]["porttree"].dbapi
1308                 bindb = self.trees[myroot]["bintree"].dbapi
1309                 pkgsettings = self.pkgsettings[myroot]
1310                 arg_atoms = []
1311                 def visible(mylist):
1312                         matches = portdb.gvisible(portdb.visible(mylist))
1313                         return [x for x in mylist \
1314                                 if x in matches or not portdb.cpv_exists(x)]
1315                 for x in myfiles:
1316                         ext = os.path.splitext(x)[1]
1317                         if ext==".tbz2":
1318                                 if not os.path.exists(x):
1319                                         if os.path.exists(
1320                                                 os.path.join(pkgsettings["PKGDIR"], "All", x)):
1321                                                 x = os.path.join(pkgsettings["PKGDIR"], "All", x)
1322                                         elif os.path.exists(
1323                                                 os.path.join(pkgsettings["PKGDIR"], x)):
1324                                                 x = os.path.join(pkgsettings["PKGDIR"], x)
1325                                         else:
1326                                                 print "\n\n!!! Binary package '"+str(x)+"' does not exist."
1327                                                 print "!!! Please ensure the tbz2 exists as specified.\n"
1328                                                 sys.exit(1)
1329                                 mytbz2=portage.xpak.tbz2(x)
1330                                 mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0]
1331                                 if os.path.realpath(x) != \
1332                                         os.path.realpath(self.trees[myroot]["bintree"].getname(mykey)):
1333                                         print colorize("BAD", "\n*** You need to adjust PKGDIR to emerge this package.\n")
1334                                         sys.exit(1)
1335                                 if not self.create(["binary", myroot, mykey],
1336                                         None, "--onlydeps" not in self.myopts):
1337                                         return (0,myfavorites)
1338                                 elif not "--oneshot" in self.myopts:
1339                                         myfavorites.append(mykey)
1340                         elif ext==".ebuild":
1341                                 x = os.path.realpath(x)
1342                                 mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0]
1343                                 ebuild_path = portdb.findname(mykey)
1344                                 if ebuild_path:
1345                                         if os.path.realpath(ebuild_path) != x:
1346                                                 print colorize("BAD", "\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n")
1347                                                 sys.exit(1)
1348                                         if mykey not in portdb.xmatch(
1349                                                 "match-visible", portage.dep_getkey(mykey)):
1350                                                 print colorize("BAD", "\n*** You are emerging a masked package. It is MUCH better to use")
1351                                                 print colorize("BAD", "*** /etc/portage/package.* to accomplish this. See portage(5) man")
1352                                                 print colorize("BAD", "*** page for details.")
1353                                                 countdown(int(self.settings["EMERGE_WARNING_DELAY"]),
1354                                                         "Continuing...")
1355                                 else:
1356                                         raise portage.exception.PackageNotFound(
1357                                                 "%s is not in a valid portage tree hierarchy or does not exist" % x)
1358                                 if not self.create(["ebuild", myroot, mykey],
1359                                         None, "--onlydeps" not in self.myopts):
1360                                         return (0,myfavorites)
1361                                 elif not "--oneshot" in self.myopts:
1362                                         myfavorites.append(mykey)
1363                         else:
1364                                 if not is_valid_package_atom(x):
1365                                         portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x,
1366                                                 noiselevel=-1)
1367                                         portage.writemsg("!!! Please check ebuild(5) for full details.\n")
1368                                         portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
1369                                         return (0,[])
1370                                 try:
1371                                         mykey = None
1372                                         if "--usepkg" in self.myopts:
1373                                                 mykey = portage.dep_expand(x, mydb=bindb,
1374                                                         settings=pkgsettings)
1375                                         if (mykey and not mykey.startswith("null/")) or \
1376                                                 "--usepkgonly" in self.myopts:
1377                                                 arg_atoms.append((x, mykey))
1378                                                 continue
1379
1380                                         mykey = portage.dep_expand(x,
1381                                                 mydb=portdb, settings=pkgsettings)
1382                                         arg_atoms.append((x, mykey))
1383                                 except ValueError, errpkgs:
1384                                         print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous.  Please specify"
1385                                         print "!!! one of the following fully-qualified ebuild names instead:\n"
1386                                         for i in errpkgs[0]:
1387                                                 print "    " + green(i)
1388                                         print
1389                                         sys.exit(1)
1390
1391                 if "--update" in self.myopts:
1392                         """Make sure all installed slots are updated when possible. Do this
1393                         with --emptytree also, to ensure that all slots are remerged."""
1394                         vardb = self.trees[self.target_root]["vartree"].dbapi
1395                         greedy_atoms = []
1396                         for myarg, myatom in arg_atoms:
1397                                 greedy_atoms.append((myarg, myatom))
1398                                 myslots = set()
1399                                 for cpv in vardb.match(myatom):
1400                                         myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
1401                                 if myslots:
1402                                         best_pkgs = []
1403                                         if "--usepkg" in self.myopts:
1404                                                 mymatches = bindb.match(myatom)
1405                                                 if "--usepkgonly" not in self.myopts:
1406                                                         mymatches = visible(mymatches)
1407                                                 best_pkg = portage.best(mymatches)
1408                                                 if best_pkg:
1409                                                         best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
1410                                                         best_pkgs.append(("binary", best_pkg, best_slot))
1411                                         if "--usepkgonly" not in self.myopts:
1412                                                 best_pkg = portage.best(portdb.match(myatom))
1413                                                 if best_pkg:
1414                                                         best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
1415                                                         best_pkgs.append(("ebuild", best_pkg, best_slot))
1416                                         if best_pkgs:
1417                                                 best_pkg = portage.best([x[1] for x in best_pkgs])
1418                                                 best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
1419                                                 best_slot = best_pkgs[0][2]
1420                                                 myslots.add(best_slot)
1421                                 if len(myslots) > 1:
1422                                         for myslot in myslots:
1423                                                 myslot_atom = "%s:%s" % \
1424                                                         (portage.dep_getkey(myatom), myslot)
1425                                                 available = False
1426                                                 if "--usepkgonly" not in self.myopts and \
1427                                                         self.trees[self.target_root][
1428                                                         "porttree"].dbapi.match(myslot_atom):
1429                                                         available = True
1430                                                 elif "--usepkg" in self.myopts:
1431                                                         mymatches = bindb.match(myslot_atom)
1432                                                         if "--usepkgonly" not in self.myopts:
1433                                                                 mymatches = visible(mymatches)
1434                                                         if mymatches:
1435                                                                 available = True
1436                                                 if available:
1437                                                         greedy_atoms.append((myarg, myslot_atom))
1438                         arg_atoms = greedy_atoms
1439
1440                 """ These are used inside self.create() in order to ensure packages
1441                 that happen to match arguments are not incorrectly marked as nomerge."""
1442                 self.args_keys = [x[1] for x in arg_atoms]
1443                 for myarg, myatom in arg_atoms:
1444                                 try:
1445                                         self.mysd = self.select_dep(myroot, myatom, arg=myarg)
1446                                 except portage.exception.MissingSignature, e:
1447                                         portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n")
1448                                         portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
1449                                         portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
1450                                         portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
1451                                         portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
1452                                         sys.exit(1)
1453                                 except portage.exception.InvalidSignature, e:
1454                                         portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n")
1455                                         portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n")
1456                                         portage.writemsg("!!! to aid in the detection of malicious intent.\n\n")
1457                                         portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n")
1458                                         portage.writemsg("!!! Affected file: %s\n" % (e), noiselevel=-1)
1459                                         sys.exit(1)
1460                                 except SystemExit, e:
1461                                         raise # Needed else can't exit
1462                                 except Exception, e:
1463                                         print >> sys.stderr, "\n\n!!! Problem in '%s' dependencies." % mykey
1464                                         print >> sys.stderr, "!!!", str(e), getattr(e, "__module__", None)
1465                                         raise
1466
1467                                 if not self.mysd:
1468                                         return (0,myfavorites)
1469                                 elif not "--oneshot" in self.myopts:
1470                                         mykey = portage.dep_getkey(myatom)
1471                                         if mykey not in myfavorites:
1472                                                 myfavorites.append(mykey)
1473
1474                 missing=0
1475                 if "--usepkgonly" in self.myopts:
1476                         for xs in self.digraph.all_nodes():
1477                                 if len(xs) >= 4 and xs[0] != "binary" and xs[3] == "merge":
1478                                         if missing == 0:
1479                                                 print
1480                                         missing += 1
1481                                         print "Missing binary for:",xs[2]
1482
1483                 if not self.validate_blockers():
1484                         return False, myfavorites
1485                 
1486                 # We're true here unless we are missing binaries.
1487                 return (not missing,myfavorites)
1488
1489         def select_dep(self, myroot, depstring, myparent=None, arg=None,
1490                 myuse=None, raise_on_missing=False, priority=DepPriority(),
1491                 rev_deps=False, parent_arg=None):
1492                 """ Given a depstring, create the depgraph such that all dependencies are satisfied.
1493                     myroot = $ROOT from environment, where {R,P}DEPENDs are merged to.
1494                     myparent = the node whose depstring is being passed in
1495                     arg = package was specified on the command line, merge even if it's already installed
1496                     myuse = USE flags at present
1497                     raise_on_missing = Given that the depgraph is not proper, raise an exception if true
1498                     else continue trying.
1499                     return 1 on success, 0 for failure
1500                 """
1501
1502                 portdb = self.trees[myroot]["porttree"].dbapi
1503                 bindb  = self.trees[myroot]["bintree"].dbapi
1504                 vardb  = self.trees[myroot]["vartree"].dbapi
1505                 pkgsettings = self.pkgsettings[myroot]
1506                 if myparent:
1507                         p_type, p_root, p_key, p_status = myparent
1508
1509                 if "--debug" in self.myopts:
1510                         print
1511                         print "Parent:   ",myparent
1512                         print "Depstring:",depstring
1513                         if rev_deps:
1514                                 print "Reverse:", rev_deps
1515                         print "Priority:", priority
1516
1517                 #processing dependencies
1518                 """ Call portage.dep_check to evaluate the use? conditionals and make sure all
1519                 dependencies are satisfiable. """
1520                 try:
1521                         if myparent and p_status == "nomerge":
1522                                 portage.dep._dep_check_strict = False
1523                         mycheck = portage.dep_check(depstring, None,
1524                                 pkgsettings, myuse=myuse,
1525                                 use_binaries=("--usepkgonly" in self.myopts),
1526                                 myroot=myroot, trees=self.trees)
1527                 finally:
1528                         portage.dep._dep_check_strict = True
1529
1530                 if not mycheck[0]:
1531                         if myparent:
1532                                 show_invalid_depstring_notice(myparent, depstring, mycheck[1])
1533                         else:
1534                                 sys.stderr.write("\n%s\n%s\n" % (depstring, mycheck[1]))
1535                         return 0
1536                 mymerge = mycheck[1]
1537
1538                 if not mymerge and arg and \
1539                         portage.best_match_to_list(depstring, self.args_keys):
1540                         # A provided package has been specified on the command line.  The
1541                         # package will not be merged and a warning will be displayed.
1542                         self._pprovided_args.append(arg)
1543
1544                 if myparent:
1545                         # The parent is added after it's own dep_check call so that it
1546                         # isn't allowed to satisfy a direct bootstrap dependency on itself
1547                         # via an old-style virtual.  This isn't a problem with new-style
1548                         # virtuals, which are preferenced in dep_zapdeps by looking only at
1549                         # the depstring, vdb, and available packages.
1550
1551                         p_type, p_root, p_key, p_status = myparent
1552                         if p_status == "merge":
1553                                 # Update old-style virtuals if this package provides any.
1554                                 # These are needed for dep_virtual calls inside dep_check.
1555                                 self.pkgsettings[p_root].setinst(p_key,
1556                                         self.trees[p_root][self.pkg_tree_map[p_type]].dbapi)
1557
1558                 if "--debug" in self.myopts:
1559                         print "Candidates:",mymerge
1560                 for x in mymerge:
1561                         selected_pkg = None
1562                         if x[0]=="!":
1563                                 selected_pkg = ["blocks", myroot, x[1:], None]
1564                         else:
1565                                 #We are not processing a blocker but a normal dependency
1566                                 if myparent:
1567                                         """In some cases, dep_check will return deps that shouldn't
1568                                         be proccessed any further, so they are identified and
1569                                         discarded here."""
1570                                         if "empty" not in self.myparams and \
1571                                                 "deep" not in self.myparams and \
1572                                                 not ("--update" in self.myopts and parent_arg) and \
1573                                                 vardb.match(x):
1574                                                 continue
1575
1576                                 # List of acceptable packages, ordered by type preference.
1577                                 matched_packages = []
1578                                 myeb_matches = portdb.xmatch("match-visible", x)
1579                                 myeb = None
1580                                 if "--usepkgonly" not in self.myopts:
1581                                         myeb = portage.best(myeb_matches)
1582
1583                                 myeb_pkg=None
1584                                 if "--usepkg" in self.myopts:
1585                                         # The next line assumes the binarytree has been populated.
1586                                         # XXX: Need to work out how we use the binary tree with roots.
1587                                         myeb_pkg_matches = bindb.match(x)
1588                                         if "--usepkgonly" not in self.myopts:
1589                                                 # Remove any binary package entries that are masked in the portage tree (#55871)
1590                                                 myeb_pkg_matches = [pkg for pkg in myeb_pkg_matches \
1591                                                         if pkg in myeb_matches or  \
1592                                                         not portdb.cpv_exists(pkg)]
1593                                         if myeb_pkg_matches:
1594                                                 myeb_pkg = portage.best(myeb_pkg_matches)
1595
1596                                 if myeb_pkg and "--newuse" in self.myopts:
1597                                         iuses = set(filter_iuse_defaults(
1598                                                 bindb.aux_get(myeb_pkg, ["IUSE"])[0].split()))
1599                                         old_use = bindb.aux_get(myeb_pkg, ["USE"])[0].split()
1600                                         mydb = None
1601                                         if "--usepkgonly" not in self.myopts and myeb:
1602                                                 mydb = portdb
1603                                         if myeb:
1604                                                 pkgsettings.setcpv(myeb, mydb=mydb)
1605                                         else:
1606                                                 pkgsettings.setcpv(myeb_pkg, mydb=mydb)
1607                                         now_use = pkgsettings["USE"].split()
1608                                         forced_flags = set()
1609                                         forced_flags.update(pkgsettings.useforce)
1610                                         forced_flags.update(pkgsettings.usemask)
1611                                         cur_iuse = iuses
1612                                         if "--usepkgonly" not in self.myopts and myeb:
1613                                                 cur_iuse = set(filter_iuse_defaults(
1614                                                         portdb.aux_get(myeb, ["IUSE"])[0].split()))
1615                                         if iuses.symmetric_difference(
1616                                                 cur_iuse).difference(forced_flags):
1617                                                 myeb_pkg = None
1618                                         elif iuses.intersection(old_use) != \
1619                                                 cur_iuse.intersection(now_use):
1620                                                 myeb_pkg = None
1621                                 if myeb_pkg:
1622                                         binpkguseflags = \
1623                                                 self.trees[myroot]["bintree"].dbapi.aux_get(
1624                                                         myeb_pkg, ["USE"])[0].split()
1625                                         matched_packages.append(
1626                                                 ["binary", myroot, myeb_pkg, binpkguseflags])
1627
1628                                 if "--usepkgonly" not in self.myopts and myeb_matches:
1629                                         matched_packages.append(
1630                                                 ["ebuild", myroot, myeb, None])
1631
1632                                 if not matched_packages and \
1633                                         not (arg and "selective" not in self.myparams):
1634                                         """Fall back to the installed package database.  This is a
1635                                         last resort because the metadata tends to diverge from that
1636                                         of the ebuild in the tree."""
1637                                         myeb_inst_matches = vardb.match(x)
1638                                         if "--usepkgonly" not in self.myopts:
1639                                                 """ TODO: Improve masking check for installed and
1640                                                 binary packages. bug #149816"""
1641                                                 myeb_inst_matches = [pkg for pkg in myeb_inst_matches \
1642                                                         if not portdb.cpv_exists(pkg)]
1643                                         myeb_inst = None
1644                                         if myeb_inst_matches:
1645                                                 myeb_inst = portage.best(myeb_inst_matches)
1646                                         if myeb_inst:
1647                                                 binpkguseflags = vardb.aux_get(
1648                                                         myeb_inst, ["USE"])[0].split()
1649                                                 matched_packages.append(
1650                                                         ["installed", myroot, myeb_inst, binpkguseflags])
1651
1652                                 if not matched_packages:
1653                                         if raise_on_missing:
1654                                                 raise ValueError
1655                                         if not arg:
1656                                                 xinfo='"'+x+'"'
1657                                         else:
1658                                                 xinfo='"'+arg+'"'
1659                                         if myparent:
1660                                                 xfrom = '(dependency required by '+ \
1661                                                         green('"%s"' % myparent[2]) + \
1662                                                         red(' [%s]' % myparent[0]) + ')'
1663                                         alleb = portdb.xmatch("match-all", x)
1664                                         if alleb:
1665                                                 if "--usepkgonly" not in self.myopts:
1666                                                         print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.")
1667                                                         print "!!! One of the following masked packages is required to complete your request:"
1668                                                         oldcomment = ""
1669                                                         for p in alleb:
1670                                                                 mreasons = portage.getmaskingstatus(p,
1671                                                                         settings=pkgsettings, portdb=portdb)
1672                                                                 print "- "+p+" (masked by: "+", ".join(mreasons)+")"
1673                                                                 comment = portage.getmaskingreason(p,
1674                                                                         settings=pkgsettings, portdb=portdb)
1675                                                                 if comment and comment != oldcomment:
1676                                                                         print comment
1677                                                                         oldcomment = comment
1678                                                         print
1679                                                         print "For more information, see MASKED PACKAGES section in the emerge man page or "
1680                                                         print "refer to the Gentoo Handbook."
1681                                                 else:
1682                                                         print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo)
1683                                                         print "!!! Either add a suitable binary package or compile from an ebuild."
1684                                         else:
1685                                                 print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"."
1686                                         if myparent:
1687                                                 print xfrom
1688                                         print
1689                                         return 0
1690
1691                                 if "--debug" in self.myopts:
1692                                         for pkg in matched_packages:
1693                                                 print (pkg[0] + ":").rjust(10), pkg[2]
1694
1695                                 if len(matched_packages) > 1:
1696                                         bestmatch = portage.best(
1697                                                 [pkg[2] for pkg in matched_packages])
1698                                         matched_packages = [pkg for pkg in matched_packages \
1699                                                 if pkg[2] == bestmatch]
1700
1701                                 # ordered by type preference ("ebuild" type is the last resort)
1702                                 selected_pkg =  matched_packages[0]
1703                                 pkgtype, myroot, mycpv, myuse = selected_pkg
1704                                 mydbapi = self.trees[myroot][self.pkg_tree_map[pkgtype]].dbapi
1705                                 slot_atom = "%s:%s" % (portage.dep_getkey(mycpv),
1706                                         mydbapi.aux_get(mycpv, ["SLOT"])[0])
1707                                 existing_node = self._slot_node_map[myroot].get(
1708                                         slot_atom, None)
1709                                 if existing_node:
1710                                         e_type, myroot, e_cpv, e_status = existing_node
1711                                         if portage.match_from_list(x, [e_cpv]):
1712                                                 # The existing node can be reused.
1713                                                 selected_pkg = [e_type, myroot, e_cpv,
1714                                                         self.useFlags[myroot][e_cpv]]
1715
1716                         if myparent:
1717                                 #we are a dependency, so we want to be unconditionally added
1718                                 mypriority = priority.copy()
1719                                 if vardb.match(x):
1720                                         mypriority.satisfied = True
1721                                 if not self.create(selected_pkg[0:3], myparent,
1722                                         myuse=selected_pkg[-1], priority=mypriority,
1723                                         rev_dep=rev_deps, arg=arg):
1724                                         return 0
1725                         else:
1726                                 #if mysource is not set, then we are a command-line dependency and should not be added
1727                                 #if --onlydeps is specified.
1728                                 if not self.create(selected_pkg[0:3], myparent,
1729                                         addme=("--onlydeps" not in self.myopts),
1730                                         myuse=selected_pkg[-1], rev_dep=rev_deps, arg=arg):
1731                                         return 0
1732
1733                 if "--debug" in self.myopts:
1734                         print "Exiting...",myparent
1735                 return 1
1736
1737         def validate_blockers(self):
1738                 """Remove any blockers from the digraph that do not match any of the
1739                 packages within the graph.  If necessary, create hard deps to ensure
1740                 correct merge order such that mutually blocking packages are never
1741                 installed simultaneously."""
1742
1743                 if "--buildpkgonly" in self.myopts or \
1744                         "--nodeps" in self.myopts:
1745                         return True
1746
1747                 modified_slots = {}
1748                 for myroot in self.trees:
1749                         myslots = {}
1750                         modified_slots[myroot] = myslots
1751                         final_db = self.mydbapi[myroot]
1752                         slot_node_map = self._slot_node_map[myroot]
1753                         for slot_atom, mynode in slot_node_map.iteritems():
1754                                 mytype, myroot, mycpv, mystatus = mynode
1755                                 if mystatus == "merge":
1756                                         myslots[slot_atom] = mycpv
1757
1758                 #if "deep" in self.myparams:
1759                 if True:
1760                         # Pull in blockers from all installed packages that haven't already
1761                         # been pulled into the depgraph.  This is not enabled by default
1762                         # due to the performance penalty that is incurred by all the
1763                         # additional dep_check calls that are required.
1764
1765                         # Optimization hack for dep_check calls that minimizes the
1766                         # available matches by replacing the portdb with a fakedbapi
1767                         # instance.
1768                         class FakePortageTree(object):
1769                                 def __init__(self, mydb):
1770                                         self.dbapi = mydb
1771                         dep_check_trees = {}
1772                         for myroot in self.trees:
1773                                 dep_check_trees[myroot] = self.trees[myroot].copy()
1774                                 dep_check_trees[myroot]["porttree"] = \
1775                                         FakePortageTree(self.mydbapi[myroot])
1776
1777                         dep_keys = ["DEPEND","RDEPEND","PDEPEND"]
1778                         for myroot in self.trees:
1779                                 pkg_node_map = self.pkg_node_map[myroot]
1780                                 vardb = self.trees[myroot]["vartree"].dbapi
1781                                 portdb = self.trees[myroot]["porttree"].dbapi
1782                                 pkgsettings = self.pkgsettings[myroot]
1783                                 final_db = self.mydbapi[myroot]
1784                                 cpv_all_installed = self.trees[myroot]["vartree"].dbapi.cpv_all()
1785                                 blocker_cache = BlockerCache(myroot, vardb)
1786                                 for pkg in cpv_all_installed:
1787                                         blocker_atoms = None
1788                                         matching_node = pkg_node_map.get(pkg, None)
1789                                         if matching_node and \
1790                                                 matching_node[3] == "nomerge":
1791                                                 continue
1792                                         # If this node has any blockers, create a "nomerge"
1793                                         # node for it so that they can be enforced.
1794                                         self.spinner.update()
1795                                         blocker_data = blocker_cache.get(pkg)
1796                                         if blocker_data:
1797                                                 blocker_atoms = blocker_data.atoms
1798                                         else:
1799                                                 dep_vals = vardb.aux_get(pkg, dep_keys)
1800                                                 myuse = vardb.aux_get(pkg, ["USE"])[0].split()
1801                                                 depstr = " ".join(dep_vals)
1802                                                 # It is crucial to pass in final_db here in order to
1803                                                 # optimize dep_check calls by eliminating atoms via
1804                                                 # dep_wordreduce and dep_eval calls.
1805                                                 try:
1806                                                         portage.dep._dep_check_strict = False
1807                                                         success, atoms = portage.dep_check(depstr,
1808                                                                 final_db, pkgsettings, myuse=myuse,
1809                                                                 trees=dep_check_trees, myroot=myroot)
1810                                                 finally:
1811                                                         portage.dep._dep_check_strict = True
1812                                                 if not success:
1813                                                         slot_atom = "%s:%s" % (portage.dep_getkey(pkg),
1814                                                                 vardb.aux_get(pkg, ["SLOT"])[0])
1815                                                         if slot_atom in modified_slots[myroot]:
1816                                                                 # This package is being replaced anyway, so
1817                                                                 # ignore invalid dependencies so as not to
1818                                                                 # annoy the user too much (otherwise they'd be
1819                                                                 # forced to manually unmerge it first).
1820                                                                 continue
1821                                                         show_invalid_depstring_notice(
1822                                                                 ("installed", myroot, pkg, "nomerge"),
1823                                                                 depstr, atoms)
1824                                                         return False
1825                                                 blocker_atoms = [myatom for myatom in atoms \
1826                                                         if myatom.startswith("!")]
1827                                                 counter = long(vardb.aux_get(pkg, ["COUNTER"])[0])
1828                                                 blocker_cache[pkg] = \
1829                                                         blocker_cache.BlockerData(counter, blocker_atoms)
1830                                         if blocker_atoms:
1831                                                 # Don't store this parent in pkg_node_map, because it's
1832                                                 # not needed there and it might overwrite a "merge"
1833                                                 # node with the same cpv.
1834                                                 myparent = ("installed", myroot, pkg, "nomerge")
1835                                                 for myatom in blocker_atoms:
1836                                                         blocker = ("blocks", myroot, myatom[1:])
1837                                                         myparents = \
1838                                                                 self.blocker_parents.get(blocker, None)
1839                                                         if not myparents:
1840                                                                 myparents = set()
1841                                                                 self.blocker_parents[blocker] = myparents
1842                                                         myparents.add(myparent)
1843                                 blocker_cache.flush()
1844                                 del blocker_cache
1845
1846                 for blocker in self.blocker_parents.keys():
1847                         mytype, myroot, mydep = blocker
1848                         initial_db = self.trees[myroot]["vartree"].dbapi
1849                         final_db = self.mydbapi[myroot]
1850                         blocked_initial = initial_db.match(mydep)
1851                         blocked_final = final_db.match(mydep)
1852                         if not blocked_initial and not blocked_final:
1853                                 del self.blocker_parents[blocker]
1854                                 continue
1855                         blocked_slots_initial = {}
1856                         blocked_slots_final = {}
1857                         for cpv in blocked_initial:
1858                                 blocked_slots_initial[cpv] = \
1859                                         "%s:%s" % (portage.dep_getkey(cpv),
1860                                                 initial_db.aux_get(cpv, ["SLOT"])[0])
1861                         for cpv in blocked_final:
1862                                 blocked_slots_final[cpv] = \
1863                                         "%s:%s" % (portage.dep_getkey(cpv),
1864                                                 final_db.aux_get(cpv, ["SLOT"])[0])
1865                         blocked_slots_final_values = set(blocked_slots_final.itervalues())
1866                         for parent in list(self.blocker_parents[blocker]):
1867                                 ptype, proot, pcpv, pstatus = parent
1868                                 pdbapi = self.trees[proot][self.pkg_tree_map[ptype]].dbapi
1869                                 pslot = pdbapi.aux_get(pcpv, ["SLOT"])[0]
1870                                 pslot_atom = "%s:%s" % (portage.dep_getkey(pcpv), pslot)
1871                                 parent_static = pslot_atom not in modified_slots[proot]
1872                                 unresolved_blocks = False
1873                                 depends_on_order = set()
1874                                 for cpv in blocked_initial:
1875                                         slot_atom = blocked_slots_initial[cpv]
1876                                         if slot_atom == pslot_atom:
1877                                                 # The parent blocks an initial package in the same
1878                                                 # slot as itself.  The merge/nomerge status of neither
1879                                                 # node matters.  In any case, this particular block is
1880                                                 # automatically resolved.
1881                                                 continue
1882                                         if parent_static and \
1883                                                 slot_atom not in modified_slots[myroot]:
1884                                                 # This blocker will be handled the next time that a
1885                                                 # merge of either package is triggered.
1886                                                 continue
1887                                         if pstatus == "merge" and \
1888                                                 slot_atom not in blocked_slots_final_values:
1889                                                 upgrade_matches = final_db.match(slot_atom)
1890                                                 if upgrade_matches:
1891                                                         # Apparently an upgrade may be able to invalidate
1892                                                         # this block.
1893                                                         upgrade_node = \
1894                                                                 self.pkg_node_map[proot][upgrade_matches[0]]
1895                                                         depends_on_order.add(upgrade_node)
1896                                                         continue
1897                                         # None of the above blocker resolutions techniques apply,
1898                                         # so apparently this one is unresolvable.
1899                                         unresolved_blocks = True
1900                                 for cpv in blocked_final:
1901                                         slot_atom = blocked_slots_final[cpv]
1902                                         if slot_atom == pslot_atom:
1903                                                 # The parent blocks itself, so the merge order does not
1904                                                 # need to be enforced.
1905                                                 continue
1906                                         if parent_static and \
1907                                                 slot_atom not in modified_slots[myroot]:
1908                                                 # This blocker will be handled the next time that a
1909                                                 # merge of either package is triggered.
1910                                                 continue
1911                                         # None of the above blocker resolutions techniques apply,
1912                                         # so apparently this one is unresolvable.
1913                                         unresolved_blocks = True
1914                                 if not unresolved_blocks and depends_on_order:
1915                                         for node in depends_on_order:
1916                                                 # Enforce correct merge order with a hard dep.
1917                                                 self.digraph.addnode(node, parent,
1918                                                         priority=DepPriority(buildtime=True))
1919                                                 # Count references to this blocker so that it can be
1920                                                 # invalidated after nodes referencing it have been
1921                                                 # merged.
1922                                                 self.blocker_digraph.addnode(node, blocker)
1923                                 if not unresolved_blocks and not depends_on_order:
1924                                         self.blocker_parents[blocker].remove(parent)
1925                         if not self.blocker_parents[blocker]:
1926                                 del self.blocker_parents[blocker]
1927                 # Validate blockers that depend on merge order.
1928                 if not self.blocker_digraph.empty():
1929                         self.altlist()
1930                 if self._slot_collision_info:
1931                         # The user is only notified of a slot collision if there are no
1932                         # unresolvable blocks.
1933                         for x in self.altlist():
1934                                 if x[0] == "blocks":
1935                                         return True
1936                         self._show_slot_collision_notice(self._slot_collision_info[0])
1937                         if not self._accept_collisions():
1938                                 return False
1939                 return True
1940
1941         def _accept_collisions(self):
1942                 acceptable = False
1943                 for x in ("--nodeps", "--pretend", "--fetchonly", "--fetch-all-uri"):
1944                         if x in self.myopts:
1945                                 acceptable = True
1946                                 break
1947                 return acceptable
1948
1949         def altlist(self, reversed=False):
1950                 if reversed in self._altlist_cache:
1951                         return self._altlist_cache[reversed][:]
1952                 mygraph=self.digraph.copy()
1953                 myblockers = self.blocker_digraph.copy()
1954                 retlist=[]
1955                 circular_blocks = False
1956                 blocker_deps = None
1957                 asap_nodes = []
1958                 if reversed:
1959                         get_nodes = mygraph.root_nodes
1960                 else:
1961                         get_nodes = mygraph.leaf_nodes
1962                         for cpv, node in self.pkg_node_map["/"].iteritems():
1963                                 if "portage" == portage.catsplit(portage.dep_getkey(cpv))[-1]:
1964                                         asap_nodes.append(node)
1965                                         break
1966                 ignore_priority_range = [None]
1967                 ignore_priority_range.extend(
1968                         xrange(DepPriority.MIN, DepPriority.MEDIUM + 1))
1969                 while not mygraph.empty():
1970                         ignore_priority = None
1971                         nodes = None
1972                         if asap_nodes:
1973                                 """ASAP nodes are merged before their soft deps."""
1974                                 for node in asap_nodes:
1975                                         if not mygraph.contains(node):
1976                                                 asap_nodes.remove(node)
1977                                                 continue
1978                                         if not mygraph.child_nodes(node,
1979                                                 ignore_priority=DepPriority.SOFT):
1980                                                 nodes = [node]
1981                                                 asap_nodes.remove(node)
1982                                                 break
1983                         if not nodes:
1984                                 for ignore_priority in ignore_priority_range:
1985                                         nodes = get_nodes(ignore_priority=ignore_priority)
1986                                         if nodes:
1987                                                 break
1988                         selected_nodes = None
1989                         if nodes:
1990                                 if ignore_priority <= DepPriority.SOFT:
1991                                         if ignore_priority is None and not reversed:
1992                                                 # Greedily pop all of these nodes since no relationship
1993                                                 # has been ignored.  This optimization destroys --tree
1994                                                 # output, so it's disabled in reversed mode.
1995                                                 selected_nodes = nodes
1996                                         else:
1997                                                 # Only pop one node for optimal merge order.
1998                                                 selected_nodes = [nodes[0]]
1999                                 else:
2000                                         """Recursively gather a group of nodes that RDEPEND on
2001                                         eachother.  This ensures that they are merged as a group
2002                                         and get their RDEPENDs satisfied as soon as possible."""
2003                                         def gather_deps(mergeable_nodes, selected_nodes, node):
2004                                                 if node in selected_nodes:
2005                                                         return True
2006                                                 if node not in mergeable_nodes:
2007                                                         return False
2008                                                 selected_nodes.add(node)
2009                                                 for child in mygraph.child_nodes(node,
2010                                                         ignore_priority=DepPriority.SOFT):
2011                                                         if not gather_deps(
2012                                                                 mergeable_nodes, selected_nodes, child):
2013                                                                 return False
2014                                                 return True
2015                                         mergeable_nodes = set(nodes)
2016                                         for node in nodes:
2017                                                 selected_nodes = set()
2018                                                 if gather_deps(
2019                                                         mergeable_nodes, selected_nodes, node):
2020                                                         break
2021                                                 else:
2022                                                         selected_nodes = None
2023
2024                         if not selected_nodes:
2025                                 if not myblockers.is_empty():
2026                                         """A blocker couldn't be circumnavigated while keeping all
2027                                         dependencies satisfied.  The user will have to resolve this
2028                                         manually.  This is a panic condition and thus the order
2029                                         doesn't really matter, so just pop a random node in order
2030                                         to avoid a circular dependency panic if possible."""
2031                                         if not circular_blocks:
2032                                                 circular_blocks = True
2033                                                 blocker_deps = myblockers.leaf_nodes()
2034                                         if blocker_deps:
2035                                                 selected_nodes = [blocker_deps.pop()]
2036
2037                         if not selected_nodes:
2038                                 if reversed:
2039                                         """The circular deps ouput should have less noise when
2040                                         altlist is not in reversed mode."""
2041                                         self.altlist()
2042                                 print "!!! Error: circular dependencies:"
2043                                 print
2044                                 mygraph.debug_print()
2045                                 sys.exit(1)
2046
2047                         for node in selected_nodes:
2048                                 retlist.append(list(node))
2049                                 mygraph.remove(node)
2050                                 if not reversed and not circular_blocks and myblockers.contains(node):
2051                                         """This node may have invalidated one or more blockers."""
2052                                         myblockers.remove(node)
2053                                         for blocker in myblockers.root_nodes():
2054                                                 if not myblockers.child_nodes(blocker):
2055                                                         myblockers.remove(blocker)
2056                                                         del self.blocker_parents[blocker]
2057
2058                 if not reversed:
2059                         """Blocker validation does not work with reverse mode,
2060                         so self.altlist() should first be called with reverse disabled
2061                         so that blockers are properly validated."""
2062                         self.blocker_digraph = myblockers
2063
2064                 """ Add any unresolved blocks so that they can be displayed."""
2065                 for blocker in self.blocker_parents:
2066                         retlist.append(list(blocker))
2067                 self._altlist_cache[reversed] = retlist[:]
2068                 return retlist
2069
2070         def xcreate(self,mode="system"):
2071                 vardb = self.trees[self.target_root]["vartree"].dbapi
2072                 portdb = self.trees[self.target_root]["porttree"].dbapi
2073                 bindb = self.trees[self.target_root]["bintree"].dbapi
2074                 def visible(mylist):
2075                         matches = portdb.gvisible(portdb.visible(mylist))
2076                         return [x for x in mylist \
2077                                 if x in matches or not portdb.cpv_exists(x)]
2078                 world_problems = False
2079                 if mode=="system":
2080                         mylist = getlist(self.settings, "system")
2081                 else:
2082                         #world mode
2083                         worldlist = getlist(self.settings, "world")
2084                         sysdict = genericdict(getlist(self.settings, "system"))
2085                         worlddict=genericdict(worldlist)
2086
2087                         for x in worlddict.keys():
2088                                 if not portage.isvalidatom(x):
2089                                         world_problems = True
2090                                 elif not self.trees[self.target_root]["vartree"].dbapi.match(x):
2091                                         world_problems = True
2092                                 else:
2093                                         sysdict[x]=worlddict[x]
2094
2095                         mylist = sysdict.keys()
2096
2097                 newlist = []
2098                 for atom in mylist:
2099                         mykey = portage.dep_getkey(atom)
2100                         if True:
2101                                 newlist.append(atom)
2102                                 """Make sure all installed slots are updated when possible.
2103                                 Do this with --emptytree also, to ensure that all slots are
2104                                 remerged."""
2105                                 myslots = set()
2106                                 for cpv in vardb.match(mykey):
2107                                         myslots.add(vardb.aux_get(cpv, ["SLOT"])[0])
2108                                 if myslots:
2109                                         best_pkgs = []
2110                                         if "--usepkg" in self.myopts:
2111                                                 mymatches = bindb.match(atom)
2112                                                 if "--usepkgonly" not in self.myopts:
2113                                                         mymatches = visible(mymatches)
2114                                                 best_pkg = portage.best(mymatches)
2115                                                 if best_pkg:
2116                                                         best_slot = bindb.aux_get(best_pkg, ["SLOT"])[0]
2117                                                         best_pkgs.append(("binary", best_pkg, best_slot))
2118                                         if "--usepkgonly" not in self.myopts:
2119                                                 best_pkg = portage.best(portdb.match(atom))
2120                                                 if best_pkg:
2121                                                         best_slot = portdb.aux_get(best_pkg, ["SLOT"])[0]
2122                                                         best_pkgs.append(("ebuild", best_pkg, best_slot))
2123                                         if best_pkgs:
2124                                                 best_pkg = portage.best([x[1] for x in best_pkgs])
2125                                                 best_pkgs = [x for x in best_pkgs if x[1] == best_pkg]
2126                                                 best_slot = best_pkgs[0][2]
2127                                                 myslots.add(best_slot)
2128                                 if len(myslots) > 1:
2129                                         for myslot in myslots:
2130                                                 myslot_atom = "%s:%s" % (mykey, myslot)
2131                                                 available = False
2132                                                 if "--usepkgonly" not in self.myopts and \
2133                                                         self.trees[self.target_root][
2134                                                         "porttree"].dbapi.match(myslot_atom):
2135                                                         available = True
2136                                                 elif "--usepkg" in self.myopts:
2137                                                         mymatches = bindb.match(myslot_atom)
2138                                                         if "--usepkgonly" not in self.myopts:
2139                                                                 mymatches = visible(mymatches)
2140                                                         if mymatches:
2141                                                                 available = True
2142                                                 if available:
2143                                                         newlist.append(myslot_atom)
2144                 mylist = newlist
2145                 
2146                 missing_atoms = []
2147                 for mydep in mylist:
2148                         try:
2149                                 if not self.select_dep(
2150                                         self.target_root, mydep, raise_on_missing=True, arg=mydep):
2151                                         print >> sys.stderr, "\n\n!!! Problem resolving dependencies for", mydep
2152                                         return 0
2153                         except ValueError:
2154                                 missing_atoms.append(mydep)
2155
2156                 if not self.validate_blockers():
2157                         return False
2158
2159                 if world_problems:
2160                         print >> sys.stderr, "\n!!! Problems have been detected with your world file"
2161                         print >> sys.stderr, "!!! Please run "+green("emaint --check world")+"\n"
2162
2163                 if missing_atoms:
2164                         print >> sys.stderr, "\n" + colorize("BAD", "!!!") + \
2165                                 " Ebuilds for the following packages are either all"
2166                         print >> sys.stderr, colorize("BAD", "!!!") + " masked or don't exist:"
2167                         print >> sys.stderr, " ".join(missing_atoms) + "\n"
2168
2169                 return 1
2170
2171         def display(self,mylist,verbosity=None):
2172                 if verbosity is None:
2173                         verbosity = ("--quiet" in self.myopts and 1 or \
2174                                 "--verbose" in self.myopts and 3 or 2)
2175                 changelogs=[]
2176                 p=[]
2177
2178                 counters = PackageCounters()
2179
2180                 if verbosity == 1 and "--verbose" not in self.myopts:
2181                         def create_use_string(*args):
2182                                 return ""
2183                 else:
2184                         def create_use_string(name, cur_iuse, iuse_forced, cur_use,
2185                                 old_iuse, old_use,
2186                                 is_new, all_flags=(verbosity == 3 or "--quiet" in self.myopts),
2187                                 alphabetical=("--alphabetical" in self.myopts)):
2188                                 enabled = []
2189                                 if alphabetical:
2190                                         disabled = enabled
2191                                         removed = enabled
2192                                 else:
2193                                         disabled = []
2194                                         removed = []
2195                                 cur_iuse = set(cur_iuse)
2196                                 enabled_flags = cur_iuse.intersection(cur_use)
2197                                 removed_iuse = set(old_iuse).difference(cur_iuse)
2198                                 any_iuse = cur_iuse.union(old_iuse)
2199                                 any_iuse = list(any_iuse)
2200                                 any_iuse.sort()
2201                                 for flag in any_iuse:
2202                                         flag_str = None
2203                                         isEnabled = False
2204                                         if flag in enabled_flags:
2205                                                 isEnabled = True
2206                                                 if is_new or flag in old_use and all_flags:
2207                                                         flag_str = red(flag)
2208                                                 elif flag not in old_iuse:
2209                                                         flag_str = yellow(flag) + "%*"
2210                                                 elif flag not in old_use:
2211                                                         flag_str = green(flag) + "*"
2212                                         elif flag in removed_iuse:
2213                                                 if all_flags:
2214                                                         flag_str = yellow("-" + flag) + "%"
2215                                                         if flag in old_use:
2216                                                                 flag_str += "*"
2217                                                         flag_str = "(" + flag_str + ")"
2218                                                         removed.append(flag_str)
2219                                                 continue
2220                                         else:
2221                                                 if is_new or flag in old_iuse and flag not in old_use and all_flags:
2222                                                         flag_str = blue("-" + flag)
2223                                                 elif flag not in old_iuse:
2224                                                         flag_str = yellow("-" + flag)
2225                                                         if flag not in iuse_forced:
2226                                                                 flag_str += "%"
2227                                                 elif flag in old_use:
2228                                                         flag_str = green("-" + flag) + "*"
2229                                         if flag_str:
2230                                                 if flag in iuse_forced:
2231                                                         flag_str = "(" + flag_str + ")"
2232                                                 if isEnabled:
2233                                                         enabled.append(flag_str)
2234                                                 else:
2235                                                         disabled.append(flag_str)
2236
2237                                 if alphabetical:
2238                                         ret = " ".join(enabled)
2239                                 else:
2240                                         ret = " ".join(enabled + disabled + removed)
2241                                 if ret:
2242                                         ret = '%s="%s" ' % (name, ret)
2243                                 return ret
2244
2245                 if verbosity == 3:
2246                         # FIXME: account for the possibility of different overlays in
2247                         # /etc/make.conf vs. ${PORTAGE_CONFIGROOT}/etc/make.conf
2248                         overlays = self.settings["PORTDIR_OVERLAY"].split()
2249                         overlays_real = [os.path.realpath(t) \
2250                                 for t in self.settings["PORTDIR_OVERLAY"].split()]
2251
2252                 tree_nodes = []
2253                 node_depth = {}
2254                 i = 0
2255                 depth = 0
2256                 for x in mylist:
2257                         if "blocks" == x[0]:
2258                                 continue
2259                         graph_key = tuple(x)
2260                         if "--tree" in self.myopts:
2261                                 depth = len(tree_nodes)
2262                                 while depth and graph_key not in \
2263                                         self.digraph.child_nodes(tree_nodes[depth-1]):
2264                                                 depth -= 1
2265                                 tree_nodes = tree_nodes[:depth]
2266                                 tree_nodes.append(graph_key)
2267                         node_depth[graph_key] = depth
2268
2269                 last_merge_depth = 0
2270                 for i in xrange(len(mylist)-1,-1,-1):
2271                         if "blocks" == mylist[i][0]:
2272                                 continue
2273                         graph_key = tuple(mylist[i])
2274                         if mylist[i][-1] != "nomerge":
2275                                 last_merge_depth = node_depth[graph_key]
2276                                 continue
2277                         if node_depth[graph_key] >= last_merge_depth or \
2278                                 i < len(mylist) - 1 and \
2279                                 node_depth[graph_key] >= node_depth[tuple(mylist[i+1])]:
2280                                         del mylist[i]
2281                                         del node_depth[graph_key]
2282                 del tree_nodes
2283
2284                 display_overlays=False
2285                 # files to fetch list - avoids counting a same file twice
2286                 # in size display (verbose mode)
2287                 myfetchlist=[]
2288                 for x in mylist:
2289                         pkg_type = x[0]
2290                         myroot = x[1]
2291                         pkg_key = x[2]
2292                         portdb = self.trees[myroot]["porttree"].dbapi
2293                         bindb  = self.trees[myroot]["bintree"].dbapi
2294                         vardb = self.trees[myroot]["vartree"].dbapi
2295                         vartree = self.trees[myroot]["vartree"]
2296                         pkgsettings = self.pkgsettings[myroot]
2297
2298                         fetch=" "
2299
2300                         if x[0]=="blocks":
2301                                 addl=""+red("B")+"  "+fetch+"  "
2302                                 counters.blocks += 1
2303                                 resolved = portage.key_expand(
2304                                         pkg_key, mydb=vardb, settings=pkgsettings)
2305                                 if "--columns" in self.myopts and "--quiet" in self.myopts:
2306                                         print addl,red(resolved),
2307                                 else:
2308                                         print "["+x[0]+" "+addl+"]",red(resolved),
2309                                 block_parents = self.blocker_parents[tuple(x)]
2310                                 block_parents = set([pnode[2] for pnode in block_parents])
2311                                 block_parents = ", ".join(block_parents)
2312                                 if resolved!=x[2]:
2313                                         print bad("(\"%s\" is blocking %s)") % \
2314                                                 (pkg_key, block_parents)
2315                                 else:
2316                                         print bad("(is blocking %s)") % block_parents
2317                         else:
2318                                 mydbapi = self.trees[myroot][self.pkg_tree_map[pkg_type]].dbapi
2319                                 binary_package = True
2320                                 if "ebuild" == pkg_type:
2321                                         if "merge" == x[3] or \
2322                                                 not vartree.dbapi.cpv_exists(pkg_key):
2323                                                 """An ebuild "merge" node or a --onlydeps "nomerge"
2324                                                 node."""
2325                                                 binary_package = False
2326                                                 pkgsettings.setcpv(pkg_key, mydb=portdb)
2327                                                 if pkg_key not in self.useFlags[myroot]:
2328                                                         self.useFlags[myroot][pkg_key] = \
2329                                                                 pkgsettings["USE"].split()
2330                                         else:
2331                                                 # An ebuild "nomerge" node, so USE come from the vardb.
2332                                                 mydbapi = vartree.dbapi
2333                                 if pkg_key not in self.useFlags[myroot]:
2334                                         """If this is a --resume then the USE flags need to be
2335                                         fetched from the appropriate locations here."""
2336                                         self.useFlags[myroot][pkg_key] = mydbapi.aux_get(
2337                                                 pkg_key, ["USE"])[0].split()
2338
2339                                 if "ebuild" == pkg_type and x[3] != "nomerge" and \
2340                                         "fetch" in portdb.aux_get(
2341                                         x[2], ["RESTRICT"])[0].split():
2342                                         fetch = red("F")
2343                                         counters.restrict_fetch += 1
2344                                         if portdb.fetch_check(
2345                                                 pkg_key, self.useFlags[myroot][pkg_key]):
2346                                                 fetch = green("f")
2347                                                 counters.restrict_fetch_satisfied += 1
2348
2349                                 #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty"
2350                                 #param is used for -u, where you still *do* want to see when something is being upgraded.
2351                                 myoldbest=""
2352                                 if vardb.cpv_exists(pkg_key):
2353                                         addl="  "+yellow("R")+fetch+"  "
2354                                         if x[3] != "nomerge":
2355                                                 counters.reinst += 1
2356                                 elif vardb.match(portage.dep_getkey(pkg_key)):
2357                                         mynewslot = mydbapi.aux_get(pkg_key, ["SLOT"])[0]
2358                                         myoldlist = self.trees[x[1]]["vartree"].dbapi.match(
2359                                                 portage.pkgsplit(x[2])[0])
2360                                         myinslotlist = [inst_pkg for inst_pkg in myoldlist
2361                                                 if mynewslot == vardb.aux_get(inst_pkg, ["SLOT"])[0]]
2362                                         if myinslotlist:
2363                                                 myoldbest=portage.best(myinslotlist)
2364                                                 addl="   "+fetch
2365                                                 if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0:
2366                                                         # Downgrade in slot
2367                                                         addl+=turquoise("U")+blue("D")
2368                                                         counters.downgrades += 1
2369                                                 else:
2370                                                         # Update in slot
2371                                                         addl+=turquoise("U")+" "
2372                                                         counters.upgrades += 1
2373                                         else:
2374                                                 # New slot, mark it new.
2375                                                 addl=" "+green("NS")+fetch+"  "
2376                                                 counters.newslot += 1
2377
2378                                         if "--changelog" in self.myopts:
2379                                                 slot_atom = "%s:%s" % (portage.dep_getkey(pkg_key),
2380                                                         mydbapi.aux_get(pkg_key, ["SLOT"])[0])
2381                                                 inst_matches = vardb.match(slot_atom)
2382                                                 if inst_matches:
2383                                                         changelogs.extend(self.calc_changelog(
2384                                                                 portdb.findname(pkg_key),
2385                                                                 inst_matches[0], pkg_key))
2386                                 else:
2387                                         addl=" "+green("N")+" "+fetch+"  "
2388                                         counters.new += 1
2389
2390                                 verboseadd=""
2391                                 
2392                                 if pkg_key in self.useFlags[myroot]:
2393                                         # USE flag display
2394                                         cur_iuse = list(filter_iuse_defaults(
2395                                                 mydbapi.aux_get(pkg_key, ["IUSE"])[0].split()))
2396
2397                                         forced_flags = set()
2398                                         if not binary_package:
2399                                                 forced_flags.update(pkgsettings.useforce)
2400                                                 forced_flags.update(pkgsettings.usemask)
2401
2402                                         cur_iuse = portage.unique_array(cur_iuse)
2403                                         cur_iuse.sort()
2404                                         cur_use = self.useFlags[myroot][pkg_key]
2405                                         cur_use = [flag for flag in cur_use if flag in cur_iuse]
2406
2407                                         if myoldbest:
2408                                                 pkg = myoldbest
2409                                         else:
2410                                                 pkg = x[2]
2411                                         if self.trees[x[1]]["vartree"].dbapi.cpv_exists(pkg):
2412                                                 old_iuse, old_use = \
2413                                                         self.trees[x[1]]["vartree"].dbapi.aux_get(
2414                                                                 pkg, ["IUSE", "USE"])
2415                                                 old_iuse = list(set(
2416                                                         filter_iuse_defaults(old_iuse.split())))
2417                                                 old_iuse.sort()
2418                                                 old_use = old_use.split()
2419                                                 is_new = False
2420                                         else:
2421                                                 old_iuse = []
2422                                                 old_use = []
2423                                                 is_new = True
2424
2425                                         old_use = [flag for flag in old_use if flag in old_iuse]
2426
2427                                         use_expand = pkgsettings["USE_EXPAND"].lower().split()
2428                                         use_expand.sort()
2429                                         use_expand.reverse()
2430                                         use_expand_hidden = \
2431                                                 pkgsettings["USE_EXPAND_HIDDEN"].lower().split()
2432
2433                                         def map_to_use_expand(myvals, forcedFlags=False):
2434                                                 ret = {}
2435                                                 forced = {}
2436                                                 for exp in use_expand:
2437                                                         ret[exp] = []
2438                                                         forced[exp] = set()
2439                                                         for val in myvals[:]:
2440                                                                 if val.startswith(exp.lower()+"_"):
2441                                                                         if val in forced_flags:
2442                                                                                 forced[exp].add(val[len(exp)+1:])
2443                                                                         ret[exp].append(val[len(exp)+1:])
2444                                                                         myvals.remove(val)
2445                                                 ret["USE"] = myvals
2446                                                 forced["USE"] = [val for val in myvals \
2447                                                         if val in forced_flags]
2448                                                 for exp in use_expand_hidden:
2449                                                         if exp in ret:
2450                                                                 del ret[exp]
2451                                                 if forcedFlags:
2452                                                         return ret, forced
2453                                                 return ret
2454
2455                                         cur_iuse_map, iuse_forced = \
2456                                                 map_to_use_expand(cur_iuse, forcedFlags=True)
2457                                         cur_use_map = map_to_use_expand(cur_use)
2458                                         old_iuse_map = map_to_use_expand(old_iuse)
2459                                         old_use_map = map_to_use_expand(old_use)
2460
2461                                         use_expand.sort()
2462                                         use_expand.insert(0, "USE")
2463                                         
2464                                         for key in use_expand:
2465                                                 if key in use_expand_hidden:
2466                                                         continue
2467                                                 verboseadd += create_use_string(key.upper(),
2468                                                         cur_iuse_map[key], iuse_forced[key],
2469                                                         cur_use_map[key], old_iuse_map[key],
2470                                                         old_use_map[key], is_new)
2471
2472                                 if verbosity == 3:
2473                                         # size verbose
2474                                         mysize=0
2475                                         if x[0] == "ebuild" and x[-1]!="nomerge":
2476                                                 myfilesdict = portdb.getfetchsizes(
2477                                                         pkg_key, useflags=self.useFlags[myroot][pkg_key],
2478                                                         debug=self.edebug)
2479                                                 if myfilesdict is None:
2480                                                         myfilesdict="[empty/missing/bad digest]"
2481                                                 else:
2482                                                         for myfetchfile in myfilesdict.keys():
2483                                                                 if myfetchfile not in myfetchlist:
2484                                                                         mysize+=myfilesdict[myfetchfile]
2485                                                                         myfetchlist.append(myfetchfile)
2486                                                         counters.totalsize += mysize
2487                                                 verboseadd+=format_size(mysize)+" "
2488
2489                                         # overlay verbose
2490                                         # XXX: Invalid binaries have caused tracebacks here. 'if file_name'
2491                                         # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge']
2492                                         file_name = portdb.findname(pkg_key)
2493                                         if file_name: # It might not exist in the tree
2494                                                 dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..")
2495                                                 if (overlays_real.count(dir_name)>0):
2496                                                         verboseadd+=teal("["+str(overlays_real.index(
2497                                                                 os.path.normpath(dir_name))+1)+"]")+" "
2498                                                         display_overlays=True
2499                                         else:
2500                                                 verboseadd += "[No ebuild?]"
2501
2502                                 xs=portage.pkgsplit(x[2])
2503                                 if xs[2]=="r0":
2504                                         xs[2]=""
2505                                 else:
2506                                         xs[2]="-"+xs[2]
2507
2508                                 mywidth = 130
2509                                 if "COLUMNWIDTH" in self.settings:
2510                                         try:
2511                                                 mywidth = int(self.settings["COLUMNWIDTH"])
2512                                         except ValueError, e:
2513                                                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
2514                                                 portage.writemsg(
2515                                                         "!!! Unable to parse COLUMNWIDTH='%s'\n" % \
2516                                                         self.settings["COLUMNWIDTH"], noiselevel=-1)
2517                                                 del e
2518                                 oldlp=mywidth-30
2519                                 newlp=oldlp-30
2520
2521                                 indent = " " * node_depth[tuple(x)]
2522
2523                                 if myoldbest:
2524                                         myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2]
2525                                         if myoldbest[-3:]=="-r0":
2526                                                 myoldbest=myoldbest[:-3]
2527                                         myoldbest=blue("["+myoldbest+"]")
2528
2529                                 if x[1]!="/":
2530                                         if myoldbest:
2531                                                 myoldbest +=" "
2532                                         if "--columns" in self.myopts:
2533                                                 if "--quiet" in self.myopts:
2534                                                         myprint=addl+" "+indent+darkgreen(xs[0])
2535                                                         myprint=myprint+darkblue(" "+xs[1]+xs[2])+" "
2536                                                         myprint=myprint+myoldbest
2537                                                         myprint=myprint+darkgreen("to "+x[1])
2538                                                 else:
2539                                                         myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
2540                                                         if (newlp-nc_len(myprint)) > 0:
2541                                                                 myprint=myprint+(" "*(newlp-nc_len(myprint)))
2542                                                         myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] "
2543                                                         if (oldlp-nc_len(myprint)) > 0:
2544                                                                 myprint=myprint+" "*(oldlp-nc_len(myprint))
2545                                                         myprint=myprint+myoldbest
2546                                                         myprint=myprint+darkgreen("to "+x[1])+" "+verboseadd
2547                                         else:
2548                                                 if x[3] == "nomerge":
2549                                                         myprint = darkblue("[nomerge      ] ")
2550                                                 else:
2551                                                         myprint = "[" + pkg_type + " " + addl + "] "
2552                                                 myprint += indent + darkgreen(pkg_key) + " " + \
2553                                                         myoldbest + darkgreen("to " + myroot) + " " + \
2554                                                         verboseadd
2555                                 else:
2556                                         if "--columns" in self.myopts:
2557                                                 if "--quiet" in self.myopts:
2558                                                         myprint=addl+" "+indent+darkgreen(xs[0])
2559                                                         myprint=myprint+" "+green(xs[1]+xs[2])+" "
2560                                                         myprint=myprint+myoldbest
2561                                                 else:
2562                                                         myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0])
2563                                                         if (newlp-nc_len(myprint)) > 0:
2564                                                                 myprint=myprint+(" "*(newlp-nc_len(myprint)))
2565                                                         myprint=myprint+green(" ["+xs[1]+xs[2]+"] ")
2566                                                         if (oldlp-nc_len(myprint)) > 0:
2567                                                                 myprint=myprint+(" "*(oldlp-nc_len(myprint)))
2568                                                         myprint=myprint+myoldbest+"  "+verboseadd
2569                                         else:
2570                                                 if x[3]=="nomerge":
2571                                                         myprint=darkblue("[nomerge      ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd
2572                                                 else:
2573                                                         myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd
2574                                 p.append(myprint)
2575
2576                         mysplit = portage.pkgsplit(x[2])
2577                         if "--tree" not in self.myopts and mysplit and \
2578                                 len(mysplit) == 3 and mysplit[0] == "sys-apps/portage" and \
2579                                 x[1] == "/":
2580
2581                                 if mysplit[2] == "r0":
2582                                         myversion = mysplit[1]
2583                                 else:
2584                                         myversion = "%s-%s" % (mysplit[1], mysplit[2])
2585
2586                                 if myversion != portage.VERSION and "--quiet" not in self.myopts:
2587                                         if mylist.index(x) < len(mylist) - 1 and \
2588                                                 "livecvsportage" not in self.settings.features:
2589                                                 p.append(colorize("WARN", "*** Portage will stop merging at this point and reload itself,"))
2590                                                 p.append(colorize("WARN", "    then resume the merge."))
2591                                                 print
2592                         del mysplit
2593
2594                 for x in p:
2595                         print x
2596
2597                 if verbosity == 3:
2598                         print
2599                         print counters
2600                         if overlays and display_overlays:
2601                                 print "Portage overlays:"
2602                                 y=0
2603                                 for x in overlays:
2604                                         y=y+1
2605                                         print " "+teal("["+str(y)+"]"),x
2606
2607                 if "--changelog" in self.myopts:
2608                         print
2609                         for revision,text in changelogs:
2610                                 print bold('*'+revision)
2611                                 sys.stdout.write(text)
2612
2613                 if self._pprovided_args:
2614                         msg = []
2615                         msg.append(bad("\nWARNING: "))
2616                         if len(self._pprovided_args) > 1:
2617                                 msg.append("Requested packages will not be " + \
2618                                         "merged because they are listed in\n")
2619                         else:
2620                                 msg.append("A requested package will not be " + \
2621                                         "merged because it is listed in\n")
2622                         msg.append("         package.provided:\n\n")
2623                         for arg in self._pprovided_args:
2624                                 msg.append("             " + arg + "\n")
2625                         msg.append("\n")
2626                         sys.stderr.write("".join(msg))
2627
2628         def calc_changelog(self,ebuildpath,current,next):
2629                 current = '-'.join(portage.catpkgsplit(current)[1:])
2630                 if current.endswith('-r0'): current = current[:-3]
2631                 next = '-'.join(portage.catpkgsplit(next)[1:])
2632                 if next.endswith('-r0'): next = next[:-3]
2633                 changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog')
2634                 try:
2635                         changelog = open(changelogpath).read()
2636                 except SystemExit, e:
2637                         raise # Needed else can't exit
2638                 except:
2639                         return []
2640                 divisions = self.find_changelog_tags(changelog)
2641                 #print 'XX from',current,'to',next
2642                 #for div,text in divisions: print 'XX',div
2643                 # skip entries for all revisions above the one we are about to emerge
2644                 for i in range(len(divisions)):
2645                         if divisions[i][0]==next:
2646                                 divisions = divisions[i:]
2647                                 break
2648                 # find out how many entries we are going to display
2649                 for i in range(len(divisions)):
2650                         if divisions[i][0]==current:
2651                                 divisions = divisions[:i]
2652                                 break
2653                 else:
2654                     # couldnt find the current revision in the list. display nothing
2655                         return []
2656                 return divisions
2657
2658         def find_changelog_tags(self,changelog):
2659                 divs = []
2660                 release = None
2661                 while 1:
2662                         match = re.search(r'^\*\ ?([-a-zA-Z0-9_.+]*)(?:\ .*)?\n',changelog,re.M)
2663                         if match is None:
2664                                 if release is not None:
2665                                         divs.append((release,changelog))
2666                                 return divs
2667                         if release is not None:
2668                                 divs.append((release,changelog[:match.start()]))
2669                         changelog = changelog[match.end():]
2670                         release = match.group(1)
2671                         if release.endswith('.ebuild'):
2672                                 release = release[:-7]
2673                         if release.endswith('-r0'):
2674                                 release = release[:-3]
2675
2676         def outdated(self):
2677                 return self.outdatedpackages
2678
2679 class PackageCounters(object):
2680
2681         def __init__(self):
2682                 self.upgrades   = 0
2683                 self.downgrades = 0
2684                 self.new        = 0
2685                 self.newslot    = 0
2686                 self.reinst     = 0
2687                 self.blocks     = 0
2688                 self.totalsize  = 0
2689                 self.restrict_fetch           = 0
2690                 self.restrict_fetch_satisfied = 0
2691
2692         def __str__(self):
2693                 total_installs = self.upgrades + self.downgrades + self.newslot + self.new + self.reinst
2694                 myoutput = []
2695                 details = []
2696                 myoutput.append("Total: %s package" % total_installs)
2697                 if total_installs != 1:
2698                         myoutput.append("s")
2699                 if total_installs != 0:
2700                         myoutput.append(" (")
2701                 if self.upgrades > 0:
2702                         details.append("%s upgrade" % self.upgrades)
2703                         if self.upgrades > 1:
2704                                 details[-1] += "s"
2705                 if self.downgrades > 0:
2706                         details.append("%s downgrade" % self.downgrades)
2707                         if self.downgrades > 1:
2708                                 details[-1] += "s"
2709                 if self.new > 0:
2710                         details.append("%s new" % self.new)
2711                 if self.newslot > 0:
2712                         details.append("%s in new slot" % self.newslot)
2713                         if self.newslot > 1:
2714                                 details[-1] += "s"
2715                 if self.reinst > 0:
2716                         details.append("%s reinstall" % self.reinst)
2717                         if self.reinst > 1:
2718                                 details[-1] += "s"
2719                 if self.blocks > 0:
2720                         details.append("%s block" % self.blocks)
2721                         if self.blocks > 1:
2722                                 details[-1] += "s"
2723                 myoutput.append(", ".join(details))
2724                 if total_installs != 0:
2725                         myoutput.append(")")
2726                 myoutput.append(", Size of downloads: %s" % format_size(self.totalsize))
2727                 if self.restrict_fetch:
2728                         myoutput.append("\nFetch Restriction: %s package" % \
2729                                 self.restrict_fetch)
2730                         if self.restrict_fetch > 1:
2731                                 myoutput.append("s")
2732                 if self.restrict_fetch_satisfied < self.restrict_fetch:
2733                         myoutput.append(bad(" (%s unsatisfied)") % \
2734                                 (self.restrict_fetch - self.restrict_fetch_satisfied))
2735                 return "".join(myoutput)
2736
2737 class MergeTask(object):
2738
2739         def __init__(self, settings, trees, myopts):
2740                 self.settings = settings
2741                 self.target_root = settings["ROOT"]
2742                 self.trees = trees
2743                 self.myopts = myopts
2744                 self.edebug = 0
2745                 if settings.get("PORTAGE_DEBUG", "") == "1":
2746                         self.edebug = 1
2747                 self.pkgsettings = {}
2748                 self.pkgsettings[self.target_root] = portage.config(clone=settings)
2749                 if self.target_root != "/":
2750                         self.pkgsettings["/"] = \
2751                                 portage.config(clone=trees["/"]["vartree"].settings)
2752
2753         def merge(self, mylist, favorites, mtimedb):
2754                 failed_fetches = []
2755                 mymergelist=[]
2756                 ldpath_mtimes = mtimedb["ldpath"]
2757                 xterm_titles = "notitles" not in self.settings.features
2758
2759                 #check for blocking dependencies
2760                 if "--fetchonly" not in self.myopts and \
2761                         "--buildpkgonly" not in self.myopts:
2762                         for x in mylist:
2763                                 if x[0]=="blocks":
2764                                         print "\n!!! Error: the "+x[2]+" package conflicts with another package;"
2765                                         print   "!!!        the two packages cannot be installed on the same system together."
2766                                         print   "!!!        Please use 'emerge --pretend' to determine blockers."
2767                                         if "--quiet" not in self.myopts:
2768                                                 show_blocker_docs_link()
2769                                         if "--pretend" not in self.myopts:
2770                                                 try:
2771                                                         del mtimedb["resume"]
2772                                                 except KeyError:
2773                                                         pass
2774                                                 sys.exit(1)
2775
2776                 #buildsyspkg: I need mysysdict also on resume (moved from the else block)
2777                 mysysdict = genericdict(getlist(self.settings, "system"))
2778                 if "--resume" in self.myopts:
2779                         # We're resuming.
2780                         print colorize("GOOD", "*** Resuming merge...")
2781                         emergelog(xterm_titles, " *** Resuming merge...")
2782                         mymergelist=mtimedb["resume"]["mergelist"][:]
2783                         if "--skipfirst" in self.myopts and mymergelist:
2784                                 del mtimedb["resume"]["mergelist"][0]
2785                                 del mymergelist[0]
2786                                 mtimedb.commit()
2787                         validate_merge_list(self.trees, mymergelist)
2788                 else:
2789                         myfavs = portage.grabfile(
2790                                 os.path.join(self.target_root, portage.WORLD_FILE))
2791                         myfavdict=genericdict(myfavs)
2792                         for x in range(len(mylist)):
2793                                 if mylist[x][3]!="nomerge":
2794                                         # Add to the mergelist
2795                                         mymergelist.append(mylist[x])
2796                                 else:
2797                                         myfavkey=portage.cpv_getkey(mylist[x][2])
2798                                         if "--onlydeps" in self.myopts:
2799                                                 continue
2800                                         # Add to the world file. Since we won't be able to later.
2801                                         if "--fetchonly" not in self.myopts and \
2802                                                 myfavkey in favorites:
2803                                                 #don't record if already in system profile or already recorded
2804                                                 if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)):
2805                                                         #we don't have a favorites entry for this package yet; add one
2806                                                         myfavdict[myfavkey]=myfavkey
2807                                                         print ">>> Recording",myfavkey,"in \"world\" favorites file..."
2808                         if not ("--fetchonly" in self.myopts or \
2809                                 "--fetch-all-uri" in self.myopts or \
2810                                 "--pretend" in self.myopts):
2811                                 portage.write_atomic(
2812                                         os.path.join(self.target_root, portage.WORLD_FILE),
2813                                         "\n".join(myfavdict.values()))
2814
2815                         mtimedb["resume"]["mergelist"]=mymergelist[:]
2816                         mtimedb.commit()
2817
2818                 myfeat = self.settings.features[:]
2819                 bad_resume_opts = set(["--ask", "--tree", "--changelog", "--skipfirst",
2820                         "--resume"])
2821                 if "parallel-fetch" in myfeat and \
2822                         not ("--pretend" in self.myopts or \
2823                         "--fetch-all-uri" in self.myopts or \
2824                         "--fetchonly" in self.myopts):
2825                         if "distlocks" not in myfeat:
2826                                 print red("!!!")
2827                                 print red("!!!")+" parallel-fetching requires the distlocks feature enabled"
2828                                 print red("!!!")+" you have it disabled, thus parallel-fetching is being disabled"
2829                                 print red("!!!")
2830                         elif len(mymergelist) > 1:
2831                                 print ">>> starting parallel fetching"
2832                                 fetch_log = "/var/log/emerge-fetch.log"
2833                                 logfile = open(fetch_log, "w")
2834                                 fd_pipes = {1:logfile.fileno(), 2:logfile.fileno()}
2835                                 portage.util.apply_secpass_permissions(fetch_log,
2836                                         uid=portage.portage_uid, gid=portage.portage_gid,
2837                                         mode=0660)
2838                                 fetch_env = os.environ.copy()
2839                                 fetch_env["FEATURES"] = fetch_env.get("FEATURES", "") + " -cvs"
2840                                 fetch_env["PORTAGE_NICENESS"] = "0"
2841                                 fetch_args = [sys.argv[0], "--resume", "--fetchonly"]
2842                                 for myopt, myarg in self.myopts.iteritems():
2843                                         if myopt not in bad_resume_opts:
2844                                                 if myarg is True:
2845                                                         fetch_args.append(myopt)
2846                                                 else:
2847                                                         fetch_args.append(myopt +"="+ myarg)
2848                                 portage.process.spawn(fetch_args, env=fetch_env,
2849                                         fd_pipes=fd_pipes, returnpid=True)
2850                                 logfile.close() # belongs to the spawned process
2851
2852                 mergecount=0
2853                 for x in mymergelist:
2854                         mergecount+=1
2855                         myroot=x[1]
2856                         pkg_key = x[2]
2857                         pkgindex=2
2858                         portdb = self.trees[myroot]["porttree"].dbapi
2859                         bindb  = self.trees[myroot]["bintree"].dbapi
2860                         vartree = self.trees[myroot]["vartree"]
2861                         pkgsettings = self.pkgsettings[myroot]
2862                         if x[0]=="blocks":
2863                                 pkgindex=3
2864                         y = portdb.findname(pkg_key)
2865                         if "--pretend" not in self.myopts:
2866                                 print "\n>>> Emerging (" + \
2867                                         colorize("MERGE_LIST_PROGRESS", str(mergecount)) + " of " + \
2868                                         colorize("MERGE_LIST_PROGRESS", str(len(mymergelist))) + ") " + \
2869                                         colorize("GOOD", x[pkgindex]) + " to " + x[1]
2870                                 emergelog(xterm_titles, " >>> emerge ("+\
2871                                         str(mergecount)+" of "+str(len(mymergelist))+\
2872                                         ") "+x[pkgindex]+" to "+x[1])
2873
2874                         pkgsettings["EMERGE_FROM"] = x[0]
2875                         pkgsettings.backup_changes("EMERGE_FROM")
2876                         pkgsettings.reset()
2877
2878                         #buildsyspkg: Check if we need to _force_ binary package creation
2879                         issyspkg = ("buildsyspkg" in myfeat) \
2880                                         and x[0] != "blocks" \
2881                                         and mysysdict.has_key(portage.cpv_getkey(x[2])) \
2882                                         and "--buildpkg" not in self.myopts
2883                         if x[0] in ["ebuild","blocks"]:
2884                                 if x[0] == "blocks" and "--fetchonly" not in self.myopts:
2885                                         raise Exception, "Merging a blocker"
2886                                 elif "--fetchonly" in self.myopts or \
2887                                         "--fetch-all-uri" in self.myopts:
2888                                         if "--fetch-all-uri" in self.myopts:
2889                                                 retval = portage.doebuild(y, "fetch", myroot,
2890                                                         pkgsettings, self.edebug,
2891                                                         "--pretend" in self.myopts, fetchonly=1,
2892                                                         fetchall=1, mydbapi=portdb, tree="porttree")
2893                                         else:
2894                                                 retval = portage.doebuild(y, "fetch", myroot,
2895                                                         pkgsettings, self.edebug,
2896                                                         "--pretend" in self.myopts, fetchonly=1,
2897                                                         mydbapi=portdb, tree="porttree")
2898                                         if (retval is None) or retval:
2899                                                 print
2900                                                 print "!!! Fetch for",y,"failed, continuing..."
2901                                                 print
2902                                                 failed_fetches.append(pkg_key)
2903                                         continue
2904
2905                                 portage.doebuild_environment(y, "setup", myroot,
2906                                         pkgsettings, self.edebug, 1, portdb)
2907                                 catdir = os.path.dirname(pkgsettings["PORTAGE_BUILDDIR"])
2908                                 portage.util.ensure_dirs(os.path.dirname(catdir),
2909                                         uid=portage.portage_uid, gid=portage.portage_gid,
2910                                         mode=070, mask=0)
2911                                 builddir_lock = None
2912                                 catdir_lock = None
2913                                 try:
2914                                         catdir_lock = portage.locks.lockdir(catdir)
2915                                         portage.util.ensure_dirs(catdir,
2916                                                 uid=portage.portage_uid, gid=portage.portage_gid,
2917                                                 mode=070, mask=0)
2918                                         builddir_lock = portage.locks.lockdir(
2919                                                 pkgsettings["PORTAGE_BUILDDIR"])
2920                                         try:
2921                                                 portage.locks.unlockdir(catdir_lock)
2922                                         finally:
2923                                                 catdir_lock = None
2924                                         msg = " === (%s of %s) Cleaning (%s::%s)" % \
2925                                                 (mergecount, len(mymergelist), pkg_key, y)
2926                                         short_msg = "emerge: (%s of %s) %s Clean" % \
2927                                                 (mergecount, len(mymergelist), pkg_key)
2928                                         emergelog(xterm_titles, msg, short_msg=short_msg)
2929                                         retval = portage.doebuild(y, "clean", myroot,
2930                                                 pkgsettings, self.edebug, cleanup=1,
2931                                                 mydbapi=portdb, tree="porttree")
2932                                         if retval != os.EX_OK:
2933                                                 return retval
2934                                         if "--buildpkg" in self.myopts or issyspkg:
2935                                                 if issyspkg:
2936                                                         print ">>> This is a system package, " + \
2937                                                                 "let's pack a rescue tarball."
2938                                                 msg = " === (%s of %s) Compiling/Packaging (%s::%s)" % \
2939                                                         (mergecount, len(mymergelist), pkg_key, y)
2940                                                 short_msg = "emerge: (%s of %s) %s Compile" % \
2941                                                         (mergecount, len(mymergelist), pkg_key)
2942                                                 emergelog(xterm_titles, msg, short_msg=short_msg)
2943                                                 self.trees[myroot]["bintree"].prevent_collision(pkg_key)
2944                                                 retval = portage.doebuild(y, "package", myroot,
2945                                                         pkgsettings, self.edebug, mydbapi=portdb,
2946                                                         tree="porttree")
2947                                                 if retval != os.EX_OK:
2948                                                         return retval
2949                                                 if "--buildpkgonly" not in self.myopts:
2950                                                         bintree = self.trees[myroot]["bintree"]
2951                                                         bintree.inject(pkg_key)
2952                                                         mytbz2 = bintree.getname(pkg_key)
2953                                                         msg = " === (%s of %s) Merging (%s::%s)" % \
2954                                                                 (mergecount, len(mymergelist), pkg_key, y)
2955                                                         short_msg = "emerge: (%s of %s) %s Merge" % \
2956                                                                 (mergecount, len(mymergelist), pkg_key)
2957                                                         emergelog(xterm_titles, msg, short_msg=short_msg)
2958                                                         retval = portage.merge(pkgsettings["CATEGORY"],
2959                                                                 pkgsettings["PF"], pkgsettings["D"],
2960                                                                 os.path.join(pkgsettings["PORTAGE_BUILDDIR"],
2961                                                                 "build-info"), myroot, pkgsettings,
2962                                                                 myebuild=pkgsettings["EBUILD"],
2963                                                                 mytree="porttree", mydbapi=portdb,
2964                                                                 vartree=vartree, prev_mtimes=ldpath_mtimes)
2965                                                         if retval != os.EX_OK:
2966                                                                 return retval
2967                                                 elif "noclean" not in pkgsettings.features:
2968                                                         portage.doebuild(y, "clean", myroot,
2969                                                                 pkgsettings, self.edebug, mydbapi=portdb,
2970                                                                 tree="porttree")
2971                                         else:
2972                                                 msg = " === (%s of %s) Compiling/Merging (%s::%s)" % \
2973                                                         (mergecount, len(mymergelist), pkg_key, y)
2974                                                 short_msg = "emerge: (%s of %s) %s Compile" % \
2975                                                         (mergecount, len(mymergelist), pkg_key)
2976                                                 emergelog(xterm_titles, msg, short_msg=short_msg)
2977                                                 retval = portage.doebuild(y, "merge", myroot,
2978                                                         pkgsettings, self.edebug, vartree=vartree,
2979                                                         mydbapi=portdb, tree="porttree",
2980                                                         prev_mtimes=ldpath_mtimes)
2981                                                 if retval != os.EX_OK:
2982                                                         return retval
2983                                 finally:
2984                                         if builddir_lock:
2985                                                 portage.locks.unlockdir(builddir_lock)
2986                                         try:
2987                                                 if not catdir_lock:
2988                                                         # Lock catdir for removal if empty.
2989                                                         catdir_lock = portage.locks.lockdir(catdir)
2990                                         finally:
2991                                                 if catdir_lock:
2992                                                         try:
2993                                                                 os.rmdir(catdir)
2994                                                         except OSError, e:
2995                                                                 if e.errno not in (errno.ENOENT,
2996                                                                         errno.ENOTEMPTY, errno.EEXIST):
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, autoclean=1)
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, autoclean=0):
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         if not autoclean:
3408                 countdown(int(settings["CLEAN_DELAY"]), ">>> Unmerging")
3409
3410         for x in pkgmap.keys():
3411                 for y in pkgmap[x]["selected"]:
3412                         print ">>> Unmerging "+y+"..."
3413                         emergelog(xterm_titles, "=== Unmerging... ("+y+")")
3414                         mysplit=y.split("/")
3415                         #unmerge...
3416                         retval = portage.unmerge(mysplit[0], mysplit[1], settings["ROOT"],
3417                                 mysettings, unmerge_action not in ["clean","prune"],
3418                                 vartree=vartree, ldpath_mtimes=ldpath_mtimes)
3419                         if retval != os.EX_OK:
3420                                 emergelog(xterm_titles, " !!! unmerge FAILURE: "+y)
3421                                 ebuild = vartree.dbapi.findname(y)
3422                                 show_unmerge_failure_message(y, ebuild, retval)
3423                                 sys.exit(retval)
3424                         else:
3425                                 clean_world(vartree.dbapi, y)
3426                                 emergelog(xterm_titles, " >>> unmerge success: "+y)
3427         return 1
3428
3429 def show_unmerge_failure_message(pkg, ebuild, retval):
3430
3431         from formatter import AbstractFormatter, DumbWriter
3432         f = AbstractFormatter(DumbWriter(sys.stderr, maxcol=72))
3433
3434         msg = []
3435         msg.append("A removal phase of the '%s' package " % pkg)
3436         msg.append("has failed with exit value %s.  " % retval)
3437         msg.append("The problem occurred while executing ")
3438         msg.append("the ebuild located at '%s'.  " % ebuild)
3439         msg.append("If necessary, manually remove the ebuild " )
3440         msg.append("in order to skip the execution of removal phases.")
3441
3442         f.end_paragraph(1)
3443         for x in msg:
3444                 f.add_flowing_data(x)
3445         f.end_paragraph(1)
3446         f.writer.flush()
3447
3448 def chk_updated_info_files(root, infodirs, prev_mtimes, retval):
3449
3450         print
3451         if os.path.exists("/usr/bin/install-info"):
3452                 regen_infodirs=[]
3453                 for z in infodirs:
3454                         if z=='':
3455                                 continue
3456                         inforoot=normpath(root+z)
3457                         if os.path.isdir(inforoot):
3458                                 infomtime = long(os.stat(inforoot).st_mtime)
3459                                 if inforoot not in prev_mtimes or \
3460                                         prev_mtimes[inforoot] != infomtime:
3461                                                 regen_infodirs.append(inforoot)
3462
3463                 if not regen_infodirs:
3464                         print " "+green("*")+" GNU info directory index is up-to-date."
3465                 else:
3466                         print " "+green("*")+" Regenerating GNU info directory index..."
3467
3468                         icount=0
3469                         badcount=0
3470                         for inforoot in regen_infodirs:
3471                                 if inforoot=='':
3472                                         continue
3473                                 for filename in ("dir", "dir.gz", "dir.bz2"):
3474                                         file_path = os.path.join(inforoot, filename)
3475                                         try:
3476                                                 os.rename(file_path, file_path + ".old")
3477                                         except OSError, e:
3478                                                 if e.errno != errno.ENOENT:
3479                                                         raise
3480                                                 del e
3481
3482                                 if not os.path.isdir(inforoot):
3483                                         continue
3484                                 errmsg = ""
3485                                 file_list = os.listdir(inforoot)
3486                                 file_list.sort()
3487                                 for x in file_list:
3488                                         if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)):
3489                                                 continue
3490                                         myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1]
3491                                         existsstr="already exists, for file `"
3492                                         if myso!="":
3493                                                 if re.search(existsstr,myso):
3494                                                         # Already exists... Don't increment the count for this.
3495                                                         pass
3496                                                 elif myso[:44]=="install-info: warning: no info dir entry in ":
3497                                                         # This info file doesn't contain a DIR-header: install-info produces this
3498                                                         # (harmless) warning (the --quiet switch doesn't seem to work).
3499                                                         # Don't increment the count for this.
3500                                                         pass
3501                                                 else:
3502                                                         badcount=badcount+1
3503                                                         errmsg += myso + "\n"
3504                                         icount=icount+1
3505
3506                                 #update mtime so we can potentially avoid regenerating.
3507                                 prev_mtimes[inforoot] = long(os.stat(inforoot).st_mtime)
3508
3509                         if badcount:
3510                                 print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors."
3511                                 print errmsg
3512                         else:
3513                                 print " "+green("*")+" Processed",icount,"info files."
3514
3515
3516 def post_emerge(settings, mtimedb, retval):
3517         """
3518         Misc. things to run at the end of a merge session.
3519         
3520         Update Info Files
3521         Update Config Files
3522         Update News Items
3523         Commit mtimeDB
3524         Exit Emerge
3525         
3526         @param settings: Configuration settings (typically portage.settings)
3527         @type settings: portage.config()
3528         @param mtimedb: The mtimeDB to store data needed across merge invocations
3529         @type mtimedb: MtimeDB class instance
3530         @param retval: Emerge's return value
3531         @type retval: Int
3532         @rype: None
3533         @returns:
3534         1.  Calls sys.exit(retval)
3535         """
3536         target_root = settings["ROOT"]
3537         info_mtimes = mtimedb["info"]
3538
3539         # Load the most current variables from ${ROOT}/etc/profile.env
3540         settings.unlock()
3541         settings.regenerate()
3542         settings.lock()
3543
3544         config_protect = settings.get("CONFIG_PROTECT","").split()
3545         infodirs = settings.get("INFOPATH","").split(":") + \
3546                 settings.get("INFODIR","").split(":")
3547
3548         os.chdir("/")
3549
3550         emergelog("notitles" not in settings.features,
3551                 " *** exiting successfully.")
3552
3553         if "noinfo" not in settings.features:
3554                 chk_updated_info_files(target_root, infodirs, info_mtimes, retval)
3555
3556         chk_updated_cfg_files(target_root, config_protect)
3557         
3558         NEWS_PATH = os.path.join( "metadata", "news" )
3559         UNREAD_PATH = os.path.join( target_root, NEWS_LIB_PATH, 'news')
3560         porttree = portdbapi( porttree_root = settings["PORTDIR"], mysettings = settings )
3561         newsReaderDisplay = False
3562         
3563         for repo in porttree.getRepositories():
3564                 unreadItems = checkUpdatedNewsItems(target_root, NEWS_PATH, UNREAD_PATH, repo)
3565                 if unreadItems:
3566                         print colorize("WARN", " * IMPORTANT:"),
3567                         print "%s news items need reading for repository '%s'." % (unreadItems, repo)
3568                         newsReaderDisplay = True
3569         
3570         if newsReaderDisplay:
3571                 print colorize("WARN", " *"),
3572                 print "Use " + colorize("GOOD", "eselect news") + " to read news items."
3573         
3574         mtimedb.commit()
3575         sys.exit(retval)
3576
3577
3578 def chk_updated_cfg_files(target_root, config_protect):
3579         if config_protect:
3580                 #number of directories with some protect files in them
3581                 procount=0
3582                 for x in config_protect:
3583                         x = os.path.join(target_root, x.lstrip(os.path.sep))
3584                         try:
3585                                 mymode = os.lstat(x).st_mode
3586                         except OSError:
3587                                 continue
3588                         if stat.S_ISDIR(mymode):
3589                                 mycommand = "cd '%s'; find . -iname '._cfg????_*'" % x
3590                         else:
3591                                 mycommand = "cd '%s'; find . -maxdepth 1 -iname '._cfg????_%s'" % \
3592                                         os.path.split(x.rstrip(os.path.sep))
3593                         a = commands.getstatusoutput(mycommand)
3594                         if a[0] != 0:
3595                                 print >> sys.stderr, " " + bad("*")+ " error scanning '%s'" % x
3596                         else:
3597                                 files = a[1].split()
3598                                 if files:
3599                                         procount += 1
3600                                         print colorize("WARN", " * IMPORTANT:"),
3601                                         if stat.S_ISDIR(mymode):
3602                                                  print "%d config files in '%s' need updating." % \
3603                                                         (len(files), x)
3604                                         else:
3605                                                  print "config file '%s' needs updating." % x
3606
3607                 if procount:
3608                         #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
3609                         print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files."
3610
3611 def checkUpdatedNewsItems( root, NEWS_PATH, UNREAD_PATH, repo_id ):
3612         """
3613         Examines news items in repodir + '/' + NEWS_PATH and attempts to find unread items
3614         Returns the number of unread (yet relevent) items.
3615         
3616         @param root:
3617         @type root:
3618         @param NEWS_PATH:
3619         @type NEWS_PATH:
3620         @param UNREAD_PATH:
3621         @type UNREAD_PATH:
3622         @param repo_id:
3623         @type repo_id:
3624         @rtype: Integer
3625         @returns:
3626         1.  The number of unread but relevant news items.
3627         
3628         """
3629         from portage.news import NewsManager
3630         manager = NewsManager( root, NEWS_PATH, UNREAD_PATH )
3631         return manager.getUnreadItems( repo_id, update=True )
3632
3633 def is_valid_package_atom(x):
3634         try:
3635                 testkey = portage.dep_getkey(x)
3636         except portage.exception.InvalidData:
3637                 return False
3638         if testkey.startswith("null/"):
3639                 testatom = x.replace(testkey[5:], "cat/"+testkey[5:])
3640         elif "/" not in x:
3641                 testatom = "cat/"+x
3642         else:
3643                 testatom = x
3644         return portage.isvalidatom(testatom)
3645
3646 def validate_merge_list(trees, mergelist):
3647         """Validate the list to make sure all the packages are still available.
3648         This is needed for --resume."""
3649         for (pkg_type, myroot, pkg_key, action) in mergelist:
3650                 if pkg_type == "binary" and \
3651                         not trees[myroot]["bintree"].dbapi.match("="+pkg_key) or \
3652                         pkg_type == "ebuild" and \
3653                         not trees[myroot]["porttree"].dbapi.xmatch(
3654                         "match-all", "="+pkg_key):
3655                         print red("!!! Error: The resume list contains packages that are no longer")
3656                         print red("!!!        available to be emerged. Please restart/continue")
3657                         print red("!!!        the merge operation manually.")
3658                         sys.exit(1)
3659
3660 def show_blocker_docs_link():
3661         print
3662         print "For more information about " + bad("Blocked Packages") + ", please refer to the following"
3663         print "section of the Gentoo Linux x86 Handbook (architecture is irrelevant):"
3664         print
3665         print "http://www.gentoo.org/doc/en/handbook/handbook-x86.xml?full=1#blocked"
3666         print
3667
3668 def action_sync(settings, trees, mtimedb, myopts, myaction):
3669         xterm_titles = "notitles" not in settings.features
3670         emergelog(xterm_titles, " === sync")
3671         myportdir = settings.get("PORTDIR", None)
3672         if not myportdir:
3673                 sys.stderr.write("!!! PORTDIR is undefined.  Is /etc/make.globals missing?\n")
3674                 sys.exit(1)
3675         if myportdir[-1]=="/":
3676                 myportdir=myportdir[:-1]
3677         if not os.path.exists(myportdir):
3678                 print ">>>",myportdir,"not found, creating it."
3679                 os.makedirs(myportdir,0755)
3680         syncuri=settings["SYNC"].rstrip()
3681         os.umask(0022)
3682         updatecache_flg = False
3683         if myaction == "metadata":
3684                 print "skipping sync"
3685                 updatecache_flg = True
3686                 tmpservertimestampfile = None
3687         elif syncuri[:8]=="rsync://":
3688                 if not os.path.exists("/usr/bin/rsync"):
3689                         print "!!! /usr/bin/rsync does not exist, so rsync support is disabled."
3690                         print "!!! Type \"emerge net-misc/rsync\" to enable rsync support."
3691                         sys.exit(1)
3692                 mytimeout=180
3693
3694                 rsync_opts = []
3695
3696                 if settings["PORTAGE_RSYNC_OPTS"] == "":
3697                         portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n")
3698                         rsync_opts.extend([
3699                                 "--recursive",    # Recurse directories
3700                                 "--links",        # Consider symlinks
3701                                 "--safe-links",   # Ignore links outside of tree
3702                                 "--perms",        # Preserve permissions
3703                                 "--times",        # Preserive mod times
3704                                 "--compress",     # Compress the data transmitted
3705                                 "--force",        # Force deletion on non-empty dirs
3706                                 "--whole-file",   # Don't do block transfers, only entire files
3707                                 "--delete",       # Delete files that aren't in the master tree
3708                                 "--delete-after", # Delete only after everything else is done
3709                                 "--stats",        # Show final statistics about what was transfered
3710                                 "--timeout="+str(mytimeout), # IO timeout if not done in X seconds
3711                                 "--exclude='/distfiles'",   # Exclude distfiles from consideration
3712                                 "--exclude='/local'",       # Exclude local     from consideration
3713                                 "--exclude='/packages'",    # Exclude packages  from consideration
3714                         ])
3715
3716                 else:
3717                         # The below validation is not needed when using the above hardcoded
3718                         # defaults.
3719
3720                         portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n", 1)
3721                         rsync_opts.extend(settings["PORTAGE_RSYNC_OPTS"].split())
3722
3723                         for opt in ("--recursive", "--times"):
3724                                 if opt not in rsync_opts:
3725                                         portage.writemsg(yellow("WARNING:") + " adding required option " + \
3726                                         "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
3727                                         rsync_opts.append(opt)
3728         
3729                         for exclude in ("distfiles", "local", "packages"):
3730                                 opt = "--exclude=/%s" % exclude
3731                                 if opt not in rsync_opts:
3732                                         portage.writemsg(yellow("WARNING:") + \
3733                                         " adding required option %s not included in "  % opt + \
3734                                         "PORTAGE_RSYNC_OPTS (can be overridden with --exclude='!')\n")
3735                                         rsync_opts.append(opt)
3736         
3737                         if settings["RSYNC_TIMEOUT"] != "":
3738                                 portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \
3739                                 "use PORTAGE_RSYNC_EXTRA_OPTS instead\n")
3740                                 try:
3741                                         mytimeout = int(settings["RSYNC_TIMEOUT"])
3742                                         rsync_opts.append("--timeout=%d" % mytimeout)
3743                                 except ValueError, e:
3744                                         portage.writemsg("!!! %s\n" % str(e))
3745         
3746                         # TODO: determine options required for official servers
3747                         if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"):
3748
3749                                 def rsync_opt_startswith(opt_prefix):
3750                                         for x in rsync_opts:
3751                                                 if x.startswith(opt_prefix):
3752                                                         return True
3753                                         return False
3754
3755                                 if not rsync_opt_startswith("--timeout="):
3756                                         rsync_opts.append("--timeout=%d" % mytimeout)
3757
3758                                 for opt in ("--compress", "--whole-file"):
3759                                         if opt not in rsync_opts:
3760                                                 portage.writemsg(yellow("WARNING:") + " adding required option " + \
3761                                                 "%s not included in PORTAGE_RSYNC_OPTS\n" % opt)
3762                                                 rsync_opts.append(opt)
3763
3764                 if "--quiet" in myopts:
3765                         rsync_opts.append("--quiet")    # Shut up a lot
3766                 else:
3767                         rsync_opts.append("--verbose")  # Print filelist
3768
3769                 if "--verbose" in myopts:
3770                         rsync_opts.append("--progress")  # Progress meter for each file
3771
3772                 if "--debug" in myopts:
3773                         rsync_opts.append("--checksum") # Force checksum on all files
3774
3775                 if settings["RSYNC_EXCLUDEFROM"] != "":
3776                         portage.writemsg(yellow("WARNING:") + \
3777                         " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \
3778                         "PORTAGE_RSYNC_EXTRA_OPTS instead\n")
3779                         if os.path.exists(settings["RSYNC_EXCLUDEFROM"]):
3780                                 rsync_opts.append("--exclude-from=%s" % \
3781                                 settings["RSYNC_EXCLUDEFROM"])
3782                         else:
3783                                 portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \
3784                                 " but file does not exist.\n")
3785
3786                 if settings["RSYNC_RATELIMIT"] != "":
3787                         portage.writemsg(yellow("WARNING:") + \
3788                         " usage of RSYNC_RATELIMIT is deprecated, use " + \
3789                         "PORTAGE_RSYNC_EXTRA_OPTS instead")
3790                         rsync_opts.append("--bwlimit=%s" % \
3791                         settings["RSYNC_RATELIMIT"])
3792
3793                 # Real local timestamp file.
3794                 servertimestampfile = os.path.join(
3795                         myportdir, "metadata", "timestamp.chk")
3796                 # Temporary file for remote server timestamp comparison.
3797                 tmpservertimestampfile = os.path.join(
3798                         settings["PORTAGE_TMPDIR"], "timestamp.chk")
3799
3800                 content = portage.util.grabfile(servertimestampfile)
3801                 mytimestamp = 0
3802                 if content:
3803                         try:
3804                                 mytimestamp = time.mktime(time.strptime(content[0],
3805                                         "%a, %d %b %Y %H:%M:%S +0000"))
3806                         except OverflowError, ValueError:
3807                                 pass
3808                 del content
3809
3810                 try:
3811                         if settings.has_key("RSYNC_RETRIES"):
3812                                 print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead"
3813                                 maxretries=int(settings["RSYNC_RETRIES"])                               
3814                         else:
3815                                 maxretries=int(settings["PORTAGE_RSYNC_RETRIES"])
3816                 except SystemExit, e:
3817                         raise # Needed else can't exit
3818                 except:
3819                         maxretries=3 #default number of retries
3820
3821                 retries=0
3822                 user_name, hostname, port = re.split(
3823                         "rsync://([^:/]+@)?([^:/]*)(:[0-9]+)?", syncuri, maxsplit=3)[1:4]
3824                 if port is None:
3825                         port=""
3826                 if user_name is None:
3827                         user_name=""
3828                 updatecache_flg=True
3829                 all_rsync_opts = set(rsync_opts)
3830                 all_rsync_opts.update(
3831                         settings.get("PORTAGE_RSYNC_EXTRA_OPTS","").split())
3832                 family = socket.AF_UNSPEC
3833                 if "-4" in all_rsync_opts or "--ipv4" in all_rsync_opts:
3834                         family = socket.AF_INET
3835                 elif socket.has_ipv6 and \
3836                         ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
3837                         family = socket.AF_INET6
3838                 ips=[]
3839                 while (1):
3840                         if ips:
3841                                 del ips[0]
3842                         if ips==[]:
3843                                 try:
3844                                         for addrinfo in socket.getaddrinfo(
3845                                                 hostname, None, family, socket.SOCK_STREAM):
3846                                                 if addrinfo[0] == socket.AF_INET6:
3847                                                         # IPv6 addresses need to be enclosed in square brackets
3848                                                         ips.append("[%s]" % addrinfo[4][0])
3849                                                 else:
3850                                                         ips.append(addrinfo[4][0])
3851                                         from random import shuffle
3852                                         shuffle(ips)
3853                                 except SystemExit, e:
3854                                         raise # Needed else can't exit
3855                                 except Exception, e:
3856                                         print "Notice:",str(e)
3857                                         dosyncuri=syncuri
3858
3859                         if ips:
3860                                 try:
3861                                         dosyncuri = syncuri.replace(
3862                                                 "//" + user_name + hostname + port + "/",
3863                                                 "//" + user_name + ips[0] + port + "/", 1)
3864                                 except SystemExit, e:
3865                                         raise # Needed else can't exit
3866                                 except Exception, e:
3867                                         print "Notice:",str(e)
3868                                         dosyncuri=syncuri
3869
3870                         if (retries==0):
3871                                 if "--ask" in myopts:
3872                                         if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No":
3873                                                 print
3874                                                 print "Quitting."
3875                                                 print
3876                                                 sys.exit(0)
3877                                 emergelog(xterm_titles, ">>> Starting rsync with " + dosyncuri)
3878                                 if "--quiet" not in myopts:
3879                                         print ">>> Starting rsync with "+dosyncuri+"..."
3880                         else:
3881                                 emergelog(xterm_titles,
3882                                         ">>> Starting retry %d of %d with %s" % \
3883                                                 (retries,maxretries,dosyncuri))
3884                                 print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)
3885
3886                         if mytimestamp != 0 and "--quiet" not in myopts:
3887                                 print ">>> Checking server timestamp ..."
3888
3889                         rsynccommand = " ".join(["/usr/bin/rsync", " ".join(rsync_opts),
3890                                 settings.get("PORTAGE_RSYNC_EXTRA_OPTS","")])
3891
3892                         if "--debug" in myopts:
3893                                 print rsynccommand
3894
3895                         exitcode = os.EX_OK
3896                         servertimestamp = 0
3897                         if mytimestamp != 0:
3898                                 mycommand = rsynccommand.split()
3899                                 mycommand.append(dosyncuri.rstrip("/") + \
3900                                         "/metadata/timestamp.chk")
3901                                 mycommand.append(tmpservertimestampfile)
3902                                 try:
3903                                         exitcode = portage.process.spawn(
3904                                                 mycommand, env=settings.environ())
3905                                         content = portage.grabfile(tmpservertimestampfile)
3906                                         if content:
3907                                                 try:
3908                                                         servertimestamp = time.mktime(time.strptime(
3909                                                                 content[0], "%a, %d %b %Y %H:%M:%S +0000"))
3910                                                 except OverflowError, ValueError:
3911                                                         pass
3912                                         del content
3913                                 finally:
3914                                         try:
3915                                                 os.unlink(tmpservertimestampfile)
3916                                         except OSError:
3917                                                 pass
3918                                 del mycommand
3919                         if exitcode == os.EX_OK:
3920                                 if (servertimestamp != 0) and (servertimestamp == mytimestamp):
3921                                         emergelog(xterm_titles,
3922                                                 ">>> Cancelling sync -- Already current.")
3923                                         print
3924                                         print ">>>"
3925                                         print ">>> Timestamps on the server and in the local repository are the same."
3926                                         print ">>> Cancelling all further sync action. You are already up to date."
3927                                         print ">>>"
3928                                         print ">>> In order to force sync, remove '%s'." % servertimestampfile
3929                                         print ">>>"
3930                                         print
3931                                         sys.exit(0)
3932                                 elif (servertimestamp != 0) and (servertimestamp < mytimestamp):
3933                                         emergelog(xterm_titles,
3934                                                 ">>> Server out of date: %s" % dosyncuri)
3935                                         print
3936                                         print ">>>"
3937                                         print ">>> SERVER OUT OF DATE: %s" % dosyncuri
3938                                         print ">>>"
3939                                         print ">>> In order to force sync, remove '%s'." % servertimestampfile
3940                                         print ">>>"
3941                                         print
3942                                 elif (servertimestamp == 0) or (servertimestamp > mytimestamp):
3943                                         # actual sync
3944                                         mycommand=rsynccommand+" "+dosyncuri+"/ "+myportdir
3945                                         exitcode=portage.spawn(mycommand,settings,free=1)
3946                                         if exitcode in [0,1,2,3,4,11,14,20,21]:
3947                                                 break
3948                         elif exitcode in [0,1,2,3,4,11,14,20,21]:
3949                                 break
3950
3951                         retries=retries+1
3952
3953                         if retries<=maxretries:
3954                                 print ">>> Retrying..."
3955                                 time.sleep(11)
3956                         else:
3957                                 # over retries
3958                                 # exit loop
3959                                 updatecache_flg=False
3960                                 break
3961
3962                 if (exitcode==0):
3963                         emergelog(xterm_titles, "=== Sync completed with %s" % dosyncuri)
3964                 elif (exitcode>0):
3965                         print
3966                         if exitcode==1:
3967                                 print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure")
3968                                 print darkred("!!!")+green(" that your SYNC statement is proper.")
3969                                 print darkred("!!!")+green(" SYNC="+settings["SYNC"])
3970                         elif exitcode==11:
3971                                 print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally")
3972                                 print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption")
3973                                 print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate")
3974                                 print darkred("!!!")+green(" and try again after the problem has been fixed.")
3975                                 print darkred("!!!")+green(" PORTDIR="+settings["PORTDIR"])
3976                         elif exitcode==20:
3977                                 print darkred("!!!")+green(" Rsync was killed before it finished.")
3978                         else:
3979                                 print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep")
3980                                 print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable")
3981                                 print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a")
3982                                 print darkred("!!!")+green(" temporary problem unless complications exist with your network")
3983                                 print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.")
3984                         print
3985                         sys.exit(exitcode)
3986         elif syncuri[:6]=="cvs://":
3987                 if not os.path.exists("/usr/bin/cvs"):
3988                         print "!!! /usr/bin/cvs does not exist, so CVS support is disabled."
3989                         print "!!! Type \"emerge dev-util/cvs\" to enable CVS support."
3990                         sys.exit(1)
3991                 cvsroot=syncuri[6:]
3992                 cvsdir=os.path.dirname(myportdir)
3993                 if not os.path.exists(myportdir+"/CVS"):
3994                         #initial checkout
3995                         print ">>> Starting initial cvs checkout with "+syncuri+"..."
3996                         if os.path.exists(cvsdir+"/gentoo-x86"):
3997                                 print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting."
3998                                 sys.exit(1)
3999                         try:
4000                                 os.rmdir(myportdir)
4001                         except OSError, e:
4002                                 if e.errno != errno.ENOENT:
4003                                         sys.stderr.write(
4004                                                 "!!! existing '%s' directory; exiting.\n" % myportdir)
4005                                         sys.exit(1)
4006                                 del e
4007                         if portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",settings,free=1):
4008                                 print "!!! cvs checkout error; exiting."
4009                                 sys.exit(1)
4010                         os.rename(os.path.join(cvsdir, "gentoo-x86"), myportdir)
4011                 else:
4012                         #cvs update
4013                         print ">>> Starting cvs update with "+syncuri+"..."
4014                         retval = portage.spawn("cd '%s'; cvs -z0 -q update -dP" % \
4015                                 myportdir, settings, free=1)
4016                         if retval != os.EX_OK:
4017                                 sys.exit(retval)
4018                 dosyncuri = syncuri
4019         else:
4020                 print "!!! rsync setting: ",syncuri,"not recognized; exiting."
4021                 sys.exit(1)
4022
4023         if updatecache_flg and  \
4024                 myaction != "metadata" and \
4025                 "metadata-transfer" not in settings.features:
4026                 updatecache_flg = False
4027
4028         # Reload the whole config from scratch.
4029         settings, trees, mtimedb = load_emerge_config(trees=trees)
4030         portdb = trees[settings["ROOT"]]["porttree"].dbapi
4031
4032         if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg:
4033                 action_metadata(settings, portdb, myopts)
4034
4035         if portage.global_updates(settings, trees, mtimedb["updates"]):
4036                 mtimedb.commit()
4037                 # Reload the whole config from scratch.
4038                 settings, trees, mtimedb = load_emerge_config(trees=trees)
4039                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
4040
4041         mybestpv = portdb.xmatch("bestmatch-visible", "sys-apps/portage")
4042         mypvs = portage.best(
4043                 trees[settings["ROOT"]]["vartree"].dbapi.match("sys-apps/portage"))
4044
4045         chk_updated_cfg_files("/", settings.get("CONFIG_PROTECT","").split())
4046
4047         if myaction != "metadata":
4048                 if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK):
4049                         retval = portage.process.spawn(
4050                                 [os.path.join(portage.USER_CONFIG_PATH, "bin", "post_sync"),
4051                                 dosyncuri], env=settings.environ())
4052                         if retval != os.EX_OK:
4053                                 print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync")
4054
4055         if(mybestpv != mypvs) and not "--quiet" in myopts:
4056                 print
4057                 print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended"
4058                 print red(" * ")+"that you update portage now, before any other packages are updated."
4059                 print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your"
4060                 print red(" * ")+"configuration files."
4061                 print red(" * ")+"To update portage, run 'emerge portage'."
4062                 print
4063
4064 def action_metadata(settings, portdb, myopts):
4065         portage.writemsg_stdout("\n>>> Updating Portage cache:      ")
4066         old_umask = os.umask(0002)
4067         cachedir = os.path.normpath(settings.depcachedir)
4068         if cachedir in ["/",    "/bin", "/dev",  "/etc",  "/home",
4069                                         "/lib", "/opt", "/proc", "/root", "/sbin",
4070                                         "/sys", "/tmp", "/usr",  "/var"]:
4071                 print >> sys.stderr, "!!! PORTAGE_DEPCACHEDIR IS SET TO A PRIMARY " + \
4072                         "ROOT DIRECTORY ON YOUR SYSTEM."
4073                 print >> sys.stderr, \
4074                         "!!! This is ALMOST CERTAINLY NOT what you want: '%s'" % cachedir
4075                 sys.exit(73)
4076         if not os.path.exists(cachedir):
4077                 os.mkdir(cachedir)
4078
4079         ec = portage.eclass_cache.cache(portdb.porttree_root)
4080         myportdir = os.path.realpath(settings["PORTDIR"])
4081         cm = settings.load_best_module("portdbapi.metadbmodule")(
4082                 myportdir, "metadata/cache", portage.auxdbkeys[:])
4083
4084         from portage.cache import util
4085
4086         class percentage_noise_maker(util.quiet_mirroring):
4087                 def __init__(self, dbapi):
4088                         self.dbapi = dbapi
4089                         self.cp_all = dbapi.cp_all()
4090                         l = len(self.cp_all)
4091                         self.call_update_min = 100000000
4092                         self.min_cp_all = l/100.0
4093                         self.count = 1
4094                         self.pstr = ''
4095
4096                 def __iter__(self):
4097                         for x in self.cp_all:
4098                                 self.count += 1
4099                                 if self.count > self.min_cp_all:
4100                                         self.call_update_min = 0
4101                                         self.count = 0
4102                                 for y in self.dbapi.cp_list(x):
4103                                         yield y
4104                         self.call_update_mine = 0
4105
4106                 def update(self, *arg):
4107                         try:                            self.pstr = int(self.pstr) + 1
4108                         except ValueError:      self.pstr = 1
4109                         sys.stdout.write("%s%i%%" % \
4110                                 ("\b" * (len(str(self.pstr))+1), self.pstr))
4111                         sys.stdout.flush()
4112                         self.call_update_min = 10000000
4113
4114                 def finish(self, *arg):
4115                         sys.stdout.write("\b\b\b\b100%\n")
4116                         sys.stdout.flush()
4117
4118         if "--quiet" in myopts:
4119                 def quicky_cpv_generator(cp_all_list):
4120                         for x in cp_all_list:
4121                                 for y in portdb.cp_list(x):
4122                                         yield y
4123                 source = quicky_cpv_generator(portdb.cp_all())
4124                 noise_maker = portage.cache.util.quiet_mirroring()
4125         else:
4126                 noise_maker = source = percentage_noise_maker(portdb)
4127         portage.cache.util.mirror_cache(source, cm, portdb.auxdb[myportdir],
4128                 eclass_cache=ec, verbose_instance=noise_maker)
4129
4130         sys.stdout.flush()
4131         os.umask(old_umask)
4132
4133 def action_regen(settings, portdb):
4134         xterm_titles = "notitles" not in settings.features
4135         emergelog(xterm_titles, " === regen")
4136         #regenerate cache entries
4137         print "Regenerating cache entries... "
4138         try:
4139                 os.close(sys.stdin.fileno())
4140         except SystemExit, e:
4141                 raise # Needed else can't exit
4142         except:
4143                 pass
4144         sys.stdout.flush()
4145         mynodes = portdb.cp_all()
4146         from portage.cache.cache_errors import CacheError
4147         dead_nodes = {}
4148         for mytree in portdb.porttrees:
4149                 try:
4150                         dead_nodes[mytree] = set(portdb.auxdb[mytree].iterkeys())
4151                 except CacheError, e:
4152                         print "\n  error listing cache entries for " + \
4153                                 "'%s': %s, continuing..." % (mytree, e)
4154                         del e
4155                         dead_nodes = None
4156                         break
4157         for x in mynodes:
4158                 mymatches = portdb.xmatch("match-all",x)
4159                 portage.writemsg_stdout("processing %s\n" % x)
4160                 for y in mymatches:
4161                         try:
4162                                 foo = portdb.aux_get(y,["DEPEND"])
4163                         except SystemExit, e:
4164                                 # sys.exit is an exception... And consequently, we can't catch it.
4165                                 raise
4166                         except Exception, e:
4167                                 print "\n  error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)}
4168                         if dead_nodes:
4169                                 for mytree in portdb.porttrees:
4170                                         if portdb.findname2(y, mytree=mytree)[0]:
4171                                                 dead_nodes[mytree].discard(y)
4172         if dead_nodes:
4173                 for mytree, nodes in dead_nodes.iteritems():
4174                         auxdb = portdb.auxdb[mytree]
4175                         for y in nodes:
4176                                 try:
4177                                         del auxdb[y]
4178                                 except KeyError, CacheError:
4179                                         pass
4180         print "done!"
4181
4182 def action_config(settings, trees, myopts, myfiles):
4183         if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles:
4184                 print red("!!! config can only take a single package atom at this time\n")
4185                 sys.exit(1)
4186         if not is_valid_package_atom(myfiles[0]):
4187                 portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0],
4188                         noiselevel=-1)
4189                 portage.writemsg("!!! Please check ebuild(5) for full details.\n")
4190                 portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n")
4191                 sys.exit(1)
4192         print
4193         try:
4194                 pkgs = trees[settings["ROOT"]]["vartree"].dbapi.match(myfiles[0])
4195         except ValueError, e:
4196                 # Multiple matches thrown from cpv_expand
4197                 pkgs = e.args[0]
4198         if len(pkgs) == 0:
4199                 print "No packages found.\n"
4200                 sys.exit(0)
4201         elif len(pkgs) > 1:
4202                 if "--ask" in myopts:
4203                         options = []
4204                         print "Please select a package to configure:"
4205                         idx = 0
4206                         for pkg in pkgs:
4207                                 idx += 1
4208                                 options.append(str(idx))
4209                                 print options[-1]+") "+pkg
4210                         print "X) Cancel"
4211                         options.append("X")
4212                         idx = userquery("Selection?", options)
4213                         if idx == "X":
4214                                 sys.exit(0)
4215                         pkg = pkgs[int(idx)-1]
4216                 else:
4217                         print "The following packages available:"
4218                         for pkg in pkgs:
4219                                 print "* "+pkg
4220                         print "\nPlease use a specific atom or the --ask option."
4221                         sys.exit(1)
4222         else:
4223                 pkg = pkgs[0]
4224
4225         print
4226         if "--ask" in myopts:
4227                 if userquery("Ready to configure "+pkg+"?") == "No":
4228                         sys.exit(0)
4229         else:
4230                 print "Configuring pkg..."
4231         print
4232         ebuildpath = trees[settings["ROOT"]]["vartree"].dbapi.findname(pkg)
4233         mysettings = portage.config(clone=settings)
4234         portage.doebuild(ebuildpath, "config", settings["ROOT"], mysettings,
4235                 debug=(settings.get("PORTAGE_DEBUG", "") == 1), cleanup=True,
4236                 mydbapi=trees[settings["ROOT"]]["vartree"].dbapi, tree="vartree")
4237         print
4238
4239 def action_info(settings, trees, myopts, myfiles):
4240         unameout=commands.getstatusoutput("uname -mrp")[1]
4241         print getportageversion(settings["PORTDIR"], settings["ROOT"],
4242                 settings.profile_path, settings["CHOST"],
4243                 trees[settings["ROOT"]]["vartree"].dbapi)
4244         header_width = 65
4245         header_title = "System Settings"
4246         if myfiles:
4247                 print header_width * "="
4248                 print header_title.rjust(int(header_width/2 + len(header_title)/2))
4249         print header_width * "="
4250         print "System uname: "+unameout
4251         gentoo_release = portage.grabfile(os.path.join(
4252                 settings["PORTAGE_CONFIGROOT"], "etc", "gentoo-release"))
4253         if gentoo_release:
4254                 print gentoo_release[0]
4255         else:
4256                 print "Unknown Host Operating System"
4257         lastSync = portage.grabfile(os.path.join(
4258                 settings["PORTDIR"], "metadata", "timestamp.chk"))
4259         print "Timestamp of tree:",
4260         if lastSync:
4261                 print lastSync[0]
4262         else:
4263                 print "Unknown"
4264
4265         output=commands.getstatusoutput("distcc --version")
4266         if not output[0]:
4267                 print str(output[1].split("\n",1)[0]),
4268                 if "distcc" in settings.features:
4269                         print "[enabled]"
4270                 else:
4271                         print "[disabled]"
4272
4273         output=commands.getstatusoutput("ccache -V")
4274         if not output[0]:
4275                 print str(output[1].split("\n",1)[0]),
4276                 if "ccache" in settings.features:
4277                         print "[enabled]"
4278                 else:
4279                         print "[disabled]"
4280
4281         myvars  = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers",
4282                    "sys-devel/binutils", "sys-devel/libtool",  "dev-lang/python"]
4283         myvars += portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_pkgs")
4284         myvars  = portage.util.unique_array(myvars)
4285         myvars.sort()
4286
4287         for x in myvars:
4288                 if portage.isvalidatom(x):
4289                         pkg_matches = trees["/"]["vartree"].dbapi.match(x)
4290                         pkgs = []
4291                         for y in pkg_matches:
4292                                 mycpv   = portage.catpkgsplit(y)
4293                                 if(mycpv[3] != "r0"):
4294                                         pkgs += [mycpv[2] + "-" + mycpv[3]]
4295                                 else:
4296                                         pkgs += [mycpv[2]]
4297                         if pkgs:
4298                                 pkgs = ", ".join(sorted_versions(pkgs))
4299                                 print "%-20s %s" % (x+":", pkgs)
4300                 else:
4301                         print "%-20s %s" % (x+":", "[NOT VALID]")
4302
4303         libtool_vers = ",".join(trees["/"]["vartree"].dbapi.match("sys-devel/libtool"))
4304
4305         if "--verbose" in myopts:
4306                 myvars=settings.keys()
4307         else:
4308                 myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK',
4309                           'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR',
4310                           'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS',
4311                           'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS']
4312
4313                 myvars.extend(portage.util.grabfile(settings["PORTDIR"]+"/profiles/info_vars"))
4314
4315         myvars = portage.util.unique_array(myvars)
4316         unset_vars = []
4317         myvars.sort()
4318         for x in myvars:
4319                 if x in settings:
4320                         if x != "USE":
4321                                 print '%s="%s"' % (x, settings[x])
4322                         else:
4323                                 use = set(settings["USE"].split())
4324                                 use_expand = settings["USE_EXPAND"].split()
4325                                 use_expand.sort()
4326                                 for varname in use_expand:
4327                                         flag_prefix = varname.lower() + "_"
4328                                         for f in list(use):
4329                                                 if f.startswith(flag_prefix):
4330                                                         use.remove(f)
4331                                 use = list(use)
4332                                 use.sort()
4333                                 print 'USE="%s"' % " ".join(use),
4334                                 for varname in use_expand:
4335                                         myval = settings.get(varname)
4336                                         if myval:
4337                                                 print '%s="%s"' % (varname, myval),
4338                                 print
4339                 else:
4340                         unset_vars.append(x)
4341         if unset_vars:
4342                 print "Unset:  "+", ".join(unset_vars)
4343         print
4344
4345         if "--debug" in myopts:
4346                 for x in dir(portage):
4347                         module = getattr(portage, x)
4348                         if "cvs_id_string" in dir(module):
4349                                 print "%s: %s" % (str(x), str(module.cvs_id_string))
4350
4351         # See if we can find any packages installed matching the strings
4352         # passed on the command line
4353         mypkgs = []
4354         vardb = trees[settings["ROOT"]]["vartree"].dbapi
4355         portdb = trees[settings["ROOT"]]["porttree"].dbapi
4356         for x in myfiles:
4357                 mypkgs.extend(vardb.match(x))
4358
4359         # If some packages were found...
4360         if mypkgs:
4361                 # Get our global settings (we only print stuff if it varies from
4362                 # the current config)
4363                 mydesiredvars = [ 'CHOST', 'CFLAGS', 'CXXFLAGS' ]
4364                 auxkeys = mydesiredvars + [ "USE", "IUSE"]
4365                 global_vals = {}
4366                 pkgsettings = portage.config(clone=settings)
4367
4368                 for myvar in mydesiredvars:
4369                         global_vals[myvar] = set(settings.get(myvar, "").split())
4370
4371                 # Loop through each package
4372                 # Only print settings if they differ from global settings
4373                 header_printed = False
4374                 for pkg in mypkgs:
4375                         # Get all package specific variables
4376                         auxvalues = vardb.aux_get(pkg, auxkeys)
4377                         valuesmap = {}
4378                         for i in xrange(len(auxkeys)):
4379                                 valuesmap[auxkeys[i]] = set(auxvalues[i].split())
4380                         diff_values = {}
4381                         for myvar in mydesiredvars:
4382                                 # If the package variable doesn't match the
4383                                 # current global variable, something has changed
4384                                 # so set diff_found so we know to print
4385                                 if valuesmap[myvar] != global_vals[myvar]:
4386                                         diff_values[myvar] = valuesmap[myvar]
4387                         valuesmap["IUSE"] = set(filter_iuse_defaults(valuesmap["IUSE"]))
4388                         valuesmap["USE"] = valuesmap["USE"].intersection(valuesmap["IUSE"])
4389                         pkgsettings.reset()
4390                         # If a matching ebuild is no longer available in the tree, maybe it
4391                         # would make sense to compare against the flags for the best
4392                         # available version with the same slot?
4393                         mydb = None
4394                         if portdb.cpv_exists(pkg):
4395                                 mydb = portdb
4396                         pkgsettings.setcpv(pkg, mydb=mydb)
4397                         if valuesmap["IUSE"].intersection(pkgsettings["USE"].split()) != \
4398                                 valuesmap["USE"]:
4399                                 diff_values["USE"] = valuesmap["USE"]
4400                         # If a difference was found, print the info for
4401                         # this package.
4402                         if diff_values:
4403
4404                                 # If we have not yet printed the header, 
4405                                 # print it now
4406                                 if not header_printed:
4407                                         header_title = "Package Settings"
4408                                         print header_width * "="
4409                                         print header_title.rjust(int(header_width/2 + len(header_title)/2))
4410                                         print header_width * "="
4411                                         header_printed = True
4412
4413                                 # Print package info
4414                                 print "%s was built with the following:" % pkg
4415                                 for myvar in mydesiredvars + ["USE"]:
4416                                         if myvar in diff_values:
4417                                                 mylist = list(diff_values[myvar])
4418                                                 mylist.sort()
4419                                                 print "%s=\"%s\"" % (myvar, " ".join(mylist))
4420                                 print
4421
4422 def action_search(settings, portdb, vartree, myopts, myfiles, spinner):
4423         if not myfiles:
4424                 print "emerge: no search terms provided."
4425         else:
4426                 searchinstance = search(settings, portdb,
4427                         vartree, spinner, "--searchdesc" in myopts,
4428                         "--quiet" not in myopts)
4429                 for mysearch in myfiles:
4430                         try:
4431                                 searchinstance.execute(mysearch)
4432                         except re.error, comment:
4433                                 print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment )
4434                                 sys.exit(1)
4435                         searchinstance.output()
4436
4437 def action_depclean(settings, trees, ldpath_mtimes,
4438         myopts, spinner):
4439         # Kill packages that aren't explicitly merged or are required as a
4440         # dependency of another package. World file is explicit.
4441
4442         warn_prefix = colorize("BAD", "*** WARNING ***  ")
4443         print
4444         print warn_prefix + "Depclean may break link level dependencies.  Thus, it is"
4445         print warn_prefix + "recommended to use a tool such as " + good("`revdep-rebuild`") + " (from"
4446         print warn_prefix + "app-portage/gentoolkit) in order to detect such breakage."
4447         print warn_prefix
4448         print warn_prefix + "Also study the list of packages to be cleaned for any obvious"
4449         print warn_prefix + "mistakes. Packages that are part of the world set will always"
4450         print warn_prefix + "be kept.  They can be manually added to this set with"
4451         print warn_prefix + good("`emerge --noreplace <atom>`") + ".  Packages that are listed in"
4452         print warn_prefix + "package.provided (see portage(5)) will be removed by"
4453         print warn_prefix + "depclean, even if they are part of the world set."
4454         print warn_prefix
4455         print warn_prefix + "As a safety measure, depclean will not remove any packages"
4456         print warn_prefix + "unless *all* required dependencies have been resolved.  As a"
4457         print warn_prefix + "consequence, it is often necessary to run "
4458         print warn_prefix + good("`emerge --update --newuse --deep world`") + " prior to depclean."
4459
4460         xterm_titles = "notitles" not in settings.features
4461         myroot = settings["ROOT"]
4462         dep_check_trees = {}
4463         dep_check_trees[myroot] = {}
4464         dep_check_trees[myroot]["vartree"] = \
4465                 FakeVartree(trees[myroot]["vartree"], trees[myroot]["porttree"].dbapi)
4466         vardb = dep_check_trees[myroot]["vartree"].dbapi
4467         # Constrain dependency selection to the installed packages.
4468         dep_check_trees[myroot]["porttree"] = dep_check_trees[myroot]["vartree"]
4469         syslist = getlist(settings, "system")
4470         worldlist = getlist(settings, "world")
4471         fakedb = portage.fakedbapi(settings=settings)
4472         myvarlist = vardb.cpv_all()
4473
4474         if not syslist:
4475                 print "\n!!! You have no system list.",
4476         if not worldlist:
4477                 print "\n!!! You have no world file.",
4478         if not myvarlist:
4479                 print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH,
4480
4481         if not (syslist and worldlist and myvarlist):
4482                 print "\n!!! Proceeding "+(syslist and myvarlist and "may" or "will")
4483                 print " break your installation.\n"
4484                 if "--pretend" not in myopts:
4485                         countdown(int(settings["EMERGE_WARNING_DELAY"]), ">>> Depclean")
4486
4487         if not "--pretend" in myopts: #just check pretend, since --ask implies pretend
4488                 emergelog(xterm_titles, " >>> depclean")
4489
4490         if "--quiet" not in myopts:
4491                 print "\nCalculating dependencies  ",
4492
4493         soft = 0
4494         hard = 1
4495         remaining_atoms = [(atom, 'world', hard) for atom in worldlist if vardb.match(atom)]
4496         remaining_atoms += [(atom, 'system', hard) for atom in syslist if vardb.match(atom)]
4497         unresolveable = {}
4498         aux_keys = ["DEPEND", "RDEPEND", "PDEPEND"]
4499
4500         while remaining_atoms:
4501                 atom, parent, priority = remaining_atoms.pop()
4502                 pkgs = vardb.match(atom)
4503                 if not pkgs:
4504                         if not atom.startswith("!") and priority == hard:
4505                                 unresolveable.setdefault(atom, []).append(parent)
4506                         continue
4507                 # Could put slot checking here to ensure that there aren't two
4508                 # packages with the same slot...
4509                 for pkg in pkgs:
4510                         if fakedb.cpv_exists(pkg):
4511                                 continue
4512                         spinner.update()
4513                         fakedb.cpv_inject(pkg)
4514                         myaux = dict(izip(aux_keys, vardb.aux_get(pkg, aux_keys)))
4515                         mydeps = []
4516                         if myopts.get("--with-bdeps", "y") == "y":
4517                                 mydeps.append((myaux["DEPEND"], soft))
4518                         del myaux["DEPEND"]
4519                         mydeps.append((" ".join(myaux.values()), hard))
4520                         usedef = vardb.aux_get(pkg, ["USE"])[0].split()
4521                         for depstr, priority in mydeps:
4522
4523                                 if not depstr:
4524                                         continue
4525
4526                                 if "--debug" in myopts:
4527                                         print
4528                                         print "Parent:   ", pkg
4529                                         print "Depstring:", depstr
4530                                         print "Priority:",
4531                                         if priority == soft:
4532                                                 print "soft"
4533                                         else:
4534                                                 print "hard"
4535
4536                                 try:
4537                                         portage.dep._dep_check_strict = False
4538                                         success, atoms = portage.dep_check(depstr, None, settings,
4539                                                 myuse=usedef, trees=dep_check_trees, myroot=myroot)
4540                                 finally:
4541                                         portage.dep._dep_check_strict = True
4542                                 if not success:
4543                                         show_invalid_depstring_notice(
4544                                                 ("installed", myroot, pkg, "nomerge"),
4545                                                 depstr, atoms)
4546                                         return
4547
4548                                 if "--debug" in myopts:
4549                                         print "Candidates:", atoms
4550
4551                                 for atom in atoms:
4552                                         remaining_atoms.append((atom, pkg, priority))
4553
4554         if "--quiet" not in myopts:
4555                 print "\b\b... done!\n"
4556
4557         if unresolveable:
4558                 print "Dependencies could not be completely resolved due to"
4559                 print "the following required packages not being installed:"
4560                 print
4561                 for atom in unresolveable:
4562                         print atom, "required by", " ".join(unresolveable[atom])
4563                 print
4564                 print "Have you forgotten to run " + good("`emerge --update --newuse --deep world`") + " prior to"
4565                 print "depclean?  It may also be necessary to manually uninstalled packages that no"
4566                 print "longer exist in the portage tree since it may not be possible to satisfy their"
4567                 print "dependencies."
4568                 print
4569                 return
4570
4571         cleanlist = [pkg for pkg in vardb.cpv_all() if not fakedb.cpv_exists(pkg)]
4572
4573         if len(cleanlist):
4574                 unmerge(settings, myopts, trees[settings["ROOT"]]["vartree"],
4575                         "unmerge", cleanlist, ldpath_mtimes)
4576
4577         print "Packages installed:   "+str(len(myvarlist))
4578         print "Packages in world:    "+str(len(worldlist))
4579         print "Packages in system:   "+str(len(syslist))
4580         print "Unique package names: "+str(len(myvarlist))
4581         print "Required packages:    "+str(len(fakedb.cpv_all()))
4582         if "--pretend" in myopts:
4583                 print "Number to remove:     "+str(len(cleanlist))
4584         else:
4585                 print "Number removed:       "+str(len(cleanlist))
4586
4587 def action_build(settings, trees, mtimedb,
4588         myopts, myaction, myfiles, spinner):
4589         ldpath_mtimes = mtimedb["ldpath"]
4590         favorites=[]
4591         if ("--ask" in myopts or "--pretend" in myopts) and not "--quiet" in myopts:
4592                 action = ""
4593                 if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
4594                         action = "fetched"
4595                 else:
4596                         action = "merged"
4597                 if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching
4598                         print
4599                         print darkgreen("These are the packages that would be %s, in reverse order:") % action
4600                         print
4601                 else:
4602                         print
4603                         print darkgreen("These are the packages that would be %s, in order:") % action
4604                         print
4605
4606         # validate the state of the resume data
4607         # so that we can make assumptions later.
4608         for k in ("resume", "resume_backup"):
4609                 if k in mtimedb:
4610                         if "mergelist" in mtimedb[k]:
4611                                 if not mtimedb[k]["mergelist"]:
4612                                         del mtimedb[k]
4613                         else:
4614                                 del mtimedb[k]
4615
4616         if "--resume" in myopts and \
4617                 ("resume" in mtimedb or
4618                 "resume_backup" in mtimedb):
4619                 if "resume" not in mtimedb:
4620                         mtimedb["resume"] = mtimedb["resume_backup"]
4621                         del mtimedb["resume_backup"]
4622                         mtimedb.commit()
4623                 # XXX: "myopts" is a list for backward compatibility.
4624                 myresumeopts = dict([(k,True) for k in mtimedb["resume"]["myopts"]])
4625
4626                 for opt in ("--skipfirst", "--ask", "--tree"):
4627                         myresumeopts.pop(opt, None)
4628
4629                 for myopt, myarg in myopts.iteritems():
4630                         if myopt not in myresumeopts:
4631                                 myresumeopts[myopt] = myarg
4632                 myopts=myresumeopts
4633                 myparams = create_depgraph_params(myopts, myaction)
4634                 if not "--quiet" in myopts:
4635                         print "Calculating dependencies  ",
4636                 mydepgraph = depgraph(settings, trees,
4637                         myopts, myparams, spinner)
4638                 if not "--quiet" in myopts:
4639                         print "\b\b... done!"
4640         else:
4641                 if ("--resume" in myopts):
4642                         print darkgreen("emerge: It seems we have nothing to resume...")
4643                         sys.exit(0)
4644
4645                 myparams = create_depgraph_params(myopts, myaction)
4646                 if myaction in ["system","world"]:
4647                         if not ("--quiet" in myopts):
4648                                 print "Calculating",myaction,"dependencies  ",
4649                                 sys.stdout.flush()
4650                         mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
4651                         if not mydepgraph.xcreate(myaction):
4652                                 print "!!! Depgraph creation failed."
4653                                 sys.exit(1)
4654                         if not ("--quiet" in myopts):
4655                                 print "\b\b... done!"
4656                 else:
4657                         if not ("--quiet" in myopts):
4658                                 print "Calculating dependencies  ",
4659                                 sys.stdout.flush()
4660                         mydepgraph = depgraph(settings, trees, myopts, myparams, spinner)
4661                         try:
4662                                 retval, favorites = mydepgraph.select_files(myfiles)
4663                         except portage.exception.PackageNotFound, e:
4664                                 portage.writemsg("\n!!! %s\n" % str(e), noiselevel=-1)
4665                                 sys.exit(1)
4666                         if not retval:
4667                                 sys.exit(1)
4668                         if not ("--quiet" in myopts):
4669                                 print "\b\b... done!"
4670
4671                         if ("--usepkgonly" in myopts) and mydepgraph.missingbins:
4672                                 sys.stderr.write(red("The following binaries are not available for merging...\n"))
4673
4674                 if mydepgraph.missingbins:
4675                         for x in mydepgraph.missingbins:
4676                                 sys.stderr.write("   "+str(x)+"\n")
4677                         sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n")
4678                         sys.exit(1)
4679
4680         if "--ask" in myopts:
4681                 if "--resume" in myopts:
4682                         validate_merge_list(trees, mtimedb["resume"]["mergelist"])
4683                         mymergelist = mtimedb["resume"]["mergelist"]
4684                         if "--skipfirst" in myopts:
4685                                 mymergelist = mymergelist[1:]
4686                         if len(mymergelist) == 0:
4687                                 print colorize("INFORM", "emerge: It seems we have nothing to resume...")
4688                                 sys.exit(0)
4689                         mydepgraph.display(mymergelist)
4690                         prompt="Would you like to resume merging these packages?"
4691                 else:
4692                         mydepgraph.display(
4693                                 mydepgraph.altlist(reversed=("--tree" in myopts)))
4694                         mergecount=0
4695                         for x in mydepgraph.altlist():
4696                                 if x[0] != "blocks" and x[3] != "nomerge":
4697                                         mergecount+=1
4698                                 #check for blocking dependencies
4699                                 if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts:
4700                                         print "\n!!! Error: The above package list contains packages which cannot be installed"
4701                                         print   "!!!        at the same time on the same system."
4702                                         if "--quiet" not in myopts:
4703                                                 show_blocker_docs_link()
4704                                         sys.exit(1)
4705                         if mergecount==0:
4706                                 if "--noreplace" in myopts and favorites:
4707                                         print
4708                                         for x in favorites:
4709                                                 print " %s %s" % (good("*"), x)
4710                                         prompt="Would you like to add these packages to your world favorites?"
4711                                 elif settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
4712                                         prompt="Nothing to merge; would you like to auto-clean packages?"
4713                                 else:
4714                                         print
4715                                         print "Nothing to merge; quitting."
4716                                         print
4717                                         sys.exit(0)
4718                         elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
4719                                 prompt="Would you like to fetch the source files for these packages?"
4720                         else:
4721                                 prompt="Would you like to merge these packages?"
4722                 print
4723                 if userquery(prompt)=="No":
4724                         print
4725                         print "Quitting."
4726                         print
4727                         sys.exit(0)
4728                 # Don't ask again (e.g. when auto-cleaning packages after merge)
4729                 del myopts["--ask"]
4730
4731         if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
4732                 if ("--resume" in myopts):
4733                         validate_merge_list(trees, mtimedb["resume"]["mergelist"])
4734                         mymergelist = mtimedb["resume"]["mergelist"]
4735                         if "--skipfirst" in myopts:
4736                                 mymergelist = mymergelist[1:]
4737                         if len(mymergelist) == 0:
4738                                 print colorize("INFORM", "emerge: It seems we have nothing to resume...")
4739                                 sys.exit(0)
4740                         mydepgraph.display(mymergelist)
4741                 else:
4742                         mydepgraph.display(
4743                                 mydepgraph.altlist(reversed=("--tree" in myopts)))
4744         else:
4745                 if ("--buildpkgonly" in myopts):
4746                         if not mydepgraph.digraph.hasallzeros(ignore_priority=DepPriority.MEDIUM):
4747                                 print "\n!!! --buildpkgonly requires all dependencies to be merged."
4748                                 print "!!! Cannot merge requested packages. Merge deps and try again.\n"
4749                                 sys.exit(1)
4750
4751                 if ("--resume" in myopts):
4752                         favorites=mtimedb["resume"]["favorites"]
4753                         mergetask = MergeTask(settings, trees, myopts)
4754                         if "--fetchonly" in myopts:
4755                                 """ parallel-fetch uses --resume --fetchonly and we don't want
4756                                 it to write the mtimedb"""
4757                                 mtimedb.filename = None
4758                                 time.sleep(3) # allow the parent to have first fetch
4759                         del mydepgraph
4760                         retval = mergetask.merge(
4761                                 mtimedb["resume"]["mergelist"], favorites, mtimedb)
4762                         if retval != os.EX_OK:
4763                                 sys.exit(retval)
4764                 else:
4765                         if "resume" in mtimedb and \
4766                         "mergelist" in mtimedb["resume"] and \
4767                         len(mtimedb["resume"]["mergelist"]) > 1:
4768                                 mtimedb["resume_backup"] = mtimedb["resume"]
4769                                 del mtimedb["resume"]
4770                                 mtimedb.commit()
4771                         mtimedb["resume"]={}
4772                         # XXX: Stored as a list for backward compatibility.
4773                         mtimedb["resume"]["myopts"] = \
4774                                 [k for k in myopts if myopts[k] is True]
4775                         mtimedb["resume"]["favorites"]=favorites
4776                         if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts):
4777                                 for pkgline in mydepgraph.altlist():
4778                                         if pkgline[0]=="ebuild" and pkgline[3]=="merge":
4779                                                 y = trees[pkgline[1]]["porttree"].dbapi.findname(pkgline[2])
4780                                                 tmpsettings = portage.config(clone=settings)
4781                                                 edebug = 0
4782                                                 if settings.get("PORTAGE_DEBUG", "") == "1":
4783                                                         edebug = 1
4784                                                 retval = portage.doebuild(
4785                                                         y, "digest", settings["ROOT"], tmpsettings, edebug,
4786                                                         ("--pretend" in myopts),
4787                                                         mydbapi=trees[pkgline[1]]["porttree"].dbapi,
4788                                                         tree="porttree")
4789                         if "--fetchonly" in myopts or "--fetch-all-uri" in myopts:
4790                                 pkglist = []
4791                                 for pkg in mydepgraph.altlist():
4792                                         if pkg[0] != "blocks":
4793                                                 pkglist.append(pkg)
4794                         else:
4795                                 pkglist = mydepgraph.altlist()
4796                         del mydepgraph
4797                         mergetask = MergeTask(settings, trees, myopts)
4798                         retval = mergetask.merge(pkglist, favorites, mtimedb)
4799                         if retval != os.EX_OK:
4800                                 sys.exit(retval)
4801
4802                 if mtimedb.has_key("resume"):
4803                         del mtimedb["resume"]
4804                 if settings["AUTOCLEAN"] and "yes"==settings["AUTOCLEAN"]:
4805                         print ">>> Auto-cleaning packages..."
4806                         vartree = trees[settings["ROOT"]]["vartree"]
4807                         unmerge(settings, myopts, vartree, "clean", ["world"],
4808                                 ldpath_mtimes, autoclean=1)
4809                 else:
4810                         portage.writemsg_stdout(colorize("WARN", "WARNING:")
4811                                 + " AUTOCLEAN is disabled.  This can cause serious"
4812                                 + " problems due to overlapping packages.\n")
4813
4814 def multiple_actions(action1, action2):
4815         sys.stderr.write("\n!!! Multiple actions requested... Please choose one only.\n")
4816         sys.stderr.write("!!! '%s' or '%s'\n\n" % (action1, action2))
4817         sys.exit(1)
4818
4819 def parse_opts(tmpcmdline, silent=False):
4820         myaction=None
4821         myopts = {}
4822         myfiles=[]
4823
4824         global actions, options, shortmapping
4825
4826         longopt_aliases = {"--cols":"--columns", "--skip-first":"--skipfirst"}
4827         argument_options = {
4828                 "--config-root": {
4829                         "help":"specify the location for portage configuration files",
4830                         "action":"store"
4831                 },
4832                 "--color": {
4833                         "help":"enable or disable color output",
4834                         "type":"choice",
4835                         "choices":("y", "n")
4836                 },
4837                 "--with-bdeps": {
4838                         "help":"include unnecessary build time dependencies",
4839                         "type":"choice",
4840                         "choices":("y", "n")
4841                 }
4842         }
4843
4844         from optparse import OptionParser
4845         parser = OptionParser()
4846         if parser.has_option("--help"):
4847                 parser.remove_option("--help")
4848
4849         for action_opt in actions:
4850                 parser.add_option("--" + action_opt, action="store_true",
4851                         dest=action_opt.replace("-", "_"), default=False)
4852         for myopt in options:
4853                 parser.add_option(myopt, action="store_true",
4854                         dest=myopt.lstrip("--").replace("-", "_"), default=False)
4855         for shortopt, longopt in shortmapping.iteritems():
4856                 parser.add_option("-" + shortopt, action="store_true",
4857                         dest=longopt.lstrip("--").replace("-", "_"), default=False)
4858         for myalias, myopt in longopt_aliases.iteritems():
4859                 parser.add_option(myalias, action="store_true",
4860                         dest=myopt.lstrip("--").replace("-", "_"), default=False)
4861
4862         for myopt, kwargs in argument_options.iteritems():
4863                 parser.add_option(myopt,
4864                         dest=myopt.lstrip("--").replace("-", "_"), **kwargs)
4865
4866         myoptions, myargs = parser.parse_args(args=tmpcmdline)
4867
4868         for myopt in options:
4869                 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"))
4870                 if v:
4871                         myopts[myopt] = True
4872
4873         for myopt in argument_options:
4874                 v = getattr(myoptions, myopt.lstrip("--").replace("-", "_"), None)
4875                 if v is not None:
4876                         myopts[myopt] = v
4877
4878         for action_opt in actions:
4879                 v = getattr(myoptions, action_opt.replace("-", "_"))
4880                 if v:
4881                         if myaction:
4882                                 multiple_actions(myaction, action_opt)
4883                                 sys.exit(1)
4884                         myaction = action_opt
4885
4886         for x in myargs:
4887                 if x in actions and myaction != "search":
4888                         if not silent and x not in ["system", "world"]:
4889                                 print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x))
4890                         # special case "search" so people can search for action terms, e.g. emerge -s sync
4891                         if myaction:
4892                                 multiple_actions(myaction, x)
4893                                 sys.exit(1)
4894                         myaction = x
4895                 else:
4896                         myfiles.append(x)
4897
4898         if "--nocolor" in myopts:
4899                 if not silent:
4900                         sys.stderr.write("*** Deprecated use of '--nocolor', " + \
4901                                 "use '--color=n' instead.\n")
4902                 del myopts["--nocolor"]
4903                 myopts["--color"] = "n"
4904
4905         return myaction, myopts, myfiles
4906
4907 def validate_ebuild_environment(trees):
4908         for myroot in trees:
4909                 mysettings = trees[myroot]["vartree"].settings
4910                 if not mysettings.get("ARCH", None):
4911                         print >> sys.stderr, bad("\a!!! ARCH is not set... " + \
4912                                 "Are you missing the '%setc/make.profile' symlink?" % \
4913                                 mysettings["PORTAGE_CONFIGROOT"])
4914                         print >> sys.stderr, bad("\a!!! Is the symlink correct? " + \
4915                                 "Is your portage tree complete?\n")
4916                         sys.exit(9)
4917                 del myroot, mysettings
4918
4919 def load_emerge_config(trees=None):
4920         kwargs = {}
4921         for k, envvar in (("config_root", "PORTAGE_CONFIGROOT"), ("target_root", "ROOT")):
4922                 kwargs[k] = os.environ.get(envvar, None)
4923         trees = portage.create_trees(trees=trees, **kwargs)
4924
4925         settings = trees["/"]["vartree"].settings
4926
4927         for myroot in trees:
4928                 if myroot != "/":
4929                         settings = trees[myroot]["vartree"].settings
4930                         break
4931
4932         mtimedbfile = os.path.join("/", portage.CACHE_PATH.lstrip(os.path.sep), "mtimedb")
4933         mtimedb = portage.MtimeDB(mtimedbfile)
4934         return settings, trees, mtimedb
4935
4936 def adjust_config(myopts, settings):
4937         """Make emerge specific adjustments to the config."""
4938
4939         # To enhance usability, make some vars case insensitive by forcing them to
4940         # lower case.
4941         for myvar in ("AUTOCLEAN", "NOCOLOR"):
4942                 if myvar in settings:
4943                         settings[myvar] = settings[myvar].lower()
4944                         settings.backup_changes(myvar)
4945         del myvar
4946
4947         # Kill noauto as it will break merges otherwise.
4948         if "noauto" in settings.features:
4949                 while "noauto" in settings.features:
4950                         settings.features.remove("noauto")
4951                 settings["FEATURES"] = " ".join(settings.features)
4952                 settings.backup_changes("FEATURES")
4953
4954         CLEAN_DELAY = 5
4955         try:
4956                 CLEAN_DELAY = int(settings.get("CLEAN_DELAY", str(CLEAN_DELAY)))
4957         except ValueError, e:
4958                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
4959                 portage.writemsg("!!! Unable to parse integer: CLEAN_DELAY='%s'\n" % \
4960                         settings["CLEAN_DELAY"], noiselevel=-1)
4961         settings["CLEAN_DELAY"] = str(CLEAN_DELAY)
4962         settings.backup_changes("CLEAN_DELAY")
4963
4964         EMERGE_WARNING_DELAY = 10
4965         try:
4966                 EMERGE_WARNING_DELAY = int(settings.get(
4967                         "EMERGE_WARNING_DELAY", str(EMERGE_WARNING_DELAY)))
4968         except ValueError, e:
4969                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
4970                 portage.writemsg("!!! Unable to parse integer: EMERGE_WARNING_DELAY='%s'\n" % \
4971                         settings["EMERGE_WARNING_DELAY"], noiselevel=-1)
4972         settings["EMERGE_WARNING_DELAY"] = str(EMERGE_WARNING_DELAY)
4973         settings.backup_changes("EMERGE_WARNING_DELAY")
4974
4975         if "--quiet" in myopts:
4976                 settings["PORTAGE_QUIET"]="1"
4977                 settings.backup_changes("PORTAGE_QUIET")
4978
4979         # Set so that configs will be merged regardless of remembered status
4980         if ("--noconfmem" in myopts):
4981                 settings["NOCONFMEM"]="1"
4982                 settings.backup_changes("NOCONFMEM")
4983
4984         # Set various debug markers... They should be merged somehow.
4985         PORTAGE_DEBUG = 0
4986         try:
4987                 PORTAGE_DEBUG = int(settings.get("PORTAGE_DEBUG", str(PORTAGE_DEBUG)))
4988                 if PORTAGE_DEBUG not in (0, 1):
4989                         portage.writemsg("!!! Invalid value: PORTAGE_DEBUG='%i'\n" % \
4990                                 PORTAGE_DEBUG, noiselevel=-1)
4991                         portage.writemsg("!!! PORTAGE_DEBUG must be either 0 or 1\n",
4992                                 noiselevel=-1)
4993                         PORTAGE_DEBUG = 0
4994         except ValueError, e:
4995                 portage.writemsg("!!! %s\n" % str(e), noiselevel=-1)
4996                 portage.writemsg("!!! Unable to parse integer: PORTAGE_DEBUG='%s'\n" %\
4997                         settings["PORTAGE_DEBUG"], noiselevel=-1)
4998                 del e
4999         if "--debug" in myopts:
5000                 PORTAGE_DEBUG = 1
5001         settings["PORTAGE_DEBUG"] = str(PORTAGE_DEBUG)
5002         settings.backup_changes("PORTAGE_DEBUG")
5003
5004         if settings.get("NOCOLOR") not in ("yes","true"):
5005                 portage.output.havecolor = 1
5006
5007         """The explicit --color < y | n > option overrides the NOCOLOR environment
5008         variable and stdout auto-detection."""
5009         if "--color" in myopts:
5010                 if "y" == myopts["--color"]:
5011                         portage.output.havecolor = 1
5012                         settings["NOCOLOR"] = "false"
5013                 else:
5014                         portage.output.havecolor = 0
5015                         settings["NOCOLOR"] = "true"
5016                 settings.backup_changes("NOCOLOR")
5017         elif not sys.stdout.isatty() and settings.get("NOCOLOR") != "no":
5018                 portage.output.havecolor = 0
5019                 settings["NOCOLOR"] = "true"
5020                 settings.backup_changes("NOCOLOR")
5021
5022 def emerge_main():
5023         global portage  # NFC why this is necessary now - genone
5024         # Disable color until we're sure that it should be enabled (after
5025         # EMERGE_DEFAULT_OPTS has been parsed).
5026         portage.output.havecolor = 0
5027         # This first pass is just for options that need to be known as early as
5028         # possible, such as --config-root.  They will be parsed again later,
5029         # together with EMERGE_DEFAULT_OPTS (which may vary depending on the
5030         # the value of --config-root).
5031         myaction, myopts, myfiles = parse_opts(sys.argv[1:], silent=True)
5032         if "--debug" in myopts:
5033                 os.environ["PORTAGE_DEBUG"] = "1"
5034         if "--config-root" in myopts:
5035                 os.environ["PORTAGE_CONFIGROOT"] = myopts["--config-root"]
5036
5037         # Portage needs to ensure a sane umask for the files it creates.
5038         os.umask(022)
5039         settings, trees, mtimedb = load_emerge_config()
5040         portdb = trees[settings["ROOT"]]["porttree"].dbapi
5041
5042         try:
5043                 os.nice(int(settings.get("PORTAGE_NICENESS", "0")))
5044         except (OSError, ValueError), e:
5045                 portage.writemsg("!!! Failed to change nice value to '%s'\n" % \
5046                         settings["PORTAGE_NICENESS"])
5047                 portage.writemsg("!!! %s\n" % str(e))
5048                 del e
5049
5050         if portage.global_updates(settings, trees, mtimedb["updates"]):
5051                 mtimedb.commit()
5052                 # Reload the whole config from scratch.
5053                 settings, trees, mtimedb = load_emerge_config(trees=trees)
5054                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
5055
5056         xterm_titles = "notitles" not in settings.features
5057
5058         tmpcmdline = []
5059         if "--ignore-default-opts" not in sys.argv:
5060                 tmpcmdline.extend(settings["EMERGE_DEFAULT_OPTS"].split())
5061         tmpcmdline.extend(sys.argv[1:])
5062         myaction, myopts, myfiles = parse_opts(tmpcmdline)
5063
5064         if "--digest" in myopts:
5065                 os.environ["FEATURES"] = os.environ.get("FEATURES","") + " digest"
5066                 # Reload the whole config from scratch so that the portdbapi internal
5067                 # config is updated with new FEATURES.
5068                 settings, trees, mtimedb = load_emerge_config(trees=trees)
5069                 portdb = trees[settings["ROOT"]]["porttree"].dbapi
5070
5071         for myroot in trees:
5072                 mysettings =  trees[myroot]["vartree"].settings
5073                 mysettings.unlock()
5074                 adjust_config(myopts, mysettings)
5075                 mysettings.lock()
5076                 del myroot, mysettings
5077
5078         spinner = stdout_spinner()
5079         if "candy" in settings.features:
5080                 spinner.update = spinner.update_scroll
5081
5082         portage.deprecated_profile_check()
5083
5084         #Freeze the portdbapi for enhanced performance:
5085         for myroot in trees:
5086                 trees[myroot]["porttree"].dbapi.freeze()
5087                 del myroot
5088
5089         if "moo" in myfiles:
5090                 print """
5091
5092   Larry loves Gentoo (""" + os.uname()[0] + """)
5093
5094  _______________________
5095 < Have you mooed today? >
5096  -----------------------
5097         \   ^__^
5098          \  (oo)\_______
5099             (__)\       )\/\ 
5100                 ||----w |
5101                 ||     ||
5102
5103 """
5104
5105         if (myaction in ["world", "system"]) and myfiles:
5106                 print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both."
5107                 sys.exit(1)
5108
5109         for x in myfiles:
5110                 ext = os.path.splitext(x)[1]
5111                 if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)):
5112                         print "emerging by path implies --oneshot... adding --oneshot to options."
5113                         print colorize("BAD", "\n*** emerging by path is broken and may not always work!!!\n")
5114                         break
5115
5116         if ("--tree" in myopts) and ("--columns" in myopts):
5117                 print "emerge: can't specify both of \"--tree\" and \"--columns\"."
5118                 sys.exit(1)
5119
5120         if ("--quiet" in myopts):
5121                 spinner.update = spinner.update_quiet
5122                 portage.util.noiselimit = -1
5123
5124         # Always create packages if FEATURES=buildpkg
5125         # Imply --buildpkg if --buildpkgonly
5126         if ("buildpkg" in settings.features) or ("--buildpkgonly" in myopts):
5127                 if "--buildpkg" not in myopts:
5128                         myopts["--buildpkg"] = True
5129
5130         # Also allow -S to invoke search action (-sS)
5131         if ("--searchdesc" in myopts):
5132                 if myaction and myaction != "search":
5133                         myfiles.append(myaction)
5134                 if "--search" not in myopts:
5135                         myopts["--search"] = True
5136                 myaction = "search"
5137
5138         # Always try and fetch binary packages if FEATURES=getbinpkg
5139         if ("getbinpkg" in settings.features):
5140                 myopts["--getbinpkg"] = True
5141
5142         if "--skipfirst" in myopts and "--resume" not in myopts:
5143                 myopts["--resume"] = True
5144
5145         if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts):
5146                 myopts["--usepkgonly"] = True
5147
5148         if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts):
5149                 myopts["--getbinpkg"] = True
5150
5151         if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts):
5152                 myopts["--usepkg"] = True
5153
5154         # Also allow -K to apply --usepkg/-k
5155         if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts):
5156                 myopts["--usepkg"] = True
5157
5158         # Allow -p to remove --ask
5159         if ("--pretend" in myopts) and ("--ask" in myopts):
5160                 print ">>> --pretend disables --ask... removing --ask from options."
5161                 del myopts["--ask"]
5162
5163         # forbid --ask when not in a terminal
5164         # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway.
5165         if ("--ask" in myopts) and (not sys.stdin.isatty()):
5166                 portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n",
5167                         noiselevel=-1)
5168                 sys.exit(1)
5169
5170         if settings.get("PORTAGE_DEBUG", "") == "1":
5171                 spinner.update = spinner.update_quiet
5172                 portage.debug=1
5173                 if "python-trace" in settings.features:
5174                         import portage.debug
5175                         portage.debug.set_trace(True)
5176
5177         if ("--resume" in myopts):
5178                 if "--tree" in myopts:
5179                         print "* --tree is currently broken with --resume. Disabling..."
5180                         del myopts["--tree"]
5181
5182         if not ("--quiet" in myopts):
5183                 if not sys.stdout.isatty() or ("--nospinner" in myopts):
5184                         spinner.update = spinner.update_basic
5185
5186         if "--version" in myopts:
5187                 print getportageversion(settings["PORTDIR"], settings["ROOT"],
5188                         settings.profile_path, settings["CHOST"],
5189                         trees[settings["ROOT"]]["vartree"].dbapi)
5190                 sys.exit(0)
5191         elif "--help" in myopts:
5192                 portage.emergehelp.help(myaction, myopts, portage.output.havecolor)
5193                 sys.exit(0)
5194
5195         if portage.wheelgid == portage.portage_gid:
5196                 print "emerge: wheel group use is being deprecated. Please update group and passwd to"
5197                 print "        include the portage user as noted above, and then use group portage."
5198
5199         if "--debug" in myopts:
5200                 print "myaction", myaction
5201                 print "myopts", myopts
5202
5203         if not myaction and not myfiles and "--resume" not in myopts:
5204                 portage.emergehelp.help(myaction, myopts, portage.output.havecolor)
5205                 sys.exit(1)
5206
5207         # check if root user is the current user for the actions where emerge needs this
5208         if portage.secpass < 2:
5209                 # We've already allowed "--version" and "--help" above.
5210                 if "--pretend" not in myopts and \
5211                 myaction not in ("search","info"):
5212                         need_superuser = not \
5213                                 ("--fetchonly" in myopts or \
5214                                 "--fetch-all-uri" in myopts or \
5215                                 myaction in ("metadata", "regen"))
5216                         if portage.secpass < 1 or \
5217                                 need_superuser:
5218                                 if need_superuser:
5219                                         access_desc = "superuser"
5220                                 else:
5221                                         access_desc = "portage group"
5222                                 # Always show portage_group_warning() when only portage group
5223                                 # access is required but the user is not in the portage group.
5224                                 from portage.data import portage_group_warning
5225                                 if "--ask" in myopts:
5226                                         myopts["--pretend"] = True
5227                                         del myopts["--ask"]
5228                                         print ("%s access would be required... " + \
5229                                                 "adding --pretend to options.\n") % access_desc
5230                                         if portage.secpass < 1 and not need_superuser:
5231                                                 portage_group_warning()
5232                                 else:
5233                                         sys.stderr.write(("emerge: %s access would be " + \
5234                                                 "required.\n\n") % access_desc)
5235                                         if portage.secpass < 1 and not need_superuser:
5236                                                 portage_group_warning()
5237                                         return 1
5238
5239         disable_emergelog = False
5240         for x in ("--pretend", "--fetchonly", "--fetch-all-uri"):
5241                 if x in myopts:
5242                         disable_emergelog = True
5243                         break
5244         if myaction in ("search", "info"):
5245                 disable_emergelog = True
5246         if disable_emergelog:
5247                 """ Disable emergelog for everything except build or unmerge
5248                 operations.  This helps minimize parallel emerge.log entries that can
5249                 confuse log parsers.  We especially want it disabled during
5250                 parallel-fetch, which uses --resume --fetchonly."""
5251                 global emergelog
5252                 def emergelog(*pargs, **kargs):
5253                         pass
5254
5255         if not "--pretend" in myopts:
5256                 emergelog(xterm_titles, "Started emerge on: "+\
5257                         time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
5258                 myelogstr=""
5259                 if myopts:
5260                         myelogstr=" ".join(myopts)
5261                 if myaction:
5262                         myelogstr+=" "+myaction
5263                 if myfiles:
5264                         myelogstr+=" "+" ".join(myfiles)
5265                 emergelog(xterm_titles, " *** emerge " + myelogstr)
5266
5267         def emergeexitsig(signum, frame):
5268                 signal.signal(signal.SIGINT, signal.SIG_IGN)
5269                 signal.signal(signal.SIGTERM, signal.SIG_IGN)
5270                 portage.util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum})
5271                 sys.exit(100+signum)
5272         signal.signal(signal.SIGINT, emergeexitsig)
5273         signal.signal(signal.SIGTERM, emergeexitsig)
5274
5275         def emergeexit():
5276                 """This gets out final log message in before we quit."""
5277                 if "--pretend" not in myopts:
5278                         emergelog(xterm_titles, " *** terminating.")
5279                 if "notitles" not in settings.features:
5280                         xtermTitleReset()
5281         portage.atexit_register(emergeexit)
5282
5283         if myaction in ("config", "metadata", "regen", "sync"):
5284                 if "--pretend" in myopts:
5285                         sys.stderr.write(("emerge: The '%s' action does " + \
5286                                 "not support '--pretend'.\n") % myaction)
5287                         return 1
5288         if "sync" == myaction:
5289                 action_sync(settings, trees, mtimedb, myopts, myaction)
5290         elif "metadata" == myaction:
5291                 action_metadata(settings, portdb, myopts)
5292         elif myaction=="regen":
5293                 validate_ebuild_environment(trees)
5294                 action_regen(settings, portdb)
5295         # HELP action
5296         elif "config"==myaction:
5297                 validate_ebuild_environment(trees)
5298                 action_config(settings, trees, myopts, myfiles)
5299         
5300         # INFO action
5301         elif "info"==myaction:
5302                 action_info(settings, trees, myopts, myfiles)
5303
5304         # SEARCH action
5305         elif "search"==myaction:
5306                 validate_ebuild_environment(trees)
5307                 action_search(settings, portdb, trees["/"]["vartree"],
5308                         myopts, myfiles, spinner)
5309         elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction:
5310                 validate_ebuild_environment(trees)
5311                 vartree = trees[settings["ROOT"]]["vartree"]
5312                 if 1 == unmerge(settings, myopts, vartree, myaction, myfiles,
5313                         mtimedb["ldpath"]):
5314                         if "--pretend" not in myopts:
5315                                 post_emerge(settings, mtimedb, 0)
5316
5317         elif "depclean"==myaction:
5318                 validate_ebuild_environment(trees)
5319                 action_depclean(settings, trees, mtimedb["ldpath"],
5320                         myopts, spinner)
5321                 if "--pretend" not in myopts:
5322                         post_emerge(settings, mtimedb, 0)
5323         # "update", "system", or just process files:
5324         else:
5325                 validate_ebuild_environment(trees)
5326                 action_build(settings, trees, mtimedb,
5327                         myopts, myaction, myfiles, spinner)
5328                 if "--pretend" not in myopts:
5329                         post_emerge(settings, mtimedb, 0)
5330
5331 if __name__ == "__main__":
5332         retval = emerge_main()
5333         sys.exit(retval)