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