| #!/usr/bin/python -O |
| # Copyright 1999-2006 Gentoo Foundation |
| # Distributed under the terms of the GNU General Public License v2 |
| # $Id: /var/cvsroot/gentoo-src/portage/bin/emerge,v 1.345.2.38 2005/08/13 17:25:26 ferringb Exp $ |
| |
| import os,sys |
| os.environ["PORTAGE_CALLER"]="emerge" |
| sys.path = ["/usr/lib/portage/pym"]+sys.path |
| |
| try: |
| import portage |
| except KeyboardInterrupt: |
| sys.exit(1) # If they control C during imports, just die silently |
| |
| import emergehelp,xpak,string,re,commands,time,shutil,traceback,signal,socket,types |
| from stat import * |
| from output import * |
| |
| import portage_util |
| import portage_locks |
| import portage_exception |
| |
| |
| spinner_msgs = ["Gentoo Rocks ("+os.uname()[0]+")", |
| "Thank you for using Gentoo. :)", |
| "Are you actually trying to read this?", |
| "How many times have you stared at this?", |
| "We are generating the cache right now", |
| "You are paying too much attention.", |
| "A theory is better than its explanation.", |
| "Phasers locked on target, Captain.", |
| "Thrashing is just virtual crashing.", |
| "To be is to program.", |
| "Real Users hate Real Programmers.", |
| "When all else fails, read the instructions.", |
| "Functionality breeds Contempt.", |
| "The future lies ahead.", |
| "3.1415926535897932384626433832795028841971694", |
| "Sometimes insanity is the only alternative.", |
| "Inaccuracy saves a world of explanation.", |
| ] |
| |
| |
| def update_basic_spinner(): |
| global spinner, spinpos |
| spinpos = (spinpos+1) % 500 |
| if (spinpos % 100) == 0: |
| if spinpos == 0: |
| sys.stdout.write(". ") |
| else: |
| sys.stdout.write(".") |
| sys.stdout.flush() |
| |
| def update_scroll_spinner(): |
| global spinner, spinpos |
| if(spinpos >= len(spinner)): |
| sys.stdout.write(darkgreen(" \b\b\b"+spinner[len(spinner)-1-(spinpos%len(spinner))])) |
| else: |
| sys.stdout.write(green("\b "+spinner[spinpos])) |
| sys.stdout.flush() |
| spinpos = (spinpos+1) % (2*len(spinner)) |
| |
| def update_twirl_spinner(): |
| global spinner, spinpos |
| spinpos = (spinpos+1) % len(spinner) |
| sys.stdout.write("\b\b "+spinner[spinpos]) |
| sys.stdout.flush() |
| |
| def update_quiet_spinner(): |
| return |
| |
| spinpos = 0 |
| spinner = "/-\\|/-\\|/-\\|/-\\|\\-/|\\-/|\\-/|\\-/|" |
| update_spinner = update_twirl_spinner |
| if "candy" in portage.settings.features: |
| spinner = spinner_msgs[int(time.time()*100)%len(spinner_msgs)] |
| update_spinner = update_scroll_spinner |
| |
| if (not sys.stdout.isatty()) or (portage.settings["NOCOLOR"] in ["yes","true"]): |
| nocolor() |
| |
| |
| |
| def normpath(mystr): |
| """ |
| os.path.normpath("//foo") returns "//foo" instead of "/foo" |
| We dislike this behavior so we create our own normpath func |
| to fix it. |
| """ |
| if mystr and (mystr[0]=='/'): |
| return os.path.normpath("///"+mystr) |
| else: |
| return os.path.normpath(mystr) |
| |
| def userquery(prompt, responses=None, colours=None): |
| """Displays a prompt and a set of responses, then waits for a response |
| which is checked against the responses and the first to match is |
| returned. |
| |
| prompt: a String. |
| responses: a List of Strings. |
| colours: a List of Functions taking and returning a String, used to |
| process the responses for display. Typically these will be functions |
| like red() but could be e.g. lambda x: "DisplayString". |
| If responses is omitted, defaults to ["Yes", "No"], [green, red]. |
| If only colours is omitted, defaults to [bold, ...]. |
| |
| Returns a member of the List responses. (If called without optional |
| arguments, returns "Yes" or "No".) |
| KeyboardInterrupt is converted to SystemExit to avoid tracebacks being |
| printed.""" |
| if responses is None: |
| responses, colours = ["Yes", "No"], [green, red] |
| elif colours is None: |
| colours=[bold] |
| colours=(colours*len(responses))[:len(responses)] |
| print bold(prompt), |
| try: |
| while True: |
| response=raw_input("["+string.join([colours[i](responses[i]) for i in range(len(responses))],"/")+"] ") |
| for key in responses: |
| if response.upper()==key[:len(response)].upper(): |
| return key |
| print "Sorry, response '%s' not understood." % response, |
| except (EOFError, KeyboardInterrupt): |
| print "Interrupted." |
| sys.exit(1) |
| |
| def sorted_versions(verlist): |
| ret = [] |
| for ver in verlist: |
| verparts = ver.split("-") |
| if len(verparts) == 2: |
| verrev = int(verparts[1][1:]) |
| else: |
| verrev = 0 |
| x = 0 |
| while x < len(ret): |
| retparts = ret[x].split("-") |
| verdiff = portage.vercmp(retparts[0], verparts[0]) |
| if verdiff > 0: |
| break |
| elif verdiff == 0: |
| if len(retparts) == 2: |
| retrev = int(retparts[1][1:]) |
| else: |
| retrev = 0 |
| if retrev >= verrev: |
| break |
| x += 1 |
| ret.insert(x, ver) |
| return ret |
| |
| if portage.settings.has_key("PORTAGE_NICENESS"): |
| try: |
| os.nice(int(portage.settings["PORTAGE_NICENESS"])) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception,e: |
| print "!!! Failed to change nice value to '"+str(portage.settings["PORTAGE_NICENESS"])+"'" |
| print "!!!",e |
| |
| #Freeze the portdbapi for enhanced performance: |
| portage.portdb.freeze() |
| |
| # Kill noauto as it will break merges otherwise. |
| while 'noauto' in portage.features: |
| del portage.features[portage.features.index('noauto')] |
| |
| #number of ebuilds merged |
| merged=0 |
| params=["selective", "deep", "self", "recurse", "empty"] |
| actions=[ |
| "clean", "config", "depclean", |
| "info", "metadata", |
| "prune", "regen", "search", |
| "sync", "system", "unmerge", "world", |
| ] |
| options=[ |
| "--ask", "--alphabetical", |
| "--buildpkg", "--buildpkgonly", |
| "--changelog", "--columns", "--cols", |
| "--debug", "--deep", |
| "--digest", |
| "--emptytree", |
| "--fetchonly", "--fetch-all-uri", |
| "--getbinpkg", "--getbinpkgonly", |
| "--help", "--ignore-default-opts", |
| "--noconfmem", |
| "--newuse", "--nocolor", |
| "--nodeps", "--noreplace", |
| "--nospinner", "--oneshot", |
| "--onlydeps", "--pretend", |
| "--quiet", "--resume", |
| "--searchdesc", "--selective", |
| "--skipfirst", "--skip-first", |
| "--tree", |
| "--update", |
| "--usepkg", "--usepkgonly", |
| "--verbose", "--version" |
| ] |
| |
| shortmapping={ |
| "1":"--oneshot", |
| "a":"--ask", |
| "b":"--buildpkg", "B":"--buildpkgonly", |
| "c":"--clean", "C":"--unmerge", |
| "d":"--debug", "D":"--deep", |
| "e":"--emptytree", |
| "f":"--fetchonly", "F":"--fetch-all-uri", |
| "g":"--getbinpkg", "G":"--getbinpkgonly", |
| "h":"--help", |
| "k":"--usepkg", "K":"--usepkgonly", |
| "l":"--changelog", |
| "n":"--noreplace", "N":"--newuse", |
| "o":"--onlydeps", "O":"--nodeps", |
| "p":"--pretend", "P":"--prune", |
| "q":"--quiet", |
| "s":"--search", "S":"--searchdesc", |
| 't':"--tree", |
| "u":"--update", |
| "v":"--verbose", "V":"--version" |
| } |
| |
| myaction=None |
| myopts=[] |
| myfiles=[] |
| edebug=0 |
| |
| # process short actions |
| tmpcmdline=sys.argv[1:] |
| if "--ignore-default-opts" not in tmpcmdline: |
| tmpcmdline.extend(portage.settings["EMERGE_DEFAULT_OPTS"].split()) |
| cmdline=[] |
| for x in tmpcmdline: |
| if x[0:1]=="-" and x[1:2]!="-": |
| for y in x[1:]: |
| if shortmapping.has_key(y): |
| if shortmapping[y] in cmdline: |
| print |
| print "*** Warning: Redundant use of",shortmapping[y] |
| else: |
| cmdline.append(shortmapping[y]) |
| else: |
| print "!!! Error: -"+y+" is an invalid short action or option." |
| sys.exit(1) |
| else: |
| cmdline.append(x) |
| |
| # process the options and command arguments |
| for x in cmdline: |
| if not x: |
| continue |
| if len(x)>=2 and x[0:2]=="--": |
| if x == "--cols": |
| x = "--columns" |
| elif x == "--skip-first": |
| x = "--skipfirst" |
| if x in options: |
| if x not in myopts: |
| myopts.append(x) |
| elif x[2:] in actions: |
| if myaction: |
| if myaction not in ["system", "world"]: |
| myaction="--"+myaction |
| print |
| print red("!!!")+green(" Multiple actions requested... Please choose one only.") |
| print red("!!!")+" '"+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" |
| print |
| sys.exit(1) |
| myaction=x[2:] |
| else: |
| print "!!! Error:",x,"is an invalid option." |
| sys.exit(1) |
| elif (not myaction) and (x in actions): |
| if x not in ["system", "world"]: |
| print red("*** Deprecated use of action '%s', use '--%s' instead" % (x,x)) |
| if myaction: |
| print |
| print red("!!!")+green(" Multiple actions requested... Please choose one only.") |
| print red("!!! '")+darkgreen(myaction)+"' "+red("or")+" '"+darkgreen(x)+"'" |
| print |
| sys.exit(1) |
| myaction=x |
| elif x[-1]=="/": |
| # this little conditional helps tab completion |
| myfiles.append(x[:-1]) |
| else: |
| myfiles.append(x) |
| |
| |
| if "moo" in myfiles: |
| print """ |
| |
| Larry loves Gentoo (""" + os.uname()[0] + """) |
| |
| _______________________ |
| < Have you mooed today? > |
| ----------------------- |
| \ ^__^ |
| \ (oo)\_______ |
| (__)\ )\/\ |
| ||----w | |
| || || |
| |
| """ |
| |
| if (myaction in ["world", "system"]) and myfiles: |
| print "emerge: please specify a package class (\"world\" or \"system\") or individual packages, but not both." |
| sys.exit(1) |
| |
| for x in myfiles: |
| ext = os.path.splitext(x)[1] |
| if (ext == ".ebuild" or ext == ".tbz2") and os.path.exists(os.path.abspath(x)): |
| print "emerging by path implies --oneshot... adding --oneshot to options." |
| print red("\n*** emerging by path is broken and may not always work!!!\n") |
| break |
| |
| if ("--tree" in myopts) and ("--columns" in myopts): |
| print "emerge: can't specify both of \"--tree\" and \"--columns\"." |
| sys.exit(1) |
| |
| if ("--quiet" in myopts): |
| update_spinner = update_quiet_spinner |
| portage_util.noiselimit = -1 |
| portage.settings.unlock() |
| portage.settings["PORTAGE_QUIET"]="1" |
| portage.settings.backup_changes("PORTAGE_QUIET") |
| portage.settings.lock() |
| |
| # Always create packages if FEATURES=buildpkg |
| # Imply --buildpkg if --buildpkgonly |
| if ("buildpkg" in portage.features) or ("--buildpkgonly" in myopts): |
| if "--buildpkg" not in myopts: |
| myopts.append("--buildpkg") |
| |
| # --tree only makes sense with --pretend |
| if "--tree" in myopts and not (("--pretend" in myopts) or ("--ask" in myopts)): |
| print ">>> --tree implies --pretend... adding --pretend to options." |
| myopts.append("--pretend") |
| |
| # Also allow -S to invoke search action (-sS) |
| if ("--searchdesc" in myopts): |
| if myaction and myaction != "search": |
| myfiles.append(myaction) |
| if "--search" not in myopts: |
| myopts.append("--search") |
| myaction = "search" |
| |
| # Always try and fetch binary packages if FEATURES=getbinpkg |
| if ("getbinpkg" in portage.features): |
| myopts.append("--getbinpkg") |
| |
| if "--skipfirst" in myopts and "--resume" not in myopts: |
| myopts.append("--resume") |
| |
| if ("--getbinpkgonly" in myopts) and not ("--usepkgonly" in myopts): |
| myopts.append("--usepkgonly") |
| |
| if ("--getbinpkgonly" in myopts) and not ("--getbinpkg" in myopts): |
| myopts.append("--getbinpkg") |
| |
| if ("--getbinpkg" in myopts) and not ("--usepkg" in myopts): |
| myopts.append("--usepkg") |
| |
| # Also allow -K to apply --usepkg/-k |
| if ("--usepkgonly" in myopts) and not ("--usepkg" in myopts): |
| myopts.append("--usepkg") |
| |
| if ("--newuse" in myopts) and not ("--update" in myopts): |
| print ">>> --newuse implies --update... adding --update to options." |
| myopts.append("--update") |
| |
| # Also allow -l to apply --pretend/-p, but if already in --ask mode |
| if ("--changelog" in myopts) and not (("--pretend" in myopts) or ("--ask" in myopts)): |
| print ">>> --changelog implies --pretend... adding --pretend to options." |
| myopts.append("--pretend") |
| |
| # Allow -p to remove --ask |
| if ("--pretend" in myopts) and ("--ask" in myopts): |
| print ">>> --pretend disables --ask... removing --ask from options." |
| myopts.remove("--ask") |
| |
| # forbid --ask when not in a terminal |
| # note: this breaks `emerge --ask | tee logfile`, but that doesn't work anyway. |
| if ("--ask" in myopts) and (not sys.stdin.isatty()): |
| portage.writemsg("!!! \"--ask\" should only be used in a terminal. Exiting.\n") |
| sys.exit(1) |
| |
| # Set so that configs will be merged regardless of remembered status |
| if ("--noconfmem" in myopts): |
| portage.settings.unlock() |
| portage.settings["NOCONFMEM"]="1" |
| portage.settings.backup_changes("NOCONFMEM") |
| portage.settings.lock() |
| |
| # Set various debug markers... They should be merged somehow. |
| if ("--debug" in myopts): |
| portage.settings.unlock() |
| portage.settings["PORTAGE_DEBUG"]="1" |
| portage.settings.backup_changes("PORTAGE_DEBUG") |
| portage.debug=1 |
| portage.settings.lock() |
| if "python-trace" in portage.features: |
| import portage_debug |
| portage_debug.set_trace(True) |
| |
| if ("--resume" in myopts): |
| if "--tree" in myopts: |
| print "* --tree is currently broken with --resume. Disabling..." |
| myopts.remove("--tree") |
| |
| # Set color output |
| if "--nocolor" in myopts or \ |
| portage.settings["NOCOLOR"] in ("yes","true"): |
| nocolor() |
| if "NOCOLOR" not in portage.settings: |
| portage.settings.unlock() |
| portage.settings["NOCOLOR"] = "true" |
| portage.settings.backup_changes("NOCOLOR") |
| portage.settings.lock() |
| |
| if not ("--quiet" in myopts): |
| if not sys.stdout.isatty() or ("--nospinner" in myopts): |
| update_spinner = update_basic_spinner |
| |
| CLEAN_DELAY = 5 |
| EMERGE_WARNING_DELAY = 10 |
| if portage.settings["CLEAN_DELAY"]: |
| CLEAN_DELAY = string.atoi("0"+portage.settings["CLEAN_DELAY"]) |
| if portage.settings["EMERGE_WARNING_DELAY"]: |
| EMERGE_WARNING_DELAY = string.atoi("0"+portage.settings["EMERGE_WARNING_DELAY"]) |
| |
| def emergelog(mystr,short_msg=None): |
| if "notitles" not in portage.features: |
| if short_msg: |
| xtermTitle(short_msg) |
| else: |
| xtermTitle(mystr) |
| try: |
| #seems odd opening a file each write... |
| if not os.path.exists("/var/log/emerge.log"): |
| mylogfile=open("/var/log/emerge.log", "w") |
| os.chmod("/var/log/emerge.log", S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP) |
| os.chown("/var/log/emerge.log", portage.portage_uid, portage.portage_gid) |
| else: |
| mylogfile=open("/var/log/emerge.log", "a") |
| |
| l=portage_locks.lockfile(mylogfile) |
| # seek because we may have gotten held up by the lock. |
| # if so, we may not be positioned at the end of the file. |
| mylogfile.seek(0,2) |
| mylogfile.write(str(time.time())[:10]+": "+mystr+"\n") |
| mylogfile.flush() |
| portage_locks.unlockfile(l) |
| mylogfile.close() |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| if edebug: |
| print "emergelog():",e |
| pass |
| |
| def emergeexit(): |
| """This gets out final log message in before we quit.""" |
| if "--pretend" not in myopts: |
| emergelog(" *** terminating.") |
| if "notitles" not in portage.features: |
| xtermTitleReset() |
| portage.atexit_register(emergeexit) |
| |
| def emergeexitsig(signum, frame): |
| signal.signal(signal.SIGINT, signal.SIG_IGN) |
| portage.portageexit() |
| portage_util.writemsg("\n\nExiting on signal %(signal)s\n" % {"signal":signum}) |
| sys.exit(100+signum) |
| signal.signal(signal.SIGINT, emergeexitsig) |
| |
| def countdown(secs=5, doing="Starting"): |
| if secs: |
| print ">>> Waiting",secs,"seconds before starting..." |
| print ">>> (Control-C to abort)...\n"+doing+" in: ", |
| ticks=range(secs) |
| ticks.reverse() |
| for sec in ticks: |
| sys.stdout.write(red(str(sec+1)+" ")) |
| sys.stdout.flush() |
| time.sleep(1) |
| print |
| |
| # formats a size given in bytes nicely |
| def format_size(mysize): |
| if type(mysize) not in [types.IntType,types.LongType]: |
| return str(mysize) |
| mystr=str(mysize/1024) |
| mycount=len(mystr) |
| while (mycount > 3): |
| mycount-=3 |
| mystr=mystr[:mycount]+","+mystr[mycount:] |
| return mystr+" kB" |
| |
| |
| def getgccversion(): |
| """ |
| rtype: C{str} |
| return: the current in-use gcc version |
| """ |
| |
| gcc_env_dir = os.path.join('/', 'etc', 'env.d', 'gcc') |
| gcc_config_config = os.path.join(gcc_env_dir, 'config') |
| gcc_ver_command = 'gcc -dumpversion' |
| gcc_ver_prefix = 'gcc-' |
| |
| gcc_not_found_error = red( |
| "!!! No gcc found. You probably need to 'source /etc/profile'\n" + |
| "!!! to update the environment of this terminal and possibly\n" + |
| "!!! other terminals also." |
| ) |
| |
| gcc_distcc_broken_error = green( |
| '!!! Relying on the shell to locate gcc, this may break\n' + |
| '!!! DISTCC, installing gcc-config and setting your current gcc\n' + |
| '!!! profile will fix this' |
| ) |
| |
| def fallback(): |
| |
| print >>sys.stderr, gcc_distcc_broken_error |
| |
| gccout = commands.getstatusoutput(gcc_ver_command) |
| |
| if gccout[0] != 0: |
| print >>sys.stderr, gcc_not_found_error |
| gccver = "[unavailable]" |
| else: |
| gccver = gcc_ver_prefix + gccout[1] |
| |
| return gccver |
| |
| if os.path.isfile(gcc_config_config): |
| try: |
| gccver_str = open(gcc_config_config).read().strip() |
| gccver = gcc_ver_prefix + string.join(gccver_str.split('-')[4:], '-') |
| except IndexError: |
| gccver = fallback() |
| |
| else: |
| import glob |
| dir_l = glob.glob(os.path.join(gcc_env_dir, '*-*')) |
| |
| if len(dir_l) == 1: |
| try: |
| gccver = gcc_ver_prefix + dir_l[0].split('-')[-1] |
| except IndexError: |
| gccver = fallback() |
| |
| else: |
| # There was no "config" file in /etc/env.d/gcc and there was more |
| # than one profile in /etc/env.d/gcc so we can't actively |
| # determine what version of gcc we are using so we fall back on the |
| # old way that breaks distcc |
| |
| gccver = fallback() |
| |
| return gccver |
| |
| def getportageversion(): |
| try: |
| import re |
| profilever = os.path.normpath("///"+os.readlink("/etc/make.profile")) |
| basepath = os.path.normpath("///"+portage.settings["PORTDIR"]+"/profiles") |
| if re.match(basepath,profilever): |
| profilever = profilever[len(basepath)+1:] |
| else: |
| profilever = "!"+profilever |
| del basepath |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| profilever="unavailable" |
| libcver=[] |
| libclist = portage.vardbapi(portage.root).match("virtual/libc") |
| libclist += portage.vardbapi(portage.root).match("virtual/glibc") |
| libclist = portage_util.unique_array(libclist) |
| for x in libclist: |
| xs=portage.catpkgsplit(x) |
| if libcver: |
| libcver+=","+string.join(xs[1:], "-") |
| else: |
| libcver=string.join(xs[1:], "-") |
| if libcver==[]: |
| libcver="unavailable" |
| |
| gccver = getgccversion() |
| unameout=os.uname()[2]+" "+os.uname()[4] |
| |
| return "Portage " + portage.VERSION +" ("+profilever+", "+gccver+", "+libcver+", "+unameout+")" |
| |
| def help(): |
| # Move all the help stuff out of this file. |
| emergehelp.help(myaction,myopts,havecolor) |
| |
| if "--version" in myopts: |
| print getportageversion() |
| sys.exit(0) |
| elif "--help" in myopts: |
| help() |
| sys.exit(0) |
| |
| if portage.wheelgid == portage.portage_gid: |
| print "emerge: wheel group use is being deprecated. Please update group and passwd to" |
| print " include the portage user as noted above, and then use group portage." |
| |
| # check if root user is the current user for the actions where emerge needs this |
| if portage.secpass < 2: |
| # We've already allowed "--version" and "--help" above. |
| if "--pretend" not in myopts and \ |
| myaction not in ("search","info"): |
| if "--debug" in myopts: |
| print "myaction",myaction |
| print "myopts",myopts |
| print "emerge: root access required." |
| sys.exit(1) |
| |
| if not "--pretend" in myopts: |
| emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime())) |
| myelogstr="" |
| if myopts: |
| myelogstr=string.join(myopts, " ") |
| if myaction: |
| myelogstr+=" "+myaction |
| if myfiles: |
| myelogstr+=" "+string.join(myfiles, " ") |
| emergelog(" *** emerge "+myelogstr) |
| |
| #configure emerge engine parameters |
| # |
| # self: include _this_ package regardless of if it is merged. |
| # selective: exclude the package if it is merged |
| # recurse: go into the dependencies |
| # empty: pretend nothing is merged |
| myparams=["self","recurse"] |
| add=[] |
| sub=[] |
| if "--update" in myopts or myaction in ("system", "world"): |
| add.extend(["selective","empty"]) |
| if "--emptytree" in myopts: |
| add.extend(["empty"]) |
| sub.extend(["selective"]) |
| if "--nodeps" in myopts: |
| sub.extend(["recurse"]) |
| if "--noreplace" in myopts: |
| add.extend(["selective"]) |
| if "--deep" in myopts: |
| add.extend(["deep"]) |
| if "--selective" in myopts: |
| add.extend(["selective"]) |
| if myaction in ["world","system"]: |
| add.extend(["selective"]) |
| elif myaction in ["depclean"]: |
| add.extend(["empty"]) |
| sub.extend(["selective"]) |
| for x in add: |
| if (x not in myparams) and (x not in sub): |
| myparams.append(x) |
| for x in sub: |
| if x in myparams: |
| myparams.remove(x) |
| |
| # search functionality |
| class search: |
| |
| # |
| # class constants |
| # |
| VERSION_SHORT=1 |
| VERSION_RELEASE=2 |
| |
| # |
| # public interface |
| # |
| def __init__(self): |
| """Searches the available and installed packages for the supplied search key. |
| The list of available and installed packages is created at object instantiation. |
| This makes successive searches faster.""" |
| self.installcache = portage.db["/"]["vartree"] |
| |
| def execute(self,searchkey): |
| """Performs the search for the supplied search key""" |
| global myopts |
| match_category = 0 |
| self.searchkey=searchkey |
| self.packagematches = [] |
| if "--searchdesc" in myopts: |
| self.searchdesc=1 |
| self.matches = {"pkg":[], "desc":[]} |
| else: |
| self.searchdesc=0 |
| self.matches = {"pkg":[]} |
| print "Searching... ", |
| |
| if self.searchkey[0] == '@': |
| match_category = 1 |
| self.searchkey = self.searchkey[1:] |
| if self.searchkey=="*": |
| #hack for people who aren't regular expression gurus |
| self.searchkey==".*" |
| if re.search("\+\+", self.searchkey): |
| #hack for people who aren't regular expression gurus |
| self.searchkey=re.sub("\+\+","\+\+",self.searchkey) |
| self.searchre=re.compile(self.searchkey.lower(),re.I) |
| for package in portage.portdb.cp_all(): |
| update_spinner() |
| |
| if match_category: |
| match_string = package[:] |
| else: |
| match_string = package.split("/")[-1] |
| |
| masked=0 |
| if self.searchre.search(match_string): |
| if not portage.portdb.xmatch("match-visible",package): |
| masked=1 |
| self.matches["pkg"].append([package,masked]) |
| elif self.searchdesc: # DESCRIPTION searching |
| full_package = portage.portdb.xmatch("bestmatch-visible",package) |
| if not full_package: |
| #no match found; we don't want to query description |
| full_package=portage.best(portage.portdb.xmatch("match-all",package)) |
| if not full_package: |
| continue |
| else: |
| masked=1 |
| try: |
| full_desc = portage.portdb.aux_get(full_package,["DESCRIPTION"])[0] |
| except KeyError: |
| print "emerge: search: aux_get() failed, skipping" |
| continue |
| if self.searchre.search(full_desc): |
| self.matches["desc"].append([full_package,masked]) |
| self.mlen=0 |
| for mtype in self.matches.keys(): |
| self.matches[mtype].sort() |
| self.mlen += len(self.matches[mtype]) |
| |
| def output(self): |
| """Outputs the results of the search.""" |
| print "\b\b \n[ Results for search key : "+white(self.searchkey)+" ]" |
| print "[ Applications found : "+white(str(self.mlen))+" ]" |
| print " " |
| for mtype in self.matches.keys(): |
| for match,masked in self.matches[mtype]: |
| if mtype=="pkg": |
| catpack=match |
| full_package = portage.portdb.xmatch("bestmatch-visible",match) |
| if not full_package: |
| #no match found; we don't want to query description |
| masked=1 |
| full_package=portage.best(portage.portdb.xmatch("match-all",match)) |
| else: |
| full_package = match |
| match = portage.pkgsplit(match)[0] |
| |
| if full_package: |
| try: |
| desc, homepage, license = portage.portdb.aux_get(full_package,["DESCRIPTION","HOMEPAGE","LICENSE"]) |
| except KeyError: |
| print "emerge: search: aux_get() failed, skipping" |
| continue |
| if masked: |
| print green("*")+" "+white(match)+" "+red("[ Masked ]") |
| else: |
| print green("*")+" "+white(match) |
| myversion = self.getVersion(full_package, search.VERSION_RELEASE) |
| |
| mysum = [0,0] |
| mycat = match.split("/")[0] |
| mypkg = match.split("/")[1] |
| |
| mydigest = portage.db["/"]["porttree"].dbapi.finddigest(mycat+"/"+mypkg + "-" + myversion) |
| |
| try: |
| myfile = open(mydigest,"r") |
| for line in myfile.readlines(): |
| mysum[0] += int(line.split(" ")[3]) |
| myfile.close() |
| mystr = str(mysum[0]/1024) |
| mycount=len(mystr) |
| while (mycount > 3): |
| mycount-=3 |
| mystr=mystr[:mycount]+","+mystr[mycount:] |
| mysum[0]=mystr+" kB" |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| if edebug: |
| print "!!! Exception:",e |
| mysum[0]=" [no/bad digest]" |
| |
| if "--quiet" not in myopts: |
| print " ", darkgreen("Latest version available:"),myversion |
| print " ", self.getInstallationStatus(mycat+'/'+mypkg) |
| print " ", darkgreen("Size of files:"),mysum[0] |
| print " ", darkgreen("Homepage:")+" ",homepage |
| print " ", darkgreen("Description:")+" ",desc |
| print " ", darkgreen("License:")+" ",license |
| print |
| print |
| # |
| # private interface |
| # |
| def getInstallationStatus(self,package): |
| installed_package = self.installcache.dep_bestmatch(package) |
| result = "" |
| version = self.getVersion(installed_package,search.VERSION_RELEASE) |
| if len(version) > 0: |
| result = darkgreen("Latest version installed:")+" "+version |
| else: |
| result = darkgreen("Latest version installed:")+" [ Not Installed ]" |
| return result |
| |
| def getVersion(self,full_package,detail): |
| if len(full_package) > 1: |
| package_parts = portage.catpkgsplit(full_package) |
| if detail == search.VERSION_RELEASE and package_parts[3] != 'r0': |
| result = package_parts[2]+ "-" + package_parts[3] |
| else: |
| result = package_parts[2] |
| else: |
| result = "" |
| return result |
| |
| |
| #build our package digraph |
| def getlist(mode): |
| if mode=="system": |
| mylines=portage.settings.packages |
| elif mode=="world": |
| try: |
| myfile = open(os.path.join(portage.root, portage.WORLD_FILE), "r") |
| mylines=myfile.readlines() |
| myfile.close() |
| except OSError: |
| print "!!! Couldn't open "+pfile+"; exiting." |
| sys.exit(1) |
| except IOError: |
| #world file doesn't exist |
| mylines=[] |
| mynewlines=[] |
| for x in mylines: |
| myline=string.join(string.split(x)) |
| if not len(myline): |
| continue |
| elif myline[0]=="#": |
| continue |
| elif mode=="system": |
| if myline[0]!="*": |
| continue |
| myline=myline[1:] |
| mynewlines.append(myline.strip()) |
| |
| # Remove everything that is package.provided from our list |
| for atom in mynewlines[:]: |
| for expanded_atom in portage.flatten(portage.dep_virtual([atom], portage.settings)): |
| mykey = portage.dep_getkey(expanded_atom) |
| if portage.settings.pprovideddict.has_key(mykey) and \ |
| portage.match_from_list(expanded_atom, portage.settings.pprovideddict[mykey]): |
| mynewlines.remove(atom) |
| break |
| |
| return mynewlines |
| |
| def genericdict(mylist): |
| mynewdict={} |
| for x in mylist: |
| mynewdict[portage.dep_getkey(x)]=x |
| return mynewdict |
| |
| olddbapi=None |
| class depgraph: |
| |
| def __init__(self,myaction,myopts): |
| global olddbapi |
| self.pkgsettings = portage.config(clone=portage.settings) |
| if not self.pkgsettings["ARCH"]: |
| portage.writemsg(red("\a!!! ARCH is not set... Are you missing the /etc/make.profile symlink?\n")) |
| portage.writemsg(red("\a!!! Is the symlink correct? Is your portage tree complete?\n\n")) |
| sys.exit(9) |
| self.applied_useflags = {} |
| |
| self.missingbins=[] |
| self.myaction=myaction |
| self.digraph=portage.digraph() |
| self.orderedkeys=[] |
| self.outdatedpackages=[] |
| self.mydbapi={} |
| self.mydbapi["/"] = portage.fakedbapi() |
| if "empty" not in myparams or portage.root != "/": |
| for pkg in portage.db["/"]["vartree"].getallcpv(): |
| self.mydbapi["/"].cpv_inject(pkg) |
| if portage.root != "/": |
| self.mydbapi[portage.root] = portage.fakedbapi() |
| if "empty" not in myparams: |
| for pkg in portage.db[portage.root]["vartree"].getallcpv(): |
| self.mydbapi[portage.root].cpv_inject(pkg) |
| |
| if "--usepkg" in myopts: |
| portage.db["/"]["bintree"].populate(("--getbinpkg" in myopts), ("--getbinpkgonly" in myopts)) |
| |
| def create(self,mybigkey,myparent=None,addme=1,myuse=None): |
| """creates the actual digraph of packages to merge. return 1 on success, 0 on failure |
| mybigkey = specification of package to merge; myparent = parent package (one depending on me); |
| addme = should I be added to the tree? (for the --onlydeps mode)""" |
| #stuff to add: |
| #SLOT-aware emerge |
| #IUSE-aware emerge |
| #"no downgrade" emerge |
| #print "mybigkey:",mybigkey |
| |
| jbigkey=string.join(mybigkey) |
| if self.digraph.hasnode(jbigkey+" merge") or self.digraph.hasnode(jbigkey+" nomerge"): |
| #this conditional is needed to prevent infinite recursion on already-processed deps |
| return 1 |
| |
| update_spinner() |
| |
| mytype,myroot,mykey=mybigkey |
| # select the correct /var database that we'll be checking against |
| vardbapi=portage.db[myroot]["vartree"].dbapi |
| |
| # if the package is already on the system, we add a "nomerge" |
| # directive, otherwise we add a "merge" directive. |
| if mytype=="blocks": |
| # we've encountered a "blocks" node. We will totally ignore this |
| # node and not add it to our digraph if it doesn't apply to us. |
| if addme and "--buildpkgonly" not in myopts and myparent and (self.mydbapi[myroot].match(mykey) or vardbapi.match(mykey)): |
| mybigkey.append(myparent.split()[2]) |
| self.digraph.addnode(string.join(mybigkey),myparent) |
| return 1 |
| |
| if myuse == None: |
| self.pkgsettings.setcpv(mykey) |
| myuse = self.pkgsettings["USE"].split() |
| self.applied_useflags[mykey] = myuse |
| |
| merging=1 |
| if addme: |
| # this is where we add the node to the list of packages to merge |
| if not myparent: |
| # command-line specified or part of a world list... |
| if ("self" not in myparams) or (("selective" in myparams) and vardbapi.cpv_exists(mykey)): |
| # the package is on the system, so don't merge it. |
| merging=0 |
| elif ("selective" in myparams) and vardbapi.cpv_exists(mykey): |
| merging=0 |
| |
| if (merging==0 and "--newuse" in myopts and vardbapi.cpv_exists(mykey)): |
| old_use = vardbapi.aux_get(mykey, ["USE"])[0].split() |
| if mytype == "binary": |
| iuses = portage.db["/"]["bintree"].dbapi.aux_get(mykey, ["IUSE"])[0].split() |
| else: |
| iuses = portage.db["/"]["porttree"].dbapi.aux_get(mykey, ["IUSE"])[0].split() |
| for x in iuses: |
| if (old_use.count(x) and not myuse.count(x)) or (not old_use.count(x) and myuse.count(x)): |
| merging=1 |
| break |
| else: |
| #onlydeps mode; don't merge |
| merging=2 |
| if merging==1: |
| mybigkey.append("merge") |
| else: |
| mybigkey.append("nomerge") |
| |
| # whatever the case, we need to add the node to our digraph so |
| # that children can depend upon it. |
| self.digraph.addnode(string.join(mybigkey),myparent) |
| if ("deep" not in myparams) and (not merging): |
| return 1 |
| elif "recurse" not in myparams: |
| return 1 |
| |
| edepend={} |
| if mytype=="binary": |
| mypkgparts=portage.catpkgsplit(mykey) |
| tbz2name = string.split(mykey, "/")[1]+".tbz2" |
| if tbz2name in portage.db[portage.root]["bintree"].invalids: |
| sys.stderr.write("\nINVALID PACKAGE (is required to continue): "+str(mykey)+"\n") |
| sys.exit(1) |
| if portage.db[portage.root]["bintree"].isremote(mykey): |
| edepend = portage.db[portage.root]["bintree"].remotepkgs[tbz2name] |
| edepend["DEPEND"] ="" |
| edepend["RDEPEND"]=string.join(string.split(edepend["RDEPEND"])," ") |
| edepend["PDEPEND"]=string.join(string.split(edepend["PDEPEND"])," ") |
| edepend["SLOT"] =string.strip(edepend["SLOT"]) |
| #portage.db[portage.root]["bintree"].gettbz2(mykey) |
| else: # It's local. |
| mytbz2=xpak.tbz2(portage.db[portage.root]["bintree"].getname(mykey)) |
| edepend["DEPEND"] ="" |
| edepend["RDEPEND"]=string.join(mytbz2.getelements("RDEPEND")," ") |
| edepend["PDEPEND"]=string.join(mytbz2.getelements("PDEPEND")," ") |
| edepend["SLOT"] =mytbz2.getfile("SLOT",mypkgparts[2]) |
| elif mytype=="ebuild": |
| try: |
| mymeta = ["DEPEND","RDEPEND","PDEPEND"] |
| myfoo = portage.portdb.aux_get(mykey, mymeta) |
| for index in range(0,len(mymeta)): |
| edepend[mymeta[index]] = myfoo[index] |
| if "--buildpkgonly" in myopts: |
| edepend["RDEPEND"] = "" |
| edepend["PDEPEND"] = "" |
| except (KeyError,IOError): |
| print "emerge: create(): aux_get() error on",mykey+"; aborting..." |
| sys.exit(1) |
| mydep={} |
| mp=string.join(mybigkey) |
| |
| if myroot=="/": |
| mydep["/"]=edepend["DEPEND"]+" "+edepend["RDEPEND"] |
| if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): |
| return 0 |
| else: |
| mydep["/"]=edepend["DEPEND"] |
| mydep[myroot]=edepend["RDEPEND"] |
| if not self.select_dep("/",mydep["/"],myparent=mp,myuse=myuse): |
| return 0 |
| if not self.select_dep(myroot,mydep[myroot],myparent=mp,myuse=myuse): |
| return 0 |
| |
| if edepend.has_key("PDEPEND") and edepend["PDEPEND"]: |
| # Post Depend -- Add to the list without a parent, as it depends |
| # on a package being present AND must be built after that package. |
| if not self.select_dep(myroot,edepend["PDEPEND"],myuse=myuse): |
| return 0 |
| |
| return 1 |
| |
| def select_files(self,myfiles): |
| "given a list of .tbz2s, .ebuilds and deps, create the appropriate depgraph and return a favorite list" |
| myfavorites=[] |
| for x in myfiles: |
| ext = os.path.splitext(x)[1] |
| if ext==".tbz2": |
| if not os.path.exists(x): |
| if os.path.exists(self.pkgsettings["PKGDIR"]+"/All/"+x): |
| x=self.pkgsettings["PKGDIR"]+"/All/"+x |
| elif os.path.exists(self.pkgsettings["PKGDIR"]+"/"+x): |
| x=self.pkgsettings["PKGDIR"]+"/"+x |
| else: |
| print "\n\n!!! Binary package '"+str(x)+"' does not exist." |
| print "!!! Please ensure the tbz2 exists as specified.\n" |
| sys.exit(1) |
| mytbz2=xpak.tbz2(x) |
| mykey=mytbz2.getelements("CATEGORY")[0]+"/"+os.path.splitext(os.path.basename(x))[0] |
| if os.path.realpath(portage.db["/"]["bintree"].getname(mykey)) != os.path.realpath(x): |
| print red("\n*** You need to adjust PKGDIR to emerge this package.\n") |
| sys.exit(1) |
| if not self.create(["binary",portage.root,mykey],None,"--onlydeps" not in myopts): |
| return (0,myfavorites) |
| elif not "--oneshot" in myopts: |
| myfavorites.append(mykey) |
| elif ext==".ebuild": |
| x = os.path.realpath(x) |
| mykey=os.path.basename(os.path.normpath(x+"/../.."))+"/"+os.path.splitext(os.path.basename(x))[0] |
| ebuild_path = portage.db["/"]["porttree"].dbapi.findname(mykey) |
| if ebuild_path: |
| if os.path.realpath(ebuild_path) != x: |
| print red("\n*** You need to adjust PORTDIR or PORTDIR_OVERLAY to emerge this package.\n") |
| sys.exit(1) |
| if mykey not in portage.db["/"]["porttree"].dbapi.xmatch("match-visible", portage.dep_getkey(mykey)): |
| print red("\n*** You are emerging a masked package. It is MUCH better to use") |
| print red("*** /etc/portage/package.* to accomplish this. See portage(5) man") |
| print red("*** page for details.") |
| countdown(EMERGE_WARNING_DELAY, "Continuing...") |
| else: |
| print red("\n*** %s is not in a valid PORTDIR heirarchy or does not exist" % x) |
| sys.exit(1) |
| if not self.create(["ebuild",portage.root,mykey],None,"--onlydeps" not in myopts): |
| return (0,myfavorites) |
| elif not "--oneshot" in myopts: |
| myfavorites.append(mykey) |
| else: |
| if not is_valid_package_atom(x): |
| portage.writemsg("\n\n!!! '%s' is not a valid package atom.\n" % x) |
| portage.writemsg("!!! Please check ebuild(5) for full details.\n") |
| portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") |
| return (0,[]) |
| try: |
| mykey=portage.dep_expand(x,mydb=portage.portdb) |
| except ValueError, errpkgs: |
| print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" |
| print "!!! one of the following fully-qualified ebuild names instead:\n" |
| for i in errpkgs[0]: |
| print " " + green(i) |
| print |
| sys.exit(1) |
| |
| # select needs to return 0 on dep_check failure |
| |
| sys.stdout.flush() |
| sys.stderr.flush() |
| |
| try: |
| self.mysd = self.select_dep(portage.root,mykey,arg=x) |
| except portage_exception.MissingSignature, e: |
| portage.writemsg("\n\n!!! A missing gpg signature is preventing portage from calculating the\n") |
| portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") |
| portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") |
| portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n") |
| portage.writemsg("!!! Affected file: %s\n" % (e)) |
| sys.exit(1) |
| except portage_exception.InvalidSignature, e: |
| portage.writemsg("\n\n!!! An invalid gpg signature is preventing portage from calculating the\n") |
| portage.writemsg("!!! required dependencies. This is a security feature enabled by the admin\n") |
| portage.writemsg("!!! to aid in the detection of malicious intent.\n\n") |
| portage.writemsg("!!! THIS IS A POSSIBLE INDICATION OF TAMPERED FILES -- CHECK CAREFULLY.\n") |
| portage.writemsg("!!! Affected file: %s\n" % (e)) |
| sys.exit(1) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| if "--debug" in myopts: |
| raise |
| print "\n\n!!! Problem in",mykey,"dependencies." |
| print "!!!",str(e),e.__module__ |
| sys.exit(1) |
| |
| if not self.mysd: |
| return (0,myfavorites) |
| elif not "--oneshot" in myopts: |
| myfavorites.append(portage.dep_getkey(mykey)) |
| |
| missing=0 |
| if "--usepkgonly" in myopts: |
| for x in self.digraph.dict.keys(): |
| xs=string.split(x," ") |
| if (xs[0] != "binary") and (xs[3]=="merge"): |
| if missing == 0: |
| print |
| missing += 1 |
| print "Missing binary for:",xs[2] |
| |
| # We're true here unless we are missing binaries. |
| return (not missing,myfavorites) |
| |
| def is_newer_ver_installed(self,myroot,pkg,pkgver): |
| "if there is a version of pkg installed newer than pkgver, return it" |
| vardbapi=portage.db[myroot]["vartree"].dbapi |
| |
| matches=portage.db[myroot]["vartree"].dbapi.match(pkg) |
| if matches: |
| myslot=portage.db["/"]["porttree"].getslot(pkgver) |
| for match in matches: |
| if portage.pkgcmp(portage.catpkgsplit(pkgver)[1:], portage.catpkgsplit(match)[1:]) < 0: |
| curslot=portage.db[myroot]["vartree"].getslot(match) |
| if curslot == myslot: |
| return match |
| |
| def select_dep(self,myroot,depstring,myparent=None,arg=None,myuse=None,raise_on_missing=False): |
| "given a dependency string, create the appropriate depgraph and return 1 on success and 0 on failure" |
| if "--debug" in myopts: |
| print |
| print "Parent: ",myparent |
| print "Depstring:",depstring |
| if not arg: |
| #processing dependencies |
| mycheck=portage.dep_check(depstring,self.mydbapi[myroot],self.pkgsettings,myuse=myuse,use_binaries=("--usepkgonly" in myopts),myroot=myroot) |
| |
| if not mycheck[0]: |
| mymerge=[] |
| else: |
| mymerge=mycheck[1] |
| |
| else: |
| #we're processing a command-line argument; unconditionally merge it even if it's already merged |
| mymerge=[depstring] |
| |
| # dep_check has been run so we can now add our parent to our |
| # build state to update virtuals and other settings. This |
| # happens after the package is added to the tree so that a |
| # package can depend on a virtual which it satisfies. |
| if myparent: |
| myp = myparent.split() |
| if myp[3]=="merge": |
| self.mydbapi[myroot].cpv_inject(myp[2]) |
| if myp[0]=="binary": |
| self.pkgsettings.setinst(myp[2],portage.db["/"]["bintree"].dbapi) |
| else: |
| self.pkgsettings.setinst(myp[2],portage.db[myroot]["porttree"].dbapi) |
| |
| if not mymerge: |
| return 1 |
| |
| if "--debug" in myopts: |
| print "Candidates:",mymerge |
| for x in mymerge: |
| myk=None |
| binpkguseflags=None |
| if x[0]=="!": |
| # if this package is myself, don't append it to block list. |
| if "--debug" in myopts: |
| print "Myparent",myparent |
| if (myparent): |
| if myparent.split()[2] in portage.portdb.xmatch("match-all", x[1:]): |
| # myself, so exit. |
| continue |
| # adding block |
| myk=["blocks",myroot,x[1:]] |
| else: |
| #We are not processing a blocker but a normal dependency |
| myeb=None |
| myeb_matches = portage.portdb.xmatch("match-visible",x) |
| if ("--usepkgonly" not in myopts): |
| myeb=portage.best(myeb_matches) |
| |
| myeb_pkg=None |
| if ("--usepkg" in myopts): |
| # The next line assumes the binarytree has been populated. |
| # XXX: Need to work out how we use the binary tree with roots. |
| myeb_pkg_matches=portage.db["/"]["bintree"].dbapi.match(x) |
| if ("--usepkgonly" not in myopts): |
| # Remove any binary package entries that are masked in the portage tree (#55871) |
| for idx in range(len(myeb_pkg_matches)-1,-1,-1): |
| if myeb_pkg_matches[idx] not in myeb_matches: |
| del myeb_pkg_matches[idx] |
| myeb_pkg = portage.best(myeb_pkg_matches) |
| |
| if not myeb_pkg: |
| myeb_pkg = None |
| elif ("--newuse" in myopts): |
| iuses=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["IUSE"])[0]) |
| old_use=string.split(portage.db["/"]["bintree"].dbapi.aux_get(myeb_pkg, ["USE"])[0]) |
| self.pkgsettings.setcpv(myeb_pkg) |
| now_use=string.split(self.pkgsettings["USE"]) |
| for x in iuses: |
| if (old_use.count(x) and not now_use.count(x)) or (not old_use.count(x) and now_use.count(x)): |
| myeb_pkg = None |
| break |
| |
| if (not myeb) and (not myeb_pkg): |
| if raise_on_missing: |
| raise ValueError |
| if not arg: |
| xinfo='"'+x+'"' |
| else: |
| xinfo='"'+arg+'"' |
| if myparent: |
| xfrom = '(dependency required by '+green('"'+myparent.split()[2]+'"')+red(' ['+myparent.split()[0]+"]")+')' |
| alleb=portage.portdb.xmatch("match-all",x) |
| if alleb: |
| if "--usepkgonly" not in myopts: |
| print "\n!!! "+red("All ebuilds that could satisfy ")+green(xinfo)+red(" have been masked.") |
| print "!!! One of the following masked packages is required to complete your request:" |
| oldcomment = "" |
| for p in alleb: |
| mreasons = portage.getmaskingstatus(p) |
| print "- "+p+" (masked by: "+string.join(mreasons, ", ")+")" |
| comment = portage.getmaskingreason(p) |
| if comment and comment != oldcomment: |
| print comment |
| oldcomment = comment |
| print |
| print "For more information, see MASKED PACKAGES section in the emerge man page or " |
| print "refer to the Gentoo Handbook." |
| else: |
| print "\n!!! "+red("There are no packages available to satisfy: ")+green(xinfo) |
| print "!!! Either add a suitable binary package or compile from an ebuild." |
| else: |
| print "\nemerge: there are no ebuilds to satisfy "+green(xinfo)+"." |
| if myparent: |
| print xfrom |
| print |
| return 0 |
| |
| if "--debug" in myopts: |
| print "ebuild:",myeb |
| print "binpkg:",myeb_pkg |
| |
| if myeb and myeb_pkg: |
| myeb_s = portage.catpkgsplit(myeb) |
| myeb_s = [myeb_s[0]+"/"+myeb_s[1], myeb_s[2], myeb_s[3]] |
| myeb_pkg_s = portage.catpkgsplit(myeb_pkg) |
| myeb_pkg_s = [myeb_pkg_s[0]+"/"+myeb_pkg_s[1], myeb_pkg_s[2], myeb_pkg_s[3]] |
| |
| if portage.pkgcmp(myeb_s, myeb_pkg_s) == 0: # pkg is same version as ebuild |
| myeb = None |
| else: |
| myeb_pkg = None |
| |
| if myeb: |
| myk=["ebuild",myroot,myeb] |
| elif myeb_pkg: |
| binpkguseflags=portage.db[portage.root]["bintree"].get_use(myeb_pkg) |
| myk=["binary",myroot,myeb_pkg] |
| else: |
| sys.stderr.write("!!! Confused... Don't know what's being used for dependency info. :(\n") |
| sys.exit(1) |
| |
| #if "--usepkg" in myopts: |
| # #If we want to use packages, see if we have a pre-built one... |
| # mypk=portage.db["/"]["bintree"].dbapi.match(x) |
| # if myeb in mypk: |
| # #Use it only if it's exactly the version we want. |
| # myk=["binary",myroot,myeb] |
| # else: |
| # myk=["ebuild",myroot,myeb] |
| #else: |
| # myk=["ebuild",myroot,myeb] |
| if myparent: |
| #we are a dependency, so we want to be unconditionally added |
| if not self.create(myk,myparent,myuse=binpkguseflags): |
| return 0 |
| else: |
| #if mysource is not set, then we are a command-line dependency and should not be added |
| #if --onlydeps is specified. |
| if not self.create(myk,myparent,"--onlydeps" not in myopts,myuse=binpkguseflags): |
| return 0 |
| |
| if "--debug" in myopts: |
| print "Exiting...",myparent |
| return 1 |
| |
| |
| def altlist(self): |
| mygraph=self.digraph.copy() |
| dolist=["/"] |
| retlist=[] |
| for x in portage.db.keys(): |
| portage.db[x]["merge"]=[] |
| if x not in dolist: |
| dolist.append(x) |
| while (not mygraph.empty()): |
| mycurkey=mygraph.firstzero() |
| if not mycurkey: |
| print "!!! Error: circular dependencies:" |
| print |
| for x in mygraph.dict.keys(): |
| for y in mygraph.dict[x][1]: |
| print y,"depends on",x |
| print |
| sys.exit(1) |
| splitski=string.split(mycurkey) |
| #I'm not sure of the significance of the following lines (vestigal?) so I'm commenting 'em out. |
| #These lines remove already-merged things from our alt-list |
| #if "--update" in myopts: |
| # if not portage.db["/"]["vartree"].exists_specific(splitski[2]): |
| # portage.db["/"]["merge"].append(splitski) |
| #else: |
| portage.db[splitski[1]]["merge"].append(splitski) |
| mygraph.delnode(mycurkey) |
| for x in dolist: |
| for y in portage.db[x]["merge"]: |
| retlist.append(y) |
| return retlist |
| |
| def xcreate(self,mode="system"): |
| global syslist |
| world_problems = False |
| if mode=="system": |
| mylist=syslist |
| else: |
| #world mode |
| worldlist=getlist("world") |
| sysdict=genericdict(syslist) |
| worlddict=genericdict(worldlist) |
| |
| for x in worlddict.keys(): |
| if not portage.isvalidatom(x): |
| world_problems = True |
| elif not portage.db["/"]["vartree"].dbapi.match(x): |
| world_problems = True |
| else: |
| sysdict[x]=worlddict[x] |
| |
| mylist = sysdict.keys() |
| |
| newlist = [] |
| for atom in mylist: |
| if portage.dep_getkey(atom).split("/")[-1] == "portage": |
| newlist.insert(0, atom) |
| else: |
| newlist.append(atom) |
| mylist = newlist |
| |
| missing_atoms = [] |
| for mydep in mylist: |
| try: |
| if not self.select_dep(portage.root, mydep, raise_on_missing=True): |
| print "\n\n!!! Problem resolving dependencies for", mydep |
| return 0 |
| except ValueError: |
| if "--debug" in myopts: |
| raise |
| missing_atoms.append(mydep) |
| |
| if world_problems: |
| print "\n!!! Problems have been detected with your world file" |
| print "!!! Please run "+green("emaint --check world")+"\n" |
| |
| if missing_atoms and "--verbose" in myopts: |
| print "\n!!! Packages for the following atoms are either all" |
| print "!!! masked or don't exist:" |
| print " ".join(missing_atoms) + "\n" |
| |
| return 1 |
| |
| def match(self,mydep,myroot=portage.root,mykey=None): |
| # support mutual exclusive deps |
| mydep2=mydep |
| if mydep2[0]=="!": |
| mydep2=mydep[1:] |
| |
| if mydep[0]=="!": |
| #add our blocker; it will be ignored later if necessary (if we are remerging the same pkg, for example) |
| myk="blocks "+myroot+" "+mydep2 |
| else: |
| myeb=portage.db[portage.root]["porttree"].dep_bestmatch(mydep2) |
| if not myeb: |
| if not mykey: |
| print "\n!!! Error: couldn't find match for",mydep |
| else: |
| print "\n!!! Error: couldn't find match for",mydep,"in",mykey |
| print |
| sys.exit(1) |
| |
| if "--usepkg" in myopts: |
| mypk=portage.db[portage.root]["bintree"].dep_bestmatch(mydep) |
| if myeb==mypk: |
| myk="binary "+portage.root+" "+mypk |
| else: |
| myk="ebuild "+myroot+" "+myeb |
| else: |
| myk="ebuild "+myroot+" "+myeb |
| |
| return myk |
| |
| def display(self,mylist,verbosity=("--quiet" in myopts and 1 or "--verbose" in myopts and 3 or 2)): |
| changelogs=[] |
| p=[] |
| totalsize=0 |
| |
| if verbosity == 1: |
| def create_use_string(*args): |
| return "" |
| else: |
| def create_use_string(name, cur_iuse, cur_use, old_iuse, old_use, is_new, |
| all_flags=(verbosity == 3), alphabetical=("--alphabetical" in myopts)): |
| enabled = [] |
| if alphabetical: |
| disabled = enabled |
| else: |
| disabled = [] |
| for flag in cur_iuse: |
| if flag in cur_use: |
| if is_new or flag in old_use and all_flags: |
| enabled.append(red(flag)) |
| elif flag not in old_iuse: |
| enabled.append(yellow(flag)+"%") |
| elif flag not in old_use: |
| enabled.append(green(flag)+"*") |
| else: |
| if is_new or flag in old_iuse and flag not in old_use and all_flags: |
| disabled.append(blue("-"+flag)) |
| elif flag not in old_iuse: |
| disabled.append(yellow("-"+flag)+"%") |
| elif flag in old_use: |
| disabled.append(green("-"+flag)+"*") |
| |
| enabled = " ".join(enabled) |
| if alphabetical: |
| disabled = "" |
| else: |
| disabled = " ".join(disabled) |
| if enabled and disabled: |
| ret = enabled + " " + disabled |
| elif enabled: |
| ret = enabled |
| else: |
| ret = disabled |
| if ret: |
| ret = '%s="%s" ' % (name, ret) |
| return ret |
| |
| if verbosity == 3: |
| overlays = string.split(portage.settings['PORTDIR_OVERLAY']) |
| |
| if "--tree" in myopts: |
| mylist.reverse() |
| mygraph=self.digraph.copy() |
| |
| i = 0 |
| while i < len(mylist): |
| if mylist[i][-1]=="nomerge": |
| if not ("--tree" in myopts): |
| # we don't care about this elements |
| mylist.pop(i) |
| continue |
| if (i == (len(mylist) - 1)) \ |
| or (mygraph.depth(string.join(mylist[i])) \ |
| >= mygraph.depth(string.join(mylist[i+1]))): |
| # end of a useless branch (may be the last one) |
| # -> delete the element and test the previous one |
| mylist.pop(i) |
| if i > 0: |
| i -= 1 |
| continue |
| # the branch continues, or we've found a good element. |
| # -> let's see what's next, if anything |
| i += 1 |
| |
| display_overlays=False |
| # files to fetch list - avoids counting a same file twice |
| # in size display (verbose mode) |
| myfetchlist=[] |
| for x in mylist: |
| pkg_type = x[0] |
| pkg_key = x[2] |
| if pkg_key not in self.applied_useflags: |
| if "binary" == pkg_type: |
| self.applied_useflags[pkg_key] = portage.db["/"]["bintree"].dbapi.aux_get(pkg_key, ["USE"])[0].split() |
| elif "ebuild" == pkg_type: |
| self.pkgsettings.setcpv(pkg_key) |
| self.applied_useflags[pkg_key] = self.pkgsettings["USE"].split() |
| |
| fetch=" " |
| |
| if x[0]=="blocks": |
| addl=""+red("B")+" "+fetch+" " |
| resolved=portage.db[x[1]]["vartree"].resolve_key(x[2]) |
| print "["+x[0]+" "+addl+"]",red(resolved), |
| if resolved!=x[2]: |
| if x[3]: |
| print red("(\""+x[2]+"\" is blocking "+x[3]+")") |
| else: |
| print red("(\""+x[2]+"\")") |
| else: |
| if x[3]: |
| print red("(is blocking "+x[3]+")") |
| else: |
| print |
| else: |
| if (x[0]!="binary") and ("fetch" in string.split(portage.portdb.aux_get(x[2],["RESTRICT"])[0])): |
| fetch = red("F") |
| if portage.portdb.fetch_check(x[2], self.applied_useflags[x[2]]): |
| fetch = green("f") |
| |
| #we need to use "--emptrytree" testing here rather than "empty" param testing because "empty" |
| #param is used for -u, where you still *do* want to see when something is being upgraded. |
| myoldbest="" |
| if (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific(x[2]): |
| addl=" "+yellow("R")+fetch+" " |
| elif (not "--emptytree" in myopts) and portage.db[x[1]]["vartree"].exists_specific_cat(x[2]): |
| if x[0] == "binary": |
| mynewslot=portage.db["/"]["bintree"].getslot(x[2]) |
| elif x[0] == "ebuild": |
| mynewslot=portage.db["/"]["porttree"].getslot(x[2]) |
| myoldlist=portage.db[x[1]]["vartree"].dbapi.match(portage.pkgsplit(x[2])[0]) |
| myinslotlist=filter((lambda p: portage.db[portage.root]["vartree"].getslot(p)==mynewslot),myoldlist) |
| if myinslotlist: |
| myoldbest=portage.best(myinslotlist) |
| addl=" "+fetch |
| if portage.pkgcmp(portage.pkgsplit(x[2]), portage.pkgsplit(myoldbest)) < 0: |
| # Downgrade in slot |
| addl+=turquoise("U")+blue("D") |
| else: |
| # Update in slot |
| addl+=turquoise("U")+" " |
| else: |
| # New slot, mark it new. |
| addl=" "+green("NS")+fetch+" " |
| |
| if "--changelog" in myopts: |
| changelogs.extend(self.calc_changelog( |
| portage.portdb.findname(x[2]), |
| portage.db[x[1]]["vartree"].dep_bestmatch('/'.join(portage.catpkgsplit(x[2])[:2])), |
| x[2] |
| )) |
| else: |
| addl=" "+green("N")+" "+fetch+" " |
| |
| verboseadd="" |
| |
| if x[2] in self.applied_useflags: |
| # USE flag display |
| if x[0] == "binary": |
| cur_iuse = string.split(portage.db["/"]["bintree"].dbapi.aux_get(x[2],["IUSE"])[0]) |
| elif x[0] == "ebuild": |
| cur_iuse = string.split(portage.portdb.aux_get(x[2],["IUSE"])[0]) |
| else: |
| cur_iuse = [] |
| |
| cur_iuse = portage.unique_array(cur_iuse) |
| cur_iuse = [flag for flag in cur_iuse if flag not in portage.settings.usemask] |
| cur_iuse.sort() |
| cur_use = self.applied_useflags[x[2]] |
| cur_use = [flag for flag in cur_use if flag in cur_iuse] |
| |
| if myoldbest: |
| pkg = myoldbest |
| else: |
| pkg = x[2] |
| if portage.db[x[1]]["vartree"].dbapi.cpv_exists(pkg): |
| (old_iuse, old_use) = portage.db[x[1]]["vartree"].dbapi.aux_get(pkg, ["IUSE", "USE"]) |
| old_iuse = portage.unique_array(old_iuse.split()) |
| old_iuse.sort() |
| old_use = old_use.split() |
| is_new = False |
| else: |
| old_iuse = [] |
| old_use = [] |
| is_new = True |
| old_iuse = [flag for flag in old_iuse if flag not in portage.settings.usemask] |
| old_use = [flag for flag in old_use if flag in old_iuse] |
| |
| use_expand = portage.settings["USE_EXPAND"].lower().split() |
| use_expand.sort() |
| use_expand.reverse() |
| use_expand_hidden = portage.settings["USE_EXPAND_HIDDEN"].lower().split() |
| |
| def map_to_use_expand(myvals): |
| ret = {} |
| for exp in use_expand: |
| ret[exp] = [] |
| for val in myvals[:]: |
| if val.startswith(exp.lower()+"_"): |
| ret[exp].append(val[len(exp)+1:]) |
| myvals.remove(val) |
| ret["USE"] = myvals |
| for exp in use_expand_hidden: |
| if exp in ret: |
| del ret[exp] |
| return ret |
| |
| cur_iuse_map = map_to_use_expand(cur_iuse) |
| cur_use_map = map_to_use_expand(cur_use) |
| old_iuse_map = map_to_use_expand(old_iuse) |
| old_use_map = map_to_use_expand(old_use) |
| |
| use_expand.sort() |
| use_expand.insert(0, "USE") |
| |
| for key in use_expand: |
| verboseadd += create_use_string(key.upper(), cur_iuse_map[key], cur_use_map[key], |
| old_iuse_map[key], old_use_map[key], is_new) |
| |
| if verbosity == 3: |
| # size verbose |
| mysize=0 |
| if x[0] == "ebuild" and x[-1]!="nomerge": |
| myfilesdict=portage.portdb.getfetchsizes(x[2], useflags=self.applied_useflags[x[2]], debug=edebug) |
| if myfilesdict==None: |
| myfilesdict="[empty/missing/bad digest]" |
| else: |
| for myfetchfile in myfilesdict.keys(): |
| if myfetchfile not in myfetchlist: |
| mysize+=myfilesdict[myfetchfile] |
| myfetchlist.append(myfetchfile) |
| totalsize+=mysize |
| verboseadd+=format_size(mysize)+" " |
| |
| # overlay verbose |
| # XXX: Invalid binaries have caused tracebacks here. 'if file_name' |
| # x = ['binary', '/', 'sys-apps/pcmcia-cs-3.2.7.2.6', 'merge'] |
| file_name=portage.portdb.findname(x[2]) |
| if file_name: # It might not exist in the tree |
| dir_name=os.path.abspath(os.path.dirname(file_name)+"/../..") |
| if (overlays.count(dir_name)>0): |
| verboseadd+=teal("["+str(overlays.index(os.path.normpath(dir_name))+1)+"]")+" " |
| display_overlays=True |
| else: |
| verboseadd += "[No ebuild?]" |
| |
| xs=portage.pkgsplit(x[2]) |
| if xs[2]=="r0": |
| xs[2]="" |
| else: |
| xs[2]="-"+xs[2] |
| |
| if self.pkgsettings.has_key("COLUMNWIDTH"): |
| mywidth=int(self.pkgsettings.settings["COLUMNWIDTH"]) |
| else: |
| mywidth=130 |
| oldlp=mywidth-30 |
| newlp=oldlp-30 |
| |
| indent="" |
| if ("--tree" in myopts): |
| indent=" "*mygraph.depth(string.join(x)) |
| |
| if myoldbest: |
| myoldbest=portage.pkgsplit(myoldbest)[1]+"-"+portage.pkgsplit(myoldbest)[2] |
| if myoldbest[-3:]=="-r0": |
| myoldbest=myoldbest[:-3] |
| myoldbest=blue("["+myoldbest+"]") |
| |
| if x[1]!="/": |
| if "--columns" in myopts: |
| if "--quiet" in myopts: |
| myprint=addl+" "+indent+darkgreen(xs[0]) |
| myprint=myprint+darkblue(xs[1]+xs[2])+" " |
| myprint=myprint+myoldbest |
| myprint=myprint+darkgreen(" to "+x[1]) |
| else: |
| myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) |
| if (newlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(newlp-nc_len(myprint))) |
| myprint=myprint+"["+darkblue(xs[1]+xs[2])+"] " |
| if (oldlp-nc_len(myprint)) > 0: |
| myprint=myprint+" "*(oldlp-nc_len(myprint)) |
| myprint=myprint+myoldbest |
| myprint=myprint+darkgreen(" to "+x[1])+" "+verboseadd |
| else: |
| myprint="["+x[0]+" "+addl+"] "+darkgreen(x[2])+" "+myoldbest+" "+darkgreen("to "+x[1])+" "+verboseadd |
| else: |
| if "--columns" in myopts: |
| if "--quiet" in myopts: |
| myprint=addl+" "+indent+darkgreen(xs[0]) |
| myprint=myprint+" "+green(xs[1]+xs[2]) |
| myprint=myprint+myoldbest |
| else: |
| myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(xs[0]) |
| if (newlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(newlp-nc_len(myprint))) |
| myprint=myprint+green(" ["+xs[1]+xs[2]+"] ") |
| if (oldlp-nc_len(myprint)) > 0: |
| myprint=myprint+(" "*(oldlp-nc_len(myprint))) |
| myprint=myprint+myoldbest+" "+verboseadd |
| else: |
| if x[3]=="nomerge": |
| myprint=darkblue("[nomerge ] "+indent+x[2]+" "+myoldbest+" ")+verboseadd |
| else: |
| myprint="["+x[0]+" "+addl+"] "+indent+darkgreen(x[2])+" "+myoldbest+" "+verboseadd |
| p.append(myprint) |
| |
| if ("--tree" not in myopts): |
| mysplit=portage.pkgsplit(x[2]) |
| |
| # XXX mysplit _can_ be None.... Why? |
| if mysplit and (len(mysplit)==3): |
| if "--emptytree" not in myopts: |
| if mysplit[0]=="sys-apps/portage": |
| if ((mysplit[1]+mysplit[2]) != portage.VERSION) and \ |
| ("livecvsportage" not in portage.settings.features): |
| if mylist.index(x)<len(mylist)-1: |
| p.append(red("*** Portage will stop merging at this point and reload itself,")) |
| p.append(red(" then resume the merge.")) |
| print |
| else: |
| if mysplit[0]=="sys-apps/portage" and ("--emptytree" in myopts): |
| if mysplit[1]+mysplit[2]!=portage.VERSION: |
| p.append(red("***")+" Please update portage to the above version before proceeding.") |
| p.append(" Failure to do so may result in failed or improper merges.") |
| p.append(" A simple '"+green("emerge -u portage")+"' is sufficient.") |
| p.append("") |
| del mysplit |
| |
| for x in p: |
| print x |
| |
| if verbosity == 3: |
| print |
| print "Total size of downloads: "+format_size(totalsize) |
| if overlays and display_overlays: |
| print "Portage overlays:" |
| y=0 |
| for x in overlays: |
| y=y+1 |
| print " "+teal("["+str(y)+"]"),x |
| |
| if "--changelog" in myopts: |
| print |
| for revision,text in changelogs: |
| print bold('*'+revision) |
| sys.stdout.write(text) |
| |
| def calc_changelog(self,ebuildpath,current,next): |
| current = '-'.join(portage.catpkgsplit(current)[1:]) |
| if current.endswith('-r0'): current = current[:-3] |
| next = '-'.join(portage.catpkgsplit(next)[1:]) |
| if next.endswith('-r0'): next = next[:-3] |
| changelogpath = os.path.join(os.path.split(ebuildpath)[0],'ChangeLog') |
| try: |
| changelog = open(changelogpath).read() |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| return [] |
| divisions = self.find_changelog_tags(changelog) |
| #print 'XX from',current,'to',next |
| #for div,text in divisions: print 'XX',div |
| # skip entries for all revisions above the one we are about to emerge |
| for i in range(len(divisions)): |
| if divisions[i][0]==next: |
| divisions = divisions[i:] |
| break |
| # find out how many entries we are going to display |
| for i in range(len(divisions)): |
| if divisions[i][0]==current: |
| divisions = divisions[:i] |
| break |
| else: |
| # couldnt find the current revision in the list. display nothing |
| return [] |
| return divisions |
| |
| def find_changelog_tags(self,changelog): |
| divs = [] |
| release = None |
| while 1: |
| match = re.search(r'^\*\ ?([-a-zA-Z0-9_.]*)(?:\ .*)?\n',changelog,re.M) |
| if match is None: |
| if release is not None: |
| divs.append((release,changelog)) |
| return divs |
| if release is not None: |
| divs.append((release,changelog[:match.start()])) |
| changelog = changelog[match.end():] |
| release = match.group(1) |
| if release.endswith('.ebuild'): |
| release = release[:-7] |
| if release.endswith('-r0'): |
| release = release[:-3] |
| |
| def outdated(self): |
| return self.outdatedpackages |
| |
| def merge(self,mylist): |
| returnme=0 |
| mymergelist=[] |
| |
| #check for blocking dependencies |
| if ("--fetchonly" not in myopts) and ("--buildpkgonly" not in myopts): |
| for x in mylist: |
| if x[0]=="blocks": |
| print "\n!!! Error: the "+x[2]+" package conflicts with another package;" |
| print "!!! the two packages cannot be installed on the same system together." |
| print "!!! Please use 'emerge --pretend' to determine blockers." |
| print |
| if ("--pretend" not in myopts): |
| sys.exit(1) |
| |
| #buildsyspkg: I need mysysdict also on resume (moved from the else block) |
| mysysdict=genericdict(syslist) |
| if ("--resume" in myopts): |
| # We're resuming. |
| print green("*** Resuming merge...") |
| emergelog(" *** Resuming merge...") |
| mymergelist=portage.mtimedb["resume"]["mergelist"][:] |
| if ("--skipfirst" in myopts) and mymergelist: |
| del portage.mtimedb["resume"]["mergelist"][0] |
| del mymergelist[0] |
| for bigkey in mymergelist: |
| (pkgtype, root, cpv, action) = bigkey |
| if pkgtype == "binary" and not portage.db["/"]["bintree"].dbapi.match("="+cpv) or \ |
| pkgtype == "ebuild" and not portage.db["/"]["porttree"].dbapi.xmatch("match-all", "="+cpv): |
| print red("!!! Error: The resume list contains packages that no longer") |
| print red("!!! available to be emerged. Please restart/continue") |
| print red("!!! the merge operation manually.") |
| sys.exit(1) |
| else: |
| myfavs = portage.grabfile(os.path.join(portage.root, portage.WORLD_FILE)) |
| myfavdict=genericdict(myfavs) |
| for x in range(len(mylist)): |
| if mylist[x][3]!="nomerge": |
| # Add to the mergelist |
| mymergelist.append(mylist[x]) |
| else: |
| myfavkey=portage.cpv_getkey(mylist[x][2]) |
| if "--onlydeps" in myopts: |
| continue |
| # Add to the world file. Since we won't be able to later. |
| if (not "--fetchonly" in myopts) and (myfavkey in favorites): |
| #don't record if already in system profile or already recorded |
| if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): |
| #we don't have a favorites entry for this package yet; add one |
| myfavdict[myfavkey]=myfavkey |
| print ">>> Recording",myfavkey,"in \"world\" favorites file..." |
| if not "--fetchonly" in myopts: |
| portage.write_atomic( |
| os.path.join(portage.root, portage.WORLD_FILE), |
| "\n".join(myfavdict.values())) |
| |
| portage.mtimedb["resume"]["mergelist"]=mymergelist[:] |
| |
| # We need to yank the harmful-to-new-builds settings from features. |
| myorigfeat=self.pkgsettings["FEATURES"] |
| myfeat=myorigfeat.split() |
| while ("keeptemp" in myfeat): |
| del myfeat[myfeat.index("keeptemp")] |
| while ("keepwork" in myfeat): |
| del myfeat[myfeat.index("keepwork")] |
| |
| self.pkgsettings["FEATURES"]=string.join(myfeat) |
| |
| if "parallel-fetch" in myfeat and not ("--ask" in myopts or "--pretend" in myopts or "--fetchonly" in myopts): |
| if "distlocks" not in myfeat: |
| print red("!!!") |
| print red("!!!")+" parallel-fetching requires the distlocks feature enabled" |
| print red("!!!")+" you have it disabled, thus parallel-fetching is being disabled" |
| print red("!!!") |
| elif len(mymergelist) > 1: |
| print ">>> starting parallel fetching" |
| pid = os.fork() |
| if not pid: |
| sys.stdin.close() |
| sys.stdout.close() |
| sys.stderr.close() |
| time.sleep(3) # allow the parent to have first fetch |
| sys.stdout = open("/dev/null","w") |
| sys.stderr = open("/dev/null","w") |
| os.dup2(sys.stdout.fileno(), 1) |
| os.dup2(sys.stdout.fileno(), 2) |
| # wipe the mtimedb so that portage doesn't attempt to flush it. |
| # do not convert this code away from a fork without correcting this. |
| portage.mtimedb = None |
| for x in ("autoaddcvs", "cvs"): |
| try: myfeat.remove(x) |
| except ValueError: pass |
| self.pkgsettings["FEATURES"] = " ".join(myfeat) |
| ret = 0 |
| for x in mymergelist: |
| if x[0] != "ebuild": |
| continue |
| try: |
| ret = portage.doebuild(portage.portdb.findname(x[2]), "fetch", x[1], self.pkgsettings, |
| cleanup=0, fetchonly=True, tree="porttree") |
| except SystemExit: |
| raise |
| except Exception: |
| ret = 1 |
| sys.exit(0) |
| portage.portage_exec.spawned_pids.append(pid) |
| |
| mergecount=0 |
| for x in mymergelist: |
| mergecount+=1 |
| myroot=x[1] |
| pkgindex=2 |
| if x[0]=="blocks": |
| pkgindex=3 |
| y=portage.portdb.findname(x[pkgindex]) |
| if not "--pretend" in myopts: |
| print ">>> Emerging ("+str(mergecount)+" of "+str(len(mymergelist))+")",x[pkgindex],"to",x[1] |
| emergelog(" >>> emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" to "+x[1]) |
| |
| self.pkgsettings["EMERGE_FROM"] = x[0][:] |
| self.pkgsettings.backup_changes("EMERGE_FROM") |
| self.pkgsettings.reset() |
| |
| #buildsyspkg: Check if we need to _force_ binary package creation |
| issyspkg = ("buildsyspkg" in myfeat) \ |
| and x[0] != "blocks" \ |
| and mysysdict.has_key(portage.cpv_getkey(x[2])) \ |
| and not ("--buildpkg" in myopts) |
| if x[0] in ["ebuild","blocks"]: |
| if (x[0]=="blocks") and ("--fetchonly" not in myopts): |
| raise Exception, "Merging a blocker" |
| elif ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): |
| if ("--fetch-all-uri" in myopts): |
| retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,fetchall=1,tree="porttree") |
| else: |
| retval=portage.doebuild(y,"fetch",myroot,self.pkgsettings,edebug,("--pretend" in myopts),fetchonly=1,tree="porttree") |
| if (retval == None) or retval: |
| print |
| print "!!! Fetch for",y,"failed, continuing..." |
| print |
| returnme=1 |
| continue |
| elif "--buildpkg" in myopts or issyspkg: |
| #buildsyspkg: Sounds useful to display something, but I don't know if we should also log it |
| if issyspkg: |
| print ">>> This is a system package, let's pack a rescue tarball." |
| #emergelog(">>> This is a system package, let's pack a rescue tarball.") |
| #create pkg, then merge pkg |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) |
| retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree") |
| if (retval == None): |
| portage_util.writemsg("Unable to run required binary.\n") |
| sys.exit(127) |
| if retval: |
| sys.exit(retval) |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Packaging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) |
| retval=portage.doebuild(y,"package",myroot,self.pkgsettings,edebug,tree="porttree") |
| if (retval == None): |
| portage_util.writemsg("Unable to run required binary.\n") |
| sys.exit(127) |
| if retval: |
| sys.exit(retval) |
| #dynamically update our database |
| if "--buildpkgonly" not in myopts: |
| portage.db[portage.root]["bintree"].inject(x[2]) |
| mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) |
| |
| self.pkgsettings["EMERGE_FROM"] = "binary" |
| self.pkgsettings.backup_changes("EMERGE_FROM") |
| |
| retval=portage.pkgmerge(mytbz2,myroot,self.pkgsettings) |
| if retval==None: |
| sys.exit(1) |
| else: |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Clean" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Cleaning ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) |
| retval=portage.doebuild(y,"clean",myroot,self.pkgsettings,edebug,cleanup=1,tree="porttree") |
| if (retval == None): |
| portage_util.writemsg("Unable to run required binary.\n") |
| sys.exit(127) |
| if retval: |
| sys.exit(retval) |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Compile" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Compiling/Merging ("+x[pkgindex]+"::"+y+")", short_msg=short_msg) |
| retval=portage.doebuild(y,"merge",myroot,self.pkgsettings,edebug,tree="porttree") |
| if (retval == None): |
| portage_util.writemsg("Unable to run required binary.\n") |
| sys.exit(127) |
| if retval: |
| sys.exit(retval) |
| #dynamically update our database |
| elif x[0]=="binary": |
| #merge the tbz2 |
| mytbz2=portage.db[portage.root]["bintree"].getname(x[2]) |
| if portage.db[portage.root]["bintree"].isremote(x[2]): |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Fetch" |
| emergelog(" --- ("+str(mergecount)+" of "+str(len(mymergelist))+") Fetching Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) |
| if not portage.db[portage.root]["bintree"].gettbz2(x[2]): |
| sys.exit(1) |
| |
| if ("--fetchonly" in myopts) or ("--fetch-all-uri" in myopts): |
| continue |
| |
| short_msg = "emerge: ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[pkgindex]+" Merge Binary" |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Merging Binary ("+x[pkgindex]+"::"+mytbz2+")", short_msg=short_msg) |
| retval=portage.pkgmerge(mytbz2,x[1],self.pkgsettings) |
| if retval==None: |
| sys.exit(1) |
| #need to check for errors |
| if "--buildpkgonly" not in myopts: |
| portage.db[x[1]]["vartree"].inject(x[2]) |
| myfavkey=portage.cpv_getkey(x[2]) |
| if "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts and myfavkey in favorites: |
| myfavs = portage.grabfile(os.path.join(myroot, portage.WORLD_FILE)) |
| myfavdict=genericdict(myfavs) |
| mysysdict=genericdict(syslist) |
| #don't record if already in system profile or already recorded |
| if (not mysysdict.has_key(myfavkey)) and (not myfavdict.has_key(myfavkey)): |
| #we don't have a favorites entry for this package yet; add one |
| myfavdict[myfavkey]=myfavkey |
| print ">>> Recording",myfavkey,"in \"world\" favorites file..." |
| emergelog(" === ("+str(mergecount)+" of "+str(len(mymergelist))+") Updating world file ("+x[pkgindex]+")") |
| portage.write_atomic( |
| os.path.join(myroot, portage.WORLD_FILE), |
| "\n".join(myfavdict.values())) |
| |
| if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): |
| # Clean the old package that we have merged over top of it. |
| if self.pkgsettings["AUTOCLEAN"]=="yes": |
| xsplit=portage.pkgsplit(x[2]) |
| emergelog(" >>> AUTOCLEAN: "+xsplit[0]) |
| retval=unmerge("clean", [xsplit[0]]) |
| if not retval: |
| emergelog(" --- AUTOCLEAN: Nothing unmerged.") |
| |
| # Figure out if we need a restart. |
| mysplit=portage.pkgsplit(x[2]) |
| if mysplit[0]=="sys-apps/portage": |
| myver=mysplit[1]+"-"+mysplit[2] |
| if myver[-3:]=='-r0': |
| myver=myver[:-3] |
| if (myver != portage.VERSION) and \ |
| ("livecvsportage" not in portage.settings.features): |
| if len(mymergelist) > mergecount: |
| emergelog(" *** RESTARTING emerge via exec() after change of portage version.") |
| del portage.mtimedb["resume"]["mergelist"][0] |
| portage.run_exitfuncs() |
| mynewargv=[sys.argv[0],"--resume"] |
| badlongopts = ("--ask","--tree","--changelog","--skipfirst","--resume") |
| for arg in myopts: |
| if arg in badlongopts: |
| continue |
| mynewargv.append(arg) |
| os.execv(mynewargv[0], mynewargv) |
| |
| if ("--pretend" not in myopts) and ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): |
| if "noclean" not in portage.features: |
| short_msg = "emerge: (%s of %s) %s Clean Post" % \ |
| (mergecount, len(mymergelist), x[pkgindex]) |
| emergelog(" === (%s of %s) Post-Build Cleaning (%s::%s)" % \ |
| (mergecount, len(mymergelist), x[pkgindex], y), short_msg=short_msg) |
| emergelog(" ::: completed emerge ("+str(mergecount)+" of "+str(len(mymergelist))+") "+x[2]+" to "+x[1]) |
| |
| # Unsafe for parallel merges |
| del portage.mtimedb["resume"]["mergelist"][0] |
| # Commit after each merge so that --resume may still work in |
| # in the event that portage is not allowed to exit normally |
| # due to power failure, SIGKILL, etc... |
| portage.commit_mtimedb() |
| |
| emergelog(" *** Finished. Cleaning up...") |
| |
| # We're out of the loop... We're done. Delete the resume data. |
| if portage.mtimedb.has_key("resume"): |
| del portage.mtimedb["resume"] |
| |
| if ("--pretend" not in myopts): |
| if ("--fetchonly" not in myopts) and ("--fetch-all-uri" not in myopts): |
| if (mergecount>0): |
| if retval: |
| portage.env_update() |
| |
| #by doing an exit this way, --fetchonly can continue to try to |
| #fetch everything even if a particular download fails. |
| if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: |
| if returnme: |
| print "\n\n!!! Some fetch errors were encountered. Please see above for details.\n\n" |
| sys.exit(returnme) |
| else: |
| sys.exit(0) |
| |
| def unmerge(unmerge_action, unmerge_files): |
| candidate_catpkgs=[] |
| global_unmerge=0 |
| |
| realsyslist = getlist("system") |
| syslist = [] |
| for x in realsyslist: |
| mycp = portage.dep_getkey(x) |
| if mycp in portage.settings.getvirtuals(): |
| providers = [] |
| for provider in portage.settings.getvirtuals()[mycp]: |
| if portage.db[portage.root]["vartree"].dbapi.match(provider): |
| providers.append(provider) |
| if len(providers) == 1: |
| syslist.extend(providers) |
| else: |
| syslist.append(mycp) |
| |
| global myopts |
| mysettings = portage.config(clone=portage.settings) |
| |
| if not unmerge_files or "world" in unmerge_files or "system" in unmerge_files: |
| if "unmerge"==unmerge_action: |
| print |
| print bold("emerge unmerge")+" can only be used with specific package names, not with "+bold("world")+" or" |
| print bold("system")+" targets." |
| print |
| return 0 |
| else: |
| global_unmerge=1 |
| |
| localtree=portage.db[portage.root]["vartree"] |
| # process all arguments and add all valid db entries to candidate_catpkgs |
| if global_unmerge: |
| if not unmerge_files or "world" in unmerge_files: |
| candidate_catpkgs.extend(localtree.getallnodes()) |
| elif "system" in unmerge_files: |
| candidate_catpkgs.extend(getlist("system")) |
| else: |
| #we've got command-line arguments |
| if not unmerge_files: |
| print "\nNo packages to unmerge have been provided.\n" |
| return 0 |
| for x in unmerge_files: |
| arg_parts=x.split('/') |
| if (x[0] not in [".","/"]) and (arg_parts[-1][-7:] != ".ebuild"): |
| #possible cat/pkg or dep; treat as such |
| candidate_catpkgs.append(x) |
| elif unmerge_action in ["prune","clean"]: |
| print "\n!!! Prune and clean do not accept individual ebuilds as arguments;\n skipping.\n" |
| continue |
| else: |
| # it appears that the user is specifying an installed ebuild and we're in "unmerge" mode, so it's |
| # ok. |
| if not os.path.exists(x): |
| print "\n!!! The path '"+x+"' doesn't exist.\n" |
| return 0 |
| |
| absx = os.path.abspath(x) |
| sp_absx = absx.split("/") |
| if sp_absx[-1][-7:] == ".ebuild": |
| del sp_absx[-1] |
| absx = string.join(sp_absx,"/") |
| |
| sp_absx_len = len(sp_absx) |
| |
| vdb_path = portage.root+portage.VDB_PATH |
| vdb_len = len(vdb_path) |
| |
| sp_vdb = vdb_path.split("/") |
| sp_vdb_len = len(sp_vdb) |
| |
| if not os.path.exists(absx+"/CONTENTS"): |
| print "!!! Not a valid db dir: "+str(absx) |
| return 0 |
| |
| if sp_absx_len <= sp_vdb_len: |
| # The Path is shorter... so it can't be inside the vdb. |
| print spabsx |
| print absx |
| print "\n!!!",x,"cannot be inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" |
| return 0 |
| |
| for idx in range(0,sp_vdb_len): |
| if (idx >= sp_absx_len) or (sp_vdb[idx] != sp_absx[idx]): |
| print sp_absx |
| print absx |
| print "\n!!!",x,"is not inside "+(portage.root+portage.VDB_PATH)+"; aborting.\n" |
| return 0 |
| |
| print "="+string.join(sp_absx[sp_vdb_len:],"/") |
| candidate_catpkgs.append("="+string.join(sp_absx[sp_vdb_len:],"/")) |
| |
| if (("--pretend" in myopts) or ("--ask" in myopts)) and not ("--quiet" in myopts): |
| print darkgreen("\n>>> These are the packages that would be unmerged:") |
| |
| pkgmap={} |
| numselected=0 |
| for x in candidate_catpkgs: |
| #cycle through all our candidate deps and determine what will and will not get unmerged |
| try: |
| mymatch=localtree.dep_match(x) |
| except KeyError: |
| mymatch=None |
| except ValueError, errpkgs: |
| print "\n\n!!! The short ebuild name \"" + x + "\" is ambiguous. Please specify" |
| print "!!! one of the following fully-qualified ebuild names instead:\n" |
| for i in errpkgs[0]: |
| print " " + green(i) |
| print |
| sys.exit(1) |
| |
| if not mymatch and x[0] not in "<>=~": |
| #add a "=" if missing |
| mymatch=localtree.dep_match("="+x) |
| if not mymatch: |
| print "\n--- Couldn't find " + white(x) + " to "+unmerge_action+"." |
| continue |
| mykey=portage.key_expand(portage.dep_getkey(mymatch[0]),portage.db["/"]["vartree"].dbapi) |
| if not pkgmap.has_key(mykey): |
| pkgmap[mykey]={"protected":[], "selected":[], "omitted":[] } |
| if unmerge_action=="unmerge": |
| for y in mymatch: |
| if y not in pkgmap[mykey]["selected"]: |
| pkgmap[mykey]["selected"].append(y) |
| numselected=numselected+len(mymatch) |
| |
| else: |
| #unmerge_action in ["prune", clean"] |
| slotmap={} |
| for mypkg in mymatch: |
| if unmerge_action=="clean": |
| myslot=localtree.getslot(mypkg) |
| else: |
| #since we're pruning, we don't care about slots and put all the pkgs in together |
| myslot=0 |
| if not slotmap.has_key(myslot): |
| slotmap[myslot]={} |
| slotmap[myslot][localtree.dbapi.cpv_counter(mypkg)]=mypkg |
| for myslot in slotmap.keys(): |
| counterkeys=slotmap[myslot].keys() |
| counterkeys.sort() |
| if not counterkeys: |
| continue |
| counterkeys.sort() |
| pkgmap[mykey]["protected"].append(slotmap[myslot][counterkeys[-1]]) |
| del counterkeys[-1] |
| #be pretty and get them in order of merge: |
| for ckey in counterkeys: |
| pkgmap[mykey]["selected"].append(slotmap[myslot][ckey]) |
| numselected=numselected+1 |
| #ok, now the last-merged package is protected, and the rest are selected |
| if global_unmerge and not numselected: |
| print "\n>>> No outdated packages were found on your system.\n" |
| return 0 |
| |
| if not numselected: |
| print "\n>>> No packages selected for removal by",unmerge_action+".\n" |
| return 0 |
| |
| for x in pkgmap.keys(): |
| for y in localtree.dep_match(x): |
| if y not in pkgmap[x]["omitted"] and \ |
| y not in pkgmap[x]["selected"] and \ |
| y not in pkgmap[x]["protected"]: |
| pkgmap[x]["omitted"].append(y) |
| if global_unmerge and not pkgmap[x]["selected"]: |
| #avoid cluttering the preview printout with stuff that isn't getting unmerged |
| continue |
| if not (pkgmap[x]["protected"] or pkgmap[x]["omitted"]) and (x in syslist): |
| print red("\a\n\n!!! '%s' is part of your system profile." % mykey) |
| print yellow("\a!!! Unmerging it may be damaging to your system.\n") |
| if "--pretend" not in myopts and "--ask" not in myopts: |
| global EMERGE_WARNING_DELAY |
| countdown(EMERGE_WARNING_DELAY,red("Press Ctrl-C to Stop")) |
| print "\n "+white(x) |
| for mytype in ["selected","protected","omitted"]: |
| print string.rjust(mytype,12)+":", |
| if pkgmap[x][mytype]: |
| for mypkg in pkgmap[x][mytype]: |
| mysplit=portage.catpkgsplit(mypkg) |
| if mysplit[3]=="r0": |
| myversion=mysplit[2] |
| else: |
| myversion=mysplit[2]+"-"+mysplit[3] |
| if mytype=="selected": |
| print red(myversion), |
| else: |
| print green(myversion), |
| else: |
| print "none", |
| print |
| |
| if portage.settings["ROOT"]: |
| print string.rjust("ROOT:", 12) + " " + white(portage.settings["ROOT"]) |
| |
| print "\n>>>",red("'Selected'"),"packages are slated for removal." |
| print ">>>",green("'Protected'"),"and",green("'omitted'"),"packages will not be removed.\n" |
| |
| if "--pretend" in myopts: |
| #we're done... return |
| return 0 |
| if "--ask" in myopts: |
| if userquery("Do you want me to unmerge these packages?")=="No": |
| # enter pretend mode for correct formatting of results |
| myopts+=["--pretend"] |
| print |
| print "Quitting." |
| print |
| return 0 |
| #the real unmerging begins, after a short delay.... |
| |
| global CLEAN_DELAY |
| countdown(CLEAN_DELAY, ">>> Unmerging") |
| |
| for x in pkgmap.keys(): |
| for y in pkgmap[x]["selected"]: |
| print ">>> Unmerging "+y+"..." |
| emergelog("=== Unmerging... ("+y+")") |
| mysplit=string.split(y,"/") |
| #unmerge... |
| retval=portage.unmerge(mysplit[0],mysplit[1],portage.root,mysettings,unmerge_action not in ["clean","prune"]) |
| if retval: |
| emergelog(" !!! unmerge FAILURE: "+y) |
| else: |
| emergelog(" >>> unmerge success: "+y) |
| #run ldconfig, etc... |
| portage.env_update() |
| if not numselected: |
| return 0 |
| else: |
| return 1 |
| |
| |
| def chk_updated_info_files(retval): |
| root=portage.root |
| |
| infodirs=[] |
| infodirs.extend(string.split(portage.settings["INFOPATH"], ":")) |
| infodirs.extend(string.split(portage.settings["INFODIR"], ":")) |
| |
| print |
| if os.path.exists("/usr/bin/install-info"): |
| regen_infodirs=[] |
| for z in infodirs: |
| if z=='': |
| continue |
| inforoot=normpath(root+z) |
| if os.path.isdir(inforoot): |
| try: |
| infomtime=os.stat(inforoot)[ST_MTIME] |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| infomtime=0 |
| |
| if not portage.mtimedb.has_key("info"): |
| portage.mtimedb["info"]={} |
| if portage.mtimedb["info"].has_key(inforoot): |
| if portage.mtimedb["info"][inforoot]==infomtime: |
| pass |
| else: |
| portage.mtimedb["info"][inforoot]=infomtime |
| regen_infodirs.append(inforoot) |
| else: |
| regen_infodirs.append(inforoot) |
| |
| if not regen_infodirs: |
| print " "+green("*")+" GNU info directory index is up-to-date." |
| else: |
| print " "+green("*")+" Regenerating GNU info directory index..." |
| |
| icount=0 |
| badcount=0 |
| for inforoot in regen_infodirs: |
| if inforoot=='': |
| continue |
| try: |
| os.rename(inforoot+"/dir",inforoot+"/dir.old") |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| pass |
| |
| if not os.path.isdir(inforoot): |
| continue |
| errmsg = "" |
| for x in os.listdir(inforoot): |
| if (x[0] == ".") or (x in ["dir","dir.old"]) or (os.path.isdir(inforoot+"/"+x)): |
| continue |
| myso=commands.getstatusoutput("LANG=C LANGUAGE=C /usr/bin/install-info --dir-file="+inforoot+"/dir "+inforoot+"/"+x)[1] |
| existsstr="already exists, for file `" |
| if myso!="": |
| if re.search(existsstr,myso): |
| # Already exists... Don't increment the count for this. |
| pass |
| elif myso[:44]=="install-info: warning: no info dir entry in ": |
| # This info file doesn't contain a DIR-header: install-info produces this |
| # (harmless) warning (the --quiet switch doesn't seem to work). |
| # Don't increment the count for this. |
| pass |
| else: |
| badcount=badcount+1 |
| errmsg += myso + "\n" |
| icount=icount+1 |
| |
| #update mtime so we can potentially avoid regenerating. |
| portage.mtimedb["info"][inforoot]=os.stat(inforoot)[ST_MTIME] |
| |
| if badcount: |
| print " "+yellow("*")+" Processed",icount,"info files;",badcount,"errors." |
| print errmsg |
| else: |
| print " "+green("*")+" Processed",icount,"info files." |
| |
| |
| def post_emerge(retval=0): |
| global myopts |
| os.chdir("/") |
| if "--pretend" in myopts: |
| sys.exit(retval) |
| |
| emergelog(" *** exiting successfully.") |
| |
| if "noinfo" not in portage.settings.features: |
| chk_updated_info_files(retval) |
| |
| chk_updated_cfg_files() |
| sys.exit(retval) |
| |
| |
| def chk_updated_cfg_files(): |
| if portage.settings["CONFIG_PROTECT"]: |
| #number of directories with some protect files in them |
| procount=0 |
| for x in string.split(portage.settings["CONFIG_PROTECT"]): |
| if os.path.isdir(x): |
| a=commands.getstatusoutput("cd "+x+"; find . -iname '._cfg????_*'") |
| if a[0]!=0: |
| print " "+red("*")+" error scanning",x |
| else: |
| files=string.split(a[1]) |
| if files: |
| procount=procount+1 |
| print " "+yellow("* IMPORTANT:")+"",len(files),"config files in",x,"need updating." |
| if procount: |
| #print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." |
| print " "+yellow("*")+" Type "+green("emerge --help config")+" to learn how to update config files." |
| print |
| |
| def is_valid_package_atom(x): |
| testkey = portage.dep_getkey(x) |
| if testkey.startswith("null/"): |
| testatom = x.replace(testkey[5:], "cat/"+testkey[5:]) |
| elif "/" not in x: |
| testatom = "cat/"+x |
| else: |
| testatom = x |
| return portage.isvalidatom(testatom) |
| |
| # general options that should be taken into account before any action |
| if "--debug" in myopts: |
| edebug=1 |
| |
| if myaction in ["sync","metadata"] and (not "--help" in myopts): |
| if "--pretend" in myopts: |
| print "emerge: \"sync\" actions do not support \"--pretend.\"" |
| sys.exit(1) |
| |
| emergelog(" === "+str(myaction)) |
| myportdir=portage.settings["PORTDIR"] |
| if myportdir[-1]=="/": |
| myportdir=myportdir[:-1] |
| if not os.path.exists(myportdir): |
| print ">>>",myportdir,"not found, creating it." |
| os.makedirs(myportdir,0755) |
| syncuri=string.rstrip(portage.settings["SYNC"]) |
| os.umask(0022) |
| if myaction == "metadata": |
| if "--ask" in myopts: |
| if userquery("Are you sure?") == "No": |
| sys.exit(1) |
| print "skipping sync" |
| updatecache_flg = True |
| tmpservertimestampfile = None |
| elif syncuri[:8]=="rsync://": |
| if not os.path.exists("/usr/bin/rsync"): |
| print "!!! /usr/bin/rsync does not exist, so rsync support is disabled." |
| print "!!! Type \"emerge net-misc/rsync\" to enable rsync support." |
| sys.exit(1) |
| mytimeout=180 |
| |
| rsync_opts = [] |
| |
| if portage.settings["PORTAGE_RSYNC_OPTS"] == "": |
| portage.writemsg("PORTAGE_RSYNC_OPTS empty or unset, using hardcoded defaults\n") |
| rsync_opts.extend([ |
| "--recursive", # Recurse directories |
| "--links", # Consider symlinks |
| "--safe-links", # Ignore links outside of tree |
| "--perms", # Preserve permissions |
| "--times", # Preserive mod times |
| "--compress", # Compress the data transmitted |
| "--force", # Force deletion on non-empty dirs |
| "--whole-file", # Don't do block transfers, only entire files |
| "--delete", # Delete files that aren't in the master tree |
| "--delete-after", # Delete only after everything else is done |
| "--stats", # Show final statistics about what was transfered |
| "--timeout="+str(mytimeout), # IO timeout if not done in X seconds |
| "--exclude='/distfiles'", # Exclude distfiles from consideration |
| "--exclude='/local'", # Exclude local from consideration |
| "--exclude='/packages'", # Exclude packages from consideration |
| ]) |
| |
| else: |
| # The below validation is not needed when using the above hardcoded |
| # defaults. |
| |
| portage.writemsg("Using PORTAGE_RSYNC_OPTS instead of hardcoded defaults\n") |
| rsync_opts.extend(portage.settings["PORTAGE_RSYNC_OPTS"].split()) |
| |
| for opt in ("--recursive", "--times"): |
| if opt not in rsync_opts: |
| portage.writemsg(yellow("WARNING:") + " adding required option " + \ |
| "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) |
| rsync_opts.append(opt) |
| |
| for exclude in ("distfiles", "local", "packages"): |
| opt = "--exclude='/%s'" % exclude |
| if opt not in rsync_opts: |
| portage.writemsg(yellow("WARNING:") + \ |
| " adding required option %s not included in " % opt + \ |
| "PORTAGE_RSYNC_OPTS (override with --exclude='!')\n") |
| rsync_opts.append(opt) |
| |
| if portage.settings["RSYNC_TIMEOUT"] != "": |
| portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \ |
| "use PORTAGE_RSYNC_OPTS instead\n") |
| try: |
| mytimeout = int(portage.settings["RSYNC_TIMEOUT"]) |
| rsync_opts.append("--timeout=%d" % mytimeout) |
| except ValueError, e: |
| portage.writemsg("!!! %s\n" % str(e)) |
| |
| # TODO: determine options required for official servers |
| if syncuri.rstrip("/").endswith(".gentoo.org/gentoo-portage"): |
| |
| def rsync_opt_startswith(opt_prefix): |
| for x in rsync_opts: |
| if x.startswith(opt_prefix): |
| return True |
| return False |
| |
| if not rsync_opt_startswith("--timeout="): |
| rsync_opts.append("--timeout=%d" % mytimeout) |
| |
| for opt in ("--compress", "--whole-file"): |
| if opt not in rsync_opts: |
| portage.writemsg(yellow("WARNING:") + " adding required option " + \ |
| "%s not included in PORTAGE_RSYNC_OPTS\n" % opt) |
| rsync_opts.append(opt) |
| |
| if "--quiet" in myopts: |
| rsync_opts.append("--quiet") # Shut up a lot |
| else: |
| rsync_opts.append("--progress") # Progress meter for each file |
| |
| if "--verbose" in myopts: |
| rsync_opts.append("--verbose") # More noise? Not really sure what |
| |
| if "--debug" in myopts: |
| rsync_opts.append("--checksum") # Force checksum on all files |
| |
| if portage.settings["RSYNC_EXCLUDEFROM"] != "": |
| portage.writemsg(yellow("WARNING:") + \ |
| " usage of RSYNC_EXCLUDEFROM is deprecated, use " + \ |
| "PORTAGE_RSYNC_EXTRA_OPTS instead\n") |
| if os.path.exists(portage.settings["RSYNC_EXCLUDEFROM"]): |
| rsync_opts.append("--exclude-from=%s" % \ |
| portage.settings["RSYNC_EXCLUDEFROM"]) |
| else: |
| portage.writemsg("!!! RSYNC_EXCLUDEFROM specified," + \ |
| " but file does not exist.\n") |
| |
| if portage.settings["RSYNC_RATELIMIT"] != "": |
| portage.writemsg(yellow("WARNING:") + \ |
| " usage of RSYNC_RATELIMIT is deprecated, use " + \ |
| "PORTAGE_RSYNC_EXTRA_OPTS instead") |
| rsync_opts.append("--bwlimit=%s" % \ |
| portage.settings["RSYNC_RATELIMIT"]) |
| |
| servertimestampdir = portage.settings.depcachedir+"/" |
| servertimestampfile = portage.settings.depcachedir+"/timestamp.chk" |
| tmpservertimestampdir = portage.settings["PORTAGE_TMPDIR"]+"/" |
| tmpservertimestampfile = portage.settings["PORTAGE_TMPDIR"]+"/timestamp.chk" |
| |
| # We only use the backup if a timestamp exists in the portdir. |
| content=None |
| if os.path.exists(myportdir+"/metadata/timestamp.chk"): |
| content=portage.grabfile(servertimestampfile) |
| if (not content): |
| content=portage.grabfile(myportdir+"/metadata/timestamp.chk") |
| |
| if (content): |
| try: |
| mytimestamp=time.mktime(time.strptime(content[0], "%a, %d %b %Y %H:%M:%S +0000")) |
| except ValueError: |
| mytimestamp=0 |
| else: |
| mytimestamp=0 |
| |
| if not os.path.exists(servertimestampdir): |
| os.mkdir(servertimestampdir) |
| os.chown(servertimestampdir, os.getuid(), portage.portage_gid) |
| os.chmod(servertimestampdir, 02775) |
| |
| #exitcode=0 |
| try: |
| if portage.settings.has_key("RSYNC_RETRIES"): |
| print yellow("WARNING:")+" usage of RSYNC_RETRIES is deprecated, use PORTAGE_RSYNC_RETRIES instead" |
| maxretries=int(portage.settings["RSYNC_RETRIES"]) |
| else: |
| maxretries=int(portage.settings["PORTAGE_RSYNC_RETRIES"]) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| maxretries=3 #default number of retries |
| |
| retries=0 |
| hostname, port=re.split("rsync://([^:/]*)(:[0-9]+)?", syncuri)[1:3]; |
| if port==None: |
| port="" |
| updatecache_flg=True |
| |
| ips=[] |
| while (1): |
| if ips: |
| del ips[0] |
| if ips==[]: |
| try: |
| ips=socket.gethostbyname_ex(hostname)[2] |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| print "Notice:",str(e) |
| dosyncuri=syncuri |
| |
| if ips: |
| try: |
| dosyncuri=string.replace(syncuri, "//"+hostname+port+"/", "//"+ips[0]+port+"/", 1) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| print "Notice:",str(e) |
| dosyncuri=syncuri |
| |
| if (retries==0): |
| if "--ask" in myopts: |
| if userquery("Do you want to sync your Portage tree with the mirror at\n" + blue(dosyncuri) + bold("?"))=="No": |
| print |
| print "Quitting." |
| print |
| sys.exit(0) |
| emergelog(">>> Starting rsync with "+dosyncuri) |
| if "--quiet" not in myopts: |
| print ">>> Starting rsync with "+dosyncuri+"..." |
| else: |
| emergelog(">>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri)) |
| print "\n\n>>> Starting retry %d of %d with %s" % (retries,maxretries,dosyncuri) |
| |
| if "--quiet" not in myopts: |
| print ">>> Checking server timestamp ..." |
| |
| rsynccommand = " ".join(["/usr/bin/rsync", |
| portage.settings["PORTAGE_RSYNC_EXTRA_OPTS"], |
| " ".join(rsync_opts)]) |
| |
| if "--debug" in myopts: |
| print rsynccommand |
| |
| mycommand = " ".join([rsynccommand, |
| dosyncuri + "/metadata/timestamp.chk", |
| tmpservertimestampdir]) |
| exitcode=portage.spawn(mycommand,portage.settings,free=1) |
| if (exitcode==0): |
| try: |
| servertimestamp = time.mktime(time.strptime(portage.grabfile(tmpservertimestampfile)[0], "%a, %d %b %Y %H:%M:%S +0000")) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| servertimestamp = 0 |
| |
| if (servertimestamp != 0) and (servertimestamp == mytimestamp): |
| emergelog(">>> Cancelling sync -- Already current.") |
| print |
| print ">>>" |
| print ">>> Timestamps on the server and in the local repository are the same." |
| print ">>> Cancelling all further sync action. You are already up to date." |
| print ">>>" |
| print |
| sys.exit(0) |
| elif (servertimestamp != 0) and (servertimestamp < mytimestamp): |
| emergelog(">>> Server out of date: %s" % dosyncuri) |
| print |
| print ">>>" |
| print ">>> SERVER OUT OF DATE: %s" % dosyncuri |
| print ">>>" |
| print |
| elif (servertimestamp == 0) or (servertimestamp > mytimestamp): |
| # actual sync |
| mycommand=rsynccommand+" "+dosyncuri+"/ "+myportdir |
| exitcode=portage.spawn(mycommand,portage.settings,free=1) |
| if exitcode in [0,1,2,3,4,11,14,20,21]: |
| break |
| elif exitcode in [0,1,2,3,4,11,14,20,21]: |
| break |
| |
| retries=retries+1 |
| |
| if retries<=maxretries: |
| print ">>> Retrying..." |
| time.sleep(11) |
| else: |
| # over retries |
| # exit loop |
| updatecache_flg=False |
| break |
| |
| if (exitcode==0): |
| emergelog("=== Sync completed with %s" % dosyncuri) |
| elif (exitcode>0): |
| print |
| if exitcode==1: |
| print darkred("!!!")+green(" Rsync has reported that there is a syntax error. Please ensure") |
| print darkred("!!!")+green(" that your SYNC statement is proper.") |
| print darkred("!!!")+green(" SYNC="+portage.settings["SYNC"]) |
| elif exitcode==11: |
| print darkred("!!!")+green(" Rsync has reported that there is a File IO error. Normally") |
| print darkred("!!!")+green(" this means your disk is full, but can be caused by corruption") |
| print darkred("!!!")+green(" on the filesystem that contains PORTDIR. Please investigate") |
| print darkred("!!!")+green(" and try again after the problem has been fixed.") |
| print darkred("!!!")+green(" PORTDIR="+portage.settings["PORTDIR"]) |
| elif exitcode==20: |
| print darkred("!!!")+green(" Rsync was killed before it finished.") |
| else: |
| print darkred("!!!")+green(" Rsync has not successfully finished. It is recommended that you keep") |
| print darkred("!!!")+green(" trying or that you use the 'emerge-webrsync' option if you are unable") |
| print darkred("!!!")+green(" to use rsync due to firewall or other restrictions. This should be a") |
| print darkred("!!!")+green(" temporary problem unless complications exist with your network") |
| print darkred("!!!")+green(" (and possibly your system's filesystem) configuration.") |
| print |
| sys.exit(exitcode) |
| elif syncuri[:6]=="cvs://": |
| if not os.path.exists("/usr/bin/cvs"): |
| print "!!! /usr/bin/cvs does not exist, so CVS support is disabled." |
| print "!!! Type \"emerge dev-util/cvs\" to enable CVS support." |
| sys.exit(1) |
| cvsroot=syncuri[6:] |
| cvsdir=os.path.dirname(myportdir) |
| if not os.path.exists(myportdir+"/CVS"): |
| #initial checkout |
| print ">>> Starting initial cvs checkout with "+syncuri+"..." |
| if not portage.spawn("cd "+cvsdir+"; cvs -d "+cvsroot+" login",portage.settings,free=1): |
| print "!!! cvs login error; exiting." |
| sys.exit(1) |
| if os.path.exists(cvsdir+"/gentoo-x86"): |
| print "!!! existing",cvsdir+"/gentoo-x86 directory; exiting." |
| sys.exit(1) |
| if not portage.spawn("cd "+cvsdir+"; cvs -z0 -d "+cvsroot+" co -P gentoo-x86",portage.settings,free=1): |
| print "!!! cvs checkout error; exiting." |
| sys.exit(1) |
| if cvsdir!=myportdir: |
| portage.movefile(cvsdir,portage.settings["PORTDIR"]) |
| sys.exit(0) |
| else: |
| #cvs update |
| print ">>> Starting cvs update with "+syncuri+"..." |
| sys.exit(portage.spawn("cd "+myportdir+"; cvs -z0 -q update -dP",portage.settings,free=1)) |
| else: |
| print "!!! rsync setting: ",syncuri,"not recognized; exiting." |
| sys.exit(1) |
| |
| try: # Prevent users from affecting ebuild.sh. |
| os.close(sys.stdin.fileno()) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| pass |
| |
| if updatecache_flg and \ |
| myaction != "metadata" and \ |
| "metadata-transfer" not in portage.settings.features: |
| updatecache_flg = False |
| |
| if os.path.exists(myportdir+"/metadata/cache") and updatecache_flg: |
| if "--quiet" not in myopts: |
| print "\n>>> Updating Portage cache: ", |
| os.umask(0002) |
| cachedir = os.path.normpath(portage.settings.depcachedir) |
| if cachedir in ["/", "/bin", "/dev", "/etc", "/home", |
| "/lib", "/opt", "/proc", "/root", "/sbin", |
| "/sys", "/tmp", "/usr", "/var"]: |
| print "!!! PORTAGE_CACHEDIR IS SET TO A PRIMARY ROOT DIRECTORY ON YOUR SYSTEM." |
| print "!!! This is ALMOST CERTAINLY NOT what you want: "+str(cachedir) |
| sys.exit(73) |
| if not os.path.exists(cachedir): |
| os.mkdir(cachedir) |
| |
| # Potentially bad |
| #if os.path.exists(cachedir+"/"+myportdir): |
| # portage.spawn("rm -Rf "+cachedir+"/"+myportdir+"/*",portage.settings,free=1) |
| |
| # save timestamp.chk for next timestamp check. |
| try: |
| if tmpservertimestampfile != None: |
| portage.movefile(tmpservertimestampfile, servertimestampfile) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except Exception, e: |
| print "!!! Failed to save current timestamp." |
| print "!!!",e |
| |
| portage.portdb.flush_cache() |
| |
| ec = portage.eclass_cache.cache(portage.portdb.porttree_root) |
| # kinda ugly. |
| # XXX: nuke the filter when mr UNUSED_0? keys are dead |
| cm = portage.settings.load_best_module("portdbapi.metadbmodule")(myportdir, "metadata/cache", |
| filter(lambda x: not x.startswith("UNUSED_0"), portage.auxdbkeys)) |
| |
| # we don't make overlay trees cache here, plus we don't trust portage.settings.categories |
| porttree_root = portage.portdb.porttree_root |
| conf = portage.config(config_profile_path=portage.settings.profile_path[:], \ |
| config_incrementals=portage.settings.incrementals[:]) |
| |
| conf["PORTDIR_OVERLAY"] = '' |
| conf.categories = portage.grabfile(os.path.join(porttree_root, "profiles", "categories")) |
| try: |
| i = conf.categories.index("virtual") |
| if i != -1: |
| conf.categories.remove(i) |
| except (ValueError, IndexError): |
| pass |
| |
| pdb = portage.portdbapi(porttree_root, conf) |
| |
| cp_all_list = pdb.cp_all() |
| import cache.util |
| |
| class percentage_noise_maker(cache.util.quiet_mirroring): |
| def __init__(self, dbapi): |
| self.dbapi = dbapi |
| self.cp_all = dbapi.cp_all() |
| l = len(self.cp_all) |
| self.call_update_min = 100000000 |
| self.min_cp_all = l/100.0 |
| self.count = 1 |
| self.pstr = '' |
| |
| def __iter__(self): |
| for x in self.cp_all: |
| self.count += 1 |
| if self.count > self.min_cp_all: |
| self.call_update_min = 0 |
| self.count = 0 |
| for y in self.dbapi.cp_list(x): |
| yield y |
| self.call_update_mine = 0 |
| |
| def update(self, *arg): |
| try: self.pstr = int(self.pstr) + 1 |
| except ValueError: self.pstr = 1 |
| sys.stdout.write("%s%i%%" % ("\b" * (len(str(self.pstr))+1), self.pstr)) |
| sys.stdout.flush() |
| self.call_update_min = 10000000 |
| |
| def finish(self, *arg): |
| sys.stdout.write("\b\b\b\b100%\n") |
| sys.stdout.flush() |
| |
| |
| if "--quiet" in myopts: |
| def quicky_cpv_generator(cp_all_list): |
| for x in cp_all_list: |
| for y in pdb.cp_list(x): |
| yield y |
| source = quicky_cpv_generator(pdb.cp_all()) |
| noise_maker = cache.util.quiet_mirroring() |
| else: |
| noise_maker = source = percentage_noise_maker(pdb) |
| cache.util.mirror_cache(source, cm, pdb.auxdb[porttree_root], eclass_cache=ec, verbose_instance=noise_maker) |
| |
| sys.stdout.flush() |
| |
| portage.portageexit() |
| reload(portage) |
| mybestpv=portage.portdb.xmatch("bestmatch-visible","sys-apps/portage") |
| mypvs=portage.best(portage.db[portage.root]["vartree"].dbapi.match("sys-apps/portage")) |
| |
| chk_updated_cfg_files() |
| |
| if myaction != "metadata": |
| if os.access(portage.USER_CONFIG_PATH + "/bin/post_sync", os.X_OK): |
| try: |
| portage.spawn(portage.USER_CONFIG_PATH + "/bin/post_sync " + dosyncuri, portage.settings, free=1) |
| except: |
| print red(" * ")+bold("spawn failed of "+ portage.USER_CONFIG_PATH + "/bin/post_sync") |
| |
| if(mybestpv != mypvs) and not "--quiet" in myopts: |
| print |
| print red(" * ")+bold("An update to portage is available.")+" It is _highly_ recommended" |
| print red(" * ")+"that you update portage now, before any other packages are updated." |
| print red(" * ")+"Please run 'emerge portage' and then update "+bold("ALL")+" of your" |
| print red(" * ")+"configuration files." |
| print |
| elif myaction=="regen": |
| emergelog(" === regen") |
| #regenerate cache entries |
| print "Regenerating cache entries... " |
| try: |
| os.close(sys.stdin.fileno()) |
| except SystemExit, e: |
| raise # Needed else can't exit |
| except: |
| pass |
| sys.stdout.flush() |
| mynodes=portage.portdb.cp_all() |
| for x in mynodes: |
| mymatches=portage.portdb.xmatch("match-all",x) |
| if not "--quiet" in myopts: |
| print "processing",x |
| for y in mymatches: |
| try: |
| foo=portage.portdb.aux_get(y,["DEPEND"]) |
| except SystemExit, e: |
| # sys.exit is an exception... And consequently, we can't catch it. |
| raise |
| except Exception, e: |
| print "\n error processing %(cpv)s, continuing... (%(e)s)" % {"cpv":y,"e":str(e)} |
| print "done!" |
| # HELP action |
| elif "config"==myaction: |
| if len(myfiles) != 1 or "system" in myfiles or "world" in myfiles: |
| print red("!!! config can only take a single package atom at this time\n") |
| sys.exit(1) |
| if not is_valid_package_atom(myfiles[0]): |
| portage.writemsg("!!! '%s' is not a valid package atom.\n" % myfiles[0]) |
| portage.writemsg("!!! Please check ebuild(5) for full details.\n") |
| portage.writemsg("!!! (Did you specify a version but forget to prefix with '='?)\n") |
| sys.exit(1) |
| print |
| pkgs = portage.db[portage.root]["vartree"].dbapi.match(myfiles[0]) |
| if len(pkgs) == 0: |
| print "No packages found.\n" |
| sys.exit(0) |
| elif len(pkgs) > 1: |
| if "--ask" in myopts: |
| options = [] |
| print "Please select a package to configure:" |
| idx = 0 |
| for pkg in pkgs: |
| idx += 1 |
| options.append(str(idx)) |
| print options[-1]+") "+pkg |
| print "X) Cancel" |
| options.append("X") |
| idx = userquery("Selection?", options) |
| if idx == "X": |
| sys.exit(0) |
| pkg = pkgs[int(idx)-1] |
| else: |
| print "The following packages available:" |
| for pkg in pkgs: |
| print "* "+pkg |
| print "\nPlease use a specific atom or the --ask option." |
| sys.exit(1) |
| else: |
| pkg = pkgs[0] |
| |
| print |
| if "--ask" in myopts: |
| if userquery("Ready to configure "+pkg+"?") == "No": |
| sys.exit(0) |
| else: |
| print "Configuring pkg..." |
| print |
| ebuildpath = portage.db[portage.root]["vartree"].dbapi.findname(pkg) |
| mysettings = portage.config(clone=portage.settings) |
| portage.doebuild(ebuildpath,"config",portage.root,mysettings,debug=("--debug" in myopts),cleanup=True,tree="vartree") |
| print |
| |
| # INFO action |
| elif "info"==myaction: |
| unameout=commands.getstatusoutput("uname -mrp")[1] |
| print getportageversion() |
| print "=================================================================" |
| print "System uname: "+unameout |
| if os.path.exists("/etc/gentoo-release"): |
| os.system("cat /etc/gentoo-release") |
| else: |
| print "Unknown Host Operating System" |
| |
| output=commands.getstatusoutput("distcc --version") |
| if not output[0]: |
| print str(string.split(output[1],"\n",1)[0]), |
| if "distcc" in portage.features: |
| print "[enabled]" |
| else: |
| print "[disabled]" |
| |
| output=commands.getstatusoutput("ccache -V") |
| if not output[0]: |
| print str(string.split(output[1],"\n",1)[0]), |
| if "ccache" in portage.features: |
| print "[enabled]" |
| else: |
| print "[disabled]" |
| |
| myvars = ["sys-devel/autoconf", "sys-devel/automake", "virtual/os-headers", |
| "sys-devel/binutils", "sys-devel/libtool", "dev-lang/python"] |
| myvars += portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_pkgs") |
| myvars = portage_util.unique_array(myvars) |
| myvars.sort() |
| |
| for x in myvars: |
| if portage.isvalidatom(x): |
| pkg_matches = portage.db["/"]["vartree"].dbapi.match(x) |
| pkgs = [] |
| for y in pkg_matches: |
| mycpv = portage.catpkgsplit(y) |
| if(mycpv[3] != "r0"): |
| pkgs += [mycpv[2] + "-" + mycpv[3]] |
| else: |
| pkgs += [mycpv[2]] |
| if not pkgs: |
| pkgs = "[Not Present]" |
| else: |
| pkgs = ", ".join(sorted_versions(pkgs)) |
| print "%-20s %s" % (x+":", pkgs) |
| else: |
| print "%-20s %s" % (x+":", "[NOT VALID]") |
| |
| libtool_vers = string.join(portage.db["/"]["vartree"].dbapi.match("sys-devel/libtool"), ",") |
| |
| if "--verbose" in myopts: |
| myvars=portage.settings.keys() |
| else: |
| myvars = ['GENTOO_MIRRORS', 'CONFIG_PROTECT', 'CONFIG_PROTECT_MASK', |
| 'PORTDIR', 'DISTDIR', 'PKGDIR', 'PORTAGE_TMPDIR', |
| 'PORTDIR_OVERLAY', 'USE', 'CHOST', 'CFLAGS', 'CXXFLAGS', |
| 'ACCEPT_KEYWORDS', 'SYNC', 'FEATURES', 'EMERGE_DEFAULT_OPTS'] |
| |
| myvars.extend(portage_util.grabfile(portage.settings["PORTDIR"]+"/profiles/info_vars")) |
| |
| myvars = portage_util.unique_array(myvars) |
| unset_vars = [] |
| myvars.sort() |
| for x in myvars: |
| if portage.settings.has_key(x): |
| print x+'="'+portage.settings[x]+'"' |
| else: |
| unset_vars.append(x) |
| if unset_vars: |
| print "Unset: "+", ".join(unset_vars) |
| print |
| |
| if "--debug" in myopts: |
| for x in dir(portage): |
| module = getattr(portage, x) |
| if "cvs_id_string" in dir(module): |
| print "%s: %s" % (str(x), str(module.cvs_id_string)) |
| |
| # SEARCH action |
| elif "search"==myaction: |
| if not myfiles: |
| print "emerge: no search terms provided." |
| else: |
| searchinstance = search() |
| for mysearch in myfiles: |
| try: |
| searchinstance.execute(mysearch) |
| except re.error, comment: |
| print "\n!!! Regular expression error in \"%s\": %s" % ( mysearch, comment ) |
| sys.exit(1) |
| searchinstance.output() |
| elif "unmerge"==myaction or "prune"==myaction or "clean"==myaction: |
| if 1==unmerge(myaction, myfiles): |
| post_emerge() |
| |
| elif "depclean"==myaction: |
| # Kill packages that aren't explicitly merged or are required as a |
| # dependency of another package. World file is explicit. |
| |
| print |
| print red("*** WARNING ***")+" --depclean is known to be broken. It is highly recommended" |
| print red("*** WARNING ***")+" that "+green("`emerge --update --newuse --deep world`")+" be ran before" |
| print red("*** WARNING ***")+" commencing. However, using --depclean may still break link" |
| print red("*** WARNING ***")+" level consistency within your system. "+green("`revdep-rebuild`") |
| print red("*** WARNING ***")+" from app-portage/gentoolkit can help to detect breakage." |
| print red("*** WARNING ***") |
| print red("*** WARNING ***")+" Also study the list of packages to be cleaned for any" |
| print red("*** WARNING ***")+" obvious mistakes. Packages can be manually added to the" |
| print red("*** WARNING ***")+" world list by running "+green("`emerge --noreplace <atom>`")+"." |
| print red("*** WARNING ***") |
| print red("*** WARNING ***")+" "+bold("Make sure you have a backup.") |
| |
| syslist=getlist("system") |
| worldlist=getlist("world") |
| myvarlist=portage.vardbapi(portage.root).cp_all() |
| |
| if not syslist: |
| print "\n!!! You have no system list.", |
| if not worldlist: |
| print "\n!!! You have no world file.", |
| if not myvarlist: |
| print "\n!!! You have no installed package database (%s)." % portage.VDB_PATH, |
| |
| if not (syslist and worldlist and myvarlist): |
| print "\n!!! Proceeding will break your installation.\n" |
| countdown(EMERGE_WARNING_DELAY, ">>> Depclean") |
| |
| if not "--pretend" in myopts: #just check pretend, since --ask implies pretend |
| emergelog(" >>> depclean") |
| |
| mydepgraph=depgraph(myaction,myopts) |
| |
| if not ("--quiet" in myopts): |
| print "\nCalculating dependencies ", |
| if not mydepgraph.xcreate("world"): |
| print "\n!!! Failed to create deptree." |
| sys.exit(1) |
| if not ("--quiet" in myopts): |
| print "\b\b... done!" |
| |
| if ("--usepkgonly" in myopts) and mydepgraph.missingbins: |
| sys.stderr.write(red("The following binaries are not available for merging...\n")) |
| for x in mydepgraph.missingbins: |
| sys.stderr.write(" "+str(x)+"\n") |
| sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") |
| sys.exit(1) |
| |
| alldeps=mydepgraph.digraph.allnodes() |
| |
| if not alldeps: |
| print "!!! You have no dependencies. Impossible. Bug." |
| sys.exit(1) |
| |
| reallist=[] |
| for x in alldeps: |
| myparts=portage.catpkgsplit(string.split(x)[2]) |
| if not myparts: |
| sys.stderr.write( |
| red("!!! There appears to be a problem with the following package:\n")+ |
| red("!!! "+str(string.split(x)[2])+"\n\n")+ |
| "!!! Please ensure that blocking/conflicting packages are not merged."+ |
| "!!! 'emerge -p "+str(string.split(x)[2])+"\n\n") |
| if ("--pretend" not in myopts) and ("--ask" not in myopts): |
| countdown(EMERGE_WARNING_DELAY, "*** Continuing") |
| continue |
| |
| catpack=myparts[0]+"/"+myparts[1] |
| if catpack not in reallist: |
| reallist.append(catpack) |
| |
| cleanlist=[] |
| for x in myvarlist: |
| if x not in reallist: |
| if x not in cleanlist: |
| cleanlist.append(x) |
| |
| for x in syslist+worldlist: |
| myparts = portage.catpkgsplit(x) |
| if myparts: |
| if myparts[0][0] in ('<','>','='): |
| myparts[0] = myparts[0][1:] |
| if myparts[0][0] in ('<','>','='): |
| myparts[0] = myparts[0][1:] |
| catpack=myparts[0]+"/"+myparts[1] |
| else: |
| catpack=x |
| if catpack in cleanlist: |
| cleanlist.remove(catpack) |
| |
| #print "\n\n\nCleaning: " |
| #for x in cleanlist: |
| # print x |
| #print |
| |
| if len(cleanlist): |
| unmerge("unmerge", cleanlist) |
| |
| print |
| print "Packages installed: "+str(len(myvarlist)) |
| print "Packages in world: "+str(len(worldlist)) |
| print "Packages in system: "+str(len(syslist)) |
| print "Unique package names: "+str(len(reallist)) |
| print "Required packages: "+str(len(alldeps)) |
| if "--pretend" in myopts: |
| print "Number to remove: "+str(len(cleanlist)) |
| else: |
| print "Number removed: "+str(len(cleanlist)) |
| post_emerge() |
| |
| # "update", "system", or just process files: |
| else: |
| favorites=[] |
| syslist=getlist("system") |
| if ("--ask" in myopts or "--pretend" in myopts) and not "--quiet" in myopts: |
| action = "" |
| if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: |
| action = "fetched" |
| else: |
| action = "merged" |
| if "--tree" in myopts and action != "fetched": # Tree doesn't work with fetching |
| print |
| print darkgreen("These are the packages that would be %s, in reverse order:") % action |
| print |
| else: |
| print |
| print darkgreen("These are the packages that would be %s, in order:") % action |
| print |
| |
| if "--resume" in myopts and \ |
| ("resume" in portage.mtimedb or |
| "resume_backup" in portage.mtimedb): |
| if "resume" not in portage.mtimedb: |
| portage.mtimedb["resume"] = portage.mtimedb["resume_backup"] |
| del portage.mtimedb["resume_backup"] |
| portage.commit_mtimedb() |
| myresumeopts=portage.mtimedb["resume"]["myopts"][:] |
| |
| for opt in ("--skipfirst", "--ask", "--tree"): |
| while opt in myresumeopts: |
| myresumeopts.remove(opt) |
| |
| for myopt in myopts: |
| if myopt not in myresumeopts: |
| myresumeopts.append(myopt) |
| myopts=myresumeopts |
| mydepgraph=depgraph("resume",myopts) |
| if "--resume" not in myopts: |
| myopts+=["--resume"] |
| else: |
| if ("--resume" in myopts): |
| del myopts[myopts.index("--resume")] |
| print darkgreen("emerge: It seems we have nothing to resume...") |
| sys.exit(0) |
| |
| mydepgraph=depgraph(myaction,myopts) |
| if myaction in ["system","world"]: |
| if not ("--quiet" in myopts): |
| print "Calculating",myaction,"dependencies ", |
| sys.stdout.flush() |
| if not mydepgraph.xcreate(myaction): |
| print "!!! Depgraph creation failed." |
| sys.exit(1) |
| if not ("--quiet" in myopts): |
| print "\b\b... done!" |
| else: |
| if not myfiles: |
| print "emerge: please tell me what to do." |
| help() |
| sys.exit(1) |
| #we don't have any files to process; skip this step and exit |
| if not ("--quiet" in myopts): |
| print "Calculating dependencies ", |
| sys.stdout.flush() |
| retval,favorites=mydepgraph.select_files(myfiles) |
| if not retval: |
| sys.exit(1) |
| if not ("--quiet" in myopts): |
| print "\b\b... done!" |
| |
| if ("--usepkgonly" in myopts) and mydepgraph.missingbins: |
| sys.stderr.write(red("The following binaries are not available for merging...\n")) |
| |
| if mydepgraph.missingbins: |
| for x in mydepgraph.missingbins: |
| sys.stderr.write(" "+str(x)+"\n") |
| sys.stderr.write("\nThese are required by '--usepkgonly' -- Terminating.\n\n") |
| sys.exit(1) |
| |
| if "--ask" in myopts: |
| if "--resume" in myopts: |
| mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) |
| prompt="Do you want me to resume merging these packages?" |
| else: |
| mydepgraph.display(mydepgraph.altlist()) |
| mergecount=0 |
| for x in mydepgraph.altlist(): |
| if x[3]!="nomerge": |
| mergecount+=1 |
| #check for blocking dependencies |
| if x[0]=="blocks" and "--fetchonly" not in myopts and "--fetch-all-uri" not in myopts: |
| print "\n!!! Error: The above package list contains packages which cannot be installed" |
| print "!!! at the same time on the same system." |
| print |
| sys.exit(1) |
| if mergecount==0: |
| if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: |
| prompt="Nothing to merge; do you want me to auto-clean packages?" |
| else: |
| print |
| print "Nothing to merge; quitting." |
| print |
| sys.exit(0) |
| elif "--fetchonly" in myopts or "--fetch-all-uri" in myopts: |
| prompt="Do you want me to fetch the source files for these packages?" |
| else: |
| prompt="Do you want me to merge these packages?" |
| print |
| if userquery(prompt)=="No": |
| print |
| print "Quitting." |
| print |
| sys.exit(0) |
| # Don't ask again (e.g. when auto-cleaning packages after merge) |
| myopts.remove("--ask") |
| |
| if ("--pretend" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): |
| if ("--resume" in myopts): |
| mydepgraph.display(portage.mtimedb["resume"]["mergelist"]) |
| else: |
| mydepgraph.display(mydepgraph.altlist()) |
| else: |
| if ("--buildpkgonly" in myopts): |
| if not mydepgraph.digraph.hasallzeros(): |
| print "\n!!! --buildpkgonly requires all dependencies to be merged." |
| print "!!! Cannot merge requested packages. Merge deps and try again.\n" |
| sys.exit(1) |
| |
| if ("--resume" in myopts): |
| favorites=portage.mtimedb["resume"]["favorites"] |
| mydepgraph.merge(portage.mtimedb["resume"]["mergelist"]) |
| else: |
| if "resume" in portage.mtimedb and \ |
| "mergelist" in portage.mtimedb["resume"] and \ |
| len(portage.mtimedb["resume"]["mergelist"]) > 1: |
| portage.mtimedb["resume_backup"] = portage.mtimedb["resume"] |
| del portage.mtimedb["resume"] |
| portage.commit_mtimedb() |
| portage.mtimedb["resume"]={} |
| portage.mtimedb["resume"]["myopts"]=myopts |
| portage.mtimedb["resume"]["favorites"]=favorites |
| if ("--digest" in myopts) and not ("--fetchonly" in myopts or "--fetch-all-uri" in myopts): |
| for pkgline in mydepgraph.altlist(): |
| if pkgline[0]=="ebuild" and pkgline[3]=="merge": |
| y=portage.portdb.findname(pkgline[2]) |
| tmpsettings = portage.config(clone=portage.settings) |
| retval=portage.doebuild(y,"digest",portage.root,tmpsettings,edebug,("--pretend" in myopts),tree="porttree") |
| if "--fetchonly" in myopts or "--fetch-all-uri" in myopts: |
| pkglist = [] |
| for pkg in mydepgraph.altlist(): |
| if pkg[0] != "blocks": |
| pkglist.append(pkg) |
| else: |
| pkglist = mydepgraph.altlist() |
| mydepgraph.merge(pkglist) |
| |
| if portage.mtimedb.has_key("resume"): |
| del portage.mtimedb["resume"] |
| if portage.settings["AUTOCLEAN"] and "yes"==portage.settings["AUTOCLEAN"]: |
| print ">>> Auto-cleaning packages..." |
| unmerge("clean", ["world"]) |
| post_emerge() |