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