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