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