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