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