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