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