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