diff options
-rw-r--r-- | pym/portage.py.orig | 7427 |
1 files changed, 0 insertions, 7427 deletions
diff --git a/pym/portage.py.orig b/pym/portage.py.orig deleted file mode 100644 index 8868782db..000000000 --- a/pym/portage.py.orig +++ /dev/null @@ -1,7427 +0,0 @@ -# portage.py -- core Portage functionality -# Copyright 1998-2004 Gentoo Foundation -# Distributed under the terms of the GNU General Public License v2 -# $Id: /var/cvsroot/gentoo-src/portage/pym/portage.py,v 1.524.2.59 2005/04/23 07:26:04 jstubbs Exp $ -cvs_id_string="$Id: portage.py,v 1.524.2.59 2005/04/23 07:26:04 jstubbs Exp $"[5:-2] - -VERSION="$Revision: 1.524.2.59 $"[11:-2] + "-cvs" - -# =========================================================================== -# START OF IMPORTS -- START OF IMPORTS -- START OF IMPORTS -- START OF IMPORT -# =========================================================================== - -try: - import sys -except SystemExit, e: - raise -except: - print "Failed to import sys! Something is _VERY_ wrong with python." - raise SystemExit, 127 - -try: - import os,string,types,atexit,signal,fcntl - import time,cPickle,traceback,copy - import re,pwd,grp,commands - import shlex,shutil - - import stat - import commands - from time import sleep - from random import shuffle -except SystemExit, e: - raise -except Exception, e: - sys.stderr.write("\n\n") - sys.stderr.write("!!! Failed to complete python imports. There are internal modules for\n") - sys.stderr.write("!!! python and failure here indicates that you have a problem with python\n") - sys.stderr.write("!!! itself and thus portage is no able to continue processing.\n\n") - - sys.stderr.write("!!! You might consider starting python with verbose flags to see what has\n") - sys.stderr.write("!!! gone wrong. Here is the information we got for this exception:\n") - - sys.stderr.write(" "+str(e)+"\n\n"); - sys.exit(127) -except: - sys.stderr.write("\n\n") - sys.stderr.write("!!! Failed to complete python imports. There are internal modules for\n") - sys.stderr.write("!!! python and failure here indicates that you have a problem with python\n") - sys.stderr.write("!!! itself and thus portage is no able to continue processing.\n\n") - - sys.stderr.write("!!! You might consider starting python with verbose flags to see what has\n") - sys.stderr.write("!!! gone wrong. The exception was non-standard and we were unable to catch it.\n\n") - sys.exit(127) - -try: - # XXX: This should get renamed to bsd_chflags, I think. - import chflags - bsd_chflags = chflags -except SystemExit, e: - raise -except: - # XXX: This should get renamed to bsd_chflags, I think. - bsd_chflags = None - -try: - import cvstree - import xpak - import getbinpkg - import portage_dep - - # XXX: This needs to get cleaned up. - import output - from output import blue, bold, brown, darkblue, darkgreen, darkred, darkteal, \ - darkyellow, fuchsia, fuscia, green, purple, red, teal, turquoise, white, \ - xtermTitle, xtermTitleReset, yellow - - import portage_const - from portage_const import VDB_PATH, PRIVATE_PATH, CACHE_PATH, DEPCACHE_PATH, \ - USER_CONFIG_PATH, MODULES_FILE_PATH, CUSTOM_PROFILE_PATH, PORTAGE_BASE_PATH, \ - PORTAGE_BIN_PATH, PORTAGE_PYM_PATH, PROFILE_PATH, LOCALE_DATA_PATH, \ - EBUILD_SH_BINARY, SANDBOX_BINARY, DEPSCAN_SH_BINARY, BASH_BINARY, \ - MOVE_BINARY, PRELINK_BINARY, WORLD_FILE, MAKE_CONF_FILE, MAKE_DEFAULTS_FILE, \ - DEPRECATED_PROFILE_FILE, USER_VIRTUALS_FILE, EBUILD_SH_ENV_FILE, \ - INVALID_ENV_FILE, CUSTOM_MIRRORS_FILE, SANDBOX_PIDS_FILE, CONFIG_MEMORY_FILE,\ - INCREMENTALS, STICKIES - - from portage_data import ostype, lchown, userland, secpass, uid, wheelgid, \ - portage_uid, portage_gid - - import portage_util - from portage_util import grab_multiple, grabdict, grabdict_package, grabfile, grabfile_package, \ - grabints, map_dictlist_vals, pickle_read, pickle_write, stack_dictlist, stack_dicts, stack_lists, \ - unique_array, varexpand, writedict, writeints, writemsg, getconfig - import portage_exception - import portage_gpg - import portage_locks - import portage_exec - from portage_locks import unlockfile,unlockdir,lockfile,lockdir - import portage_checksum - from portage_checksum import perform_md5,perform_checksum,prelink_capable - from portage_localization import _ -except SystemExit, e: - raise -except Exception, e: - sys.stderr.write("\n\n") - sys.stderr.write("!!! Failed to complete portage imports. There are internal modules for\n") - sys.stderr.write("!!! portage and failure here indicates that you have a problem with your\n") - sys.stderr.write("!!! installation of portage. Please try a rescue portage located in the\n") - sys.stderr.write("!!! portage tree under '/usr/portage/sys-apps/portage/files/' (default).\n") - sys.stderr.write("!!! There is a README.RESCUE file that details the steps required to perform\n") - sys.stderr.write("!!! a recovery of portage.\n") - - sys.stderr.write(" "+str(e)+"\n\n") - sys.exit(127) - - -# =========================================================================== -# END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END OF IMPORTS -- END -# =========================================================================== - - -def exithandler(signum,frame): - """Handles ^C interrupts in a sane manner""" - signal.signal(signal.SIGINT, signal.SIG_IGN) - signal.signal(signal.SIGTERM, signal.SIG_IGN) - - # 0=send to *everybody* in process group - portageexit() - print "Exiting due to signal" - os.kill(0,signum) - sys.exit(1) - -signal.signal(signal.SIGCHLD, signal.SIG_DFL) -signal.signal(signal.SIGINT, exithandler) -signal.signal(signal.SIGTERM, exithandler) -signal.signal(signal.SIGPIPE, signal.SIG_DFL) - -def load_mod(name): - modname = string.join(string.split(name,".")[:-1],".") - mod = __import__(modname) - components = name.split('.') - for comp in components[1:]: - mod = getattr(mod, comp) - return mod - -def best_from_dict(key, top_dict, key_order, EmptyOnError=1, FullCopy=1, AllowEmpty=1): - for x in key_order: - if top_dict.has_key(x) and top_dict[x].has_key(key): - if FullCopy: - return copy.deepcopy(top_dict[x][key]) - else: - return top_dict[x][key] - if EmptyOnError: - return "" - else: - raise KeyError, "Key not found in list; '%s'" % key - -def getcwd(): - "this fixes situations where the current directory doesn't exist" - try: - return os.getcwd() - except SystemExit, e: - raise - except: - os.chdir("/") - return "/" -getcwd() - -def abssymlink(symlink): - "This reads symlinks, resolving the relative symlinks, and returning the absolute." - mylink=os.readlink(symlink) - if mylink[0] != '/': - mydir=os.path.dirname(symlink) - mylink=mydir+"/"+mylink - return os.path.normpath(mylink) - -def suffix_array(array,suffix,doblanks=1): - """Appends a given suffix to each element in an Array/List/Tuple. - Returns a List.""" - if type(array) not in [types.ListType, types.TupleType]: - raise TypeError, "List or Tuple expected. Got %s" % type(array) - newarray=[] - for x in array: - if x or doblanks: - newarray.append(x + suffix) - else: - newarray.append(x) - return newarray - -def prefix_array(array,prefix,doblanks=1): - """Prepends a given prefix to each element in an Array/List/Tuple. - Returns a List.""" - if type(array) not in [types.ListType, types.TupleType]: - raise TypeError, "List or Tuple expected. Got %s" % type(array) - newarray=[] - for x in array: - if x or doblanks: - newarray.append(prefix + x) - else: - newarray.append(x) - return newarray - -def normalize_path(mypath): - newpath = os.path.normpath(mypath) - if len(newpath) > 1: - if newpath[:2] == "//": - newpath = newpath[1:] - return newpath - -dircache = {} -cacheHit=0 -cacheMiss=0 -cacheStale=0 -def cacheddir(my_original_path, ignorecvs, ignorelist, EmptyOnError, followSymlinks=True): - global cacheHit,cacheMiss,cacheStale - mypath = normalize_path(my_original_path) - if dircache.has_key(mypath): - cacheHit += 1 - cached_mtime, list, ftype = dircache[mypath] - else: - cacheMiss += 1 - cached_mtime, list, ftype = -1, [], [] - try: - pathstat = os.stat(mypath) - if stat.S_ISDIR(pathstat[stat.ST_MODE]): - mtime = pathstat[stat.ST_MTIME] - else: - raise Exception - except SystemExit, e: - raise - except: - if EmptyOnError: - return [], [] - return None, None - if mtime != cached_mtime: - if dircache.has_key(mypath): - cacheStale += 1 - list = os.listdir(mypath) - ftype = [] - for x in list: - try: - if followSymlinks: - pathstat = os.stat(mypath+"/"+x) - else: - pathstat = os.lstat(mypath+"/"+x) - - if stat.S_ISREG(pathstat[stat.ST_MODE]): - ftype.append(0) - elif stat.S_ISDIR(pathstat[stat.ST_MODE]): - ftype.append(1) - elif stat.S_ISLNK(pathstat[stat.ST_MODE]): - ftype.append(2) - else: - ftype.append(3) - except SystemExit, e: - raise - except: - ftype.append(3) - dircache[mypath] = mtime, list, ftype - - ret_list = [] - ret_ftype = [] - for x in range(0, len(list)): - if(ignorecvs and (len(list[x]) > 2) and (list[x][:2]!=".#")): - ret_list.append(list[x]) - ret_ftype.append(ftype[x]) - elif (list[x] not in ignorelist): - ret_list.append(list[x]) - ret_ftype.append(ftype[x]) - - writemsg("cacheddirStats: H:%d/M:%d/S:%d\n" % (cacheHit, cacheMiss, cacheStale),10) - return ret_list, ret_ftype - - -def listdir(mypath, recursive=False, filesonly=False, ignorecvs=False, ignorelist=[], followSymlinks=True, - EmptyOnError=False): - - list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks) - - if list is None: - list=[] - if ftype is None: - ftype=[] - - if not filesonly and not recursive: - return list - - if recursive: - x=0 - while x<len(ftype): - if ftype[x]==1 and not (ignorecvs and os.path.basename(list[x]) in ('CVS','.svn')): - l,f = cacheddir(mypath+"/"+list[x], ignorecvs, ignorelist, EmptyOnError, - followSymlinks) - - l=l[:] - for y in range(0,len(l)): - l[y]=list[x]+"/"+l[y] - list=list+l - ftype=ftype+f - x+=1 - if filesonly: - rlist=[] - for x in range(0,len(ftype)): - if ftype[x]==0: - rlist=rlist+[list[x]] - else: - rlist=list - - return rlist - -starttime=long(time.time()) -features=[] - -def tokenize(mystring): - """breaks a string like 'foo? (bar) oni? (blah (blah))' - into embedded lists; returns None on paren mismatch""" - - # This function is obsoleted. - # Use dep_parenreduce - - newtokens=[] - curlist=newtokens - prevlists=[] - level=0 - accum="" - for x in mystring: - if x=="(": - if accum: - curlist.append(accum) - accum="" - prevlists.append(curlist) - curlist=[] - level=level+1 - elif x==")": - if accum: - curlist.append(accum) - accum="" - if level==0: - writemsg("!!! tokenizer: Unmatched left parenthesis in:\n'"+str(mystring)+"'\n") - return None - newlist=curlist - curlist=prevlists.pop() - curlist.append(newlist) - level=level-1 - elif x in string.whitespace: - if accum: - curlist.append(accum) - accum="" - else: - accum=accum+x - if accum: - curlist.append(accum) - if (level!=0): - writemsg("!!! tokenizer: Exiting with unterminated parenthesis in:\n'"+str(mystring)+"'\n") - return None - return newtokens - -def flatten(mytokens): - """this function now turns a [1,[2,3]] list into - a [1,2,3] list and returns it.""" - newlist=[] - for x in mytokens: - if type(x)==types.ListType: - newlist.extend(flatten(x)) - else: - newlist.append(x) - return newlist - -#beautiful directed graph object - -class digraph: - def __init__(self): - self.dict={} - #okeys = keys, in order they were added (to optimize firstzero() ordering) - self.okeys=[] - - def addnode(self,mykey,myparent): - if not self.dict.has_key(mykey): - self.okeys.append(mykey) - if myparent==None: - self.dict[mykey]=[0,[]] - else: - self.dict[mykey]=[0,[myparent]] - self.dict[myparent][0]=self.dict[myparent][0]+1 - return - if myparent and (not myparent in self.dict[mykey][1]): - self.dict[mykey][1].append(myparent) - self.dict[myparent][0]=self.dict[myparent][0]+1 - - def delnode(self,mykey): - if not self.dict.has_key(mykey): - return - for x in self.dict[mykey][1]: - self.dict[x][0]=self.dict[x][0]-1 - del self.dict[mykey] - while 1: - try: - self.okeys.remove(mykey) - except ValueError: - break - - def allnodes(self): - "returns all nodes in the dictionary" - return self.dict.keys() - - def firstzero(self): - "returns first node with zero references, or NULL if no such node exists" - for x in self.okeys: - if self.dict[x][0]==0: - return x - return None - - def depth(self, mykey): - depth=0 - while (self.dict[mykey][1]): - depth=depth+1 - mykey=self.dict[mykey][1][0] - return depth - - def allzeros(self): - "returns all nodes with zero references, or NULL if no such node exists" - zerolist = [] - for x in self.dict.keys(): - mys = string.split(x) - if mys[0] != "blocks" and self.dict[x][0]==0: - zerolist.append(x) - return zerolist - - def hasallzeros(self): - "returns 0/1, Are all nodes zeros? 1 : 0" - zerolist = [] - for x in self.dict.keys(): - if self.dict[x][0]!=0: - return 0 - return 1 - - def empty(self): - if len(self.dict)==0: - return 1 - return 0 - - def hasnode(self,mynode): - return self.dict.has_key(mynode) - - def copy(self): - mygraph=digraph() - for x in self.dict.keys(): - mygraph.dict[x]=self.dict[x][:] - mygraph.okeys=self.okeys[:] - return mygraph - -# valid end of version components; integers specify offset from release version -# pre=prerelease, p=patchlevel (should always be followed by an int), rc=release candidate -# all but _p (where it is required) can be followed by an optional trailing integer - -endversion={"pre":-2,"p":0,"alpha":-4,"beta":-3,"rc":-1} -# as there's no reliable way to set {}.keys() order -# netversion_keys will be used instead of endversion.keys -# to have fixed search order, so that "pre" is checked -# before "p" -endversion_keys = ["pre", "p", "alpha", "beta", "rc"] - -#parse /etc/env.d and generate /etc/profile.env - -def env_update(makelinks=1): - global root - if not os.path.exists(root+"etc/env.d"): - prevmask=os.umask(0) - os.makedirs(root+"etc/env.d",0755) - os.umask(prevmask) - fns=listdir(root+"etc/env.d",EmptyOnError=1) - fns.sort() - pos=0 - while (pos<len(fns)): - if len(fns[pos])<=2: - del fns[pos] - continue - if (fns[pos][0] not in string.digits) or (fns[pos][1] not in string.digits): - del fns[pos] - continue - pos=pos+1 - - specials={ - "KDEDIRS":[],"PATH":[],"CLASSPATH":[],"LDPATH":[],"MANPATH":[], - "INFODIR":[],"INFOPATH":[],"ROOTPATH":[],"CONFIG_PROTECT":[], - "CONFIG_PROTECT_MASK":[],"PRELINK_PATH":[],"PRELINK_PATH_MASK":[], - "PYTHONPATH":[], "ADA_INCLUDE_PATH":[], "ADA_OBJECTS_PATH":[] - } - colon_separated = [ - "ADA_INCLUDE_PATH", "ADA_OBJECTS_PATH", - "LDPATH", "MANPATH", - "PATH", "PRELINK_PATH", - "PRELINK_PATH_MASK", "PYTHON_PATH" - ] - - env={} - - for x in fns: - # don't process backup files - if x[-1]=='~' or x[-4:]==".bak": - continue - myconfig=getconfig(root+"etc/env.d/"+x) - if myconfig==None: - writemsg("!!! Parsing error in "+str(root)+"etc/env.d/"+str(x)+"\n") - #parse error - continue - # process PATH, CLASSPATH, LDPATH - for myspec in specials.keys(): - if myconfig.has_key(myspec): - if myspec in colon_separated: - specials[myspec].extend(string.split(varexpand(myconfig[myspec]),":")) - else: - specials[myspec].append(varexpand(myconfig[myspec])) - del myconfig[myspec] - # process all other variables - for myenv in myconfig.keys(): - env[myenv]=varexpand(myconfig[myenv]) - - if os.path.exists(root+"etc/ld.so.conf"): - myld=open(root+"etc/ld.so.conf") - myldlines=myld.readlines() - myld.close() - oldld=[] - for x in myldlines: - #each line has at least one char (a newline) - if x[0]=="#": - continue - oldld.append(x[:-1]) - # os.rename(root+"etc/ld.so.conf",root+"etc/ld.so.conf.bak") - # Where is the new ld.so.conf generated? (achim) - else: - oldld=None - - ld_cache_update=False - if os.environ.has_key("PORTAGE_CALLER") and \ - os.environ["PORTAGE_CALLER"] == "env-update": - ld_cache_update = True - - newld=specials["LDPATH"] - if (oldld!=newld): - #ld.so.conf needs updating and ldconfig needs to be run - myfd=open(root+"etc/ld.so.conf","w") - myfd.write("# ld.so.conf autogenerated by env-update; make all changes to\n") - myfd.write("# contents of /etc/env.d directory\n") - for x in specials["LDPATH"]: - myfd.write(x+"\n") - myfd.close() - ld_cache_update=True - - # Update prelink.conf if we are prelink-enabled - if prelink_capable: - newprelink=open(root+"etc/prelink.conf","w") - newprelink.write("# prelink.conf autogenerated by env-update; make all changes to\n") - newprelink.write("# contents of /etc/env.d directory\n") - - for x in ["/bin","/sbin","/usr/bin","/usr/sbin","/lib","/usr/lib"]: - newprelink.write("-l "+x+"\n"); - for x in specials["LDPATH"]+specials["PATH"]+specials["PRELINK_PATH"]: - if not x: - continue - if x[-1]!='/': - x=x+"/" - plmasked=0 - for y in specials["PRELINK_PATH_MASK"]: - if not y: - continue - if y[-1]!='/': - y=y+"/" - if y==x[0:len(y)]: - plmasked=1 - break - if not plmasked: - newprelink.write("-h "+x+"\n") - for x in specials["PRELINK_PATH_MASK"]: - newprelink.write("-b "+x+"\n") - newprelink.close() - - if not mtimedb.has_key("ldpath"): - mtimedb["ldpath"]={} - - for x in specials["LDPATH"]+['/usr/lib','/lib']: - try: - newldpathtime=os.stat(x)[stat.ST_MTIME] - except SystemExit, e: - raise - except: - newldpathtime=0 - if mtimedb["ldpath"].has_key(x): - if mtimedb["ldpath"][x]==newldpathtime: - pass - else: - mtimedb["ldpath"][x]=newldpathtime - ld_cache_update=True - else: - mtimedb["ldpath"][x]=newldpathtime - ld_cache_update=True - - if (ld_cache_update or makelinks): - # We can't update links if we haven't cleaned other versions first, as - # an older package installed ON TOP of a newer version will cause ldconfig - # to overwrite the symlinks we just made. -X means no links. After 'clean' - # we can safely create links. - writemsg(">>> Regenerating "+str(root)+"etc/ld.so.cache...\n") - if makelinks: - commands.getstatusoutput("cd / ; /sbin/ldconfig -r "+root) - else: - commands.getstatusoutput("cd / ; /sbin/ldconfig -X -r "+root) - - del specials["LDPATH"] - - penvnotice = "# THIS FILE IS AUTOMATICALLY GENERATED BY env-update.\n" - penvnotice += "# DO NOT EDIT THIS FILE. CHANGES TO STARTUP PROFILES\n" - cenvnotice = penvnotice[:] - penvnotice += "# GO INTO /etc/profile NOT /etc/profile.env\n\n" - cenvnotice += "# GO INTO /etc/csh.cshrc NOT /etc/csh.env\n\n" - - #create /etc/profile.env for bash support - outfile=open(root+"/etc/profile.env","w") - outfile.write(penvnotice) - - for path in specials.keys(): - if len(specials[path])==0: - continue - outstring="export "+path+"='" - if path in ["CONFIG_PROTECT","CONFIG_PROTECT_MASK"]: - for x in specials[path][:-1]: - outstring += x+" " - else: - for x in specials[path][:-1]: - outstring=outstring+x+":" - outstring=outstring+specials[path][-1]+"'" - outfile.write(outstring+"\n") - - #create /etc/profile.env - for x in env.keys(): - if type(env[x])!=types.StringType: - continue - outfile.write("export "+x+"='"+env[x]+"'\n") - outfile.close() - - #create /etc/csh.env for (t)csh support - outfile=open(root+"/etc/csh.env","w") - outfile.write(cenvnotice) - - for path in specials.keys(): - if len(specials[path])==0: - continue - outstring="setenv "+path+" '" - if path in ["CONFIG_PROTECT","CONFIG_PROTECT_MASK"]: - for x in specials[path][:-1]: - outstring += x+" " - else: - for x in specials[path][:-1]: - outstring=outstring+x+":" - outstring=outstring+specials[path][-1]+"'" - outfile.write(outstring+"\n") - #get it out of the way - del specials[path] - - #create /etc/csh.env - for x in env.keys(): - if type(env[x])!=types.StringType: - continue - outfile.write("setenv "+x+" '"+env[x]+"'\n") - outfile.close() - if os.path.exists(DEPSCAN_SH_BINARY): - spawn(DEPSCAN_SH_BINARY,settings,free=1) - -def new_protect_filename(mydest, newmd5=None): - """Resolves a config-protect filename for merging, optionally - using the last filename if the md5 matches. - (dest,md5) ==> 'string' --- path_to_target_filename - (dest) ==> ('next', 'highest') --- next_target and most-recent_target - """ - - # config protection filename format: - # ._cfg0000_foo - # 0123456789012 - prot_num=-1 - last_pfile="" - - if (len(mydest) == 0): - raise ValueError, "Empty path provided where a filename is required" - if (mydest[-1]=="/"): # XXX add better directory checking - raise ValueError, "Directory provided but this function requires a filename" - if not os.path.exists(mydest): - return mydest - - real_filename = os.path.basename(mydest) - real_dirname = os.path.dirname(mydest) - for pfile in listdir(real_dirname): - if pfile[0:5] != "._cfg": - continue - if pfile[10:] != real_filename: - continue - try: - new_prot_num = int(pfile[5:9]) - if new_prot_num > prot_num: - prot_num = new_prot_num - last_pfile = pfile - except SystemExit, e: - raise - except: - continue - prot_num = prot_num + 1 - - new_pfile = os.path.normpath(real_dirname+"/._cfg"+string.zfill(prot_num,4)+"_"+real_filename) - old_pfile = os.path.normpath(real_dirname+"/"+last_pfile) - if last_pfile and newmd5: - if portage_checksum.perform_md5(real_dirname+"/"+last_pfile) == newmd5: - return old_pfile - else: - return new_pfile - elif newmd5: - return new_pfile - else: - return (new_pfile, old_pfile) - -#XXX: These two are now implemented in portage_util.py but are needed here -#XXX: until the isvalidatom() dependency is sorted out. - -def grabdict_package(myfilename,juststrings=0): - pkgs=grabdict(myfilename, juststrings=juststrings, empty=1) - for x in pkgs.keys(): - if not isvalidatom(x): - del(pkgs[x]) - writemsg("--- Invalid atom in %s: %s\n" % (myfilename, x)) - return pkgs - -def grabfile_package(myfilename,compatlevel=0): - pkgs=grabfile(myfilename,compatlevel) - for x in range(len(pkgs)-1,-1,-1): - pkg = pkgs[x] - if pkg[0] == "-": - pkg = pkg[1:] - if pkg[0] == "*": - pkg = pkg[1:] - if not isvalidatom(pkg): - writemsg("--- Invalid atom in %s: %s\n" % (myfilename, pkgs[x])) - del(pkgs[x]) - return pkgs - -# returns a tuple. (version[string], error[string]) -# They are pretty much mutually exclusive. -# Either version is a string and error is none, or -# version is None and error is a string -# -def ExtractKernelVersion(base_dir): - lines = [] - pathname = os.path.join(base_dir, 'Makefile') - try: - f = open(pathname, 'r') - except OSError, details: - return (None, str(details)) - except IOError, details: - return (None, str(details)) - - try: - for i in range(4): - lines.append(f.readline()) - except OSError, details: - return (None, str(details)) - except IOError, details: - return (None, str(details)) - - lines = map(string.strip, lines) - - version = '' - - #XXX: The following code relies on the ordering of vars within the Makefile - for line in lines: - # split on the '=' then remove annoying whitespace - items = string.split(line, '=') - items = map(string.strip, items) - if items[0] == 'VERSION' or \ - items[0] == 'PATCHLEVEL': - version += items[1] - version += "." - elif items[0] == 'SUBLEVEL': - version += items[1] - elif items[0] == 'EXTRAVERSION' and \ - items[-1] != items[0]: - version += items[1] - - # Grab a list of files named localversion* and sort them - localversions = os.listdir(base_dir) - for x in range(len(localversions)-1,-1,-1): - if localversions[x][:12] != "localversion": - del localversions[x] - localversions.sort() - - # Append the contents of each to the version string, stripping ALL whitespace - for lv in localversions: - version += string.join(string.split(string.join(grabfile(base_dir+"/"+lv))), "") - - # Check the .config for a CONFIG_LOCALVERSION and append that too, also stripping whitespace - kernelconfig = getconfig(base_dir+"/.config") - if kernelconfig and kernelconfig.has_key("CONFIG_LOCALVERSION"): - version += string.join(string.split(kernelconfig["CONFIG_LOCALVERSION"]), "") - - return (version,None) - - -autouse_val = None -def autouse(myvartree,use_cache=1): - "returns set of USE variables auto-enabled due to packages being installed" - global usedefaults, autouse_val - if autouse_val is not None: - return autouse_val - if profiledir==None: - autouse_val = "" - return "" - myusevars="" - for myuse in usedefaults: - dep_met = True - for mydep in usedefaults[myuse]: - if not myvartree.dep_match(mydep,use_cache=True): - dep_met = False - break - if dep_met: - myusevars += " "+myuse - autouse_val = myusevars - return myusevars - -def check_config_instance(test): - if not test or (str(test.__class__) != 'portage.config'): - raise TypeError, "Invalid type for config object: %s" % test.__class__ - -class config: - def __init__(self, clone=None, mycpv=None, config_profile_path=None, config_incrementals=None): - - self.already_in_regenerate = 0 - - self.locked = 0 - self.mycpv = None - self.puse = [] - self.modifiedkeys = [] - - self.virtuals = {} - self.v_count = 0 - - # Virtuals obtained from the vartree - self.treeVirtuals = {} - # Virtuals by user specification. Includes negatives. - self.userVirtuals = {} - # Virtual negatives from user specifications. - self.negVirtuals = {} - - self.user_profile_dir = None - - if clone: - self.incrementals = copy.deepcopy(clone.incrementals) - self.profile_path = copy.deepcopy(clone.profile_path) - self.user_profile_dir = copy.deepcopy(clone.user_profile_dir) - - self.module_priority = copy.deepcopy(clone.module_priority) - self.modules = copy.deepcopy(clone.modules) - - self.depcachedir = copy.deepcopy(clone.depcachedir) - - self.packages = copy.deepcopy(clone.packages) - self.virtuals = copy.deepcopy(clone.virtuals) - - self.treeVirtuals = copy.deepcopy(clone.treeVirtuals) - self.userVirtuals = copy.deepcopy(clone.userVirtuals) - self.negVirtuals = copy.deepcopy(clone.negVirtuals) - - self.use_defs = copy.deepcopy(clone.use_defs) - self.usemask = copy.deepcopy(clone.usemask) - - self.configlist = copy.deepcopy(clone.configlist) - self.configlist[-1] = os.environ.copy() - self.configdict = { "globals": self.configlist[0], - "defaults": self.configlist[1], - "conf": self.configlist[2], - "pkg": self.configlist[3], - "auto": self.configlist[4], - "backupenv": self.configlist[5], - "env": self.configlist[6] } - self.profiles = copy.deepcopy(clone.profiles) - self.backupenv = copy.deepcopy(clone.backupenv) - self.pusedict = copy.deepcopy(clone.pusedict) - self.categories = copy.deepcopy(clone.categories) - self.pkeywordsdict = copy.deepcopy(clone.pkeywordsdict) - self.pmaskdict = copy.deepcopy(clone.pmaskdict) - self.punmaskdict = copy.deepcopy(clone.punmaskdict) - self.prevmaskdict = copy.deepcopy(clone.prevmaskdict) - self.pprovideddict = copy.deepcopy(clone.pprovideddict) - self.lookuplist = copy.deepcopy(clone.lookuplist) - self.uvlist = copy.deepcopy(clone.uvlist) - self.dirVirtuals = copy.deepcopy(clone.dirVirtuals) - self.treeVirtuals = copy.deepcopy(clone.treeVirtuals) - else: - self.depcachedir = DEPCACHE_PATH - - if not config_profile_path: - global profiledir - writemsg("config_profile_path not specified to class config\n") - self.profile_path = profiledir[:] - else: - self.profile_path = config_profile_path[:] - - if not config_incrementals: - writemsg("incrementals not specified to class config\n") - self.incrementals = copy.deepcopy(portage_const.INCREMENTALS) - else: - self.incrementals = copy.deepcopy(config_incrementals) - - self.module_priority = ["user","default"] - self.modules = {} - self.modules["user"] = getconfig(MODULES_FILE_PATH) - if self.modules["user"] == None: - self.modules["user"] = {} - self.modules["default"] = { - "portdbapi.metadbmodule": "portage_db_flat.database", - "portdbapi.auxdbmodule": "portage_db_flat.database", - "eclass_cache.dbmodule": "portage_db_cpickle.database", - } - - self.usemask=[] - self.configlist=[] - self.backupenv={} - # back up our incremental variables: - self.configdict={} - # configlist will contain: [ globals, defaults, conf, pkg, auto, backupenv (incrementals), origenv ] - - # The symlink might not exist or might not be a symlink. - try: - self.profiles=[abssymlink(self.profile_path)] - except SystemExit, e: - raise - except: - self.profiles=[self.profile_path] - - mypath = self.profiles[0] - while os.path.exists(mypath+"/parent"): - mypath = os.path.normpath(mypath+"///"+grabfile(mypath+"/parent")[0]) - if os.path.exists(mypath): - self.profiles.insert(0,mypath) - - if os.environ.has_key("PORTAGE_CALLER") and os.environ["PORTAGE_CALLER"] == "repoman": - pass - else: - # XXX: This should depend on ROOT? - if os.path.exists("/"+CUSTOM_PROFILE_PATH): - self.user_profile_dir = os.path.normpath("/"+"///"+CUSTOM_PROFILE_PATH) - self.profiles.append(self.user_profile_dir[:]) - - self.packages_list = grab_multiple("packages", self.profiles, grabfile_package) - self.packages = stack_lists(self.packages_list, incremental=1) - del self.packages_list - #self.packages = grab_stacked("packages", self.profiles, grabfile, incremental_lines=1) - - # revmaskdict - self.prevmaskdict={} - for x in self.packages: - mycatpkg=dep_getkey(x) - if not self.prevmaskdict.has_key(mycatpkg): - self.prevmaskdict[mycatpkg]=[x] - else: - self.prevmaskdict[mycatpkg].append(x) - - # get profile-masked use flags -- INCREMENTAL Child over parent - usemask_lists = grab_multiple("use.mask", self.profiles, grabfile) - self.usemask = stack_lists(usemask_lists, incremental=True) - del usemask_lists - use_defs_lists = grab_multiple("use.defaults", self.profiles, grabdict) - self.use_defs = stack_dictlist(use_defs_lists, incremental=True) - del use_defs_lists - - try: - mygcfg_dlists = grab_multiple("make.globals", self.profiles+["/etc"], getconfig) - self.mygcfg = stack_dicts(mygcfg_dlists, incrementals=portage_const.INCREMENTALS, ignore_none=1) - - if self.mygcfg == None: - self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - writemsg("!!! %s\n" % (e)) - writemsg("!!! Incorrect multiline literals can cause this. Do not use them.\n") - writemsg("!!! Errors in this file should be reported on bugs.gentoo.org.\n") - sys.exit(1) - self.configlist.append(self.mygcfg) - self.configdict["globals"]=self.configlist[-1] - - self.mygcfg = {} - if self.profiles: - try: - mygcfg_dlists = grab_multiple("make.defaults", self.profiles, getconfig) - self.mygcfg = stack_dicts(mygcfg_dlists, incrementals=portage_const.INCREMENTALS, ignore_none=1) - #self.mygcfg = grab_stacked("make.defaults", self.profiles, getconfig) - if self.mygcfg == None: - self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - writemsg("!!! %s\n" % (e)) - writemsg("!!! 'rm -Rf /usr/portage/profiles; emerge sync' may fix this. If it does\n") - writemsg("!!! not then please report this to bugs.gentoo.org and, if possible, a dev\n") - writemsg("!!! on #gentoo (irc.freenode.org)\n") - sys.exit(1) - self.configlist.append(self.mygcfg) - self.configdict["defaults"]=self.configlist[-1] - - try: - # XXX: Should depend on root? - self.mygcfg=getconfig("/"+MAKE_CONF_FILE,allow_sourcing=True) - if self.mygcfg == None: - self.mygcfg = {} - except SystemExit, e: - raise - except Exception, e: - writemsg("!!! %s\n" % (e)) - writemsg("!!! Incorrect multiline literals can cause this. Do not use them.\n") - sys.exit(1) - - - self.configlist.append(self.mygcfg) - self.configdict["conf"]=self.configlist[-1] - - self.configlist.append({}) - self.configdict["pkg"]=self.configlist[-1] - - #auto-use: - self.configlist.append({}) - self.configdict["auto"]=self.configlist[-1] - - #backup-env (for recording our calculated incremental variables:) - self.backupenv = os.environ.copy() - self.configlist.append(self.backupenv) # XXX Why though? - self.configdict["backupenv"]=self.configlist[-1] - - self.configlist.append(os.environ.copy()) - self.configdict["env"]=self.configlist[-1] - - - # make lookuplist for loading package.* - self.lookuplist=self.configlist[:] - self.lookuplist.reverse() - - archlist = grabfile(self["PORTDIR"]+"/profiles/arch.list") - self.configdict["conf"]["PORTAGE_ARCHLIST"] = string.join(archlist) - - if os.environ.get("PORTAGE_CALLER","") == "repoman": - # repoman shouldn't use local settings. - locations = [self["PORTDIR"] + "/profiles"] - self.pusedict = {} - self.pkeywordsdict = {} - self.punmaskdict = {} - else: - locations = [self["PORTDIR"] + "/profiles", USER_CONFIG_PATH] - - pusedict=grabdict_package(USER_CONFIG_PATH+"/package.use") - self.pusedict = {} - for key in pusedict.keys(): - cp = dep_getkey(key) - if not self.pusedict.has_key(cp): - self.pusedict[cp] = {} - self.pusedict[cp][key] = pusedict[key] - - #package.keywords - pkgdict=grabdict_package(USER_CONFIG_PATH+"/package.keywords") - self.pkeywordsdict = {} - for key in pkgdict.keys(): - # default to ~arch if no specific keyword is given - if not pkgdict[key]: - mykeywordlist = [] - if self.configdict["defaults"] and self.configdict["defaults"].has_key("ACCEPT_KEYWORDS"): - groups = self.configdict["defaults"]["ACCEPT_KEYWORDS"].split() - else: - groups = [] - for keyword in groups: - if not keyword[0] in "~-": - mykeywordlist.append("~"+keyword) - pkgdict[key] = mykeywordlist - cp = dep_getkey(key) - if not self.pkeywordsdict.has_key(cp): - self.pkeywordsdict[cp] = {} - self.pkeywordsdict[cp][key] = pkgdict[key] - - #package.unmask - pkgunmasklines = grabfile_package(USER_CONFIG_PATH+"/package.unmask") - self.punmaskdict = {} - for x in pkgunmasklines: - mycatpkg=dep_getkey(x) - if self.punmaskdict.has_key(mycatpkg): - self.punmaskdict[mycatpkg].append(x) - else: - self.punmaskdict[mycatpkg]=[x] - - #getting categories from an external file now - categories = grab_multiple("categories", locations, grabfile) - self.categories = stack_lists(categories, incremental=1) - del categories - - # get virtuals -- needs categories - self.loadVirtuals('/') - - #package.mask - pkgmasklines = grab_multiple("package.mask", self.profiles + locations, grabfile_package) - pkgmasklines = stack_lists(pkgmasklines, incremental=1) - - self.pmaskdict = {} - for x in pkgmasklines: - mycatpkg=dep_getkey(x) - if self.pmaskdict.has_key(mycatpkg): - self.pmaskdict[mycatpkg].append(x) - else: - self.pmaskdict[mycatpkg]=[x] - - pkgprovidedlines = grab_multiple("package.provided", self.profiles, grabfile) - pkgprovidedlines = stack_lists(pkgprovidedlines, incremental=1) - for x in range(len(pkgprovidedlines)-1, -1, -1): - cpvr = catpkgsplit(pkgprovidedlines[x]) - if not cpvr or cpvr[0] == "null": - writemsg("Invalid package name in package.provided: "+pkgprovidedlines[x]+"\n") - del pkgprovidedlines[x] - - self.pprovideddict = {} - for x in pkgprovidedlines: - cpv=catpkgsplit(x) - if not x: - continue - mycatpkg=dep_getkey(x) - if self.pprovideddict.has_key(mycatpkg): - self.pprovideddict[mycatpkg].append(x) - else: - self.pprovideddict[mycatpkg]=[x] - - self.lookuplist=self.configlist[:] - self.lookuplist.reverse() - - useorder=self["USE_ORDER"] - if not useorder: - # reasonable defaults; this is important as without USE_ORDER, - # USE will always be "" (nothing set)! - useorder="env:pkg:conf:auto:defaults" - useordersplit=useorder.split(":") - - self.uvlist=[] - for x in useordersplit: - if self.configdict.has_key(x): - if "PKGUSE" in self.configdict[x].keys(): - del self.configdict[x]["PKGUSE"] # Delete PkgUse, Not legal to set. - #prepend db to list to get correct order - self.uvlist[0:0]=[self.configdict[x]] - - self.configdict["env"]["PORTAGE_GID"]=str(portage_gid) - self.backupenv["PORTAGE_GID"]=str(portage_gid) - - if self.has_key("PORT_LOGDIR") and not self["PORT_LOGDIR"]: - # port_logdir is defined, but empty. this causes a traceback in doebuild. - writemsg(yellow("!!!")+" PORT_LOGDIR was defined, but set to nothing.\n") - writemsg(yellow("!!!")+" Disabling it. Please set it to a non null value.\n") - del self["PORT_LOGDIR"] - - if self["PORTAGE_CACHEDIR"]: - # XXX: Deprecated -- April 15 -- NJ - writemsg(yellow(">>> PORTAGE_CACHEDIR has been deprecated!")+"\n") - writemsg(">>> Please use PORTAGE_DEPCACHEDIR instead.\n") - self.depcachedir = self["PORTAGE_CACHEDIR"] - del self["PORTAGE_CACHEDIR"] - - if self["PORTAGE_DEPCACHEDIR"]: - #the auxcache is the only /var/cache/edb/ entry that stays at / even when "root" changes. - # XXX: Could move with a CHROOT functionality addition. - self.depcachedir = self["PORTAGE_DEPCACHEDIR"] - del self["PORTAGE_DEPCACHEDIR"] - - overlays = string.split(self["PORTDIR_OVERLAY"]) - if overlays: - new_ov=[] - for ov in overlays: - ov=os.path.normpath(ov) - if os.path.isdir(ov): - new_ov.append(ov) - else: - writemsg(red("!!! Invalid PORTDIR_OVERLAY (not a dir): "+ov+"\n")) - self["PORTDIR_OVERLAY"] = string.join(new_ov) - self.backup_changes("PORTDIR_OVERLAY") - - self.regenerate() - - self.features = portage_util.unique_array(self["FEATURES"].split()) - - #XXX: Should this be temporary? Is it possible at all to have a default? - if "gpg" in self.features: - if not os.path.exists(self["PORTAGE_GPG_DIR"]) or not os.path.isdir(self["PORTAGE_GPG_DIR"]): - writemsg("PORTAGE_GPG_DIR is invalid. Removing gpg from FEATURES.\n") - self.features.remove("gpg") - - if "maketest" in self.features and "test" not in self.features: - self.features.append("test") - - if not portage_exec.sandbox_capable and ("sandbox" in self.features or "usersandbox" in self.features): - writemsg(red("!!! Problem with sandbox binary. Disabling...\n\n")) - if "sandbox" in self.features: - self.features.remove("sandbox") - if "usersandbox" in self.features: - self.features.remove("usersandbox") - - self.features.sort() - self["FEATURES"] = " ".join(["-*"]+self.features) - self.backup_changes("FEATURES") - - if not len(self["CBUILD"]): - self["CBUILD"] = self["CHOST"] - self.backup_changes("CBUILD") - - if mycpv: - self.setcpv(mycpv) - - def loadVirtuals(self,root): - self.virtuals = self.getvirtuals(root) - - def load_best_module(self,property_string): - best_mod = best_from_dict(property_string,self.modules,self.module_priority) - return load_mod(best_mod) - - def lock(self): - self.locked = 1 - - def unlock(self): - self.locked = 0 - - def modifying(self): - if self.locked: - raise Exception, "Configuration is locked." - - def backup_changes(self,key=None): - if key and self.configdict["env"].has_key(key): - self.backupenv[key] = copy.deepcopy(self.configdict["env"][key]) - else: - raise KeyError, "No such key defined in environment: %s" % key - - def reset(self,keeping_pkg=0,use_cache=1): - "reset environment to original settings" - for x in self.configlist[-1].keys(): - if x not in self.backupenv.keys(): - del self.configlist[-1][x] - - self.configdict["env"].update(self.backupenv) - - self.modifiedkeys = [] - if not keeping_pkg: - self.puse = "" - self.configdict["pkg"].clear() - self.regenerate(use_cache=use_cache) - - def load_infodir(self,infodir): - if self.configdict.has_key("pkg"): - for x in self.configdict["pkg"].keys(): - del self.configdict["pkg"][x] - else: - writemsg("No pkg setup for settings instance?\n") - sys.exit(17) - - if os.path.exists(infodir): - if os.path.exists(infodir+"/environment"): - self.configdict["pkg"]["PORT_ENV_FILE"] = infodir+"/environment" - - myre = re.compile('^[A-Z]+$') - for filename in listdir(infodir,filesonly=1,EmptyOnError=1): - if myre.match(filename): - try: - mydata = string.strip(open(infodir+"/"+filename).read()) - if len(mydata)<2048: - if filename == "USE": - self.configdict["pkg"][filename] = "-* "+mydata - else: - self.configdict["pkg"][filename] = mydata - except SystemExit, e: - raise - except: - writemsg("!!! Unable to read file: %s\n" % infodir+"/"+filename) - pass - return 1 - return 0 - - def setcpv(self,mycpv,use_cache=1): - self.modifying() - self.mycpv = mycpv - cp = dep_getkey(mycpv) - newpuse = "" - if self.pusedict.has_key(cp): - self.pusekey = best_match_to_list(self.mycpv, self.pusedict[cp].keys()) - if self.pusekey: - newpuse = string.join(self.pusedict[cp][self.pusekey]) - if newpuse == self.puse: - return - self.puse = newpuse - self.configdict["pkg"]["PKGUSE"] = self.puse[:] # For saving to PUSE file - self.configdict["pkg"]["USE"] = self.puse[:] # this gets appended to USE - self.reset(keeping_pkg=1,use_cache=use_cache) - - def setinst(self,mycpv,mydbapi): - # Grab the virtuals this package provides and add them into the tree virtuals. - provides = mydbapi.aux_get(mycpv, ["PROVIDE"])[0] - if isinstance(mydbapi, portdbapi): - myuse = self["USE"] - else: - myuse = mydbapi.aux_get(mycpv, ["USE"])[0] - virts = flatten(portage_dep.use_reduce(portage_dep.paren_reduce(provides), uselist=myuse.split())) - - cp = dep_getkey(mycpv) - for virt in virts: - virt = dep_getkey(virt) - if not self.treeVirtuals.has_key(virt): - self.treeVirtuals[virt] = [] - # XXX: Is this bad? -- It's a permanent modification - self.treeVirtuals[virt] = portage_util.unique_array(self.treeVirtuals[virt]+[cp]) - - self.virtuals = self.__getvirtuals_compile() - - - def regenerate(self,useonly=0,use_cache=1): - global usesplit,profiledir - - if self.already_in_regenerate: - # XXX: THIS REALLY NEEDS TO GET FIXED. autouse() loops. - writemsg("!!! Looping in regenerate.\n",1) - return - else: - self.already_in_regenerate = 1 - - if useonly: - myincrementals=["USE"] - else: - myincrementals=portage_const.INCREMENTALS - for mykey in myincrementals: - if mykey=="USE": - mydbs=self.uvlist - # XXX Global usage of db... Needs to go away somehow. - if db.has_key(root) and db[root].has_key("vartree"): - self.configdict["auto"]["USE"]=autouse(db[root]["vartree"],use_cache=use_cache) - else: - self.configdict["auto"]["USE"]="" - else: - mydbs=self.configlist[:-1] - - myflags=[] - for curdb in mydbs: - if not curdb.has_key(mykey): - continue - #variables are already expanded - mysplit=curdb[mykey].split() - - for x in mysplit: - if x=="-*": - # "-*" is a special "minus" var that means "unset all settings". - # so USE="-* gnome" will have *just* gnome enabled. - myflags=[] - continue - - if x[0]=="+": - # Not legal. People assume too much. Complain. - writemsg(red("USE flags should not start with a '+': %s\n" % x)) - x=x[1:] - - if (x[0]=="-"): - if (x[1:] in myflags): - # Unset/Remove it. - del myflags[myflags.index(x[1:])] - continue - - # We got here, so add it now. - if x not in myflags: - myflags.append(x) - - myflags.sort() - #store setting in last element of configlist, the original environment: - self.configlist[-1][mykey]=string.join(myflags," ") - del myflags - - #cache split-up USE var in a global - usesplit=[] - - for x in string.split(self.configlist[-1]["USE"]): - if x not in self.usemask: - usesplit.append(x) - - if self.has_key("USE_EXPAND"): - for var in string.split(self["USE_EXPAND"]): - if self.has_key(var): - for x in string.split(self[var]): - mystr = string.lower(var)+"_"+x - if mystr not in usesplit: - usesplit.append(mystr) - - # Pre-Pend ARCH variable to USE settings so '-*' in env doesn't kill arch. - if self.configdict["defaults"].has_key("ARCH"): - if self.configdict["defaults"]["ARCH"]: - if self.configdict["defaults"]["ARCH"] not in usesplit: - usesplit.insert(0,self.configdict["defaults"]["ARCH"]) - - self.configlist[-1]["USE"]=string.join(usesplit," ") - - self.already_in_regenerate = 0 - - def getvirtuals(self, myroot): - myvirts = {} - - # This breaks catalyst/portage when setting to a fresh/empty root. - # Virtuals cannot be calculated because there is nothing to work - # from. So the only ROOT prefixed dir should be local configs. - #myvirtdirs = prefix_array(self.profiles,myroot+"/") - myvirtdirs = copy.deepcopy(self.profiles) - while self.user_profile_dir in myvirtdirs: - myvirtdirs.remove(self.user_profile_dir) - - - # Rules - # R1: Collapse profile virtuals - # R2: Extract user-negatives. - # R3: Collapse user-virtuals. - # R4: Apply user negatives to all except user settings. - - # Order of preference: - # 1. user-declared that are installed - # 3. installed and in profile - # 4. installed - # 2. user-declared set - # 5. profile - - self.dirVirtuals = grab_multiple("virtuals", myvirtdirs, grabdict) - self.dirVirtuals.reverse() - - if self.user_profile_dir and os.path.exists(self.user_profile_dir+"/virtuals"): - self.userVirtuals = grabdict(self.user_profile_dir+"/virtuals") - - # Store all the negatives for later. - for x in self.userVirtuals.keys(): - self.negVirtuals[x] = [] - for y in self.userVirtuals[x]: - if y[0] == '-': - self.negVirtuals[x].append(y[:]) - - # Collapse the user virtuals so that we don't deal with negatives. - self.userVirtuals = stack_dictlist([self.userVirtuals],incremental=1) - - # Collapse all the profile virtuals including user negations. - self.dirVirtuals = stack_dictlist([self.negVirtuals]+self.dirVirtuals,incremental=1) - - # Repoman does not use user or tree virtuals. - if os.environ.get("PORTAGE_CALLER","") != "repoman": - # XXX: vartree does not use virtuals, does user set matter? - temp_vartree = vartree(myroot,self.dirVirtuals,categories=self.categories) - # Reduce the provides into a list by CP. - self.treeVirtuals = map_dictlist_vals(getCPFromCPV,temp_vartree.get_all_provides()) - - return self.__getvirtuals_compile() - - def __getvirtuals_compile(self): - """Actually generate the virtuals we have collected. - The results are reversed so the list order is left to right. - Given data is [Best,Better,Good] sets of [Good, Better, Best]""" - - # Virtuals by profile+tree preferences. - ptVirtuals = {} - # Virtuals by user+tree preferences. - utVirtuals = {} - - # If a user virtual is already installed, we preference it. - for x in self.userVirtuals.keys(): - utVirtuals[x] = [] - if self.treeVirtuals.has_key(x): - for y in self.userVirtuals[x]: - if y in self.treeVirtuals[x]: - utVirtuals[x].append(y) - #print "F:",utVirtuals - #utVirtuals[x].reverse() - #print "R:",utVirtuals - - # If a profile virtual is already installed, we preference it. - for x in self.dirVirtuals.keys(): - ptVirtuals[x] = [] - if self.treeVirtuals.has_key(x): - for y in self.dirVirtuals[x]: - if y in self.treeVirtuals[x]: - ptVirtuals[x].append(y) - - # UserInstalled, ProfileInstalled, Installed, User, Profile - biglist = [utVirtuals, ptVirtuals, self.treeVirtuals, - self.userVirtuals, self.dirVirtuals] - - # We reverse each dictlist so that the order matches everything - # else in portage. [-*, a, b] [b, c, d] ==> [b, a] - for dictlist in biglist: - for key in dictlist: - dictlist[key].reverse() - - # User settings and profile settings take precedence over tree. - val = stack_dictlist(biglist,incremental=1) - - return val - - def __delitem__(self,mykey): - for x in self.lookuplist: - if x != None: - if mykey in x: - del x[mykey] - - def __getitem__(self,mykey): - match = '' - for x in self.lookuplist: - if x == None: - writemsg("!!! lookuplist is null.\n") - elif x.has_key(mykey): - match = x[mykey] - break - - if 0 and match and mykey in ["PORTAGE_BINHOST"]: - # These require HTTP Encoding - try: - import urllib - if urllib.unquote(match) != match: - writemsg("Note: %s already contains escape codes." % (mykey)) - else: - match = urllib.quote(match) - except SystemExit, e: - raise - except: - writemsg("Failed to fix %s using urllib, attempting to continue.\n" % (mykey)) - pass - - elif mykey == "CONFIG_PROTECT_MASK": - match += " /etc/env.d" - - return match - - def has_key(self,mykey): - for x in self.lookuplist: - if x.has_key(mykey): - return 1 - return 0 - - def keys(self): - mykeys=[] - for x in self.lookuplist: - for y in x.keys(): - if y not in mykeys: - mykeys.append(y) - return mykeys - - def __setitem__(self,mykey,myvalue): - "set a value; will be thrown away at reset() time" - if type(myvalue) != types.StringType: - raise ValueError("Invalid type being used as a value: '%s': '%s'" % (str(mykey),str(myvalue))) - self.modifying() - self.modifiedkeys += [mykey] - self.configdict["env"][mykey]=myvalue - - def environ(self): - "return our locally-maintained environment" - mydict={} - for x in self.keys(): - mydict[x]=self[x] - if not mydict.has_key("HOME") and mydict.has_key("BUILD_PREFIX"): - writemsg("*** HOME not set. Setting to "+mydict["BUILD_PREFIX"]+"\n") - mydict["HOME"]=mydict["BUILD_PREFIX"][:] - - return mydict - - -# XXX This would be to replace getstatusoutput completely. -# XXX Issue: cannot block execution. Deadlock condition. -def spawn(mystring,mysettings,debug=0,free=0,droppriv=0,fd_pipes=None,**keywords): - """spawn a subprocess with optional sandbox protection, - depending on whether sandbox is enabled. The "free" argument, - when set to 1, will disable sandboxing. This allows us to - spawn processes that are supposed to modify files outside of the - sandbox. We can't use os.system anymore because it messes up - signal handling. Using spawn allows our Portage signal handler - to work.""" - - if type(mysettings) == types.DictType: - env=mysettings - keywords["opt_name"]="[ %s ]" % "portage" - else: - check_config_instance(mysettings) - env=mysettings.environ() - keywords["opt_name"]="[%s]" % mysettings["PF"] - - # XXX: Negative RESTRICT word - droppriv=(droppriv and ("userpriv" in features) and not \ - (("nouserpriv" in string.split(mysettings["RESTRICT"])) or \ - ("userpriv" in string.split(mysettings["RESTRICT"])))) - - - if ("sandbox" in features) and (not free): - keywords["opt_name"] += " sandbox" - if droppriv and portage_gid and portage_uid: - keywords.update({"uid":portage_uid,"gid":portage_gid,"groups":[portage_gid],"umask":002}) - return portage_exec.spawn_sandbox(mystring,env=env,**keywords) - else: - keywords["opt_name"] += " bash" - return portage_exec.spawn_bash(mystring,env=env,**keywords) - - - -def fetch(myuris, mysettings, listonly=0, fetchonly=0, locks_in_subdir=".locks",use_locks=1, try_mirrors=1): - "fetch files. Will use digest file if available." - - # 'nomirror' is bad/negative logic. You Restrict mirroring, not no-mirroring. - if ("mirror" in mysettings["RESTRICT"].split()) or \ - ("nomirror" in mysettings["RESTRICT"].split()): - if ("mirror" in features) and ("lmirror" not in features): - # lmirror should allow you to bypass mirror restrictions. - # XXX: This is not a good thing, and is temporary at best. - print ">>> \"mirror\" mode desired and \"mirror\" restriction found; skipping fetch." - return 1 - - global thirdpartymirrors - - check_config_instance(mysettings) - - custommirrors=grabdict(CUSTOM_MIRRORS_FILE) - - mymirrors=[] - - if listonly or ("distlocks" not in features): - use_locks = 0 - - fetch_to_ro = 0 - if "skiprocheck" in features: - fetch_to_ro = 1 - - if not os.access(mysettings["DISTDIR"],os.W_OK) and fetch_to_ro: - if use_locks: - writemsg(red("!!! You are fetching to a read-only filesystem, you should turn locking off")); - writemsg("!!! This can be done by adding -distlocks to FEATURES in /etc/make.conf"); -# use_locks = 0 - - # local mirrors are always added - if custommirrors.has_key("local"): - mymirrors += custommirrors["local"] - - if ("nomirror" in mysettings["RESTRICT"].split()) or \ - ("mirror" in mysettings["RESTRICT"].split()): - # We don't add any mirrors. - pass - else: - if try_mirrors: - for x in mysettings["GENTOO_MIRRORS"].split(): - if x: - if x[-1] == '/': - mymirrors += [x[:-1]] - else: - mymirrors += [x] - - mydigests = {} - digestfn = mysettings["FILESDIR"]+"/digest-"+mysettings["PF"] - if os.path.exists(digestfn): - mydigests = digestParseFile(digestfn) - - fsmirrors = [] - for x in range(len(mymirrors)-1,-1,-1): - if mymirrors[x] and mymirrors[x][0]=='/': - fsmirrors += [mymirrors[x]] - del mymirrors[x] - - for myuri in myuris: - myfile=os.path.basename(myuri) - try: - destdir = mysettings["DISTDIR"]+"/" - if not os.path.exists(destdir+myfile): - for mydir in fsmirrors: - if os.path.exists(mydir+"/"+myfile): - writemsg(_("Local mirror has file: %(file)s\n" % {"file":myfile})) - shutil.copyfile(mydir+"/"+myfile,destdir+"/"+myfile) - break - except (OSError,IOError),e: - # file does not exist - writemsg(_("!!! %(file)s not found in %(dir)s\n") % {"file":myfile, "dir":mysettings["DISTDIR"]}) - gotit=0 - - if "fetch" in mysettings["RESTRICT"].split(): - # fetch is restricted. Ensure all files have already been downloaded; otherwise, - # print message and exit. - gotit=1 - for myuri in myuris: - myfile=os.path.basename(myuri) - try: - mystat=os.stat(mysettings["DISTDIR"]+"/"+myfile) - except (OSError,IOError),e: - # file does not exist - writemsg(_("!!! %(file)s not found in %(dir)s\n") % {"file":myfile, "dir":mysettings["DISTDIR"]}) - gotit=0 - if not gotit: - print - print "!!!",mysettings["CATEGORY"]+"/"+mysettings["PF"],"has fetch restriction turned on." - print "!!! This probably means that this ebuild's files must be downloaded" - print "!!! manually. See the comments in the ebuild for more information." - print - spawn(EBUILD_SH_BINARY+" nofetch",mysettings) - return 0 - return 1 - locations=mymirrors[:] - filedict={} - primaryuri_indexes={} - for myuri in myuris: - myfile=os.path.basename(myuri) - if not filedict.has_key(myfile): - filedict[myfile]=[] - for y in range(0,len(locations)): - filedict[myfile].append(locations[y]+"/distfiles/"+myfile) - if myuri[:9]=="mirror://": - eidx = myuri.find("/", 9) - if eidx != -1: - mirrorname = myuri[9:eidx] - - # Try user-defined mirrors first - if custommirrors.has_key(mirrorname): - for cmirr in custommirrors[mirrorname]: - filedict[myfile].append(cmirr+"/"+myuri[eidx+1:]) - # remove the mirrors we tried from the list of official mirrors - if cmirr.strip() in thirdpartymirrors[mirrorname]: - thirdpartymirrors[mirrorname].remove(cmirr) - # now try the official mirrors - if thirdpartymirrors.has_key(mirrorname): - try: - shuffle(thirdpartymirrors[mirrorname]) - except SystemExit, e: - raise - except: - writemsg(red("!!! YOU HAVE A BROKEN PYTHON/GLIBC.\n")) - writemsg( "!!! You are most likely on a pentium4 box and have specified -march=pentium4\n") - writemsg( "!!! or -fpmath=sse2. GCC was generating invalid sse2 instructions in versions\n") - writemsg( "!!! prior to 3.2.3. Please merge the latest gcc or rebuid python with either\n") - writemsg( "!!! -march=pentium3 or set -mno-sse2 in your cflags.\n\n\n") - time.sleep(10) - - for locmirr in thirdpartymirrors[mirrorname]: - filedict[myfile].append(locmirr+"/"+myuri[eidx+1:]) - - if not filedict[myfile]: - writemsg("No known mirror by the name: %s\n" % (mirrorname)) - else: - writemsg("Invalid mirror definition in SRC_URI:\n") - writemsg(" %s\n" % (myuri)) - else: - if "primaryuri" in mysettings["RESTRICT"].split(): - # Use the source site first. - if primaryuri_indexes.has_key(myfile): - primaryuri_indexes[myfile] += 1 - else: - primaryuri_indexes[myfile] = 0 - filedict[myfile].insert(primaryuri_indexes[myfile], myuri) - else: - filedict[myfile].append(myuri) - - missingSourceHost = False - for myfile in filedict.keys(): # Gives a list, not just the first one - if not filedict[myfile]: - writemsg("Warning: No mirrors available for file '%s'\n" % (myfile)) - missingSourceHost = True - if missingSourceHost: - return 0 - del missingSourceHost - - can_fetch=True - if not os.access(mysettings["DISTDIR"]+"/",os.W_OK): - if not fetch_to_ro: - print "!!! No write access to %s" % mysettings["DISTDIR"]+"/" - can_fetch=False - else: - mystat=os.stat(mysettings["DISTDIR"]+"/") - if mystat.st_gid != portage_gid: - try: - os.chown(mysettings["DISTDIR"],-1,portage_gid) - except OSError, oe: - if oe.errno == 1: - print red("!!!")+" Unable to chgrp of %s to portage, continuing\n" % mysettings["DISTDIR"] - else: - raise oe - - # writable by portage_gid? This is specific to root, adjust perms if needed automatically. - if not stat.S_IMODE(mystat.st_mode) & 020: - try: - os.chmod(mysettings["DISTDIR"],stat.S_IMODE(mystat.st_mode) | 020) - except OSError, oe: - if oe.errno == 1: - print red("!!!")+" Unable to chmod %s to perms 0755. Non-root users will experience issues.\n" % mysettings["DISTDIR"] - else: - raise oe - - if use_locks and locks_in_subdir: - if os.path.exists(mysettings["DISTDIR"]+"/"+locks_in_subdir): - if not os.access(mysettings["DISTDIR"]+"/"+locks_in_subdir,os.W_OK): - writemsg("!!! No write access to write to %s. Aborting.\n" % mysettings["DISTDIR"]+"/"+locks_in_subdir) - return 0 - else: - old_umask=os.umask(0002) - os.mkdir(mysettings["DISTDIR"]+"/"+locks_in_subdir,0775) - if os.stat(mysettings["DISTDIR"]+"/"+locks_in_subdir).st_gid != portage_gid: - try: - os.chown(mysettings["DISTDIR"]+"/"+locks_in_subdir,-1,portage_gid) - except SystemExit, e: - raise - except: - pass - os.umask(old_umask) - - - for myfile in filedict.keys(): - fetched=0 - file_lock = None - if listonly: - writemsg("\n") - else: - if use_locks and can_fetch: - if locks_in_subdir: - file_lock = portage_locks.lockfile(mysettings["DISTDIR"]+"/"+locks_in_subdir+"/"+myfile,wantnewlockfile=1) - else: - file_lock = portage_locks.lockfile(mysettings["DISTDIR"]+"/"+myfile,wantnewlockfile=1) - try: - for loc in filedict[myfile]: - if listonly: - writemsg(loc+" ") - continue - # allow different fetchcommands per protocol - protocol = loc[0:loc.find("://")] - if mysettings.has_key("FETCHCOMMAND_"+protocol.upper()): - fetchcommand=mysettings["FETCHCOMMAND_"+protocol.upper()] - else: - fetchcommand=mysettings["FETCHCOMMAND"] - if mysettings.has_key("RESUMECOMMAND_"+protocol.upper()): - resumecommand=mysettings["RESUMECOMMAND_"+protocol.upper()] - else: - resumecommand=mysettings["RESUMECOMMAND"] - - fetchcommand=string.replace(fetchcommand,"${DISTDIR}",mysettings["DISTDIR"]) - resumecommand=string.replace(resumecommand,"${DISTDIR}",mysettings["DISTDIR"]) - - try: - mystat=os.stat(mysettings["DISTDIR"]+"/"+myfile) - if mydigests.has_key(myfile): - #if we have the digest file, we know the final size and can resume the download. - if mystat[stat.ST_SIZE]<mydigests[myfile]["size"]: - fetched=1 - else: - #we already have it downloaded, skip. - #if our file is bigger than the recorded size, digestcheck should catch it. - if not fetchonly: - fetched=2 - else: - # Check md5sum's at each fetch for fetchonly. - verified_ok,reason = portage_checksum.verify_all(mysettings["DISTDIR"]+"/"+myfile, mydigests[myfile]) - if not verified_ok: - writemsg("!!! Previously fetched file: "+str(myfile)+"\n!!! Reason: "+reason+"\nRefetching...\n\n") - os.unlink(mysettings["DISTDIR"]+"/"+myfile) - fetched=0 - else: - for x_key in mydigests[myfile].keys(): - writemsg(">>> Previously fetched file: "+str(myfile)+" "+x_key+" ;-)\n") - fetched=2 - break #No need to keep looking for this file, we have it! - else: - #we don't have the digest file, but the file exists. Assume it is fully downloaded. - fetched=2 - except (OSError,IOError),e: - writemsg("An exception was caught(1)...\nFailing the download: %s.\n" % (str(e)),1) - fetched=0 - - if not can_fetch: - if fetched != 2: - if fetched == 0: - writemsg("!!! File %s isn't fetched but unable to get it.\n" % myfile) - else: - writemsg("!!! File %s isn't fully fetched, but unable to complete it\n" % myfile) - return 0 - else: - continue - - # check if we can actually write to the directory/existing file. - if fetched!=2 and os.path.exists(mysettings["DISTDIR"]+"/"+myfile) != \ - os.access(mysettings["DISTDIR"]+"/"+myfile, os.W_OK) and not fetch_to_ro: - writemsg(red("***")+" Lack write access to %s, failing fetch\n" % str(mysettings["DISTDIR"]+"/"+myfile)) - fetched=0 - break - elif fetched!=2: - #we either need to resume or start the download - #you can't use "continue" when you're inside a "try" block - if fetched==1: - #resume mode: - writemsg(">>> Resuming download...\n") - locfetch=resumecommand - else: - #normal mode: - locfetch=fetchcommand - writemsg(">>> Downloading "+str(loc)+"\n") - myfetch=string.replace(locfetch,"${URI}",loc) - myfetch=string.replace(myfetch,"${FILE}",myfile) - try: - if selinux_enabled: - con=selinux.getcontext() - con=string.replace(con,mysettings["PORTAGE_T"],mysettings["PORTAGE_FETCH_T"]) - selinux.setexec(con) - myret=spawn(myfetch,mysettings,free=1) - selinux.setexec(None) - else: - myret=spawn(myfetch,mysettings,free=1) - finally: - #if root, -always- set the perms. - if os.path.exists(mysettings["DISTDIR"]+"/"+myfile) and (fetched != 1 or os.getuid() == 0) \ - and os.access(mysettings["DISTDIR"]+"/",os.W_OK): - if os.stat(mysettings["DISTDIR"]+"/"+myfile).st_gid != portage_gid: - try: - os.chown(mysettings["DISTDIR"]+"/"+myfile,-1,portage_gid) - except SystemExit, e: - raise - except: - portage_util.writemsg("chown failed on distfile: " + str(myfile)) - os.chmod(mysettings["DISTDIR"]+"/"+myfile,0664) - - if mydigests!=None and mydigests.has_key(myfile): - try: - mystat=os.stat(mysettings["DISTDIR"]+"/"+myfile) - # no exception? file exists. let digestcheck() report - # an appropriately for size or md5 errors - if (mystat[stat.ST_SIZE]<mydigests[myfile]["size"]): - # Fetch failed... Try the next one... Kill 404 files though. - if (mystat[stat.ST_SIZE]<100000) and (len(myfile)>4) and not ((myfile[-5:]==".html") or (myfile[-4:]==".htm")): - html404=re.compile("<title>.*(not found|404).*</title>",re.I|re.M) - try: - if html404.search(open(mysettings["DISTDIR"]+"/"+myfile).read()): - try: - os.unlink(mysettings["DISTDIR"]+"/"+myfile) - writemsg(">>> Deleting invalid distfile. (Improper 404 redirect from server.)\n") - except SystemExit, e: - raise - except: - pass - except SystemExit, e: - raise - except: - pass - continue - if not fetchonly: - fetched=2 - break - else: - # File is the correct size--check the MD5 sum for the fetched - # file NOW, for those users who don't have a stable/continuous - # net connection. This way we have a chance to try to download - # from another mirror... - verified_ok,reason = portage_checksum.verify_all(mysettings["DISTDIR"]+"/"+myfile, mydigests[myfile]) - if not verified_ok: - writemsg("!!! Fetched file: "+str(myfile)+" VERIFY FAILED!\n!!! Reason: "+reason+"\nRemoving corrupt distfile...\n") - os.unlink(mysettings["DISTDIR"]+"/"+myfile) - fetched=0 - else: - for x_key in mydigests[myfile].keys(): - writemsg(">>> "+str(myfile)+" "+x_key+" ;-)\n") - fetched=2 - break - except (OSError,IOError),e: - writemsg("An exception was caught(2)...\nFailing the download: %s.\n" % (str(e)),1) - fetched=0 - else: - if not myret: - fetched=2 - break - elif mydigests!=None: - writemsg("No digest file available and download failed.\n\n") - finally: - if use_locks and file_lock: - portage_locks.unlockfile(file_lock) - - if listonly: - writemsg("\n") - if (fetched!=2) and not listonly: - writemsg("!!! Couldn't download "+str(myfile)+". Aborting.\n") - return 0 - return 1 - - -def digestCreate(myfiles,basedir,oldDigest={}): - """Takes a list of files and the directory they are in and returns the - dict of dict[filename][CHECKSUM_KEY] = hash - returns None on error.""" - mydigests={} - for x in myfiles: - print "<<<",x - myfile=os.path.normpath(basedir+"///"+x) - if os.path.exists(myfile): - if not os.access(myfile, os.R_OK): - print "!!! Given file does not appear to be readable. Does it exist?" - print "!!! File:",myfile - return None - mydigests[x] = portage_checksum.perform_all(myfile) - mysize = os.stat(myfile)[stat.ST_SIZE] - else: - if x in oldDigest: - # DeepCopy because we might not have a unique reference. - mydigests[x] = copy.deepcopy(oldDigest[x]) - mysize = copy.deepcopy(oldDigest[x]["size"]) - else: - print "!!! We have a source URI, but no file..." - print "!!! File:",myfile - return None - - if mydigests[x].has_key("size") and (mydigests[x]["size"] != mysize): - raise portage_exception.DigestException, "Size mismatch during checksums" - mydigests[x]["size"] = copy.deepcopy(mysize) - return mydigests - -def digestCreateLines(filelist, mydict): - mylines = [] - mydigests = copy.deepcopy(mydict) - for myarchive in filelist: - mysize = mydigests[myarchive]["size"] - if len(mydigests[myarchive]) == 0: - raise portage_exception.DigestException, "No generate digest for '%(file)s'" % {"file":myarchive} - for sumName in mydigests[myarchive].keys(): - if sumName not in portage_checksum.get_valid_checksum_keys(): - continue - mysum = mydigests[myarchive][sumName] - - myline = sumName[:] - myline += " "+mysum - myline += " "+myarchive - myline += " "+str(mysize) - if sumName != "MD5": - # XXXXXXXXXXXXXXXX This cannot be used! - # Older portage make very dumb assumptions about the formats. - # We need a lead-in period before we break everything. - continue - mylines.append(myline) - return mylines - -def digestgen(myarchives,mysettings,overwrite=1,manifestonly=0): - """generates digest file if missing. Assumes all files are available. If - overwrite=0, the digest will only be created if it doesn't already exist.""" - - # archive files - basedir=mysettings["DISTDIR"]+"/" - digestfn=mysettings["FILESDIR"]+"/digest-"+mysettings["PF"] - - # portage files -- p(ortagefiles)basedir - pbasedir=mysettings["O"]+"/" - manifestfn=pbasedir+"Manifest" - - if not manifestonly: - if not os.path.isdir(mysettings["FILESDIR"]): - os.makedirs(mysettings["FILESDIR"]) - mycvstree=cvstree.getentries(pbasedir, recursive=1) - - if ("cvs" in features) and os.path.exists(pbasedir+"/CVS"): - if not cvstree.isadded(mycvstree,"files"): - if "autoaddcvs" in features: - print ">>> Auto-adding files/ dir to CVS..." - spawn("cd "+pbasedir+"; cvs add files",mysettings,free=1) - else: - print "--- Warning: files/ is not added to cvs." - - if (not overwrite) and os.path.exists(digestfn): - return 1 - - print green(">>> Generating digest file...") - - # Track the old digest so we can assume checksums without requiring - # all files to be downloaded. 'Assuming' - myolddigest = {} - if os.path.exists(digestfn): - myolddigest = digestParseFile(digestfn) - - mydigests=digestCreate(myarchives, basedir, oldDigest=myolddigest) - if mydigests==None: # There was a problem, exit with an errorcode. - return 0 - - try: - outfile=open(digestfn, "w+") - except SystemExit, e: - raise - except Exception, e: - print "!!! Filesystem error skipping generation. (Read-Only?)" - print "!!!",e - return 0 - for x in digestCreateLines(myarchives, mydigests): - outfile.write(x+"\n") - outfile.close() - try: - os.chown(digestfn,os.getuid(),portage_gid) - os.chmod(digestfn,0664) - except SystemExit, e: - raise - except Exception,e: - print e - - print green(">>> Generating manifest file...") - mypfiles=listdir(pbasedir,recursive=1,filesonly=1,ignorecvs=1,EmptyOnError=1) - mypfiles=cvstree.apply_cvsignore_filter(mypfiles) - for x in ["Manifest"]: - if x in mypfiles: - mypfiles.remove(x) - - mydigests=digestCreate(mypfiles, pbasedir) - if mydigests==None: # There was a problem, exit with an errorcode. - return 0 - - try: - outfile=open(manifestfn, "w+") - except SystemExit, e: - raise - except Exception, e: - print "!!! Filesystem error skipping generation. (Read-Only?)" - print "!!!",e - return 0 - for x in digestCreateLines(mypfiles, mydigests): - outfile.write(x+"\n") - outfile.close() - try: - os.chown(manifestfn,os.getuid(),portage_gid) - os.chmod(manifestfn,0664) - except SystemExit, e: - raise - except Exception,e: - print e - - if "cvs" in features and os.path.exists(pbasedir+"/CVS"): - mycvstree=cvstree.getentries(pbasedir, recursive=1) - myunaddedfiles="" - if not manifestonly and not cvstree.isadded(mycvstree,digestfn): - if digestfn[:len(pbasedir)]==pbasedir: - myunaddedfiles=digestfn[len(pbasedir):]+" " - else: - myunaddedfiles=digestfn+" " - if not cvstree.isadded(mycvstree,manifestfn[len(pbasedir):]): - if manifestfn[:len(pbasedir)]==pbasedir: - myunaddedfiles+=manifestfn[len(pbasedir):]+" " - else: - myunaddedfiles+=manifestfn - if myunaddedfiles: - if "autoaddcvs" in features: - print blue(">>> Auto-adding digest file(s) to CVS...") - spawn("cd "+pbasedir+"; cvs add "+myunaddedfiles,mysettings,free=1) - else: - print "--- Warning: digests are not yet added into CVS." - print darkgreen(">>> Computed message digests.") - print - return 1 - - -def digestParseFile(myfilename): - """(filename) -- Parses a given file for entries matching: - MD5 MD5_STRING_OF_HEX_CHARS FILE_NAME FILE_SIZE - Ignores lines that do not begin with 'MD5' and returns a - dict with the filenames as keys and [md5,size] as the values.""" - - if not os.path.exists(myfilename): - return None - mylines = portage_util.grabfile(myfilename, compat_level=1) - - mydigests={} - for x in mylines: - myline=string.split(x) - if len(myline) < 4: - #invalid line - continue - if myline[0] not in portage_checksum.get_valid_checksum_keys(): - continue - mykey = myline.pop(0) - myhash = myline.pop(0) - mysize = long(myline.pop()) - myfn = string.join(myline, " ") - if myfn not in mydigests: - mydigests[myfn] = {} - mydigests[myfn][mykey] = myhash - if "size" in mydigests[myfn]: - if mydigests[myfn]["size"] != mysize: - raise portage_exception.DigestException, "Conflicting sizes in digest: %(filename)s" % {"filename":myfilename} - else: - mydigests[myfn]["size"] = mysize - return mydigests - -# XXXX strict was added here to fix a missing name error. -# XXXX It's used below, but we're not paying attention to how we get it? -def digestCheckFiles(myfiles, mydigests, basedir, note="", strict=0): - """(fileslist, digestdict, basedir) -- Takes a list of files and a dict - of their digests and checks the digests against the indicated files in - the basedir given. Returns 1 only if all files exist and match the md5s. - """ - for x in myfiles: - if not mydigests.has_key(x): - print - print red("!!! No message digest entry found for file \""+x+".\"") - print "!!! Most likely a temporary problem. Try 'emerge sync' again later." - print "!!! If you are certain of the authenticity of the file then you may type" - print "!!! the following to generate a new digest:" - print "!!! ebuild /usr/portage/category/package/package-version.ebuild digest" - return 0 - myfile=os.path.normpath(basedir+"/"+x) - if not os.path.exists(myfile): - if strict: - print "!!! File does not exist:",myfile - return 0 - continue - - ok,reason = portage_checksum.verify_all(myfile,mydigests[x]) - if not ok: - print - print red("!!! Digest verification Failed:") - print red("!!!")+" "+str(myfile) - print red("!!! Reason: ")+reason - print - return 0 - else: - print ">>> md5 "+note+" ;-)",x - return 1 - - -def digestcheck(myfiles, mysettings, strict=0): - """Checks md5sums. Assumes all files have been downloaded.""" - # archive files - basedir=mysettings["DISTDIR"]+"/" - digestfn=mysettings["FILESDIR"]+"/digest-"+mysettings["PF"] - - # portage files -- p(ortagefiles)basedir - pbasedir=mysettings["O"]+"/" - manifestfn=pbasedir+"Manifest" - - if not (os.path.exists(digestfn) and os.path.exists(manifestfn)): - if "digest" in features: - print ">>> No package digest/Manifest file found." - print ">>> \"digest\" mode enabled; auto-generating new digest..." - return digestgen(myfiles,mysettings) - else: - if not os.path.exists(manifestfn): - if strict: - print red("!!! No package manifest found:"),manifestfn - return 0 - else: - print "--- No package manifest found:",manifestfn - if not os.path.exists(digestfn): - print "!!! No package digest file found:",digestfn - print "!!! Type \"ebuild foo.ebuild digest\" to generate it." - return 0 - - mydigests=digestParseFile(digestfn) - if mydigests==None: - print "!!! Failed to parse digest file:",digestfn - return 0 - mymdigests=digestParseFile(manifestfn) - if "strict" not in features: - # XXX: Remove this when manifests become mainstream. - pass - elif mymdigests==None: - print "!!! Failed to parse manifest file:",manifestfn - if strict: - return 0 - else: - # Check the portage-related files here. - mymfiles=listdir(pbasedir,recursive=1,filesonly=1,ignorecvs=1,EmptyOnError=1) - manifest_files = mymdigests.keys() - for x in ["Manifest", "ChangeLog", "metadata.xml"]: - while x in mymfiles: - mymfiles.remove(x) - while x in manifest_files: - manifest_files.remove(x) - for x in range(len(mymfiles)-1,-1,-1): - if mymfiles[x] in manifest_files: - manifest_files.remove(mymfiles[x]) - elif len(cvstree.apply_cvsignore_filter([mymfiles[x]]))==0: - # we filter here, rather then above; manifest might have files flagged by the filter. - # if something is returned, then it's flagged as a bad file - # manifest doesn't know about it, so we kill it here. - del mymfiles[x] - else: - print red("!!! Security Violation: A file exists that is not in the manifest.") - print "!!! File:",mymfiles[x] - if strict: - return 0 - if manifest_files and strict: - print red("!!! Files listed in the manifest do not exist!") - for x in manifest_files: - print x - return 0 - - if not digestCheckFiles(mymfiles, mymdigests, pbasedir, note="files ", strict=strict): - if strict: - print ">>> Please ensure you have sync'd properly. Please try '"+bold("emerge sync")+"' and" - print ">>> optionally examine the file(s) for corruption. "+bold("A sync will fix most cases.") - print - return 0 - else: - print "--- Manifest check failed. 'strict' not enabled; ignoring." - print - - # Just return the status, as it's the last check. - return digestCheckFiles(myfiles, mydigests, basedir, note="src_uri", strict=strict) - -# parse actionmap to spawn ebuild with the appropriate args -def spawnebuild(mydo,actionmap,mysettings,debug,alwaysdep=0,logfile=None): - if alwaysdep or ("noauto" not in features): - # process dependency first - if "dep" in actionmap[mydo].keys(): - retval=spawnebuild(actionmap[mydo]["dep"],actionmap,mysettings,debug,alwaysdep=alwaysdep,logfile=logfile) - if retval: - return retval - # spawn ebuild.sh - mycommand = EBUILD_SH_BINARY + " " - if selinux_enabled and ("sesandbox" in features) and (mydo in ["unpack","compile","test","install"]): - con=selinux.getcontext() - con=string.replace(con,mysettings["PORTAGE_T"],mysettings["PORTAGE_SANDBOX_T"]) - selinux.setexec(con) - retval=spawn(mycommand + mydo,mysettings,debug=debug, - free=actionmap[mydo]["args"][0], - droppriv=actionmap[mydo]["args"][1],logfile=logfile) - selinux.setexec(None) - else: - retval=spawn(mycommand + mydo,mysettings, debug=debug, - free=actionmap[mydo]["args"][0], - droppriv=actionmap[mydo]["args"][1],logfile=logfile) - return retval - -def doebuild(myebuild,mydo,myroot,mysettings,debug=0,listonly=0,fetchonly=0,cleanup=0,dbkey=None,use_cache=1,fetchall=0,tree="porttree"): - global db - - ebuild_path = os.path.abspath(myebuild) - pkg_dir = os.path.dirname(ebuild_path) - - if mysettings.configdict["pkg"].has_key("CATEGORY"): - cat = mysettings.configdict["pkg"]["CATEGORY"] - else: - cat = os.path.basename(os.path.normpath(pkg_dir+"/..")) - mypv = os.path.basename(ebuild_path)[:-7] - mycpv = cat+"/"+mypv - - mysplit=pkgsplit(mypv,silent=0) - if mysplit==None: - writemsg("!!! Error: PF is null '%s'; exiting.\n" % mypv) - return 1 - - if mydo != "depend": - # XXX: We're doing a little hack here to curtain the gvisible locking - # XXX: that creates a deadlock... Really need to isolate that. - mysettings.reset(use_cache=use_cache) - mysettings.setcpv(mycpv,use_cache=use_cache) - - validcommands = ["help","clean","prerm","postrm","preinst","postinst", - "config","setup","depend","fetch","digest", - "unpack","compile","test","install","rpm","qmerge","merge", - "package","unmerge", "manifest"] - - if mydo not in validcommands: - validcommands.sort() - writemsg("!!! doebuild: '%s' is not one of the following valid commands:" % mydo) - for vcount in range(len(validcommands)): - if vcount%6 == 0: - writemsg("\n!!! ") - writemsg(string.ljust(validcommands[vcount], 11)) - writemsg("\n") - return 1 - - if not os.path.exists(myebuild): - writemsg("!!! doebuild: "+str(myebuild)+" not found for "+str(mydo)+"\n") - return 1 - - if debug: # Otherwise it overrides emerge's settings. - # We have no other way to set debug... debug can't be passed in - # due to how it's coded... Don't overwrite this so we can use it. - mysettings["PORTAGE_DEBUG"]=str(debug) - - mysettings["ROOT"] = myroot - mysettings["STARTDIR"] = getcwd() - - mysettings["EBUILD"] = ebuild_path - mysettings["O"] = pkg_dir - mysettings["CATEGORY"] = cat - mysettings["FILESDIR"] = pkg_dir+"/files" - mysettings["PF"] = mypv - - mysettings["ECLASSDIR"] = mysettings["PORTDIR"]+"/eclass" - mysettings["SANDBOX_LOG"] = mycpv.replace("/", "_-_") - - mysettings["PROFILE_PATHS"] = string.join(mysettings.profiles,"\n")+"\n"+CUSTOM_PROFILE_PATH - mysettings["P"] = mysplit[0]+"-"+mysplit[1] - mysettings["PN"] = mysplit[0] - mysettings["PV"] = mysplit[1] - mysettings["PR"] = mysplit[2] - - if mydo != "depend": - try: - mysettings["INHERITED"], mysettings["RESTRICT"] = db[root][tree].dbapi.aux_get( \ - mycpv,["INHERITED","RESTRICT"]) - mysettings["PORTAGE_RESTRICT"]=string.join(flatten(portage_dep.use_reduce(portage_dep.paren_reduce( \ - mysettings["RESTRICT"]), uselist=mysettings["USE"].split())),' ') - except SystemExit, e: - raise - except: - pass - - if mysplit[2] == "r0": - mysettings["PVR"]=mysplit[1] - else: - mysettings["PVR"]=mysplit[1]+"-"+mysplit[2] - - mysettings["SLOT"]="" - - if mysettings.has_key("PATH"): - mysplit=string.split(mysettings["PATH"],":") - else: - mysplit=[] - if PORTAGE_BIN_PATH not in mysplit: - mysettings["PATH"]=PORTAGE_BIN_PATH+":"+mysettings["PATH"] - - - mysettings["BUILD_PREFIX"] = mysettings["PORTAGE_TMPDIR"]+"/portage" - mysettings["HOME"] = mysettings["BUILD_PREFIX"]+"/homedir" - mysettings["PKG_TMPDIR"] = mysettings["PORTAGE_TMPDIR"]+"/portage-pkg" - mysettings["BUILDDIR"] = mysettings["BUILD_PREFIX"]+"/"+mysettings["PF"] - - mysettings["PORTAGE_BASHRC"] = EBUILD_SH_ENV_FILE - - #set up KV variable -- DEP SPEEDUP :: Don't waste time. Keep var persistent. - if (mydo!="depend") or not mysettings.has_key("KV"): - mykv,err1=ExtractKernelVersion(root+"usr/src/linux") - if mykv: - # Regular source tree - mysettings["KV"]=mykv - else: - mysettings["KV"]="" - - if (mydo!="depend") or not mysettings.has_key("KVERS"): - myso=os.uname()[2] - mysettings["KVERS"]=myso[1] - - - # get possible slot information from the deps file - if mydo=="depend": - if mysettings.has_key("PORTAGE_DEBUG") and mysettings["PORTAGE_DEBUG"]=="1": - # XXX: This needs to use a FD for saving the output into a file. - # XXX: Set this up through spawn - pass - writemsg("!!! DEBUG: dbkey: %s\n" % str(dbkey), 2) - if dbkey: - mysettings["dbkey"] = dbkey - else: - mysettings["dbkey"] = mysettings.depcachedir+"/aux_db_key_temp" - - retval = spawn(EBUILD_SH_BINARY+" depend",mysettings) - return retval - - logfile=None - # Build directory creation isn't required for any of these. - if mydo not in ["fetch","digest","manifest"]: - - if not os.path.exists(mysettings["BUILD_PREFIX"]): - os.makedirs(mysettings["BUILD_PREFIX"]) - os.chown(mysettings["BUILD_PREFIX"],portage_uid,portage_gid) - os.chmod(mysettings["BUILD_PREFIX"],00775) - - # Should be ok again to set $T, as sandbox does not depend on it - mysettings["T"]=mysettings["BUILDDIR"]+"/temp" - if cleanup or mydo=="clean": - if os.path.exists(mysettings["T"]): - shutil.rmtree(mysettings["T"]) - if not os.path.exists(mysettings["T"]): - os.makedirs(mysettings["T"]) - os.chown(mysettings["T"],portage_uid,portage_gid) - os.chmod(mysettings["T"],02770) - - try: # XXX: negative RESTRICT - if not (("nouserpriv" in string.split(mysettings["PORTAGE_RESTRICT"])) or \ - ("userpriv" in string.split(mysettings["PORTAGE_RESTRICT"]))): - if ("userpriv" in features) and (portage_uid and portage_gid): - if (secpass==2): - if os.path.exists(mysettings["HOME"]): - # XXX: Potentially bad, but held down by HOME replacement above. - spawn("rm -Rf "+mysettings["HOME"],mysettings, free=1) - if not os.path.exists(mysettings["HOME"]): - os.makedirs(mysettings["HOME"]) - elif ("userpriv" in features): - print "!!! Disabling userpriv from features... Portage UID/GID not valid." - del features[features.index("userpriv")] - except SystemExit, e: - raise - except Exception, e: - print "!!! Couldn't empty HOME:",mysettings["HOME"] - print "!!!",e - - try: - # no reason to check for depend since depend returns above. - if not os.path.exists(mysettings["BUILD_PREFIX"]): - os.makedirs(mysettings["BUILD_PREFIX"]) - os.chown(mysettings["BUILD_PREFIX"],portage_uid,portage_gid) - if not os.path.exists(mysettings["BUILDDIR"]): - os.makedirs(mysettings["BUILDDIR"]) - os.chown(mysettings["BUILDDIR"],portage_uid,portage_gid) - except OSError, e: - print "!!! File system problem. (ReadOnly? Out of space?)" - print "!!! Perhaps: rm -Rf",mysettings["BUILD_PREFIX"] - print "!!!",str(e) - return 1 - - try: - if not os.path.exists(mysettings["HOME"]): - os.makedirs(mysettings["HOME"]) - os.chown(mysettings["HOME"],portage_uid,portage_gid) - os.chmod(mysettings["HOME"],02770) - except OSError, e: - print "!!! File system problem. (ReadOnly? Out of space?)" - print "!!! Failed to create fake home directory in BUILDDIR" - print "!!!",str(e) - return 1 - - try: - if ("ccache" in features): - if (not mysettings.has_key("CCACHE_DIR")) or (mysettings["CCACHE_DIR"]==""): - mysettings["CCACHE_DIR"]=mysettings["PORTAGE_TMPDIR"]+"/ccache" - if not os.path.exists(mysettings["CCACHE_DIR"]): - os.makedirs(mysettings["CCACHE_DIR"]) - mystat = os.stat(mysettings["CCACHE_DIR"]) - if ("userpriv" in features): - if mystat[stat.ST_UID] != portage_gid or ((mystat[stat.ST_MODE]&02070)!=02070): - spawn("chgrp -R "+str(portage_gid)+" "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chown "+str(portage_uid)+":"+str(portage_gid)+" "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chmod -R u+rw "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chmod -R g+rw "+mysettings["CCACHE_DIR"], mysettings, free=1) - else: - if mystat[stat.ST_UID] != 0 or ((mystat[stat.ST_MODE]&02070)!=02070): - spawn("chgrp -R "+str(portage_gid)+" "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chown 0:"+str(portage_gid)+" "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chmod -R u+rw "+mysettings["CCACHE_DIR"], mysettings, free=1) - spawn("chmod -R g+rw "+mysettings["CCACHE_DIR"], mysettings, free=1) - except OSError, e: - print "!!! File system problem. (ReadOnly? Out of space?)" - print "!!! Perhaps: rm -Rf",mysettings["BUILD_PREFIX"] - print "!!!",str(e) - return 1 - - #try: - # mystat=os.stat(mysettings["CCACHE_DIR"]) - # if (mystat[stat.ST_GID]!=portage_gid) or ((mystat[stat.ST_MODE]&02070)!=02070): - # print "*** Adjusting ccache permissions for portage user..." - # os.chown(mysettings["CCACHE_DIR"],portage_uid,portage_gid) - # os.chmod(mysettings["CCACHE_DIR"],02770) - # spawn("chown -R "+str(portage_uid)+":"+str(portage_gid)+" "+mysettings["CCACHE_DIR"],mysettings, free=1) - # spawn("chmod -R g+rw "+mysettings["CCACHE_DIR"],mysettings, free=1) - #except SystemExit, e: - # raise - #except: - # pass - - if "distcc" in features: - try: - if (not mysettings.has_key("DISTCC_DIR")) or (mysettings["DISTCC_DIR"]==""): - mysettings["DISTCC_DIR"]=mysettings["PORTAGE_TMPDIR"]+"/portage/.distcc" - if not os.path.exists(mysettings["DISTCC_DIR"]): - os.makedirs(mysettings["DISTCC_DIR"]) - os.chown(mysettings["DISTCC_DIR"],portage_uid,portage_gid) - os.chmod(mysettings["DISTCC_DIR"],02775) - for x in ("/lock", "/state"): - if not os.path.exists(mysettings["DISTCC_DIR"]+x): - os.mkdir(mysettings["DISTCC_DIR"]+x) - os.chown(mysettings["DISTCC_DIR"]+x,portage_uid,portage_gid) - os.chmod(mysettings["DISTCC_DIR"]+x,02775) - except OSError, e: - writemsg("\n!!! File system problem when setting DISTCC_DIR directory permissions.\n") - writemsg( "!!! DISTCC_DIR="+str(mysettings["DISTCC_DIR"]+"\n")) - writemsg( "!!! "+str(e)+"\n\n") - time.sleep(5) - features.remove("distcc") - mysettings["DISTCC_DIR"]="" - - mysettings["WORKDIR"]=mysettings["BUILDDIR"]+"/work" - mysettings["D"]=mysettings["BUILDDIR"]+"/image/" - - if mysettings.has_key("PORT_LOGDIR"): - if os.access(mysettings["PORT_LOGDIR"]+"/",os.W_OK): - try: - os.chown(mysettings["BUILD_PREFIX"],portage_uid,portage_gid) - os.chmod(mysettings["PORT_LOGDIR"],02770) - if not mysettings.has_key("LOG_PF") or (mysettings["LOG_PF"] != mysettings["PF"]): - mysettings["LOG_PF"]=mysettings["PF"] - mysettings["LOG_COUNTER"]=str(db[myroot]["vartree"].dbapi.get_counter_tick_core("/")) - logfile="%s/%s-%s.log" % (mysettings["PORT_LOGDIR"],mysettings["LOG_COUNTER"],mysettings["LOG_PF"]) - except ValueError, e: - mysettings["PORT_LOGDIR"]="" - print "!!! Unable to chown/chmod PORT_LOGDIR. Disabling logging." - print "!!!",e - else: - print "!!! Cannot create log... No write access / Does not exist" - print "!!! PORT_LOGDIR:",mysettings["PORT_LOGDIR"] - mysettings["PORT_LOGDIR"]="" - - if mydo=="unmerge": - return unmerge(mysettings["CATEGORY"],mysettings["PF"],myroot,mysettings) - - # if any of these are being called, handle them -- running them out of the sandbox -- and stop now. - if mydo=="clean": - logfile=None - if mydo in ["help","clean","setup"]: - return spawn(EBUILD_SH_BINARY+" "+mydo,mysettings,debug=debug,free=1,logfile=logfile) - elif mydo in ["prerm","postrm","preinst","postinst","config"]: - mysettings.load_infodir(pkg_dir) - return spawn(EBUILD_SH_BINARY+" "+mydo,mysettings,debug=debug,free=1,logfile=logfile) - - try: - mysettings["SLOT"],mysettings["RESTRICT"] = db["/"]["porttree"].dbapi.aux_get(mycpv,["SLOT","RESTRICT"]) - except (IOError,KeyError): - print red("doebuild():")+" aux_get() error reading "+mycpv+"; aborting." - sys.exit(1) - - newuris, alist = db["/"]["porttree"].dbapi.getfetchlist(mycpv,mysettings=mysettings) - alluris, aalist = db["/"]["porttree"].dbapi.getfetchlist(mycpv,mysettings=mysettings,all=1) - mysettings["A"]=string.join(alist," ") - mysettings["AA"]=string.join(aalist," ") - if ("mirror" in features) or fetchall: - fetchme=alluris[:] - checkme=aalist[:] - elif mydo=="digest": - fetchme=alluris[:] - checkme=aalist[:] - digestfn=mysettings["FILESDIR"]+"/digest-"+mysettings["PF"] - if os.path.exists(digestfn): - mydigests=digestParseFile(digestfn) - if mydigests: - for x in mydigests: - while x in checkme: - i = checkme.index(x) - del fetchme[i] - del checkme[i] - else: - fetchme=newuris[:] - checkme=alist[:] - - try: - if not os.path.exists(mysettings["DISTDIR"]): - os.makedirs(mysettings["DISTDIR"]) - if not os.path.exists(mysettings["DISTDIR"]+"/cvs-src"): - os.makedirs(mysettings["DISTDIR"]+"/cvs-src") - except OSError, e: - print "!!! File system problem. (Bad Symlink?)" - print "!!! Fetching may fail:",str(e) - - try: - mystat=os.stat(mysettings["DISTDIR"]+"/cvs-src") - if ((mystat[stat.ST_GID]!=portage_gid) or ((mystat[stat.ST_MODE]&02770)!=02770)) and not listonly: - print "*** Adjusting cvs-src permissions for portage user..." - os.chown(mysettings["DISTDIR"]+"/cvs-src",0,portage_gid) - os.chmod(mysettings["DISTDIR"]+"/cvs-src",02770) - spawn("chgrp -R "+str(portage_gid)+" "+mysettings["DISTDIR"]+"/cvs-src", free=1) - spawn("chmod -R g+rw "+mysettings["DISTDIR"]+"/cvs-src", free=1) - except SystemExit, e: - raise - except: - pass - - if not fetch(fetchme, mysettings, listonly=listonly, fetchonly=fetchonly): - return 1 - - if mydo=="fetch" and listonly: - return 0 - - if "digest" in features: - #generate digest if it doesn't exist. - if mydo=="digest": - return (not digestgen(aalist,mysettings,overwrite=1)) - else: - digestgen(aalist,mysettings,overwrite=0) - elif mydo=="digest": - #since we are calling "digest" directly, recreate the digest even if it already exists - return (not digestgen(aalist,mysettings,overwrite=1)) - if mydo=="manifest": - return (not digestgen(aalist,mysettings,overwrite=1,manifestonly=1)) - - if not digestcheck(checkme, mysettings, ("strict" in features)): - return 1 - - if mydo=="fetch": - return 0 - - #initial dep checks complete; time to process main commands - - nosandbox=(("userpriv" in features) and ("usersandbox" not in features)) - actionmap={ - "depend": { "args":(0,1)}, # sandbox / portage - "setup": { "args":(1,0)}, # without / root - "unpack": {"dep":"setup", "args":(0,1)}, # sandbox / portage - "compile": {"dep":"unpack", "args":(nosandbox,1)}, # optional / portage - "test": {"dep":"compile", "args":(nosandbox,1)}, # optional / portage - "install": {"dep":"test", "args":(0,0)}, # sandbox / root - "rpm": {"dep":"install", "args":(0,0)}, # sandbox / root - "package": {"dep":"install", "args":(0,0)}, # sandbox / root - } - - if mydo in actionmap.keys(): - if mydo=="package": - for x in ["","/"+mysettings["CATEGORY"],"/All"]: - if not os.path.exists(mysettings["PKGDIR"]+x): - os.makedirs(mysettings["PKGDIR"]+x) - # REBUILD CODE FOR TBZ2 --- XXXX - return spawnebuild(mydo,actionmap,mysettings,debug,logfile=logfile) - elif mydo=="qmerge": - #check to ensure install was run. this *only* pops up when users forget it and are using ebuild - if not os.path.exists(mysettings["BUILDDIR"]+"/.installed"): - print "!!! mydo=qmerge, but install phase hasn't been ran" - sys.exit(1) - #qmerge is specifically not supposed to do a runtime dep check - return merge(mysettings["CATEGORY"],mysettings["PF"],mysettings["D"],mysettings["BUILDDIR"]+"/build-info",myroot,mysettings) - elif mydo=="merge": - retval=spawnebuild("install",actionmap,mysettings,debug,alwaysdep=1,logfile=logfile) - if retval: - return retval - return merge(mysettings["CATEGORY"],mysettings["PF"],mysettings["D"],mysettings["BUILDDIR"]+"/build-info",myroot,mysettings,myebuild=mysettings["EBUILD"]) - else: - print "!!! Unknown mydo:",mydo - sys.exit(1) - -expandcache={} - -def movefile(src,dest,newmtime=None,sstat=None,mysettings=None): - """moves a file from src to dest, preserving all permissions and attributes; mtime will - be preserved even when moving across filesystems. Returns true on success and false on - failure. Move is atomic.""" - #print "movefile("+str(src)+","+str(dest)+","+str(newmtime)+","+str(sstat)+")" - global lchown - - try: - if not sstat: - sstat=os.lstat(src) - if bsd_chflags: - sflags=bsd_chflags.lgetflags(src) - if sflags < 0: - # Problem getting flags... - writemsg("!!! Couldn't get flags for "+dest+"\n") - return None - - except SystemExit, e: - raise - except Exception, e: - print "!!! Stating source file failed... movefile()" - print "!!!",e - return None - - destexists=1 - try: - dstat=os.lstat(dest) - except SystemExit, e: - raise - except: - dstat=os.lstat(os.path.dirname(dest)) - destexists=0 - - if bsd_chflags: - # Check that we can actually unset schg etc flags... - # Clear the flags on source and destination; we'll reinstate them after merging - if(destexists): - if bsd_chflags.lchflags(dest, 0) < 0: - writemsg("!!! Couldn't clear flags on file being merged: \n ") - # We might have an immutable flag on the parent dir; save and clear. - pflags=bsd_chflags.lgetflags(os.path.dirname(dest)) - bsd_chflags.lchflags(os.path.dirname(dest), 0) - - # Don't bother checking the return value here; if it fails then the next line will catch it. - bsd_chflags.lchflags(src, 0) - - if bsd_chflags.lhasproblems(src)>0 or (destexists and bsd_chflags.lhasproblems(dest)>0) or bsd_chflags.lhasproblems(os.path.dirname(dest))>0: - # This is bad: we can't merge the file with these flags set. - writemsg("!!! Can't merge file "+dest+" because of flags set\n") - return None - - if destexists: - if stat.S_ISLNK(dstat[stat.ST_MODE]): - try: - os.unlink(dest) - destexists=0 - except SystemExit, e: - raise - except Exception, e: - pass - - if stat.S_ISLNK(sstat[stat.ST_MODE]): - try: - target=os.readlink(src) - if mysettings and mysettings["D"]: - if target.find(mysettings["D"])==0: - target=target[len(mysettings["D"]):] - if destexists and not stat.S_ISDIR(dstat[stat.ST_MODE]): - os.unlink(dest) - if selinux_enabled: - sid = selinux.get_lsid(src) - selinux.secure_symlink(target,dest,sid) - else: - os.symlink(target,dest) - lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - if bsd_chflags: - # Restore the flags we saved before moving - if bsd_chflags.lchflags(dest, sflags) < 0 or bsd_chflags.lchflags(os.path.dirname(dest), pflags) < 0: - writemsg("!!! Couldn't restore flags ("+str(flags)+") on " + dest+":\n") - writemsg("!!! %s\n" % str(e)) - return None - return os.lstat(dest)[stat.ST_MTIME] - except SystemExit, e: - raise - except Exception, e: - print "!!! failed to properly create symlink:" - print "!!!",dest,"->",target - print "!!!",e - return None - - renamefailed=1 - if sstat[stat.ST_DEV]==dstat[stat.ST_DEV] or selinux_enabled: - try: - if selinux_enabled: - ret=selinux.secure_rename(src,dest) - else: - ret=os.rename(src,dest) - renamefailed=0 - except SystemExit, e: - raise - except Exception, e: - import errno - if e[0]!=errno.EXDEV: - # Some random error. - print "!!! Failed to move",src,"to",dest - print "!!!",e - return None - # Invalid cross-device-link 'bind' mounted or actually Cross-Device - if renamefailed: - didcopy=0 - if stat.S_ISREG(sstat[stat.ST_MODE]): - try: # For safety copy then move it over. - if selinux_enabled: - selinux.secure_copy(src,dest+"#new") - selinux.secure_rename(dest+"#new",dest) - else: - shutil.copyfile(src,dest+"#new") - os.rename(dest+"#new",dest) - didcopy=1 - except SystemExit, e: - raise - except Exception, e: - print '!!! copy',src,'->',dest,'failed.' - print "!!!",e - return None - else: - #we don't yet handle special, so we need to fall back to /bin/mv - if selinux_enabled: - a=commands.getstatusoutput(MOVE_BINARY+" -c -f "+"'"+src+"' '"+dest+"'") - else: - a=commands.getstatusoutput(MOVE_BINARY+" -f "+"'"+src+"' '"+dest+"'") - if a[0]!=0: - print "!!! Failed to move special file:" - print "!!! '"+src+"' to '"+dest+"'" - print "!!!",a - return None # failure - try: - if didcopy: - lchown(dest,sstat[stat.ST_UID],sstat[stat.ST_GID]) - os.chmod(dest, stat.S_IMODE(sstat[stat.ST_MODE])) # Sticky is reset on chown - os.unlink(src) - except SystemExit, e: - raise - except Exception, e: - print "!!! Failed to chown/chmod/unlink in movefile()" - print "!!!",dest - print "!!!",e - return None - - if newmtime: - os.utime(dest,(newmtime,newmtime)) - else: - os.utime(dest, (sstat[stat.ST_ATIME], sstat[stat.ST_MTIME])) - newmtime=sstat[stat.ST_MTIME] - - if bsd_chflags: - # Restore the flags we saved before moving - if bsd_chflags.lchflags(dest, sflags) < 0 or bsd_chflags.lchflags(os.path.dirname(dest), pflags) < 0: - writemsg("!!! Couldn't restore flags ("+str(sflags)+") on " + dest+":\n") - return None - - return newmtime - -def merge(mycat,mypkg,pkgloc,infloc,myroot,mysettings,myebuild=None): - mylink=dblink(mycat,mypkg,myroot,mysettings) - return mylink.merge(pkgloc,infloc,myroot,myebuild) - -def unmerge(cat,pkg,myroot,mysettings,mytrimworld=1): - mylink=dblink(cat,pkg,myroot,mysettings) - if mylink.exists(): - mylink.unmerge(trimworld=mytrimworld,cleanup=1) - mylink.delete() - -def relparse(myver): - "converts last version part into three components" - number=0 - suffix=0 - endtype=0 - endnumber=0 - - mynewver=string.split(myver,"_") - myver=mynewver[0] - - #normal number or number with letter at end - divider=len(myver)-1 - if myver[divider:] not in "1234567890": - #letter at end - suffix=ord(myver[divider:]) - number=string.atof(myver[0:divider]) - else: - number=string.atof(myver) - - if len(mynewver)==2: - #an endversion - for x in endversion_keys: - elen=len(x) - if mynewver[1][:elen] == x: - match=1 - endtype=endversion[x] - try: - endnumber=string.atof(mynewver[1][elen:]) - except SystemExit, e: - raise - except: - endnumber=0 - break - return [number,suffix,endtype,endnumber] - -#returns 1 if valid version string, else 0 -# valid string in format: <v1>.<v2>...<vx>[a-z,_{endversion}[vy]] -# ververify doesn't do package rev. - -vercache={} -def ververify(myorigval,silent=1): - try: - return vercache[myorigval] - except KeyError: - pass - if len(myorigval)==0: - if not silent: - print "!!! Name error: package contains empty \"-\" part." - return 0 - myval=string.split(myorigval,'.') - if len(myval)==0: - if not silent: - print "!!! Name error: empty version string." - vercache[myorigval]=0 - return 0 - #all but the last version must be a numeric - for x in myval[:-1]: - if not len(x): - if not silent: - print "!!! Name error in",myorigval+": two decimal points in a row" - vercache[myorigval]=0 - return 0 - try: - foo=int(x) - except SystemExit, e: - raise - except: - if not silent: - print "!!! Name error in",myorigval+": \""+x+"\" is not a valid version component." - vercache[myorigval]=0 - return 0 - if not len(myval[-1]): - if not silent: - print "!!! Name error in",myorigval+": two decimal points in a row" - vercache[myorigval]=0 - return 0 - try: - foo=int(myval[-1]) - vercache[myorigval]=1 - return 1 - except SystemExit, e: - raise - except: - pass - #ok, our last component is not a plain number or blank, let's continue - if myval[-1][-1] in string.lowercase: - try: - foo=int(myval[-1][:-1]) - vercache[myorigval]=1 - return 1 - # 1a, 2.0b, etc. - except SystemExit, e: - raise - except: - pass - #ok, maybe we have a 1_alpha or 1_beta2; let's see - #ep="endpart" - ep=string.split(myval[-1],"_") - if len(ep)!=2: - if not silent: - print "!!! Name error in",myorigval - vercache[myorigval]=0 - return 0 - try: - foo=int(ep[0][-1]) - chk=ep[0] - except SystemExit, e: - raise - except: - # because it's ok last char is not numeric. example: foo-1.0.0a_pre1 - chk=ep[0][:-1] - - try: - foo=int(chk) - except SystemExit, e: - raise - except: - #this needs to be numeric or numeric+single letter, - #i.e. the "1" in "1_alpha" or "1a_alpha" - if not silent: - print "!!! Name error in",myorigval+": characters before _ must be numeric or numeric+single letter" - vercache[myorigval]=0 - return 0 - for mye in endversion_keys: - if ep[1][0:len(mye)]==mye: - if len(mye)==len(ep[1]): - #no trailing numeric; ok - vercache[myorigval]=1 - return 1 - else: - try: - foo=int(ep[1][len(mye):]) - vercache[myorigval]=1 - return 1 - except SystemExit, e: - raise - except: - #if no endversions work, *then* we return 0 - pass - if not silent: - print "!!! Name error in",myorigval - vercache[myorigval]=0 - return 0 - -def isvalidatom(atom): - mycpv_cps = catpkgsplit(dep_getcpv(atom)) - operator = get_operator(atom) - if operator: - if mycpv_cps and mycpv_cps[0] != "null": - # >=cat/pkg-1.0 - return 1 - else: - # >=cat/pkg or >=pkg-1.0 (no category) - return 0 - if mycpv_cps: - # cat/pkg-1.0 - return 0 - - if (len(string.split(atom, '/'))==2): - # cat/pkg - return 1 - else: - return 0 - -def isjustname(mypkg): - myparts=string.split(mypkg,'-') - for x in myparts: - if ververify(x): - return 0 - return 1 - -iscache={} -def isspecific(mypkg): - "now supports packages with no category" - try: - return iscache[mypkg] - except SystemExit, e: - raise - except: - pass - mysplit=string.split(mypkg,"/") - if not isjustname(mysplit[-1]): - iscache[mypkg]=1 - return 1 - iscache[mypkg]=0 - return 0 - -# This function can be used as a package verification function, i.e. -# "pkgsplit("foo-1.2-1") will return None if foo-1.2-1 isn't a valid -# package (with version) name. If it is a valid name, pkgsplit will -# return a list containing: [ pkgname, pkgversion(norev), pkgrev ]. -# For foo-1.2-1, this list would be [ "foo", "1.2", "1" ]. For -# Mesa-3.0, this list would be [ "Mesa", "3.0", "0" ]. -pkgcache={} - -def pkgsplit(mypkg,silent=1): - try: - if not pkgcache[mypkg]: - return None - return pkgcache[mypkg][:] - except KeyError: - pass - myparts=string.split(mypkg,'-') - if len(myparts)<2: - if not silent: - print "!!! Name error in",mypkg+": missing a version or name part." - pkgcache[mypkg]=None - return None - for x in myparts: - if len(x)==0: - if not silent: - print "!!! Name error in",mypkg+": empty \"-\" part." - pkgcache[mypkg]=None - return None - #verify rev - revok=0 - myrev=myparts[-1] - if len(myrev) and myrev[0]=="r": - try: - int(myrev[1:]) - revok=1 - except SystemExit, e: - raise - except: - pass - if revok: - if ververify(myparts[-2]): - if len(myparts)==2: - pkgcache[mypkg]=None - return None - else: - for x in myparts[:-2]: - if ververify(x): - pkgcache[mypkg]=None - return None - #names can't have versiony looking parts - myval=[string.join(myparts[:-2],"-"),myparts[-2],myparts[-1]] - pkgcache[mypkg]=myval - return myval - else: - pkgcache[mypkg]=None - return None - - elif ververify(myparts[-1],silent=silent): - if len(myparts)==1: - if not silent: - print "!!! Name error in",mypkg+": missing name part." - pkgcache[mypkg]=None - return None - else: - for x in myparts[:-1]: - if ververify(x): - if not silent: - print "!!! Name error in",mypkg+": multiple version parts." - pkgcache[mypkg]=None - return None - myval=[string.join(myparts[:-1],"-"),myparts[-1],"r0"] - pkgcache[mypkg]=myval[:] - return myval - else: - pkgcache[mypkg]=None - return None - -def getCPFromCPV(mycpv): - """Calls pkgsplit on a cpv and returns only the cp.""" - return pkgsplit(mycpv)[0] - -catcache={} -def catpkgsplit(mydata,silent=1): - "returns [cat, pkgname, version, rev ]" - try: - if not catcache[mydata]: - return None - return catcache[mydata][:] - except KeyError: - pass - mysplit=mydata.split("/") - p_split=None - if len(mysplit)==1: - retval=["null"] - p_split=pkgsplit(mydata,silent=silent) - elif len(mysplit)==2: - retval=[mysplit[0]] - p_split=pkgsplit(mysplit[1],silent=silent) - if not p_split: - catcache[mydata]=None - return None - retval.extend(p_split) - catcache[mydata]=retval - return retval - -# vercmp: -# This takes two version strings and returns an integer to tell you whether -# the versions are the same, val1>val2 or val2>val1. -vcmpcache={} -def vercmp(val1,val2): - if val1==val2: - #quick short-circuit - return 0 - valkey=val1+" "+val2 - try: - return vcmpcache[valkey] - try: - return -vcmpcache[val2+" "+val1] - except KeyError: - pass - except KeyError: - pass - - # consider 1_p2 vc 1.1 - # after expansion will become (1_p2,0) vc (1,1) - # then 1_p2 is compared with 1 before 0 is compared with 1 - # to solve the bug we need to convert it to (1,0_p2) - # by splitting _prepart part and adding it back _after_expansion - val1_prepart = val2_prepart = '' - if val1.count('_'): - val1, val1_prepart = val1.split('_', 1) - if val2.count('_'): - val2, val2_prepart = val2.split('_', 1) - - # replace '-' by '.' - # FIXME: Is it needed? can val1/2 contain '-'? - val1=string.split(val1,'-') - if len(val1)==2: - val1[0]=val1[0]+"."+val1[1] - val2=string.split(val2,'-') - if len(val2)==2: - val2[0]=val2[0]+"."+val2[1] - - val1=string.split(val1[0],'.') - val2=string.split(val2[0],'.') - - #add back decimal point so that .03 does not become "3" ! - for x in range(1,len(val1)): - if val1[x][0] == '0' : - val1[x]='.' + val1[x] - for x in range(1,len(val2)): - if val2[x][0] == '0' : - val2[x]='.' + val2[x] - - # extend version numbers - if len(val2)<len(val1): - val2.extend(["0"]*(len(val1)-len(val2))) - elif len(val1)<len(val2): - val1.extend(["0"]*(len(val2)-len(val1))) - - # add back _prepart tails - if val1_prepart: - val1[-1] += '_' + val1_prepart - if val2_prepart: - val2[-1] += '_' + val2_prepart - #The above code will extend version numbers out so they - #have the same number of digits. - for x in range(0,len(val1)): - cmp1=relparse(val1[x]) - cmp2=relparse(val2[x]) - for y in range(0,4): - myret=cmp1[y]-cmp2[y] - if myret != 0: - vcmpcache[valkey]=myret - return myret - vcmpcache[valkey]=0 - return 0 - - -def pkgcmp(pkg1,pkg2): - """if returnval is less than zero, then pkg2 is newer than pkg1, zero if equal and positive if older.""" - if pkg1[0] != pkg2[0]: - return None - mycmp=vercmp(pkg1[1],pkg2[1]) - if mycmp>0: - return 1 - if mycmp<0: - return -1 - r1=int(pkg1[2][1:]) - r2=int(pkg2[2][1:]) - if r1>r2: - return 1 - if r2>r1: - return -1 - return 0 - -def dep_parenreduce(mysplit,mypos=0): - "Accepts a list of strings, and converts '(' and ')' surrounded items to sub-lists" - while (mypos<len(mysplit)): - if (mysplit[mypos]=="("): - firstpos=mypos - mypos=mypos+1 - while (mypos<len(mysplit)): - if mysplit[mypos]==")": - mysplit[firstpos:mypos+1]=[mysplit[firstpos+1:mypos]] - mypos=firstpos - break - elif mysplit[mypos]=="(": - #recurse - mysplit=dep_parenreduce(mysplit,mypos=mypos) - mypos=mypos+1 - mypos=mypos+1 - return mysplit - -def dep_opconvert(mysplit,myuse,mysettings): - "Does dependency operator conversion" - - #check_config_instance(mysettings) - - mypos=0 - newsplit=[] - while mypos<len(mysplit): - if type(mysplit[mypos])==types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos],myuse,mysettings)) - mypos += 1 - elif mysplit[mypos]==")": - #mismatched paren, error - return None - elif mysplit[mypos]=="||": - if ((mypos+1)>=len(mysplit)) or (type(mysplit[mypos+1])!=types.ListType): - # || must be followed by paren'd list - return None - try: - mynew=dep_opconvert(mysplit[mypos+1],myuse,mysettings) - except SystemExit, e: - raise - except Exception, e: - print "!!! Unable to satisfy OR dependency:",string.join(mysplit," || ") - raise e - mynew[0:0]=["||"] - newsplit.append(mynew) - mypos += 2 - elif mysplit[mypos][-1]=="?": - #uses clause, i.e "gnome? ( foo bar )" - #this is a quick and dirty hack so that repoman can enable all USE vars: - if (len(myuse)==1) and (myuse[0]=="*") and mysettings: - # enable it even if it's ! (for repoman) but kill it if it's - # an arch variable that isn't for this arch. XXX Sparc64? - k=mysplit[mypos][:-1] - if k[0]=="!": - k=k[1:] - if k not in archlist and k not in mysettings.usemask: - enabled=1 - elif k in archlist: - if k==mysettings["ARCH"]: - if mysplit[mypos][0]=="!": - enabled=0 - else: - enabled=1 - elif mysplit[mypos][0]=="!": - enabled=1 - else: - enabled=0 - else: - enabled=0 - else: - if mysplit[mypos][0]=="!": - myusevar=mysplit[mypos][1:-1] - if myusevar in myuse: - enabled=0 - else: - enabled=1 - else: - myusevar=mysplit[mypos][:-1] - if myusevar in myuse: - enabled=1 - else: - enabled=0 - if (mypos+2<len(mysplit)) and (mysplit[mypos+2]==":"): - #colon mode - if enabled: - #choose the first option - if type(mysplit[mypos+1])==types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+1],myuse,mysettings)) - else: - newsplit.append(mysplit[mypos+1]) - else: - #choose the alternate option - if type(mysplit[mypos+1])==types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+3],myuse,mysettings)) - else: - newsplit.append(mysplit[mypos+3]) - mypos += 4 - else: - #normal use mode - if enabled: - if type(mysplit[mypos+1])==types.ListType: - newsplit.append(dep_opconvert(mysplit[mypos+1],myuse,mysettings)) - else: - newsplit.append(mysplit[mypos+1]) - #otherwise, continue. - mypos += 2 - else: - #normal item - newsplit.append(mysplit[mypos]) - mypos += 1 - return newsplit - -def dep_virtual(mysplit, mysettings): - "Does virtual dependency conversion" - - - - newsplit=[] - for x in mysplit: - if type(x)==types.ListType: - newsplit.append(dep_virtual(x, mysettings)) - else: - mykey=dep_getkey(x) - if mysettings.virtuals.has_key(mykey): - if len(mysettings.virtuals[mykey])==1: - a=string.replace(x, mykey, mysettings.virtuals[mykey][0]) - else: - if x[0]=="!": - # blocker needs "and" not "or(||)". - a=[] - else: - a=['||'] - for y in mysettings.virtuals[mykey]: - a.append(string.replace(x, mykey, y)) - newsplit.append(a) - else: - newsplit.append(x) - return newsplit - -def dep_eval(deplist): - if len(deplist)==0: - return 1 - if deplist[0]=="||": - #or list; we just need one "1" - for x in deplist[1:]: - if type(x)==types.ListType: - if dep_eval(x)==1: - return 1 - elif x==1: - return 1 - return 0 - else: - for x in deplist: - if type(x)==types.ListType: - if dep_eval(x)==0: - return 0 - elif x==0 or x==2: - return 0 - return 1 - -def dep_zapdeps(unreduced,reduced,vardbapi=None,use_binaries=0): - """Takes an unreduced and reduced deplist and removes satisfied dependencies. - Returned deplist contains steps that must be taken to satisfy dependencies.""" - writemsg("ZapDeps -- %s\n" % (use_binaries), 2) - if unreduced==[] or unreduced==['||'] : - return [] - if unreduced[0]=="||": - if dep_eval(reduced): - #deps satisfied, return empty list. - return [] - else: - #try to find an installed dep. - ### We use fakedb when --update now, so we can't use local vardbapi here. - ### This should be fixed in the feature. - ### see bug 45468. - ##if vardbapi: - ## mydbapi=vardbapi - ##else: - ## mydbapi=db[root]["vartree"].dbapi - mydbapi=db[root]["vartree"].dbapi - - if db["/"].has_key("porttree"): - myportapi=db["/"]["porttree"].dbapi - else: - myportapi=None - - if use_binaries and db["/"].has_key("bintree"): - mybinapi=db["/"]["bintree"].dbapi - writemsg("Using bintree...\n",2) - else: - mybinapi=None - - x=1 - candidate=[] - while x<len(reduced): - writemsg("x: %s, reduced[x]: %s\n" % (x,reduced[x]), 2) - if (type(reduced[x])==types.ListType): - newcand = dep_zapdeps(unreduced[x], reduced[x], vardbapi=vardbapi, use_binaries=use_binaries) - candidate.append(newcand) - else: - if (reduced[x]==False): - candidate.append([unreduced[x]]) - else: - candidate.append([]) - x+=1 - - #use installed and no-masked package(s) in portage. - for x in candidate: - match=1 - for pkg in x: - if not mydbapi.match(pkg): - match=0 - break - if myportapi: - if not myportapi.match(pkg): - match=0 - break - if match: - writemsg("Installed match: %s\n" % (x), 2) - return x - - # Use binary packages if available. - if mybinapi: - for x in candidate: - match=1 - for pkg in x: - if not mybinapi.match(pkg): - match=0 - break - else: - writemsg("Binary match: %s\n" % (pkg), 2) - if match: - writemsg("Binary match final: %s\n" % (x), 2) - return x - - #use no-masked package(s) in portage tree - if myportapi: - for x in candidate: - match=1 - for pkg in x: - if not myportapi.match(pkg): - match=0 - break - if match: - writemsg("Porttree match: %s\n" % (x), 2) - return x - - #none of the no-masked pkg, use the first one - writemsg("Last resort candidate: %s\n" % (candidate[0]), 2) - return candidate[0] - else: - if dep_eval(reduced): - #deps satisfied, return empty list. - return [] - else: - returnme=[] - x=0 - while x<len(reduced): - if type(reduced[x])==types.ListType: - returnme+=dep_zapdeps(unreduced[x],reduced[x], vardbapi=vardbapi, use_binaries=use_binaries) - else: - if reduced[x]==False: - returnme.append(unreduced[x]) - x += 1 - return returnme - -def dep_getkey(mydep): - if not len(mydep): - return mydep - if mydep[0]=="*": - mydep=mydep[1:] - if mydep[-1]=="*": - mydep=mydep[:-1] - if mydep[0]=="!": - mydep=mydep[1:] - if mydep[:2] in [ ">=", "<=" ]: - mydep=mydep[2:] - elif mydep[:1] in "=<>~": - mydep=mydep[1:] - if isspecific(mydep): - mysplit=catpkgsplit(mydep) - if not mysplit: - return mydep - return mysplit[0]+"/"+mysplit[1] - else: - return mydep - -def dep_getcpv(mydep): - if not len(mydep): - return mydep - if mydep[0]=="*": - mydep=mydep[1:] - if mydep[-1]=="*": - mydep=mydep[:-1] - if mydep[0]=="!": - mydep=mydep[1:] - if mydep[:2] in [ ">=", "<=" ]: - mydep=mydep[2:] - elif mydep[:1] in "=<>~": - mydep=mydep[1:] - return mydep - -def cpv_getkey(mycpv): - myslash=mycpv.split("/") - mysplit=pkgsplit(myslash[-1]) - mylen=len(myslash) - if mylen==2: - return myslash[0]+"/"+mysplit[0] - elif mylen==1: - return mysplit[0] - else: - return mysplit - -def key_expand(mykey,mydb=None,use_cache=1): - mysplit=mykey.split("/") - if len(mysplit)==1: - if mydb and type(mydb)==types.InstanceType: - for x in settings.categories: - if mydb.cp_list(x+"/"+mykey,use_cache=use_cache): - return x+"/"+mykey - if virts_p.has_key(mykey): - return(virts_p[mykey][0]) - return "null/"+mykey - elif mydb: - if type(mydb)==types.InstanceType: - if (not mydb.cp_list(mykey,use_cache=use_cache)) and virts and virts.has_key(mykey): - return virts[mykey][0] - return mykey - -def cpv_expand(mycpv,mydb=None,use_cache=1): - """Given a string (packagename or virtual) expand it into a valid - cat/package string. Virtuals use the mydb to determine which provided - virtual is a valid choice and defaults to the first element when there - are no installed/available candidates.""" - myslash=mycpv.split("/") - mysplit=pkgsplit(myslash[-1]) - if len(myslash)>2: - # this is illegal case. - mysplit=[] - mykey=mycpv - elif len(myslash)==2: - if mysplit: - mykey=myslash[0]+"/"+mysplit[0] - else: - mykey=mycpv - if mydb: - writemsg("mydb.__class__: %s\n" % (mydb.__class__), 1) - if type(mydb)==types.InstanceType: - if (not mydb.cp_list(mykey,use_cache=use_cache)) and virts and virts.has_key(mykey): - writemsg("virts[%s]: %s\n" % (str(mykey),virts[mykey]), 1) - mykey_orig = mykey[:] - for vkey in virts[mykey]: - if mydb.cp_list(vkey,use_cache=use_cache): - mykey = vkey - writemsg("virts chosen: %s\n" % (mykey), 1) - break - if mykey == mykey_orig: - mykey=virts[mykey][0] - writemsg("virts defaulted: %s\n" % (mykey), 1) - #we only perform virtual expansion if we are passed a dbapi - else: - #specific cpv, no category, ie. "foo-1.0" - if mysplit: - myp=mysplit[0] - else: - # "foo" ? - myp=mycpv - mykey=None - matches=[] - if mydb: - for x in settings.categories: - if mydb.cp_list(x+"/"+myp,use_cache=use_cache): - matches.append(x+"/"+myp) - if (len(matches)>1): - raise ValueError, matches - elif matches: - mykey=matches[0] - - if not mykey and type(mydb)!=types.ListType: - if virts_p.has_key(myp): - mykey=virts_p[myp][0] - #again, we only perform virtual expansion if we have a dbapi (not a list) - if not mykey: - mykey="null/"+myp - if mysplit: - if mysplit[2]=="r0": - return mykey+"-"+mysplit[1] - else: - return mykey+"-"+mysplit[1]+"-"+mysplit[2] - else: - return mykey - -def dep_transform(mydep,oldkey,newkey): - origdep=mydep - if not len(mydep): - return mydep - if mydep[0]=="*": - mydep=mydep[1:] - prefix="" - postfix="" - if mydep[-1]=="*": - mydep=mydep[:-1] - postfix="*" - if mydep[:2] in [ ">=", "<=" ]: - prefix=mydep[:2] - mydep=mydep[2:] - elif mydep[:1] in "=<>~!": - prefix=mydep[:1] - mydep=mydep[1:] - if mydep==oldkey: - return prefix+newkey+postfix - else: - return origdep - -def dep_expand(mydep,mydb=None,use_cache=1): - if not len(mydep): - return mydep - if mydep[0]=="*": - mydep=mydep[1:] - prefix="" - postfix="" - if mydep[-1]=="*": - mydep=mydep[:-1] - postfix="*" - if mydep[:2] in [ ">=", "<=" ]: - prefix=mydep[:2] - mydep=mydep[2:] - elif mydep[:1] in "=<>~!": - prefix=mydep[:1] - mydep=mydep[1:] - return prefix+cpv_expand(mydep,mydb=mydb,use_cache=use_cache)+postfix - -def dep_check(depstring,mydbapi,mysettings,use="yes",mode=None,myuse=None,use_cache=1,use_binaries=0): - """Takes a depend string and parses the condition.""" - - #check_config_instance(mysettings) - - if use=="all": - #enable everything (for repoman) - myusesplit=["*"] - elif use=="yes": - if myuse==None: - #default behavior - myusesplit = string.split(mysettings["USE"]) - else: - myusesplit = myuse - # We've been given useflags to use. - #print "USE FLAGS PASSED IN." - #print myuse - #if "bindist" in myusesplit: - # print "BINDIST is set!" - #else: - # print "BINDIST NOT set." - else: - #we are being run by autouse(), don't consult USE vars yet. - # WE ALSO CANNOT USE SETTINGS - myusesplit=[] - - #convert parenthesis to sublists - mysplit = portage_dep.paren_reduce(depstring) - - if mysettings: - # XXX: use="all" is only used by repoman. Why would repoman checks want - # profile-masked USE flags to be enabled? - #if use=="all": - # mymasks=archlist[:] - #else: - mymasks=mysettings.usemask+archlist[:] - - while mysettings["ARCH"] in mymasks: - del mymasks[mymasks.index(mysettings["ARCH"])] - mysplit = portage_dep.use_reduce(mysplit,uselist=myusesplit,masklist=mymasks,matchall=(use=="all"),excludeall=[mysettings["ARCH"]]) - else: - mysplit = portage_dep.use_reduce(mysplit,uselist=myusesplit,matchall=(use=="all")) - - # Do the || conversions - mysplit=portage_dep.dep_opconvert(mysplit) - - #convert virtual dependencies to normal packages. - mysplit=dep_virtual(mysplit, mysettings) - #if mysplit==None, then we have a parse error (paren mismatch or misplaced ||) - #up until here, we haven't needed to look at the database tree - - if mysplit==None: - return [0,"Parse Error (parentheses mismatch?)"] - elif mysplit==[]: - #dependencies were reduced to nothing - return [1,[]] - mysplit2=mysplit[:] - mysplit2=dep_wordreduce(mysplit2,mysettings,mydbapi,mode,use_cache=use_cache) - if mysplit2==None: - return [0,"Invalid token"] - - writemsg("\n\n\n", 1) - writemsg("mysplit: %s\n" % (mysplit), 1) - writemsg("mysplit2: %s\n" % (mysplit2), 1) - myeval=dep_eval(mysplit2) - writemsg("myeval: %s\n" % (myeval), 1) - - if myeval: - return [1,[]] - else: - myzaps = dep_zapdeps(mysplit,mysplit2,vardbapi=mydbapi,use_binaries=use_binaries) - mylist = flatten(myzaps) - writemsg("myzaps: %s\n" % (myzaps), 1) - writemsg("mylist: %s\n" % (mylist), 1) - #remove duplicates - mydict={} - for x in mylist: - mydict[x]=1 - writemsg("mydict: %s\n" % (mydict), 1) - return [1,mydict.keys()] - -def dep_wordreduce(mydeplist,mysettings,mydbapi,mode,use_cache=1): - "Reduces the deplist to ones and zeros" - mypos=0 - deplist=mydeplist[:] - while mypos<len(deplist): - if type(deplist[mypos])==types.ListType: - #recurse - deplist[mypos]=dep_wordreduce(deplist[mypos],mysettings,mydbapi,mode,use_cache=use_cache) - elif deplist[mypos]=="||": - pass - else: - mykey = dep_getkey(deplist[mypos]) - if mysettings and mysettings.pprovideddict.has_key(mykey) and \ - match_from_list(deplist[mypos], mysettings.pprovideddict[mykey]): - deplist[mypos]=True - else: - if mode: - mydep=mydbapi.xmatch(mode,deplist[mypos]) - else: - mydep=mydbapi.match(deplist[mypos],use_cache=use_cache) - if mydep!=None: - tmp=(len(mydep)>=1) - if deplist[mypos][0]=="!": - #tmp=not tmp - # This is ad-hoc code. We should rewrite this later.. (See #52377) - # The reason is that portage uses fakedb when --update option now. - # So portage considers that a block package doesn't exist even if it exists. - # Then, #52377 happens. - # ==== start - # emerge checks if it's block or not, so we can always set tmp=False. - # but it's not clean.. - tmp=False - # ==== end - deplist[mypos]=tmp - else: - #encountered invalid string - return None - mypos=mypos+1 - return deplist - -def getmaskingreason(mycpv): - global portdb - mysplit = catpkgsplit(mycpv) - if not mysplit: - raise ValueError("invalid CPV: %s" % mycpv) - if not portdb.cpv_exists(mycpv): - raise KeyError("CPV %s does not exist" % mycpv) - mycp=mysplit[0]+"/"+mysplit[1] - - if settings.pmaskdict.has_key(mycp): - for x in settings.pmaskdict[mycp]: - if mycpv in portdb.xmatch("match-all", x): - pmaskfile = open(settings["PORTDIR"]+"/profiles/package.mask") - comment = "" - l = "\n" - while len(l) > 0: - l = pmaskfile.readline() - if len(l) == 0: - pmaskfile.close() - return None - if l[0] == "#": - comment += l - elif l == "\n": - comment = "" - elif l.strip() == x: - pmaskfile.close() - return comment - pmaskfile.close() - return None - -def getmaskingstatus(mycpv): - global portdb - mysplit = catpkgsplit(mycpv) - if not mysplit: - raise ValueError("invalid CPV: %s" % mycpv) - if not portdb.cpv_exists(mycpv): - raise KeyError("CPV %s does not exist" % mycpv) - mycp=mysplit[0]+"/"+mysplit[1] - - rValue = [] - - # profile checking - revmaskdict=settings.prevmaskdict - if revmaskdict.has_key(mycp): - for x in revmaskdict[mycp]: - if x[0]=="*": - myatom = x[1:] - else: - myatom = x - if not match_to_list(mycpv, [myatom]): - rValue.append("profile") - break - - # package.mask checking - maskdict=settings.pmaskdict - unmaskdict=settings.punmaskdict - if maskdict.has_key(mycp): - for x in maskdict[mycp]: - if mycpv in portdb.xmatch("match-all", x): - unmask=0 - if unmaskdict.has_key(mycp): - for z in unmaskdict[mycp]: - if mycpv in portdb.xmatch("match-all",z): - unmask=1 - break - if unmask==0: - rValue.append("package.mask") - - # keywords checking - mygroups = portdb.aux_get(mycpv, ["KEYWORDS"])[0].split() - pgroups=groups[:] - myarch = settings["ARCH"] - pkgdict = settings.pkeywordsdict - - cp = dep_getkey(mycpv) - if pkgdict.has_key(cp): - matches = match_to_list(mycpv, pkgdict[cp].keys()) - for match in matches: - pgroups.extend(pkgdict[cp][match]) - - kmask = "missing" - - for keyword in pgroups: - if keyword in mygroups: - kmask=None - - if kmask: - fallback = None - for gp in mygroups: - if gp=="*": - kmask=None - break - elif gp=="-*": - fallback="-*" - elif gp=="-"+myarch: - kmask="-"+myarch - break - elif gp=="~"+myarch: - kmask="~"+myarch - break - if kmask == "missing" and fallback: - kmask = fallback - - if kmask: - rValue.append(kmask+" keyword") - return rValue - -def fixdbentries(old_value, new_value, dbdir): - """python replacement for the fixdbentries script, replaces old_value - with new_value for package names in files in dbdir.""" - for myfile in [f for f in os.listdir(dbdir) if not f == "CONTENTS"]: - f = open(dbdir+"/"+myfile, "r") - mycontent = f.read() - f.close() - if not mycontent.count(old_value): - continue - old_value = re.escape(old_value); - mycontent = re.sub(old_value+"$", new_value, mycontent) - mycontent = re.sub(old_value+"(\\s)", new_value+"\\1", mycontent) - mycontent = re.sub(old_value+"(-[^a-zA-Z])", new_value+"\\1", mycontent) - mycontent = re.sub(old_value+"([^a-zA-Z0-9-])", new_value+"\\1", mycontent) - f = open(dbdir+"/"+myfile, "w") - f.write(mycontent) - f.close() - -class packagetree: - def __init__(self,virtual,clone=None): - if clone: - self.tree=clone.tree.copy() - self.populated=clone.populated - self.virtual=clone.virtual - self.dbapi=None - else: - self.tree={} - self.populated=0 - self.virtual=virtual - self.dbapi=None - - def resolve_key(self,mykey): - return key_expand(mykey,mydb=self.dbapi) - - def dep_nomatch(self,mypkgdep): - mykey=dep_getkey(mypkgdep) - nolist=self.dbapi.cp_list(mykey) - mymatch=self.dbapi.match(mypkgdep) - if not mymatch: - return nolist - for x in mymatch: - if x in nolist: - nolist.remove(x) - return nolist - - def depcheck(self,mycheck,use="yes",myusesplit=None): - return dep_check(mycheck,self.dbapi,use=use,myuse=myusesplit) - - def populate(self): - "populates the tree with values" - populated=1 - pass - -def best(mymatches): - "accepts None arguments; assumes matches are valid." - global bestcount - if mymatches==None: - return "" - if not len(mymatches): - return "" - bestmatch=mymatches[0] - p2=catpkgsplit(bestmatch)[1:] - for x in mymatches[1:]: - p1=catpkgsplit(x)[1:] - if pkgcmp(p1,p2)>0: - bestmatch=x - p2=catpkgsplit(bestmatch)[1:] - return bestmatch - -def match_to_list(mypkg,mylist): - """(pkgname,list) - Searches list for entries that matches the package. - """ - matches=[] - for x in mylist: - if match_from_list(x,[mypkg]): - if x not in matches: - matches.append(x) - return matches - -def best_match_to_list(mypkg,mylist): - """(pkgname,list) - Returns the most specific entry (assumed to be the longest one) - that matches the package given. - """ - # XXX Assumption is wrong sometimes. - maxlen = 0 - bestm = None - for x in match_to_list(mypkg,mylist): - if len(x) > maxlen: - maxlen = len(x) - bestm = x - return bestm - -def catsplit(mydep): - return mydep.split("/", 1) - -def get_operator(mydep): - """ - returns '~', '=', '>', '<', '=*', '>=', or '<=' - """ - if mydep[0] == "~": - operator = "~" - elif mydep[0] == "=": - if mydep[-1] == "*": - operator = "=*" - else: - operator = "=" - elif mydep[0] in "><": - if len(mydep) > 1 and mydep[1] == "=": - operator = mydep[0:2] - else: - operator = mydep[0] - else: - operator = None - - return operator - - -def match_from_list(mydep,candidate_list): - if mydep[0] == "!": - mydep = mydep[1:] - - mycpv = dep_getcpv(mydep) - mycpv_cps = catpkgsplit(mycpv) # Can be None if not specific - - if not mycpv_cps: - cat,pkg = catsplit(mycpv) - ver = None - rev = None - else: - cat,pkg,ver,rev = mycpv_cps - if mydep == mycpv: - raise KeyError, "Specific key requires an operator (%s) (try adding an '=')" % (mydep) - - if ver and rev: - operator = get_operator(mydep) - if not operator: - writemsg("!!! Invalid atom: %s\n" % mydep) - return [] - else: - operator = None - - mylist = [] - - if operator == None: - for x in candidate_list: - xs = pkgsplit(x) - if xs == None: - if x != mycpv: - continue - elif xs[0] != mycpv: - continue - mylist.append(x) - - elif operator == "=": # Exact match - if mycpv in candidate_list: - mylist = [mycpv] - - elif operator == "=*": # glob match - # The old verion ignored _tag suffixes... This one doesn't. - for x in candidate_list: - if x[0:len(mycpv)] == mycpv: - mylist.append(x) - - elif operator == "~": # version, any revision, match - for x in candidate_list: - xs = catpkgsplit(x) - if xs[0:2] != mycpv_cps[0:2]: - continue - if xs[2] != ver: - continue - mylist.append(x) - - elif operator in [">", ">=", "<", "<="]: - for x in candidate_list: - try: - result = pkgcmp(pkgsplit(x), [cat+"/"+pkg,ver,rev]) - except SystemExit, e: - raise - except: - writemsg("\nInvalid package name: %s\n" % x) - sys.exit(73) - if result == None: - continue - elif operator == ">": - if result > 0: - mylist.append(x) - elif operator == ">=": - if result >= 0: - mylist.append(x) - elif operator == "<": - if result < 0: - mylist.append(x) - elif operator == "<=": - if result <= 0: - mylist.append(x) - else: - raise KeyError, "Unknown operator: %s" % mydep - else: - raise KeyError, "Unknown operator: %s" % mydep - - - return mylist - - -def match_from_list_original(mydep,mylist): - """(dep,list) - Reduces the list down to those that fit the dep - """ - mycpv=dep_getcpv(mydep) - if isspecific(mycpv): - cp_key=catpkgsplit(mycpv) - if cp_key==None: - return [] - else: - cp_key=None - #Otherwise, this is a special call; we can only select out of the ebuilds specified in the specified mylist - if (mydep[0]=="="): - if cp_key==None: - return [] - if mydep[-1]=="*": - #example: "=sys-apps/foo-1.0*" - try: - #now, we grab the version of our dependency... - mynewsplit=string.split(cp_key[2],'.') - #split it... - mynewsplit[-1]=`int(mynewsplit[-1])+1` - #and increment the last digit of the version by one. - #We don't need to worry about _pre and friends because they're not supported with '*' deps. - new_v=string.join(mynewsplit,".")+"_alpha0" - #new_v will be used later in the code when we do our comparisons using pkgcmp() - except SystemExit, e: - raise - except: - #erp, error. - return [] - mynodes=[] - cmp1=cp_key[1:] - cmp1[1]=cmp1[1]+"_alpha0" - cmp2=[cp_key[1],new_v,"r0"] - for x in mylist: - cp_x=catpkgsplit(x) - if cp_x==None: - #hrm, invalid entry. Continue. - continue - #skip entries in our list that do not have matching categories - if cp_key[0]!=cp_x[0]: - continue - # ok, categories match. Continue to next step. - if ((pkgcmp(cp_x[1:],cmp1)>=0) and (pkgcmp(cp_x[1:],cmp2)<0)): - # entry is >= the version in specified in our dependency, and <= the version in our dep + 1; add it: - mynodes.append(x) - return mynodes - else: - # Does our stripped key appear literally in our list? If so, we have a match; if not, we don't. - if mycpv in mylist: - return [mycpv] - else: - return [] - elif (mydep[0]==">") or (mydep[0]=="<"): - if cp_key==None: - return [] - if (len(mydep)>1) and (mydep[1]=="="): - cmpstr=mydep[0:2] - else: - cmpstr=mydep[0] - mynodes=[] - for x in mylist: - cp_x=catpkgsplit(x) - if cp_x==None: - #invalid entry; continue. - continue - if cp_key[0]!=cp_x[0]: - continue - if eval("pkgcmp(cp_x[1:],cp_key[1:])"+cmpstr+"0"): - mynodes.append(x) - return mynodes - elif mydep[0]=="~": - if cp_key==None: - return [] - myrev=-1 - for x in mylist: - cp_x=catpkgsplit(x) - if cp_x==None: - #invalid entry; continue - continue - if cp_key[0]!=cp_x[0]: - continue - if cp_key[2]!=cp_x[2]: - #if version doesn't match, skip it - continue - myint = int(cp_x[3][1:]) - if myint > myrev: - myrev = myint - mymatch = x - if myrev == -1: - return [] - else: - return [mymatch] - elif cp_key==None: - if mydep[0]=="!": - return [] - #we check ! deps in emerge itself, so always returning [] is correct. - mynodes=[] - cp_key=mycpv.split("/") - for x in mylist: - cp_x=catpkgsplit(x) - if cp_x==None: - #invalid entry; continue - continue - if cp_key[0]!=cp_x[0]: - continue - if cp_key[1]!=cp_x[1]: - continue - mynodes.append(x) - return mynodes - else: - return [] - - -class portagetree: - def __init__(self,root="/",virtual=None,clone=None): - global portdb - if clone: - self.root=clone.root - self.portroot=clone.portroot - self.pkglines=clone.pkglines - else: - self.root=root - self.portroot=settings["PORTDIR"] - self.virtual=virtual - self.dbapi=portdb - - def dep_bestmatch(self,mydep): - "compatibility method" - mymatch=self.dbapi.xmatch("bestmatch-visible",mydep) - if mymatch==None: - return "" - return mymatch - - def dep_match(self,mydep): - "compatibility method" - mymatch=self.dbapi.xmatch("match-visible",mydep) - if mymatch==None: - return [] - return mymatch - - def exists_specific(self,cpv): - return self.dbapi.cpv_exists(cpv) - - def getallnodes(self): - """new behavior: these are all *unmasked* nodes. There may or may not be available - masked package for nodes in this nodes list.""" - return self.dbapi.cp_all() - - def getname(self,pkgname): - "returns file location for this particular package (DEPRECATED)" - if not pkgname: - return "" - mysplit=string.split(pkgname,"/") - psplit=pkgsplit(mysplit[1]) - return self.portroot+"/"+mysplit[0]+"/"+psplit[0]+"/"+mysplit[1]+".ebuild" - - def resolve_specific(self,myspec): - cps=catpkgsplit(myspec) - if not cps: - return None - mykey=key_expand(cps[0]+"/"+cps[1],mydb=self.dbapi) - mykey=mykey+"-"+cps[2] - if cps[3]!="r0": - mykey=mykey+"-"+cps[3] - return mykey - - def depcheck(self,mycheck,use="yes",myusesplit=None): - return dep_check(mycheck,self.dbapi,use=use,myuse=myusesplit) - - def getslot(self,mycatpkg): - "Get a slot for a catpkg; assume it exists." - myslot = "" - try: - myslot=self.dbapi.aux_get(mycatpkg,["SLOT"])[0] - except SystemExit, e: - raise - except Exception, e: - pass - return myslot - - -class dbapi: - def __init__(self): - pass - - def close_caches(self): - pass - - def cp_list(self,cp,use_cache=1): - return - - def aux_get(self,mycpv,mylist): - "stub code for returning auxiliary db information, such as SLOT, DEPEND, etc." - 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]' - 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or [] if mycpv not found' - raise NotImplementedError - - def match(self,origdep,use_cache=1): - mydep=dep_expand(origdep,mydb=self) - mykey=dep_getkey(mydep) - mycat=mykey.split("/")[0] - return match_from_list(mydep,self.cp_list(mykey,use_cache=use_cache)) - - def match2(self,mydep,mykey,mylist): - writemsg("DEPRECATED: dbapi.match2\n") - match_from_list(mydep,mylist) - - def counter_tick(self,myroot,mycpv=None): - return self.counter_tick_core(myroot,incrementing=1,mycpv=mycpv) - - def get_counter_tick_core(self,myroot,mycpv=None): - return self.counter_tick_core(myroot,incrementing=0,mycpv=mycpv)+1 - - def counter_tick_core(self,myroot,incrementing=1,mycpv=None): - "This method will grab the next COUNTER value and record it back to the global file. Returns new counter value." - cpath=myroot+"var/cache/edb/counter" - changed=0 - min_counter = 0 - if mycpv: - mysplit = pkgsplit(mycpv) - for x in self.match(mysplit[0],use_cache=0): - # fixed bug #41062 - if x==mycpv: - continue - try: - old_counter = long(self.aux_get(x,["COUNTER"])[0]) - writemsg("COUNTER '%d' '%s'\n" % (old_counter, x),1) - except SystemExit, e: - raise - except: - old_counter = 0 - writemsg("!!! BAD COUNTER in '%s'\n" % (x)) - if old_counter > min_counter: - min_counter = old_counter - - # We write our new counter value to a new file that gets moved into - # place to avoid filesystem corruption. - if os.path.exists(cpath): - cfile=open(cpath, "r") - try: - counter=long(cfile.readline()) - except (ValueError,OverflowError): - try: - counter=long(commands.getoutput("for FILE in $(find /"+VDB_PATH+" -type f -name COUNTER); do echo $(<${FILE}); done | sort -n | tail -n1 | tr -d '\n'")) - writemsg("!!! COUNTER was corrupted; resetting to value of %d\n" % counter) - changed=1 - except (ValueError,OverflowError): - writemsg("!!! COUNTER data is corrupt in pkg db. The values need to be\n") - writemsg("!!! corrected/normalized so that portage can operate properly.\n") - writemsg("!!! A simple solution is not yet available so try #gentoo on IRC.\n") - sys.exit(2) - cfile.close() - else: - try: - counter=long(commands.getoutput("for FILE in $(find /"+VDB_PATH+" -type f -name COUNTER); do echo $(<${FILE}); done | sort -n | tail -n1 | tr -d '\n'")) - writemsg("!!! Global counter missing. Regenerated from counter files to: %s\n" % counter) - except SystemExit, e: - raise - except: - writemsg("!!! Initializing global counter.\n") - counter=long(0) - changed=1 - - if counter < min_counter: - counter = min_counter+1000 - changed = 1 - - if incrementing or changed: - - #increment counter - counter += 1 - # update new global counter file - newcpath=cpath+".new" - newcfile=open(newcpath,"w") - newcfile.write(str(counter)) - newcfile.close() - # now move global counter file into place - os.rename(newcpath,cpath) - return counter - - def invalidentry(self, mypath): - if re.search("portage_lockfile$",mypath): - if not os.environ.has_key("PORTAGE_MASTER_PID"): - writemsg("Lockfile removed: %s\n" % mypath, 1) - portage_locks.unlockfile((mypath,None,None)) - else: - # Nothing we can do about it. We're probably sandboxed. - pass - elif re.search(".*/-MERGING-(.*)",mypath): - if os.path.exists(mypath): - writemsg(red("INCOMPLETE MERGE:")+" "+mypath+"\n") - else: - writemsg("!!! Invalid db entry: %s\n" % mypath) - - - -class fakedbapi(dbapi): - "This is a dbapi to use for the emptytree function. It's empty, but things can be added to it." - def __init__(self): - self.cpvdict={} - self.cpdict={} - - def cpv_exists(self,mycpv): - return self.cpvdict.has_key(mycpv) - - def cp_list(self,mycp,use_cache=1): - if not self.cpdict.has_key(mycp): - return [] - else: - return self.cpdict[mycp] - - def cp_all(self): - returnme=[] - for x in self.cpdict.keys(): - returnme.extend(self.cpdict[x]) - return returnme - - def cpv_inject(self,mycpv): - """Adds a cpv from the list of available packages.""" - mycp=cpv_getkey(mycpv) - self.cpvdict[mycpv]=1 - if not self.cpdict.has_key(mycp): - self.cpdict[mycp]=[] - if not mycpv in self.cpdict[mycp]: - self.cpdict[mycp].append(mycpv) - - #def cpv_virtual(self,oldcpv,newcpv): - # """Maps a cpv to the list of available packages.""" - # mycp=cpv_getkey(newcpv) - # self.cpvdict[newcpv]=1 - # if not self.virtdict.has_key(mycp): - # self.virtdict[mycp]=[] - # if not mycpv in self.virtdict[mycp]: - # self.virtdict[mycp].append(oldcpv) - # cpv_remove(oldcpv) - - def cpv_remove(self,mycpv): - """Removes a cpv from the list of available packages.""" - mycp=cpv_getkey(mycpv) - if self.cpvdict.has_key(mycpv): - del self.cpvdict[mycpv] - if not self.cpdict.has_key(mycp): - return - while mycpv in self.cpdict[mycp]: - del self.cpdict[mycp][self.cpdict[mycp].index(mycpv)] - if not len(self.cpdict[mycp]): - del self.cpdict[mycp] - -class bindbapi(fakedbapi): - def __init__(self,mybintree=None): - self.bintree = mybintree - self.cpvdict={} - self.cpdict={} - - def aux_get(self,mycpv,wants): - mysplit = string.split(mycpv,"/") - mylist = [] - tbz2name = mysplit[1]+".tbz2" - if self.bintree and not self.bintree.isremote(mycpv): - tbz2 = xpak.tbz2(self.bintree.getname(mycpv)) - for x in wants: - if self.bintree and self.bintree.isremote(mycpv): - # We use the cache for remote packages - if self.bintree.remotepkgs[tbz2name].has_key(x): - mylist.append(self.bintree.remotepkgs[tbz2name][x][:]) # [:] Copy String - else: - mylist.append("") - else: - myval = tbz2.getfile(x) - if myval == None: - myval = "" - else: - myval = string.join(myval.split(),' ') - mylist.append(myval) - - return mylist - - -cptot=0 -class vardbapi(dbapi): - def __init__(self,root,categories=None): - self.root = root[:] - #cache for category directory mtimes - self.mtdircache = {} - #cache for dependency checks - self.matchcache = {} - #cache for cp_list results - self.cpcache = {} - self.blockers = None - self.categories = copy.deepcopy(categories) - - def cpv_exists(self,mykey): - "Tells us whether an actual ebuild exists on disk (no masking)" - return os.path.exists(self.root+VDB_PATH+"/"+mykey) - - def cpv_counter(self,mycpv): - "This method will grab the COUNTER. Returns a counter value." - cdir=self.root+VDB_PATH+"/"+mycpv - cpath=self.root+VDB_PATH+"/"+mycpv+"/COUNTER" - - # We write our new counter value to a new file that gets moved into - # place to avoid filesystem corruption on XFS (unexpected reboot.) - corrupted=0 - if os.path.exists(cpath): - cfile=open(cpath, "r") - try: - counter=long(cfile.readline()) - except ValueError: - print "portage: COUNTER for",mycpv,"was corrupted; resetting to value of 0" - counter=long(0) - corrupted=1 - cfile.close() - elif os.path.exists(cdir): - mys = pkgsplit(mycpv) - myl = self.match(mys[0],use_cache=0) - print mys,myl - if len(myl) == 1: - try: - # Only one package... Counter doesn't matter. - myf = open(cpath, "w") - myf.write("1") - myf.flush() - myf.close() - counter = 1 - except SystemExit, e: - raise - except Exception, e: - writemsg("!!! COUNTER file is missing for "+str(mycpv)+" in /var/db.\n") - writemsg("!!! Please run /usr/lib/portage/bin/fix-db.pl or\n") - writemsg("!!! Please run /usr/lib/portage/bin/fix-db.py or\n") - writemsg("!!! unmerge this exact version.\n") - writemsg("!!! %s\n" % e) - sys.exit(1) - else: - writemsg("!!! COUNTER file is missing for "+str(mycpv)+" in /var/db.\n") - writemsg("!!! Please run /usr/lib/portage/bin/fix-db.pl or\n") - writemsg("!!! Please run /usr/lib/portage/bin/fix-db.py or\n") - writemsg("!!! remerge the package.\n") - sys.exit(1) - else: - counter=long(0) - if corrupted: - newcpath=cpath+".new" - # update new global counter file - newcfile=open(newcpath,"w") - newcfile.write(str(counter)) - newcfile.close() - # now move global counter file into place - os.rename(newcpath,cpath) - return counter - - def cpv_inject(self,mycpv): - "injects a real package into our on-disk database; assumes mycpv is valid and doesn't already exist" - os.makedirs(self.root+VDB_PATH+"/"+mycpv) - counter=db[self.root]["vartree"].dbapi.counter_tick(self.root,mycpv=mycpv) - # write local package counter so that emerge clean does the right thing - lcfile=open(self.root+VDB_PATH+"/"+mycpv+"/COUNTER","w") - lcfile.write(str(counter)) - lcfile.close() - - def isInjected(self,mycpv): - if self.cpv_exists(mycpv): - if os.path.exists(self.root+VDB_PATH+"/"+mycpv+"/INJECTED"): - return True - if not os.path.exists(self.root+VDB_PATH+"/"+mycpv+"/CONTENTS"): - return True - return False - - def move_ent(self,mylist): - origcp=mylist[1] - newcp=mylist[2] - origmatches=self.match(origcp,use_cache=0) - if not origmatches: - return - for mycpv in origmatches: - mycpsplit=catpkgsplit(mycpv) - mynewcpv=newcp+"-"+mycpsplit[2] - mynewcat=newcp.split("/")[0] - if mycpsplit[3]!="r0": - mynewcpv += "-"+mycpsplit[3] - mycpsplit_new = catpkgsplit(mynewcpv) - origpath=self.root+VDB_PATH+"/"+mycpv - if not os.path.exists(origpath): - continue - writemsg("@") - if not os.path.exists(self.root+VDB_PATH+"/"+mynewcat): - #create the directory - os.makedirs(self.root+VDB_PATH+"/"+mynewcat) - newpath=self.root+VDB_PATH+"/"+mynewcpv - if os.path.exists(newpath): - #dest already exists; keep this puppy where it is. - continue - spawn(MOVE_BINARY+" "+origpath+" "+newpath,settings, free=1) - - # We need to rename the ebuild now. - old_eb_path = newpath+"/"+mycpsplit[1] +"-"+mycpsplit[2] - new_eb_path = newpath+"/"+mycpsplit_new[1]+"-"+mycpsplit[2] - if mycpsplit[3] != "r0": - old_eb_path += "-"+mycpsplit[3] - new_eb_path += "-"+mycpsplit[3] - if os.path.exists(old_eb_path+".ebuild"): - os.rename(old_eb_path+".ebuild", new_eb_path+".ebuild") - - catfile=open(newpath+"/CATEGORY", "w") - catfile.write(mynewcat+"\n") - catfile.close() - - dbdir = self.root+VDB_PATH - for catdir in listdir(dbdir): - catdir = dbdir+"/"+catdir - if os.path.isdir(catdir): - for pkgdir in listdir(catdir): - pkgdir = catdir+"/"+pkgdir - if os.path.isdir(pkgdir): - fixdbentries(origcp, newcp, pkgdir) - - def move_slot_ent(self,mylist): - pkg=mylist[1] - origslot=mylist[2] - newslot=mylist[3] - - origmatches=self.match(pkg,use_cache=0) - if not origmatches: - return - for mycpv in origmatches: - origpath=self.root+VDB_PATH+"/"+mycpv - if not os.path.exists(origpath): - continue - - slot=grabfile(origpath+"/SLOT"); - if (not slot): - continue - - if (slot[0]!=origslot): - continue - - writemsg("s") - slotfile=open(origpath+"/SLOT", "w") - slotfile.write(newslot+"\n") - slotfile.close() - - def cp_list(self,mycp,use_cache=1): - mysplit=mycp.split("/") - if mysplit[0] == '*': - mysplit[0] = mysplit[0][1:] - try: - mystat=os.stat(self.root+VDB_PATH+"/"+mysplit[0])[stat.ST_MTIME] - except OSError: - mystat=0 - if use_cache and self.cpcache.has_key(mycp): - cpc=self.cpcache[mycp] - if cpc[0]==mystat: - return cpc[1] - list=listdir(self.root+VDB_PATH+"/"+mysplit[0],EmptyOnError=1) - - if (list==None): - return [] - returnme=[] - for x in list: - if x[0] == '-': - #writemsg(red("INCOMPLETE MERGE:")+str(x[len("-MERGING-"):])+"\n") - continue - ps=pkgsplit(x) - if not ps: - self.invalidentry(self.root+VDB_PATH+"/"+mysplit[0]+"/"+x) - continue - if len(mysplit) > 1: - if ps[0]==mysplit[1]: - returnme.append(mysplit[0]+"/"+x) - if use_cache: - self.cpcache[mycp]=[mystat,returnme] - elif self.cpcache.has_key(mycp): - del self.cpcache[mycp] - return returnme - - def cpv_all(self,use_cache=1): - returnme=[] - basepath = self.root+VDB_PATH+"/" - - mycats = self.categories - if mycats == None: - # XXX: CIRCULAR DEP! This helps backwards compat. --NJ (10 Sept 2004) - mycats = settings.categories - - for x in mycats: - for y in listdir(basepath+x,EmptyOnError=1): - subpath = x+"/"+y - # -MERGING- should never be a cpv, nor should files. - if os.path.isdir(basepath+subpath) and (pkgsplit(y) is not None): - returnme += [subpath] - return returnme - - def cp_all(self,use_cache=1): - mylist = self.cpv_all(use_cache=use_cache) - d={} - for y in mylist: - if y[0] == '*': - y = y[1:] - mysplit=catpkgsplit(y) - if not mysplit: - self.invalidentry(self.root+VDB_PATH+"/"+y) - continue - d[mysplit[0]+"/"+mysplit[1]] = None - return d.keys() - - def checkblockers(self,origdep): - pass - - def match(self,origdep,use_cache=1): - "caching match function" - mydep=dep_expand(origdep,mydb=self,use_cache=use_cache) - mykey=dep_getkey(mydep) - mycat=mykey.split("/")[0] - if not use_cache: - if self.matchcache.has_key(mycat): - del self.mtdircache[mycat] - del self.matchcache[mycat] - return match_from_list(mydep,self.cp_list(mykey,use_cache=use_cache)) - try: - curmtime=os.stat(self.root+VDB_PATH+"/"+mycat)[stat.ST_MTIME] - except SystemExit, e: - raise - except: - curmtime=0 - - if not self.matchcache.has_key(mycat) or not self.mtdircache[mycat]==curmtime: - # clear cache entry - self.mtdircache[mycat]=curmtime - self.matchcache[mycat]={} - if not self.matchcache[mycat].has_key(mydep): - mymatch=match_from_list(mydep,self.cp_list(mykey,use_cache=use_cache)) - self.matchcache[mycat][mydep]=mymatch - return self.matchcache[mycat][mydep][:] - - def aux_get(self, mycpv, wants): - global auxdbkeys - results = [] - if not self.cpv_exists(mycpv): - return [] - for x in wants: - myfn = self.root+VDB_PATH+"/"+str(mycpv)+"/"+str(x) - if os.access(myfn,os.R_OK): - myf = open(myfn, "r") - myd = myf.read() - myf.close() - myd = re.sub("[\n\r\t]+"," ",myd) - myd = re.sub(" +"," ",myd) - myd = string.strip(myd) - else: - myd = "" - results.append(myd) - return results - - -class vartree(packagetree): - "this tree will scan a var/db/pkg database located at root (passed to init)" - def __init__(self,root="/",virtual=None,clone=None,categories=None): - if clone: - self.root = clone.root[:] - self.dbapi = copy.deepcopy(clone.dbapi) - self.populated = 1 - else: - self.root = root[:] - self.dbapi = vardbapi(self.root,categories=categories) - self.populated = 1 - - def zap(self,mycpv): - return - - def inject(self,mycpv): - return - - def get_provide(self,mycpv): - myprovides=[] - try: - mylines = grabfile(self.root+VDB_PATH+"/"+mycpv+"/PROVIDE") - if mylines: - myuse = grabfile(self.root+VDB_PATH+"/"+mycpv+"/USE") - myuse = string.split(string.join(myuse)) - mylines = string.join(mylines) - mylines = flatten(portage_dep.use_reduce(portage_dep.paren_reduce(mylines), uselist=myuse)) - for myprovide in mylines: - mys = catpkgsplit(myprovide) - if not mys: - mys = string.split(myprovide, "/") - myprovides += [mys[0] + "/" + mys[1]] - return myprovides - except SystemExit, e: - raise - except Exception, e: - print - print "Check " + self.root+VDB_PATH+"/"+mycpv+"/PROVIDE and USE." - print "Possibly Invalid: " + str(mylines) - print "Exception: "+str(e) - print - return [] - - def get_all_provides(self): - myprovides = {} - for node in self.getallcpv(): - for mykey in self.get_provide(node): - if myprovides.has_key(mykey): - myprovides[mykey] += [node] - else: - myprovides[mykey] = [node] - return myprovides - - def dep_bestmatch(self,mydep,use_cache=1): - "compatibility method -- all matches, not just visible ones" - #mymatch=best(match(dep_expand(mydep,self.dbapi),self.dbapi)) - mymatch=best(self.dbapi.match(dep_expand(mydep,mydb=self.dbapi),use_cache=use_cache)) - if mymatch==None: - return "" - else: - return mymatch - - def dep_match(self,mydep,use_cache=1): - "compatibility method -- we want to see all matches, not just visible ones" - #mymatch=match(mydep,self.dbapi) - mymatch=self.dbapi.match(mydep,use_cache=use_cache) - if mymatch==None: - return [] - else: - return mymatch - - def exists_specific(self,cpv): - return self.dbapi.cpv_exists(cpv) - - def getallcpv(self): - """temporary function, probably to be renamed --- Gets a list of all - category/package-versions installed on the system.""" - return self.dbapi.cpv_all() - - def getallnodes(self): - """new behavior: these are all *unmasked* nodes. There may or may not be available - masked package for nodes in this nodes list.""" - return self.dbapi.cp_all() - - def exists_specific_cat(self,cpv,use_cache=1): - cpv=key_expand(cpv,mydb=self.dbapi,use_cache=use_cache) - a=catpkgsplit(cpv) - if not a: - return 0 - mylist=listdir(self.root+VDB_PATH+"/"+a[0],EmptyOnError=1) - for x in mylist: - b=pkgsplit(x) - if not b: - self.dbapi.invalidentry(self.root+VDB_PATH+"/"+a[0]+"/"+x) - continue - if a[1]==b[0]: - return 1 - return 0 - - def getebuildpath(self,fullpackage): - cat,package=fullpackage.split("/") - return self.root+VDB_PATH+"/"+fullpackage+"/"+package+".ebuild" - - def getnode(self,mykey,use_cache=1): - mykey=key_expand(mykey,mydb=self.dbapi,use_cache=use_cache) - if not mykey: - return [] - mysplit=mykey.split("/") - mydirlist=listdir(self.root+VDB_PATH+"/"+mysplit[0],EmptyOnError=1) - returnme=[] - for x in mydirlist: - mypsplit=pkgsplit(x) - if not mypsplit: - self.dbapi.invalidentry(self.root+VDB_PATH+"/"+mysplit[0]+"/"+x) - continue - if mypsplit[0]==mysplit[1]: - appendme=[mysplit[0]+"/"+x,[mysplit[0],mypsplit[0],mypsplit[1],mypsplit[2]]] - returnme.append(appendme) - return returnme - - - def getslot(self,mycatpkg): - "Get a slot for a catpkg; assume it exists." - myslot = "" - try: - myslot=string.join(grabfile(self.root+VDB_PATH+"/"+mycatpkg+"/SLOT")) - except SystemExit, e: - raise - except Exception, e: - pass - return myslot - - def hasnode(self,mykey,use_cache): - """Does the particular node (cat/pkg key) exist?""" - mykey=key_expand(mykey,mydb=self.dbapi,use_cache=use_cache) - mysplit=mykey.split("/") - mydirlist=listdir(self.root+VDB_PATH+"/"+mysplit[0],EmptyOnError=1) - for x in mydirlist: - mypsplit=pkgsplit(x) - if not mypsplit: - self.dbapi.invalidentry(self.root+VDB_PATH+"/"+mysplit[0]+"/"+x) - continue - if mypsplit[0]==mysplit[1]: - return 1 - return 0 - - def populate(self): - self.populated=1 - -# ---------------------------------------------------------------------------- -class eclass_cache: - """Maintains the cache information about eclasses used in ebuild.""" - def __init__(self,porttree_root,settings): - self.porttree_root = porttree_root - self.settings = settings - self.depcachedir = self.settings.depcachedir[:] - - self.dbmodule = self.settings.load_best_module("eclass_cache.dbmodule") - - self.packages = {} # {"PV": {"eclass1": ["location", "_mtime_"]}} - self.eclasses = {} # {"Name": ["location","_mtime_"]} - - # don't fool with porttree ordering unless you *ensure* that ebuild.sh's inherit - # ordering is *exactly* the same - self.porttrees=[self.porttree_root] - self.porttrees.extend(self.settings["PORTDIR_OVERLAY"].split()) - #normalize the path now, so it's not required later. - self.porttrees = [os.path.normpath(x) for x in self.porttrees] - self.update_eclasses() - - def close_caches(self): - for x in self.packages.keys(): - for y in self.packages[x].keys(): - try: - self.packages[x][y].sync() - self.packages[x][y].close() - except SystemExit, e: - raise - except Exception,e: - writemsg("Exception when closing DB: %s: %s\n" % (Exception,e)) - del self.packages[x][y] - del self.packages[x] - - def flush_cache(self): - self.packages = {} - self.eclasses = {} - self.update_eclasses() - - def update_eclasses(self): - self.eclasses = {} - for x in suffix_array(self.porttrees, "/eclass"): - if x and os.path.exists(x): - dirlist = listdir(x) - for y in dirlist: - if y[-len(".eclass"):]==".eclass": - try: - ys=y[:-len(".eclass")] - ymtime=os.stat(x+"/"+y)[stat.ST_MTIME] - except SystemExit, e: - raise - except: - continue - self.eclasses[ys] = [x, ymtime] - - def setup_package(self, location, cat, pkg): - if not self.packages.has_key(location): - self.packages[location] = {} - - if not self.packages[location].has_key(cat): - try: - self.packages[location][cat] = self.dbmodule(self.depcachedir+"/"+location, cat+"-eclass", [], uid, portage_gid) - except SystemExit, e: - raise - except Exception, e: - writemsg("\n!!! Failed to open the dbmodule for eclass caching.\n") - writemsg("!!! Generally these are permission problems. Caught exception follows:\n") - writemsg("!!! "+str(e)+"\n") - writemsg("!!! Dirname: "+str(self.depcachedir+"/"+location)+"\n") - writemsg("!!! Basename: "+str(cat+"-eclass")+"\n\n") - sys.exit(123) - - def sync(self, location, cat, pkg): - if self.packages[location].has_key(cat): - self.packages[location][cat].sync() - - def update_package(self, location, cat, pkg, eclass_list): - self.setup_package(location, cat, pkg) - if not eclass_list: - return 1 - - data = {} - for x in eclass_list: - if x not in self.eclasses: - writemsg("Eclass '%s' does not exist for '%s'\n" % (x, cat+"/"+pkg)) - return 0 - data[x] = [self.eclasses[x][0],self.eclasses[x][1]] - - self.packages[location][cat][pkg] = data - self.sync(location,cat,pkg) - return 1 - - def is_current(self, location, cat, pkg, eclass_list): - self.setup_package(location, cat, pkg) - - if not eclass_list: - return 1 - - if not (self.packages[location][cat].has_key(pkg) and self.packages[location][cat][pkg] and eclass_list): - return 0 - - myp = self.packages[location][cat][pkg] - for x in eclass_list: - if not (x in self.eclasses and x in myp and myp[x] == self.eclasses[x]): - return 0 - - return 1 - -# ---------------------------------------------------------------------------- - -auxdbkeys=[ - 'DEPEND', 'RDEPEND', 'SLOT', 'SRC_URI', - 'RESTRICT', 'HOMEPAGE', 'LICENSE', 'DESCRIPTION', - 'KEYWORDS', 'INHERITED', 'IUSE', 'CDEPEND', - 'PDEPEND', 'PROVIDE', - 'UNUSED_01', 'UNUSED_02', 'UNUSED_03', 'UNUSED_04', - 'UNUSED_05', 'UNUSED_06', 'UNUSED_07', 'UNUSED_08', - ] -auxdbkeylen=len(auxdbkeys) - -def close_portdbapi_caches(): - for i in portdbapi.portdbapi_instances: - i.close_caches() -class portdbapi(dbapi): - """this tree will scan a portage directory located at root (passed to init)""" - portdbapi_instances = [] - - def __init__(self,porttree_root,mysettings=None): - portdbapi.portdbapi_instances.append(self) - self.lock_held = 0; - - if mysettings: - self.mysettings = mysettings - else: - self.mysettings = config(clone=settings) - - self.manifestVerifyLevel = None - self.manifestVerifier = None - self.manifestCache = {} # {location: [stat, md5]} - self.manifestMissingCache = [] - - if "gpg" in self.mysettings.features: - self.manifestVerifyLevel = portage_gpg.EXISTS - if "strict" in self.mysettings.features: - self.manifestVerifyLevel = portage_gpg.MARGINAL - self.manifestVerifier = portage_gpg.FileChecker(self.mysettings["PORTAGE_GPG_DIR"], "gentoo.gpg", minimumTrust=self.manifestVerifyLevel) - elif "severe" in self.mysettings.features: - self.manifestVerifyLevel = portage_gpg.TRUSTED - self.manifestVerifier = portage_gpg.FileChecker(self.mysettings["PORTAGE_GPG_DIR"], "gentoo.gpg", requireSignedRing=True, minimumTrust=self.manifestVerifyLevel) - else: - self.manifestVerifier = portage_gpg.FileChecker(self.mysettings["PORTAGE_GPG_DIR"], "gentoo.gpg", minimumTrust=self.manifestVerifyLevel) - - #self.root=settings["PORTDIR"] - self.porttree_root = porttree_root - - self.depcachedir = self.mysettings.depcachedir[:] - - self.tmpfs = self.mysettings["PORTAGE_TMPFS"] - if self.tmpfs and not os.path.exists(self.tmpfs): - self.tmpfs = None - if self.tmpfs and not os.access(self.tmpfs, os.W_OK): - self.tmpfs = None - if self.tmpfs and not os.access(self.tmpfs, os.R_OK): - self.tmpfs = None - - self.eclassdb = eclass_cache(self.porttree_root, self.mysettings) - - self.metadb = {} - self.metadbmodule = self.mysettings.load_best_module("portdbapi.metadbmodule") - - self.auxdb = {} - self.auxdbmodule = self.mysettings.load_best_module("portdbapi.auxdbmodule") - - #if the portdbapi is "frozen", then we assume that we can cache everything (that no updates to it are happening) - self.xcache={} - self.frozen=0 - - self.porttrees=[self.porttree_root]+self.mysettings["PORTDIR_OVERLAY"].split() - - def close_caches(self): - for x in self.auxdb.keys(): - for y in self.auxdb[x].keys(): - self.auxdb[x][y].sync() - self.auxdb[x][y].close() - del self.auxdb[x][y] - del self.auxdb[x] - self.eclassdb.close_caches() - - def flush_cache(self): - self.metadb = {} - self.auxdb = {} - self.eclassdb.flush_cache() - - def finddigest(self,mycpv): - try: - mydig = self.findname2(mycpv)[0] - mydigs = string.split(mydig, "/")[:-1] - mydig = string.join(mydigs, "/") - - mysplit = mycpv.split("/") - except SystemExit, e: - raise - except: - return "" - return mydig+"/files/digest-"+mysplit[-1] - - def findname(self,mycpv): - return self.findname2(mycpv)[0] - - def findname2(self,mycpv): - "returns file location for this particular package and in_overlay flag" - if not mycpv: - return "",0 - mysplit=mycpv.split("/") - - psplit=pkgsplit(mysplit[1]) - ret=None - if psplit: - for x in self.porttrees: - # XXX Why are there errors here? XXX - try: - file=x+"/"+mysplit[0]+"/"+psplit[0]+"/"+mysplit[1]+".ebuild" - except SystemExit, e: - raise - except Exception, e: - print - print "!!! Problem with determining the name/location of an ebuild." - print "!!! Please report this on IRC and bugs if you are not causing it." - print "!!! mycpv: ",mycpv - print "!!! mysplit:",mysplit - print "!!! psplit: ",psplit - print "!!! error: ",e - print - sys.exit(17) - - if os.access(file, os.R_OK): - # when found - ret=[file, x] - if ret: - return ret[0], ret[1] - - # when not found - return None, 0 - - def aux_get(self,mycpv,mylist,strict=0,metacachedir=None,debug=0): - "stub code for returning auxilliary db information, such as SLOT, DEPEND, etc." - 'input: "sys-apps/foo-1.0",["SLOT","DEPEND","HOMEPAGE"]' - 'return: ["0",">=sys-libs/bar-1.0","http://www.foo.com"] or raise KeyError if error' - global auxdbkeys,auxdbkeylen - - cat,pkg = string.split(mycpv, "/", 1) - - if metacachedir: - if cat not in self.metadb: - self.metadb[cat] = self.metadbmodule(metacachedir,cat,auxdbkeys,uid,portage_gid) - - myebuild, mylocation=self.findname2(mycpv) - - if not myebuild: - writemsg("!!! aux_get(): ebuild path for '%(cpv)s' not specified:\n" % {"cpv":mycpv}) - writemsg("!!! %s\n" % myebuild) - raise KeyError, "'%(cpv)s' at %(path)s" % {"cpv":mycpv,"path":myebuild} - - myManifestPath = string.join(myebuild.split("/")[:-1],"/")+"/Manifest" - if "gpg" in self.mysettings.features: - try: - mys = portage_gpg.fileStats(myManifestPath) - if (myManifestPath in self.manifestCache) and \ - (self.manifestCache[myManifestPath] == mys): - pass - elif self.manifestVerifier: - if not self.manifestVerifier.verify(myManifestPath): - # Verification failed the desired level. - raise portage_exception.UntrustedSignature, "Untrusted Manifest: %(manifest)s" % {"manifest":myManifestPath} - - if ("severe" in self.mysettings.features) and \ - (mys != portage_gpg.fileStats(myManifestPath)): - raise portage_exception.SecurityViolation, "Manifest changed: %(manifest)s" % {"manifest":myManifestPath} - - except portage_exception.InvalidSignature, e: - if ("strict" in self.mysettings.features) or \ - ("severe" in self.mysettings.features): - raise - writemsg("!!! INVALID MANIFEST SIGNATURE DETECTED: %(manifest)s\n" % {"manifest":myManifestPath}) - except portage_exception.MissingSignature, e: - if ("severe" in self.mysettings.features): - raise - if ("strict" in self.mysettings.features): - if myManifestPath not in self.manifestMissingCache: - writemsg("!!! WARNING: Missing signature in: %(manifest)s\n" % {"manifest":myManifestPath}) - self.manifestMissingCache.insert(0,myManifestPath) - except (OSError,portage_exception.FileNotFound), e: - if ("strict" in self.mysettings.features) or \ - ("severe" in self.mysettings.features): - raise portage_exception.SecurityViolation, "Error in verification of signatures: %(errormsg)s" % {"errormsg":str(e)} - writemsg("!!! Manifest is missing or inaccessable: %(manifest)s\n" % {"manifest":myManifestPath}) - - if mylocation not in self.auxdb: - self.auxdb[mylocation] = {} - - if not self.auxdb[mylocation].has_key(cat): - self.auxdb[mylocation][cat] = self.auxdbmodule(self.depcachedir+"/"+mylocation,cat,auxdbkeys,uid,portage_gid) - - if os.access(myebuild, os.R_OK): - emtime=os.stat(myebuild)[stat.ST_MTIME] - else: - writemsg("!!! aux_get(): ebuild for '%(cpv)s' does not exist at:\n" % {"cpv":mycpv}) - writemsg("!!! %s\n" % myebuild) - raise KeyError - - # when mylocation is not overlay directorys and metacachedir is set, - # we use cache files, which is usually on /usr/portage/metadata/cache/. - if mylocation==self.mysettings["PORTDIR"] and metacachedir and self.metadb[cat].has_key(pkg): - metadata=self.metadb[cat][pkg] - self.eclassdb.update_package(mylocation,cat,pkg,metadata["INHERITED"].split()) - self.auxdb[mylocation][cat][pkg] = metadata - self.auxdb[mylocation][cat].sync() - else: - - try: - auxdb_is_valid = self.auxdb[mylocation][cat].has_key(pkg) and \ - self.auxdb[mylocation][cat][pkg].has_key("_mtime_") and \ - self.auxdb[mylocation][cat][pkg]["_mtime_"] == emtime - except SystemExit, e: - raise - except Exception, e: - auxdb_is_valid = 0 - writemsg("auxdb exception: [%(loc)s]: %(exception)s\n" % {"loc":mylocation+"::"+cat+"/"+pkg, "exception":str(e)}) - if self.auxdb[mylocation][cat].has_key(pkg): - self.auxdb[mylocation][cat].del_key(pkg) - self.auxdb[mylocation][cat].sync() - - writemsg("auxdb is valid: "+str(auxdb_is_valid)+" "+str(pkg)+"\n", 2) - if auxdb_is_valid: - doregen=0 - else: - doregen=1 - - if doregen or not self.eclassdb.is_current(mylocation,cat,pkg,self.auxdb[mylocation][cat][pkg]["INHERITED"].split()): - writemsg("doregen: %s %s\n" % (doregen,mycpv), 2) - writemsg("Generating cache entry(0) for: "+str(myebuild)+"\n",1) - - if self.tmpfs: - mydbkey = self.tmpfs+"/aux_db_key_temp" - else: - mydbkey = self.depcachedir+"/aux_db_key_temp" - - # XXX: Part of the gvisible hack/fix to prevent deadlock - # XXX: through doebuild. Need to isolate this somehow... - self.mysettings.reset() - - if self.lock_held: - raise "Lock is already held by me?" - self.lock_held = 1 - mylock = portage_locks.lockfile(mydbkey, wantnewlockfile=1) - - if os.path.exists(mydbkey): - try: - os.unlink(mydbkey) - except SystemExit, e: - raise - except Exception, e: - portage_locks.unlockfile(mylock) - self.lock_held = 0 - writemsg("Uncaught handled exception: %(exception)s\n" % {"exception":str(e)}) - raise - - myret=doebuild(myebuild,"depend","/",self.mysettings,dbkey=mydbkey) - if myret: - portage_locks.unlockfile(mylock) - self.lock_held = 0 - #depend returned non-zero exit code... - writemsg(str(red("\naux_get():")+" (0) Error in "+mycpv+" ebuild. ("+str(myret)+")\n" - " Check for syntax error or corruption in the ebuild. (--debug)\n\n")) - raise KeyError - - try: - mycent=open(mydbkey,"r") - os.unlink(mydbkey) - mylines=mycent.readlines() - mycent.close() - except SystemExit, e: - raise - except (IOError, OSError): - portage_locks.unlockfile(mylock) - self.lock_held = 0 - writemsg(str(red("\naux_get():")+" (1) Error in "+mycpv+" ebuild.\n" - " Check for syntax error or corruption in the ebuild. (--debug)\n\n")) - raise KeyError - except Exception, e: - portage_locks.unlockfile(mylock) - self.lock_held = 0 - writemsg("Uncaught handled exception: %(exception)s\n" % {"exception":str(e)}) - raise - - portage_locks.unlockfile(mylock) - self.lock_held = 0 - - mydata = {} - for x in range(0,len(mylines)): - if mylines[x][-1] == '\n': - mylines[x] = mylines[x][:-1] - mydata[auxdbkeys[x]] = mylines[x] - mydata["_mtime_"] = emtime - - self.auxdb[mylocation][cat][pkg] = mydata - self.auxdb[mylocation][cat].sync() - if not self.eclassdb.update_package(mylocation, cat, pkg, mylines[auxdbkeys.index("INHERITED")].split()): - sys.exit(1) - - #finally, we look at our internal cache entry and return the requested data. - mydata = self.auxdb[mylocation][cat][pkg] - returnme = [] - for x in mylist: - if mydata.has_key(x): - returnme.append(mydata[x]) - else: - returnme.append("") - - return returnme - - def getfetchlist(self,mypkg,useflags=None,mysettings=None,all=0): - if mysettings == None: - mysettings = self.mysettings - try: - myuris = self.aux_get(mypkg,["SRC_URI"])[0] - except (IOError,KeyError): - print red("getfetchlist():")+" aux_get() error reading "+mypkg+"; aborting." - sys.exit(1) - - useflags = string.split(mysettings["USE"]) - - myurilist = portage_dep.paren_reduce(myuris) - myurilist = portage_dep.use_reduce(myurilist,uselist=useflags,matchall=all) - newuris = flatten(myurilist) - - myfiles = [] - for x in newuris: - mya = os.path.basename(x) - if not mya in myfiles: - myfiles.append(mya) - return [newuris, myfiles] - - def getfetchsizes(self,mypkg,useflags=None,debug=0): - # returns a filename:size dictionnary of remaining downloads - mydigest=self.finddigest(mypkg) - mymd5s=digestParseFile(mydigest) - if not mymd5s: - if debug: print "[empty/missing/bad digest]: "+mypkg - return None - filesdict={} - if useflags == None: - myuris, myfiles = self.getfetchlist(mypkg,all=1) - else: - myuris, myfiles = self.getfetchlist(mypkg,useflags=useflags) - #XXX: maybe this should be improved: take partial downloads - # into account? check md5sums? - for myfile in myfiles: - if debug and myfile not in mymd5s.keys(): - print "[bad digest]: missing",myfile,"for",mypkg - elif myfile in mymd5s.keys(): - distfile=settings["DISTDIR"]+"/"+myfile - if not os.access(distfile, os.R_OK): - filesdict[myfile]=int(mymd5s[myfile]["size"]) - return filesdict - - def fetch_check(self, mypkg, useflags=None, mysettings=None, all=False): - if not useflags: - if mysettings: - useflags = mysettings["USE"].split() - myuri, myfiles = self.getfetchlist(mypkg, useflags=useflags, mysettings=mysettings, all=all) - mydigest = self.finddigest(mypkg) - mysums = digestParseFile(mydigest) - - failures = {} - for x in myfiles: - if not mysums or x not in mysums: - ok = False - reason = "digest missing" - else: - ok,reason = portage_checksum.verify_all(self.mysettings["DISTDIR"]+"/"+x, mysums[x]) - if not ok: - failures[x] = reason - if failures: - return False - return True - - def getsize(self,mypkg,useflags=None,debug=0): - # returns the total size of remaining downloads - # - # we use getfetchsizes() now, so this function would be obsoleted - # - filesdict=self.getfetchsizes(mypkg,useflags=useflags,debug=debug) - if filesdict==None: - return "[empty/missing/bad digest]" - mysize=0 - for myfile in filesdict.keys(): - mysum+=filesdict[myfile] - return mysum - - def cpv_exists(self,mykey): - "Tells us whether an actual ebuild exists on disk (no masking)" - cps2=mykey.split("/") - cps=catpkgsplit(mykey,silent=0) - if not cps: - #invalid cat/pkg-v - return 0 - if self.findname(cps[0]+"/"+cps2[1]): - return 1 - else: - return 0 - - def cp_all(self): - "returns a list of all keys in our tree" - d={} - for x in self.mysettings.categories: - for oroot in self.porttrees: - for y in listdir(oroot+"/"+x,EmptyOnError=1,ignorecvs=1): - mykey=x+"/"+y - d[x+"/"+y] = None - l = d.keys() - l.sort() - return l - - def p_list(self,mycp): - d={} - for oroot in self.porttrees: - for x in listdir(oroot+"/"+mycp,EmptyOnError=1,ignorecvs=1): - if x[-7:]==".ebuild": - d[x[:-7]] = None - return d.keys() - - def cp_list(self,mycp,use_cache=1): - mysplit=mycp.split("/") - d={} - for oroot in self.porttrees: - for x in listdir(oroot+"/"+mycp,EmptyOnError=1,ignorecvs=1): - if x[-7:]==".ebuild": - d[mysplit[0]+"/"+x[:-7]] = None - return d.keys() - - def freeze(self): - for x in ["list-visible","bestmatch-visible","match-visible","match-all"]: - self.xcache[x]={} - self.frozen=1 - - def melt(self): - self.xcache={} - self.frozen=0 - - def xmatch(self,level,origdep,mydep=None,mykey=None,mylist=None): - "caching match function; very trick stuff" - #if no updates are being made to the tree, we can consult our xcache... - if self.frozen: - try: - return self.xcache[level][origdep] - except KeyError: - pass - - if not mydep: - #this stuff only runs on first call of xmatch() - #create mydep, mykey from origdep - mydep=dep_expand(origdep,mydb=self) - mykey=dep_getkey(mydep) - - if level=="list-visible": - #a list of all visible packages, not called directly (just by xmatch()) - #myval=self.visible(self.cp_list(mykey)) - myval=self.gvisible(self.visible(self.cp_list(mykey))) - elif level=="bestmatch-visible": - #dep match -- best match of all visible packages - myval=best(self.xmatch("match-visible",None,mydep=mydep,mykey=mykey)) - #get all visible matches (from xmatch()), then choose the best one - elif level=="bestmatch-list": - #dep match -- find best match but restrict search to sublist - myval=best(match_from_list(mydep,mylist)) - #no point is calling xmatch again since we're not caching list deps - elif level=="match-list": - #dep match -- find all matches but restrict search to sublist (used in 2nd half of visible()) - myval=match_from_list(mydep,mylist) - elif level=="match-visible": - #dep match -- find all visible matches - myval=match_from_list(mydep,self.xmatch("list-visible",None,mydep=mydep,mykey=mykey)) - #get all visible packages, then get the matching ones - elif level=="match-all": - #match *all* visible *and* masked packages - myval=match_from_list(mydep,self.cp_list(mykey)) - else: - print "ERROR: xmatch doesn't handle",level,"query!" - raise KeyError - if self.frozen and (level not in ["match-list","bestmatch-list"]): - self.xcache[level][mydep]=myval - return myval - - def match(self,mydep,use_cache=1): - return self.xmatch("match-visible",mydep) - - def visible(self,mylist): - """two functions in one. Accepts a list of cpv values and uses the package.mask *and* - packages file to remove invisible entries, returning remaining items. This function assumes - that all entries in mylist have the same category and package name.""" - if (mylist==None) or (len(mylist)==0): - return [] - newlist=mylist[:] - #first, we mask out packages in the package.mask file - mykey=newlist[0] - cpv=catpkgsplit(mykey) - if not cpv: - #invalid cat/pkg-v - print "visible(): invalid cat/pkg-v:",mykey - return [] - mycp=cpv[0]+"/"+cpv[1] - maskdict=self.mysettings.pmaskdict - unmaskdict=self.mysettings.punmaskdict - if maskdict.has_key(mycp): - for x in maskdict[mycp]: - mymatches=self.xmatch("match-all",x) - if mymatches==None: - #error in package.mask file; print warning and continue: - print "visible(): package.mask entry \""+x+"\" is invalid, ignoring..." - continue - for y in mymatches: - unmask=0 - if unmaskdict.has_key(mycp): - for z in unmaskdict[mycp]: - mymatches_unmask=self.xmatch("match-all",z) - if y in mymatches_unmask: - unmask=1 - break - if unmask==0: - try: - newlist.remove(y) - except ValueError: - pass - - revmaskdict=self.mysettings.prevmaskdict - if revmaskdict.has_key(mycp): - for x in revmaskdict[mycp]: - #important: only match against the still-unmasked entries... - #notice how we pass "newlist" to the xmatch() call below.... - #Without this, ~ deps in the packages files are broken. - mymatches=self.xmatch("match-list",x,mylist=newlist) - if mymatches==None: - #error in packages file; print warning and continue: - print "emerge: visible(): profile packages entry \""+x+"\" is invalid, ignoring..." - continue - pos=0 - while pos<len(newlist): - if newlist[pos] not in mymatches: - del newlist[pos] - else: - pos += 1 - return newlist - - def gvisible(self,mylist): - "strip out group-masked (not in current group) entries" - global groups - if mylist==None: - return [] - newlist=[] - - pkgdict = self.mysettings.pkeywordsdict - for mycpv in mylist: - #we need to update this next line when we have fully integrated the new db api - auxerr=0 - try: - myaux=db["/"]["porttree"].dbapi.aux_get(mycpv, ["KEYWORDS"]) - except (KeyError,IOError,TypeError): - continue - if not myaux[0]: - # KEYWORDS="" - #print "!!! No KEYWORDS for "+str(mycpv)+" -- Untested Status" - continue - mygroups=myaux[0].split() - pgroups=groups[:] - match=0 - cp = dep_getkey(mycpv) - if pkgdict.has_key(cp): - matches = match_to_list(mycpv, pkgdict[cp].keys()) - for atom in matches: - pgroups.extend(pkgdict[cp][atom]) - for gp in mygroups: - if gp=="*": - writemsg("--- WARNING: Package '%s' uses '*' keyword.\n" % mycpv) - match=1 - break - elif "-"+gp in pgroups: - match=0 - break - elif gp in pgroups: - match=1 - break - if match: - newlist.append(mycpv) - return newlist - -class binarytree(packagetree): - "this tree scans for a list of all packages available in PKGDIR" - def __init__(self,root,pkgdir,virtual=None,clone=None): - - if clone: - # XXX This isn't cloning. It's an instance of the same thing. - self.root=clone.root - self.pkgdir=clone.pkgdir - self.dbapi=clone.dbapi - self.populated=clone.populated - self.tree=clone.tree - self.remotepkgs=clone.remotepkgs - self.invalids=clone.invalids - else: - self.root=root - #self.pkgdir=settings["PKGDIR"] - self.pkgdir=pkgdir - self.dbapi=bindbapi(self) - self.populated=0 - self.tree={} - self.remotepkgs={} - self.invalids=[] - - def move_ent(self,mylist): - if not self.populated: - self.populate() - origcp=mylist[1] - newcp=mylist[2] - mynewcat=newcp.split("/")[0] - origmatches=self.dbapi.cp_list(origcp) - if not origmatches: - return - for mycpv in origmatches: - - mycpsplit=catpkgsplit(mycpv) - mynewcpv=newcp+"-"+mycpsplit[2] - if mycpsplit[3]!="r0": - mynewcpv += "-"+mycpsplit[3] - - myoldpkg=mycpv.split("/")[1] - mynewpkg=mynewcpv.split("/")[1] - - if (mynewpkg != myoldpkg) and os.path.exists(self.getname(mynewcpv)): - writemsg("!!! Cannot update binary: Destination exists.\n") - writemsg("!!! "+mycpv+" -> "+mynewcpv+"\n") - continue - - tbz2path=self.getname(mycpv) - if os.path.exists(tbz2path) and not os.access(tbz2path,os.W_OK): - writemsg("!!! Cannot update readonly binary: "+mycpv+"\n") - continue - - #print ">>> Updating data in:",mycpv - sys.stdout.write("%") - sys.stdout.flush() - mytmpdir=settings["PORTAGE_TMPDIR"]+"/tbz2" - mytbz2=xpak.tbz2(tbz2path) - mytbz2.decompose(mytmpdir, cleanup=1) - - fixdbentries(origcp, newcp, mytmpdir) - - catfile=open(mytmpdir+"/CATEGORY", "w") - catfile.write(mynewcat+"\n") - catfile.close() - try: - os.rename(mytmpdir+"/"+string.split(mycpv,"/")[1]+".ebuild", mytmpdir+"/"+string.split(mynewcpv, "/")[1]+".ebuild") - except SystemExit, e: - raise - except Exception, e: - pass - - mytbz2.recompose(mytmpdir, cleanup=1) - - self.dbapi.cpv_remove(mycpv) - if (mynewpkg != myoldpkg): - os.rename(tbz2path,self.getname(mynewcpv)) - self.dbapi.cpv_inject(mynewcpv) - return 1 - - def move_slot_ent(self,mylist,mytmpdir): - #mytmpdir=settings["PORTAGE_TMPDIR"]+"/tbz2" - mytmpdir=mytmpdir+"/tbz2" - if not self.populated: - self.populate() - pkg=mylist[1] - origslot=mylist[2] - newslot=mylist[3] - origmatches=self.dbapi.match(pkg) - if not origmatches: - return - for mycpv in origmatches: - mycpsplit=catpkgsplit(mycpv) - myoldpkg=mycpv.split("/")[1] - tbz2path=self.getname(mycpv) - if os.path.exists(tbz2path) and not os.access(tbz2path,os.W_OK): - writemsg("!!! Cannot update readonly binary: "+mycpv+"\n") - continue - - #print ">>> Updating data in:",mycpv - mytbz2=xpak.tbz2(tbz2path) - mytbz2.decompose(mytmpdir, cleanup=1) - - slot=grabfile(mytmpdir+"/SLOT"); - if (not slot): - continue - - if (slot[0]!=origslot): - continue - - sys.stdout.write("S") - sys.stdout.flush() - - slotfile=open(mytmpdir+"/SLOT", "w") - slotfile.write(newslot+"\n") - slotfile.close() - mytbz2.recompose(mytmpdir, cleanup=1) - return 1 - - def update_ents(self,mybiglist,mytmpdir): - #XXX mytmpdir=settings["PORTAGE_TMPDIR"]+"/tbz2" - if not self.populated: - self.populate() - for mycpv in self.dbapi.cp_all(): - tbz2path=self.getname(mycpv) - if os.path.exists(tbz2path) and not os.access(tbz2path,os.W_OK): - writemsg("!!! Cannot update readonly binary: "+mycpv+"\n") - continue - #print ">>> Updating binary data:",mycpv - writemsg("*") - mytbz2=xpak.tbz2(tbz2path) - mytbz2.decompose(mytmpdir,cleanup=1) - for mylist in mybiglist: - mylist=string.split(mylist) - if mylist[0] != "move": - continue - fixdbentries(mylist[1], mylist[2], mytmpdir) - mytbz2.recompose(mytmpdir,cleanup=1) - return 1 - - def populate(self, getbinpkgs=0,getbinpkgsonly=0): - "populates the binarytree" - if (not os.path.isdir(self.pkgdir) and not getbinpkgs): - return 0 - if (not os.path.isdir(self.pkgdir+"/All") and not getbinpkgs): - return 0 - - if (not getbinpkgsonly) and os.path.exists(self.pkgdir+"/All"): - for mypkg in listdir(self.pkgdir+"/All"): - if mypkg[-5:]!=".tbz2": - continue - mytbz2=xpak.tbz2(self.pkgdir+"/All/"+mypkg) - mycat=mytbz2.getfile("CATEGORY") - if not mycat: - #old-style or corrupt package - writemsg("!!! Invalid binary package: "+mypkg+"\n") - self.invalids.append(mypkg) - continue - mycat=string.strip(mycat) - fullpkg=mycat+"/"+mypkg[:-5] - mykey=dep_getkey(fullpkg) - try: - # invalid tbz2's can hurt things. - self.dbapi.cpv_inject(fullpkg) - except SystemExit, e: - raise - except: - continue - - if getbinpkgs and not settings["PORTAGE_BINHOST"]: - writemsg(red("!!! PORTAGE_BINHOST unset, but use is requested.\n")) - - if getbinpkgs and settings["PORTAGE_BINHOST"] and not self.remotepkgs: - try: - chunk_size = long(settings["PORTAGE_BINHOST_CHUNKSIZE"]) - if chunk_size < 8: - chunk_size = 8 - except SystemExit, e: - raise - except: - chunk_size = 3000 - - writemsg(green("Fetching binary packages info...\n")) - self.remotepkgs = getbinpkg.dir_get_metadata(settings["PORTAGE_BINHOST"], chunk_size=chunk_size) - writemsg(green(" -- DONE!\n\n")) - - for mypkg in self.remotepkgs.keys(): - if not self.remotepkgs[mypkg].has_key("CATEGORY"): - #old-style or corrupt package - writemsg("!!! Invalid remote binary package: "+mypkg+"\n") - del self.remotepkgs[mypkg] - continue - mycat=string.strip(self.remotepkgs[mypkg]["CATEGORY"]) - fullpkg=mycat+"/"+mypkg[:-5] - mykey=dep_getkey(fullpkg) - try: - # invalid tbz2's can hurt things. - #print "cpv_inject("+str(fullpkg)+")" - self.dbapi.cpv_inject(fullpkg) - #print " -- Injected" - except SystemExit, e: - raise - except: - writemsg("!!! Failed to inject remote binary package:"+str(fullpkg)+"\n") - del self.remotepkgs[mypkg] - continue - self.populated=1 - - def inject(self,cpv): - return self.dbapi.cpv_inject(cpv) - - def exists_specific(self,cpv): - if not self.populated: - self.populate() - return self.dbapi.match(dep_expand("="+cpv,mydb=self.dbapi)) - - def dep_bestmatch(self,mydep): - "compatibility method -- all matches, not just visible ones" - if not self.populated: - self.populate() - writemsg("\n\n", 1) - writemsg("mydep: %s\n" % mydep, 1) - mydep=dep_expand(mydep,mydb=self.dbapi) - writemsg("mydep: %s\n" % mydep, 1) - mykey=dep_getkey(mydep) - writemsg("mykey: %s\n" % mykey, 1) - mymatch=best(match_from_list(mydep,self.dbapi.cp_list(mykey))) - writemsg("mymatch: %s\n" % mymatch, 1) - if mymatch==None: - return "" - return mymatch - - def getname(self,pkgname): - "returns file location for this particular package" - mysplit=string.split(pkgname,"/") - if len(mysplit)==1: - return self.pkgdir+"/All/"+self.resolve_specific(pkgname)+".tbz2" - else: - return self.pkgdir+"/All/"+mysplit[1]+".tbz2" - - def isremote(self,pkgname): - "Returns true if the package is kept remotely." - mysplit=string.split(pkgname,"/") - remote = (not os.path.exists(self.getname(pkgname))) and self.remotepkgs.has_key(mysplit[1]+".tbz2") - return remote - - def get_use(self,pkgname): - mysplit=string.split(pkgname,"/") - if self.isremote(pkgname): - return string.split(self.remotepkgs[mysplit[1]+".tbz2"]["USE"][:]) - tbz2=xpak.tbz2(self.getname(pkgname)) - return string.split(tbz2.getfile("USE")) - - def gettbz2(self,pkgname): - "fetches the package from a remote site, if necessary." - print "Fetching '"+str(pkgname)+"'" - mysplit = string.split(pkgname,"/") - tbz2name = mysplit[1]+".tbz2" - if not self.isremote(pkgname): - if (tbz2name not in self.invalids): - return - else: - writemsg("Resuming download of this tbz2, but it is possible that it is corrupt.\n") - mydest = self.pkgdir+"/All/" - try: - os.makedirs(mydest, 0775) - except SystemExit, e: - raise - except: - pass - getbinpkg.file_get(settings["PORTAGE_BINHOST"]+"/"+tbz2name, mydest, fcmd=settings["RESUMECOMMAND"]) - return - - def getslot(self,mycatpkg): - "Get a slot for a catpkg; assume it exists." - myslot = "" - try: - myslot=self.dbapi.aux_get(mycatpkg,["SLOT"])[0] - except SystemExit, e: - raise - except Exception, e: - pass - return myslot - -class dblink: - "this class provides an interface to the standard text package database" - def __init__(self,cat,pkg,myroot,mysettings): - "create a dblink object for cat/pkg. This dblink entry may or may not exist" - self.cat = cat - self.pkg = pkg - self.mycpv = self.cat+"/"+self.pkg - self.mysplit = pkgsplit(self.mycpv) - - self.dbroot = os.path.normpath(myroot+VDB_PATH) - self.dbcatdir = self.dbroot+"/"+cat - self.dbpkgdir = self.dbcatdir+"/"+pkg - self.dbtmpdir = self.dbcatdir+"/-MERGING-"+pkg - self.dbdir = self.dbpkgdir - - self.lock_pkg = None - self.lock_tmp = None - self.lock_num = 0 # Count of the held locks on the db. - - self.settings = mysettings - if self.settings==1: - raise ValueError - - self.myroot=myroot - self.updateprotect() - self.contentscache=[] - - def lockdb(self): - if self.lock_num == 0: - self.lock_pkg = portage_locks.lockdir(self.dbpkgdir) - self.lock_tmp = portage_locks.lockdir(self.dbtmpdir) - self.lock_num += 1 - - def unlockdb(self): - self.lock_num -= 1 - if self.lock_num == 0: - portage_locks.unlockdir(self.lock_tmp) - portage_locks.unlockdir(self.lock_pkg) - - def getpath(self): - "return path to location of db information (for >>> informational display)" - return self.dbdir - - def exists(self): - "does the db entry exist? boolean." - return os.path.exists(self.dbdir) - - def create(self): - "create the skeleton db directory structure. No contents, virtuals, provides or anything. Also will create /var/db/pkg if necessary." - # XXXXX Delete this eventually - raise Exception, "This is bad. Don't use it." - if not os.path.exists(self.dbdir): - os.makedirs(self.dbdir) - - def delete(self): - "erase this db entry completely" - if not os.path.exists(self.dbdir): - return - try: - for x in listdir(self.dbdir): - os.unlink(self.dbdir+"/"+x) - os.rmdir(self.dbdir) - except OSError, e: - print "!!! Unable to remove db entry for this package." - print "!!! It is possible that a directory is in this one. Portage will still" - print "!!! register this package as installed as long as this directory exists." - print "!!! You may delete this directory with 'rm -Rf "+self.dbdir+"'" - print "!!! "+str(e) - print - sys.exit(1) - - def clearcontents(self): - if os.path.exists(self.dbdir+"/CONTENTS"): - os.unlink(self.dbdir+"/CONTENTS") - - def getcontents(self): - if not os.path.exists(self.dbdir+"/CONTENTS"): - return None - if self.contentscache != []: - return self.contentscache - pkgfiles={} - myc=open(self.dbdir+"/CONTENTS","r") - mylines=myc.readlines() - myc.close() - pos=1 - for line in mylines: - mydat = string.split(line) - # we do this so we can remove from non-root filesystems - # (use the ROOT var to allow maintenance on other partitions) - try: - mydat[1]=os.path.normpath(root+mydat[1][1:]) - if mydat[0]=="obj": - #format: type, mtime, md5sum - pkgfiles[string.join(mydat[1:-2]," ")]=[mydat[0], mydat[-1], mydat[-2]] - elif mydat[0]=="dir": - #format: type - pkgfiles[string.join(mydat[1:])]=[mydat[0] ] - elif mydat[0]=="sym": - #format: type, mtime, dest - x=len(mydat)-1 - if (x >= 13) and (mydat[-1][-1]==')'): # Old/Broken symlink entry - mydat = mydat[:-10]+[mydat[-10:][stat.ST_MTIME][:-1]] - writemsg("FIXED SYMLINK LINE: %s\n" % mydat, 1) - x=len(mydat)-1 - splitter=-1 - while(x>=0): - if mydat[x]=="->": - splitter=x - break - x=x-1 - if splitter==-1: - return None - pkgfiles[string.join(mydat[1:splitter]," ")]=[mydat[0], mydat[-1], string.join(mydat[(splitter+1):-1]," ")] - elif mydat[0]=="dev": - #format: type - pkgfiles[string.join(mydat[1:]," ")]=[mydat[0] ] - elif mydat[0]=="fif": - #format: type - pkgfiles[string.join(mydat[1:]," ")]=[mydat[0]] - else: - return None - except (KeyError,IndexError): - print "portage: CONTENTS line",pos,"corrupt!" - pos += 1 - self.contentscache=pkgfiles - return pkgfiles - - def updateprotect(self): - #do some config file management prep - self.protect=[] - for x in string.split(self.settings["CONFIG_PROTECT"]): - ppath=normalize_path(self.myroot+x)+"/" - if os.path.isdir(ppath): - self.protect.append(ppath) - - self.protectmask=[] - for x in string.split(self.settings["CONFIG_PROTECT_MASK"]): - ppath=normalize_path(self.myroot+x)+"/" - if os.path.isdir(ppath): - self.protectmask.append(ppath) - #if it doesn't exist, silently skip it - - def isprotected(self,obj): - """Checks if obj is in the current protect/mask directories. Returns - 0 on unprotected/masked, and 1 on protected.""" - masked=0 - protected=0 - for ppath in self.protect: - if (len(ppath) > masked) and (obj[0:len(ppath)]==ppath): - protected=len(ppath) - #config file management - for pmpath in self.protectmask: - if (len(pmpath) >= protected) and (obj[0:len(pmpath)]==pmpath): - #skip, it's in the mask - masked=len(pmpath) - return (protected > masked) - - def unmerge(self,pkgfiles=None,trimworld=1,cleanup=0): - global dircache - dircache={} - - self.lockdb() - - self.settings.load_infodir(self.dbdir) - - if not pkgfiles: - print "No package files given... Grabbing a set." - pkgfiles=self.getcontents() - - # Now, don't assume that the name of the ebuild is the same as the - # name of the dir; the package may have been moved. - myebuildpath=None - - # We should use the environement file if possible, - # as it has all sourced files already included. - # XXX: Need to ensure it doesn't overwrite any important vars though. - if os.access(self.dbdir+"/environment.bz2", os.R_OK): - spawn("bzip2 -d "+self.dbdir+"/environment.bz2",self.settings,free=1) - - if not myebuildpath: - mystuff=listdir(self.dbdir,EmptyOnError=1) - for x in mystuff: - if x[-7:]==".ebuild": - myebuildpath=self.dbdir+"/"+x - break - - #do prerm script - if myebuildpath and os.path.exists(myebuildpath): - a=doebuild(myebuildpath,"prerm",self.myroot,self.settings,cleanup=cleanup,use_cache=0,tree="vartree") - # XXX: Decide how to handle failures here. - if a != 0: - writemsg("!!! FAILED prerm: "+str(a)+"\n") - sys.exit(123) - - if pkgfiles: - mykeys=pkgfiles.keys() - mykeys.sort() - mykeys.reverse() - - self.updateprotect() - - #process symlinks second-to-last, directories last. - mydirs=[] - mysyms=[] - modprotect="/lib/modules/" - for obj in mykeys: - obj=os.path.normpath(obj) - if obj[:2]=="//": - obj=obj[1:] - if not os.path.exists(obj): - if not os.path.islink(obj): - #we skip this if we're dealing with a symlink - #because os.path.exists() will operate on the - #link target rather than the link itself. - print "--- !found "+str(pkgfiles[obj][0]), obj - continue - # next line includes a tweak to protect modules from being unmerged, - # but we don't protect modules from being overwritten if they are - # upgraded. We effectively only want one half of the config protection - # functionality for /lib/modules. For portage-ng both capabilities - # should be able to be independently specified. - if self.isprotected(obj) or ((len(obj) > len(modprotect)) and (obj[0:len(modprotect)]==modprotect)): - print "--- cfgpro "+str(pkgfiles[obj][0]), obj - continue - - lstatobj=os.lstat(obj) - lmtime=str(lstatobj[stat.ST_MTIME]) - if (pkgfiles[obj][0] not in ("dir","fif","dev","sym")) and (lmtime != pkgfiles[obj][1]): - print "--- !mtime", pkgfiles[obj][0], obj - continue - - if pkgfiles[obj][0]=="dir": - if not os.path.isdir(obj): - print "--- !dir ","dir", obj - continue - mydirs.append(obj) - elif pkgfiles[obj][0]=="sym": - if not os.path.islink(obj): - print "--- !sym ","sym", obj - continue - mysyms.append(obj) - elif pkgfiles[obj][0]=="obj": - if not os.path.isfile(obj): - print "--- !obj ","obj", obj - continue - mymd5=portage_checksum.perform_md5(obj, calc_prelink=1) - - # string.lower is needed because db entries used to be in upper-case. The - # string.lower allows for backwards compatibility. - if mymd5 != string.lower(pkgfiles[obj][2]): - print "--- !md5 ","obj", obj - continue - try: - os.unlink(obj) - except (OSError,IOError),e: - pass - print "<<< ","obj",obj - elif pkgfiles[obj][0]=="fif": - if not stat.S_ISFIFO(lstatobj[stat.ST_MODE]): - print "--- !fif ","fif", obj - continue - try: - os.unlink(obj) - except (OSError,IOError),e: - pass - print "<<< ","fif",obj - elif pkgfiles[obj][0]=="dev": - print "--- ","dev",obj - - #Now, we need to remove symlinks and directories. We'll repeatedly - #remove dead symlinks, then directories until we stop making progress. - #This is how we'll clean up directories containing symlinks pointing to - #directories that are now empty. These cases will require several - #iterations through our two-stage symlink/directory cleaning loop. - - #main symlink and directory removal loop: - - #progress -- are we making progress? Initialized to 1 so loop will start - progress=1 - while progress: - #let's see if we're able to make progress this iteration... - progress=0 - - #step 1: remove all the dead symlinks we can... - - pos = 0 - while pos<len(mysyms): - obj=mysyms[pos] - if os.path.exists(obj): - pos += 1 - else: - #we have a dead symlink; remove it from our list, then from existence - del mysyms[pos] - #we've made progress! - progress = 1 - try: - os.unlink(obj) - print "<<< ","sym",obj - except (OSError,IOError),e: - print "!!! ","sym",obj - #immutable? - pass - - #step 2: remove all the empty directories we can... - - pos = 0 - while pos<len(mydirs): - obj=mydirs[pos] - objld=listdir(obj) - - if objld == None: - print "mydirs["+str(pos)+"]",mydirs[pos] - print "obj",obj - print "objld",objld - # the directory doesn't exist yet, continue - pos += 1 - continue - - if len(objld)>0: - #we won't remove this directory (yet), continue - pos += 1 - continue - elif (objld != None): - #zappo time - del mydirs[pos] - #we've made progress! - progress = 1 - try: - os.rmdir(obj) - print "<<< ","dir",obj - except (OSError,IOError),e: - #immutable? - pass - #else: - # print "--- !empty","dir", obj - # continue - - #step 3: if we've made progress, we'll give this another go... - - #step 4: otherwise, we'll print out the remaining stuff that we didn't unmerge (and rightly so!) - - #directories that aren't empty: - for x in mydirs: - print "--- !empty dir", x - - #symlinks whose target still exists: - for x in mysyms: - print "--- !targe sym", x - - #step 5: well, removal of package objects is complete, now for package *meta*-objects.... - - #remove self from vartree database so that our own virtual gets zapped if we're the last node - db[self.myroot]["vartree"].zap(self.mycpv) - - # New code to remove stuff from the world and virtuals files when unmerged. - if trimworld: - worldlist=grabfile(self.myroot+WORLD_FILE) - mykey=cpv_getkey(self.mycpv) - newworldlist=[] - for x in worldlist: - if dep_getkey(x)==mykey: - matches=db[self.myroot]["vartree"].dbapi.match(x,use_cache=0) - if not matches: - #zap our world entry - pass - elif (len(matches)==1) and (matches[0]==self.mycpv): - #zap our world entry - pass - else: - #others are around; keep it. - newworldlist.append(x) - else: - #this doesn't match the package we're unmerging; keep it. - newworldlist.append(x) - - # if the base dir doesn't exist, create it. - # (spanky noticed bug) - # XXX: dumb question, but abstracting the root uid might be wise/useful for - # 2nd pkg manager installation setups. - if not os.path.exists(os.path.dirname(self.myroot+WORLD_FILE)): - pdir = os.path.dirname(self.myroot + WORLD_FILE) - os.makedirs(pdir, mode=0755) - os.chown(pdir, 0, portage_gid) - os.chmod(pdir, 02770) - - myworld=open(self.myroot+WORLD_FILE,"w") - for x in newworldlist: - myworld.write(x+"\n") - myworld.close() - - #do original postrm - if myebuildpath and os.path.exists(myebuildpath): - # XXX: This should be the old config, not the current one. - # XXX: Use vardbapi to load up env vars. - a=doebuild(myebuildpath,"postrm",self.myroot,self.settings,use_cache=0,tree="vartree") - # XXX: Decide how to handle failures here. - if a != 0: - writemsg("!!! FAILED postrm: "+str(a)+"\n") - sys.exit(123) - - self.unlockdb() - - def isowner(self,filename,destroot): - """ check if filename is a new file or belongs to this package - (for this or a previous version)""" - destfile = os.path.normpath(destroot+"/"+filename) - if not os.path.exists(destfile): - return True - if self.getcontents() and filename in self.getcontents().keys(): - return True - - return False - - def treewalk(self,srcroot,destroot,inforoot,myebuild,cleanup=0): - global db - # srcroot = ${D}; - # destroot = where to merge, ie. ${ROOT}, - # inforoot = root of db entry, - # secondhand = list of symlinks that have been skipped due to - # their target not existing (will merge later), - - if not os.path.exists(self.dbcatdir): - os.makedirs(self.dbcatdir) - - # This blocks until we can get the dirs to ourselves. - self.lockdb() - - otherversions=[] - for v in db[self.myroot]["vartree"].dbapi.cp_list(self.mysplit[0]): - otherversions.append(v.split("/")[1]) - - # check for package collisions - if "collision-protect" in features: - myfilelist = listdir(srcroot, recursive=1, filesonly=1, followSymlinks=False) - - # the linkcheck only works if we are in srcroot - mycwd = os.getcwd() - os.chdir(srcroot) - mysymlinks = filter(os.path.islink, listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False)) - - stopmerge=False - starttime=time.time() - i=0 - - otherpkg=[] - mypkglist=[] - - if self.pkg in otherversions: - otherversions.remove(self.pkg) # we already checked this package - - for v in otherversions: - # should we check for same SLOT here ? - mypkglist.append(dblink(self.cat,v,destroot,self.settings)) - - print green("*")+" checking "+str(len(myfilelist))+" files for package collisions" - for f in myfilelist: - nocheck = False - # listdir isn't intelligent enough to exclude symlinked dirs, - # so we have to do it ourself - for s in mysymlinks: - # the length comparison makes sure that the symlink itself is checked - if f[:len(s)] == s and len(f) > len(s): - nocheck = True - if nocheck: - continue - i=i+1 - if i % 1000 == 0: - print str(i)+" files checked ..." - if f[0] != "/": - f="/"+f - isowned = False - for ver in [self]+mypkglist: - if (ver.isowner(f, destroot) or ver.isprotected(f)): - isowned = True - break - if not isowned: - print "existing file "+f+" is not owned by this package" - stopmerge=True - print green("*")+" spent "+str(time.time()-starttime)+" seconds checking for file collisions" - if stopmerge: - print red("*")+" This package is blocked because it wants to overwrite" - print red("*")+" files belonging to other packages (see messages above)." - print red("*")+" If you have no clue what this is all about report it " - print red("*")+" as a bug for this package on http://bugs.gentoo.org" - print - print red("package "+self.cat+"/"+self.pkg+" NOT merged") - print - # Why is the package already merged here db-wise? Shouldn't be the case - # only unmerge if it ia new package and has no contents - if not self.getcontents(): - self.unmerge() - self.delete() - self.unlockdb() - sys.exit(1) - try: - os.chdir(mycwd) - except SystemExit, e: - raise - except: - pass - - - # get old contents info for later unmerging - oldcontents = self.getcontents() - - self.dbdir = self.dbtmpdir - self.delete() - if not os.path.exists(self.dbtmpdir): - os.makedirs(self.dbtmpdir) - - print ">>> Merging",self.mycpv,"to",destroot - - # run preinst script - if myebuild: - # if we are merging a new ebuild, use *its* pre/postinst rather than using the one in /var/db/pkg - # (if any). - a=doebuild(myebuild,"preinst",root,self.settings,cleanup=cleanup,use_cache=0) - else: - a=doebuild(inforoot+"/"+self.pkg+".ebuild","preinst",root,self.settings,cleanup=cleanup,use_cache=0) - - # XXX: Decide how to handle failures here. - if a != 0: - writemsg("!!! FAILED preinst: "+str(a)+"\n") - sys.exit(123) - - # copy "info" files (like SLOT, CFLAGS, etc.) into the database - for x in listdir(inforoot): - self.copyfile(inforoot+"/"+x) - - # get current counter value (counter_tick also takes care of incrementing it) - # XXX Need to make this destroot, but it needs to be initialized first. XXX - # XXX bis: leads to some invalidentry() call through cp_all(). - counter = db["/"]["vartree"].dbapi.counter_tick(self.myroot,mycpv=self.mycpv) - # write local package counter for recording - lcfile = open(self.dbtmpdir+"/COUNTER","w") - lcfile.write(str(counter)) - lcfile.close() - - # open CONTENTS file (possibly overwriting old one) for recording - outfile=open(self.dbtmpdir+"/CONTENTS","w") - - self.updateprotect() - - #if we have a file containing previously-merged config file md5sums, grab it. - if os.path.exists(destroot+CONFIG_MEMORY_FILE): - cfgfiledict=grabdict(destroot+CONFIG_MEMORY_FILE) - else: - cfgfiledict={} - if self.settings.has_key("NOCONFMEM"): - cfgfiledict["IGNORE"]=1 - else: - cfgfiledict["IGNORE"]=0 - - # set umask to 0 for merging; back up umask, save old one in prevmask (since this is a global change) - mymtime = long(time.time()) - prevmask = os.umask(0) - secondhand = [] - - # we do a first merge; this will recurse through all files in our srcroot but also build up a - # "second hand" of symlinks to merge later - if self.mergeme(srcroot,destroot,outfile,secondhand,"",cfgfiledict,mymtime): - return 1 - - # now, it's time for dealing our second hand; we'll loop until we can't merge anymore. The rest are - # broken symlinks. We'll merge them too. - lastlen=0 - while len(secondhand) and len(secondhand)!=lastlen: - # clear the thirdhand. Anything from our second hand that - # couldn't get merged will be added to thirdhand. - - thirdhand=[] - self.mergeme(srcroot,destroot,outfile,thirdhand,secondhand,cfgfiledict,mymtime) - - #swap hands - lastlen=len(secondhand) - - # our thirdhand now becomes our secondhand. It's ok to throw - # away secondhand since thirdhand contains all the stuff that - # couldn't be merged. - secondhand = thirdhand - - if len(secondhand): - # force merge of remaining symlinks (broken or circular; oh well) - self.mergeme(srcroot,destroot,outfile,None,secondhand,cfgfiledict,mymtime) - - #restore umask - os.umask(prevmask) - - #if we opened it, close it - outfile.flush() - outfile.close() - - if (oldcontents): - print ">>> Safely unmerging already-installed instance..." - self.dbdir = self.dbpkgdir - self.unmerge(oldcontents,trimworld=0) - self.dbdir = self.dbtmpdir - print ">>> original instance of package unmerged safely." - - # We hold both directory locks. - self.dbdir = self.dbpkgdir - self.delete() - movefile(self.dbtmpdir, self.dbpkgdir, mysettings=self.settings) - - self.unlockdb() - - #write out our collection of md5sums - if cfgfiledict.has_key("IGNORE"): - del cfgfiledict["IGNORE"] - - # XXXX: HACK! PathSpec is very necessary here. - if not os.path.exists(destroot+PRIVATE_PATH): - os.makedirs(destroot+PRIVATE_PATH) - os.chown(destroot+PRIVATE_PATH,os.getuid(),portage_gid) - os.chmod(destroot+PRIVATE_PATH,02770) - dirlist = prefix_array(listdir(destroot+PRIVATE_PATH),destroot+PRIVATE_PATH+"/") - while dirlist: - dirlist.sort() - dirlist.reverse() # Gets them in file-before basedir order - x = dirlist[0] - if os.path.isdir(x): - dirlist += prefix_array(listdir(x),x+"/") - continue - os.unlink(destroot+PRIVATE_PATH+"/"+x) - - mylock = portage_locks.lockfile(destroot+CONFIG_MEMORY_FILE) - writedict(cfgfiledict,destroot+CONFIG_MEMORY_FILE) - portage_locks.unlockfile(mylock) - - #do postinst script - if myebuild: - # if we are merging a new ebuild, use *its* pre/postinst rather than using the one in /var/db/pkg - # (if any). - a=doebuild(myebuild,"postinst",root,self.settings,use_cache=0) - else: - a=doebuild(inforoot+"/"+self.pkg+".ebuild","postinst",root,self.settings,use_cache=0) - - # XXX: Decide how to handle failures here. - if a != 0: - writemsg("!!! FAILED postinst: "+str(a)+"\n") - sys.exit(123) - - downgrade = False - for v in otherversions: - if pkgcmp(catpkgsplit(self.pkg)[1:], catpkgsplit(v)[1:]) < 0: - downgrade = True - - #update environment settings, library paths. DO NOT change symlinks. - env_update(makelinks=(not downgrade)) - #dircache may break autoclean because it remembers the -MERGING-pkg file - global dircache - if dircache.has_key(self.dbcatdir): - del dircache[self.dbcatdir] - print ">>>",self.mycpv,"merged." - return 0 - - def mergeme(self,srcroot,destroot,outfile,secondhand,stufftomerge,cfgfiledict,thismtime): - srcroot=os.path.normpath("///"+srcroot)+"/" - destroot=os.path.normpath("///"+destroot)+"/" - # this is supposed to merge a list of files. There will be 2 forms of argument passing. - if type(stufftomerge)==types.StringType: - #A directory is specified. Figure out protection paths, listdir() it and process it. - mergelist=listdir(srcroot+stufftomerge) - offset=stufftomerge - # We need mydest defined up here to calc. protection paths. This is now done once per - # directory rather than once per file merge. This should really help merge performance. - # Trailing / ensures that protects/masks with trailing /'s match. - mytruncpath="/"+offset+"/" - myppath=self.isprotected(mytruncpath) - else: - mergelist=stufftomerge - offset="" - for x in mergelist: - mysrc=os.path.normpath("///"+srcroot+offset+x) - mydest=os.path.normpath("///"+destroot+offset+x) - # myrealdest is mydest without the $ROOT prefix (makes a difference if ROOT!="/") - myrealdest="/"+offset+x - # stat file once, test using S_* macros many times (faster that way) - try: - mystat=os.lstat(mysrc) - except SystemExit, e: - raise - except OSError, e: - writemsg("\n") - writemsg(red("!!! ERROR: There appears to be ")+bold("FILE SYSTEM CORRUPTION.")+red(" A file that is listed\n")) - writemsg(red("!!! as existing is not capable of being stat'd. If you are using an\n")) - writemsg(red("!!! experimental kernel, please boot into a stable one, force an fsck,\n")) - writemsg(red("!!! and ensure your filesystem is in a sane state. ")+bold("'shutdown -Fr now'\n")) - writemsg(red("!!! File: ")+str(mysrc)+"\n") - writemsg(red("!!! Error: ")+str(e)+"\n") - sys.exit(1) - except Exception, e: - writemsg("\n") - writemsg(red("!!! ERROR: An unknown error has occurred during the merge process.\n")) - writemsg(red("!!! A stat call returned the following error for the following file:")) - writemsg( "!!! Please ensure that your filesystem is intact, otherwise report\n") - writemsg( "!!! this as a portage bug at bugs.gentoo.org. Append 'emerge info'.\n") - writemsg( "!!! File: "+str(mysrc)+"\n") - writemsg( "!!! Error: "+str(e)+"\n") - sys.exit(1) - - - mymode=mystat[stat.ST_MODE] - # handy variables; mydest is the target object on the live filesystems; - # mysrc is the source object in the temporary install dir - try: - mydmode=os.lstat(mydest)[stat.ST_MODE] - except SystemExit, e: - raise - except: - #dest file doesn't exist - mydmode=None - - if stat.S_ISLNK(mymode): - # we are merging a symbolic link - myabsto=abssymlink(mysrc) - if myabsto[0:len(srcroot)]==srcroot: - myabsto=myabsto[len(srcroot):] - if myabsto[0]!="/": - myabsto="/"+myabsto - myto=os.readlink(mysrc) - if self.settings and self.settings["D"]: - if myto.find(self.settings["D"])==0: - myto=myto[len(self.settings["D"]):] - # myrealto contains the path of the real file to which this symlink points. - # we can simply test for existence of this file to see if the target has been merged yet - myrealto=os.path.normpath(os.path.join(destroot,myabsto)) - if mydmode!=None: - #destination exists - if not stat.S_ISLNK(mydmode): - if stat.S_ISDIR(mydmode): - # directory in the way: we can't merge a symlink over a directory - # we won't merge this, continue with next file... - continue - if self.isprotected(mydest): - # Use md5 of the target in ${D} if it exists... - if os.path.exists(os.path.normpath(srcroot+myabsto)): - try: - mydest = new_protect_filename(myrealdest, newmd5=portage_checksum.perform_md5(srcroot+myabsto)) - except IOError: - print "========================================" - print "mysrc",mysrc - print "mymode",mymode - print "myabsto",myabsto - print "myto",myto - print "myrealto",myrealto - print "mydest",mydest - print "mydmode",mydmode - print "========================================" - print "Please file the above in bug #71787" - sys.exit(1) - else: - mydest = new_protect_filename(myrealdest, newmd5=portage_checksum.perform_md5(myabsto)) - - # if secondhand==None it means we're operating in "force" mode and should not create a second hand. - if (secondhand!=None) and (not os.path.exists(myrealto)): - # either the target directory doesn't exist yet or the target file doesn't exist -- or - # the target is a broken symlink. We will add this file to our "second hand" and merge - # it later. - secondhand.append(mysrc[len(srcroot):]) - continue - # unlinking no longer necessary; "movefile" will overwrite symlinks atomically and correctly - mymtime=movefile(mysrc,mydest,newmtime=thismtime,sstat=mystat, mysettings=self.settings) - if mymtime!=None: - print ">>>",mydest,"->",myto - outfile.write("sym "+myrealdest+" -> "+myto+" "+str(mymtime)+"\n") - else: - print "!!! Failed to move file." - print "!!!",mydest,"->",myto - sys.exit(1) - elif stat.S_ISDIR(mymode): - # we are merging a directory - if mydmode!=None: - # destination exists - - if bsd_chflags: - # Save then clear flags on dest. - dflags=bsd_chflags.lgetflags(mydest) - if(bsd_chflags.lchflags(mydest, 0)<0): - writemsg("!!! Couldn't clear flags on '"+mydest+"'.\n") - - if not os.access(mydest, os.W_OK): - pkgstuff = pkgsplit(self.pkg) - writemsg("\n!!! Cannot write to '"+mydest+"'.\n") - writemsg("!!! Please check permissions and directories for broken symlinks.\n") - writemsg("!!! You may start the merge process again by using ebuild:\n") - writemsg("!!! ebuild "+self.settings["PORTDIR"]+"/"+self.cat+"/"+pkgstuff[0]+"/"+self.pkg+".ebuild merge\n") - writemsg("!!! And finish by running this: env-update\n\n") - return 1 - - if stat.S_ISLNK(mydmode) or stat.S_ISDIR(mydmode): - # a symlink to an existing directory will work for us; keep it: - print "---",mydest+"/" - if bsd_chflags: - bsd_chflags.lchflags(mydest, dflags) - else: - # a non-directory and non-symlink-to-directory. Won't work for us. Move out of the way. - if movefile(mydest,mydest+".backup", mysettings=self.settings) == None: - sys.exit(1) - print "bak",mydest,mydest+".backup" - #now create our directory - if selinux_enabled: - sid = selinux.get_sid(mysrc) - selinux.secure_mkdir(mydest,sid) - else: - os.mkdir(mydest) - if bsd_chflags: - bsd_chflags.lchflags(mydest, dflags) - os.chmod(mydest,mystat[0]) - lchown(mydest,mystat[4],mystat[5]) - print ">>>",mydest+"/" - else: - #destination doesn't exist - if selinux_enabled: - sid = selinux.get_sid(mysrc) - selinux.secure_mkdir(mydest,sid) - else: - os.mkdir(mydest) - os.chmod(mydest,mystat[0]) - if bsd_chflags: - bsd_chflags.lchflags(mydest, bsd_chflags.lgetflags(mysrc)) - lchown(mydest,mystat[4],mystat[5]) - print ">>>",mydest+"/" - outfile.write("dir "+myrealdest+"\n") - # recurse and merge this directory - if self.mergeme(srcroot,destroot,outfile,secondhand,offset+x+"/",cfgfiledict,thismtime): - return 1 - elif stat.S_ISREG(mymode): - # we are merging a regular file - mymd5=portage_checksum.perform_md5(mysrc,calc_prelink=1) - # calculate config file protection stuff - mydestdir=os.path.dirname(mydest) - moveme=1 - zing="!!!" - if mydmode!=None: - # destination file exists - if stat.S_ISDIR(mydmode): - # install of destination is blocked by an existing directory with the same name - moveme=0 - print "!!!",mydest - elif stat.S_ISREG(mydmode) or (stat.S_ISLNK(mydmode) and os.path.exists(mydest) and stat.S_ISREG(os.stat(mydest)[stat.ST_MODE])): - cfgprot=0 - # install of destination is blocked by an existing regular file, - # or by a symlink to an existing regular file; - # now, config file management may come into play. - # we only need to tweak mydest if cfg file management is in play. - if myppath: - # we have a protection path; enable config file management. - destmd5=portage_checksum.perform_md5(mydest,calc_prelink=1) - cycled=0 - if cfgfiledict.has_key(myrealdest): - if destmd5 in cfgfiledict[myrealdest]: - #cycle - print "cycle" - del cfgfiledict[myrealdest] - cycled=1 - if mymd5==destmd5: - #file already in place; simply update mtimes of destination - os.utime(mydest,(thismtime,thismtime)) - zing="---" - moveme=0 - elif cycled: - #mymd5!=destmd5 and we've cycled; move mysrc into place as a ._cfg file - moveme=1 - cfgfiledict[myrealdest]=[mymd5] - cfgprot=1 - elif cfgfiledict.has_key(myrealdest) and (mymd5 in cfgfiledict[myrealdest]): - #myd5!=destmd5, we haven't cycled, and the file we're merging has been already merged previously - zing="-o-" - moveme=cfgfiledict["IGNORE"] - cfgprot=cfgfiledict["IGNORE"] - else: - #mymd5!=destmd5, we haven't cycled, and the file we're merging hasn't been merged before - moveme=1 - cfgprot=1 - if not cfgfiledict.has_key(myrealdest): - cfgfiledict[myrealdest]=[] - if mymd5 not in cfgfiledict[myrealdest]: - cfgfiledict[myrealdest].append(mymd5) - #don't record more than 16 md5sums - if len(cfgfiledict[myrealdest])>16: - del cfgfiledict[myrealdest][0] - - if cfgprot: - mydest = new_protect_filename(myrealdest, newmd5=mymd5) - - # whether config protection or not, we merge the new file the - # same way. Unless moveme=0 (blocking directory) - if moveme: - mymtime=movefile(mysrc,mydest,newmtime=thismtime,sstat=mystat, mysettings=self.settings) - if mymtime == None: - sys.exit(1) - zing=">>>" - else: - mymtime=thismtime - # We need to touch the destination so that on --update the - # old package won't yank the file with it. (non-cfgprot related) - os.utime(myrealdest,(thismtime,thismtime)) - zing="---" - if self.settings["USERLAND"] == "Darwin" and myrealdest[-2:] == ".a": - - # XXX kludge, bug #58848; can be killed when portage stops relying on - # md5+mtime, and uses refcounts - # alright, we've fooled w/ mtime on the file; this pisses off static archives - # basically internal mtime != file's mtime, so the linker (falsely) thinks - # the archive is stale, and needs to have it's toc rebuilt. - - myf=open(myrealdest,"r+") - - # ar mtime field is digits padded with spaces, 12 bytes. - lms=str(thismtime+5).ljust(12) - myf.seek(0) - magic=myf.read(8) - if magic != "!<arch>\n": - # not an archive (dolib.a from portage.py makes it here fex) - myf.close() - else: - st=os.stat(myrealdest) - while myf.tell() < st.st_size - 12: - # skip object name - myf.seek(16,1) - - # update mtime - myf.write(lms) - - # skip uid/gid/mperm - myf.seek(20,1) - - # read the archive member's size - x=long(myf.read(10)) - - # skip the trailing newlines, and add the potential - # extra padding byte if it's not an even size - myf.seek(x + 2 + (x % 2),1) - - # and now we're at the end. yay. - myf.close() - mymd5=portage_checksum.perform_md5(myrealdest,calc_prelink=1) - os.utime(myrealdest,(thismtime,thismtime)) - - if mymtime!=None: - zing=">>>" - outfile.write("obj "+myrealdest+" "+mymd5+" "+str(mymtime)+"\n") - print zing,mydest - else: - # we are merging a fifo or device node - zing="!!!" - if mydmode==None: - # destination doesn't exist - if movefile(mysrc,mydest,newmtime=thismtime,sstat=mystat, mysettings=self.settings)!=None: - zing=">>>" - if stat.S_ISFIFO(mymode): - # we don't record device nodes in CONTENTS, - # although we do merge them. - outfile.write("fif "+myrealdest+"\n") - else: - sys.exit(1) - print zing+" "+mydest - - def merge(self,mergeroot,inforoot,myroot,myebuild=None,cleanup=0): - return self.treewalk(mergeroot,myroot,inforoot,myebuild,cleanup=cleanup) - - def getstring(self,name): - "returns contents of a file with whitespace converted to spaces" - if not os.path.exists(self.dbdir+"/"+name): - return "" - myfile=open(self.dbdir+"/"+name,"r") - mydata=string.split(myfile.read()) - myfile.close() - return string.join(mydata," ") - - def copyfile(self,fname): - shutil.copyfile(fname,self.dbdir+"/"+os.path.basename(fname)) - - def getfile(self,fname): - if not os.path.exists(self.dbdir+"/"+fname): - return "" - myfile=open(self.dbdir+"/"+fname,"r") - mydata=myfile.read() - myfile.close() - return mydata - - def setfile(self,fname,data): - myfile=open(self.dbdir+"/"+fname,"w") - myfile.write(data) - myfile.close() - - def getelements(self,ename): - if not os.path.exists(self.dbdir+"/"+ename): - return [] - myelement=open(self.dbdir+"/"+ename,"r") - mylines=myelement.readlines() - myreturn=[] - for x in mylines: - for y in string.split(x[:-1]): - myreturn.append(y) - myelement.close() - return myreturn - - def setelements(self,mylist,ename): - myelement=open(self.dbdir+"/"+ename,"w") - for x in mylist: - myelement.write(x+"\n") - myelement.close() - - def isregular(self): - "Is this a regular package (does it have a CATEGORY file? A dblink can be virtual *and* regular)" - return os.path.exists(self.dbdir+"/CATEGORY") - -def cleanup_pkgmerge(mypkg,origdir): - shutil.rmtree(settings["PORTAGE_TMPDIR"]+"/portage-pkg/"+mypkg) - if os.path.exists(settings["PORTAGE_TMPDIR"]+"/portage/"+mypkg+"/temp/environment"): - os.unlink(settings["PORTAGE_TMPDIR"]+"/portage/"+mypkg+"/temp/environment") - os.chdir(origdir) - -def pkgmerge(mytbz2,myroot,mysettings): - """will merge a .tbz2 file, returning a list of runtime dependencies - that must be satisfied, or None if there was a merge error. This - code assumes the package exists.""" - if mytbz2[-5:]!=".tbz2": - print "!!! Not a .tbz2 file" - return None - mypkg=os.path.basename(mytbz2)[:-5] - xptbz2=xpak.tbz2(mytbz2) - pkginfo={} - mycat=xptbz2.getfile("CATEGORY") - if not mycat: - print "!!! CATEGORY info missing from info chunk, aborting..." - return None - mycat=mycat.strip() - mycatpkg=mycat+"/"+mypkg - tmploc=mysettings["PORTAGE_TMPDIR"]+"/portage-pkg/" - pkgloc=tmploc+"/"+mypkg+"/bin/" - infloc=tmploc+"/"+mypkg+"/inf/" - myebuild=tmploc+"/"+mypkg+"/inf/"+os.path.basename(mytbz2)[:-4]+"ebuild" - if os.path.exists(tmploc+"/"+mypkg): - shutil.rmtree(tmploc+"/"+mypkg,1) - os.makedirs(pkgloc) - os.makedirs(infloc) - print ">>> extracting info" - xptbz2.unpackinfo(infloc) - # run pkg_setup early, so we can bail out early - # (before extracting binaries) if there's a problem - origdir=getcwd() - os.chdir(pkgloc) - - mysettings.configdict["pkg"]["CATEGORY"] = mycat; - a=doebuild(myebuild,"setup",myroot,mysettings,tree="bintree") - print ">>> extracting",mypkg - notok=spawn("bzip2 -dqc -- '"+mytbz2+"' | tar xpf -",mysettings,free=1) - if notok: - print "!!! Error extracting",mytbz2 - cleanup_pkgmerge(mypkg,origdir) - return None - - # the merge takes care of pre/postinst and old instance - # auto-unmerge, virtual/provides updates, etc. - mysettings.load_infodir(infloc) - mylink=dblink(mycat,mypkg,myroot,mysettings) - mylink.merge(pkgloc,infloc,myroot,myebuild,cleanup=1) - - if not os.path.exists(infloc+"/RDEPEND"): - returnme="" - else: - #get runtime dependencies - a=open(infloc+"/RDEPEND","r") - returnme=string.join(string.split(a.read())," ") - a.close() - cleanup_pkgmerge(mypkg,origdir) - return returnme - - -if os.environ.has_key("ROOT"): - root=os.environ["ROOT"] - if not len(root): - root="/" - elif root[-1]!="/": - root=root+"/" -else: - root="/" -if root != "/": - if not os.path.exists(root[:-1]): - writemsg("!!! Error: ROOT "+root+" does not exist. Please correct this.\n") - writemsg("!!! Exiting.\n\n") - sys.exit(1) - elif not os.path.isdir(root[:-1]): - writemsg("!!! Error: ROOT "+root[:-1]+" is not a directory. Please correct this.\n") - writemsg("!!! Exiting.\n\n") - sys.exit(1) - -#create tmp and var/tmp if they don't exist; read config -os.umask(0) -if not os.path.exists(root+"tmp"): - writemsg(">>> "+root+"tmp doesn't exist, creating it...\n") - os.mkdir(root+"tmp",01777) -if not os.path.exists(root+"var/tmp"): - writemsg(">>> "+root+"var/tmp doesn't exist, creating it...\n") - try: - os.mkdir(root+"var",0755) - except (OSError,IOError): - pass - try: - os.mkdir(root+"var/tmp",01777) - except SystemExit, e: - raise - except: - writemsg("portage: couldn't create /var/tmp; exiting.\n") - sys.exit(1) -if not os.path.exists(root+"var/lib/portage"): - writemsg(">>> "+root+"var/lib/portage doesn't exist, creating it...\n") - try: - os.mkdir(root+"var",0755) - except (OSError,IOError): - pass - try: - os.mkdir(root+"var/lib",0755) - except (OSError,IOError): - pass - try: - os.mkdir(root+"var/lib/portage",02750) - except SystemExit, e: - raise - except: - writemsg("portage: couldn't create /var/lib/portage; exiting.\n") - sys.exit(1) - - -##################################### -# Deprecation Checks - -os.umask(022) -profiledir=None -if "PORTAGE_CALLER" in os.environ and os.environ["PORTAGE_CALLER"] == "emerge" and os.path.isdir(PROFILE_PATH): - profiledir = PROFILE_PATH - if os.access(DEPRECATED_PROFILE_FILE, os.R_OK): - deprecatedfile = open(DEPRECATED_PROFILE_FILE, "r") - dcontent = deprecatedfile.readlines() - deprecatedfile.close() - newprofile = dcontent[0] - writemsg(red("\n!!! Your current profile is deprecated and not supported anymore.\n")) - writemsg(red("!!! Please upgrade to the following profile if possible:\n")) - writemsg(8*" "+green(newprofile)+"\n") - if len(dcontent) > 1: - writemsg("To upgrade do the following steps:\n") - for myline in dcontent[1:]: - writemsg(myline) - writemsg("\n\n") - -if os.path.exists(USER_VIRTUALS_FILE): - writemsg(red("\n!!! /etc/portage/virtuals is deprecated in favor of\n")) - writemsg(red("!!! /etc/portage/profile/virtuals. Please move it to\n")) - writemsg(red("!!! this new location.\n\n")) - -# -##################################### - -db={} - -# ============================================================================= -# ============================================================================= -# ----------------------------------------------------------------------------- -# We're going to lock the global config to prevent changes, but we need -# to ensure the global settings are right. -settings=config(config_profile_path=PROFILE_PATH,config_incrementals=portage_const.INCREMENTALS) - -# useful info -settings["PORTAGE_MASTER_PID"]=str(os.getpid()) -settings.backup_changes("PORTAGE_MASTER_PID") -# We are disabling user-specific bashrc files. -settings["BASH_ENV"] = INVALID_ENV_FILE -settings.backup_changes("BASH_ENV") - -# gets virtual package settings -def getvirtuals(myroot): - global settings - writemsg("--- DEPRECATED call to getvirtual\n") - return settings.getvirtuals(myroot) - -def do_vartree(mysettings): - global virts,virts_p - virts=mysettings.getvirtuals("/") - virts_p={} - - if virts: - myvkeys=virts.keys() - for x in myvkeys: - vkeysplit=x.split("/") - if not virts_p.has_key(vkeysplit[1]): - virts_p[vkeysplit[1]]=virts[x] - db["/"]={"virtuals":virts,"vartree":vartree("/",virts)} - if root!="/": - virts=mysettings.getvirtuals(root) - db[root]={"virtuals":virts,"vartree":vartree(root,virts)} - #We need to create the vartree first, then load our settings, and then set up our other trees - -usedefaults=settings.use_defs - -# XXX: This is a circular fix. -#do_vartree(settings) -#settings.loadVirtuals('/') -do_vartree(settings) -#settings.loadVirtuals('/') - -settings.reset() # XXX: Regenerate use after we get a vartree -- GLOBAL - - -# XXX: Might cause problems with root="/" assumptions -portdb=portdbapi(settings["PORTDIR"]) - -settings.lock() -# ----------------------------------------------------------------------------- -# ============================================================================= -# ============================================================================= - - -if 'selinux' in settings["USE"].split(" "): - try: - import selinux - selinux_enabled=1 - except OSError, e: - writemsg(red("!!! SELinux not loaded: ")+str(e)+"\n") - selinux_enabled=0 - except ImportError: - writemsg(red("!!! SELinux module not found.")+" Please verify that it was installed.\n") - selinux_enabled=0 -else: - selinux_enabled=0 - -cachedirs=[CACHE_PATH] -if root!="/": - cachedirs.append(root+CACHE_PATH) -if not os.environ.has_key("SANDBOX_ACTIVE"): - for cachedir in cachedirs: - if not os.path.exists(cachedir): - os.makedirs(cachedir,0755) - writemsg(">>> "+cachedir+" doesn't exist, creating it...\n") - if not os.path.exists(cachedir+"/dep"): - os.makedirs(cachedir+"/dep",2755) - writemsg(">>> "+cachedir+"/dep doesn't exist, creating it...\n") - try: - os.chown(cachedir,uid,portage_gid) - os.chmod(cachedir,0775) - except OSError: - pass - try: - mystat=os.lstat(cachedir+"/dep") - os.chown(cachedir+"/dep",uid,portage_gid) - os.chmod(cachedir+"/dep",02775) - if mystat[stat.ST_GID]!=portage_gid: - spawn("chown -R "+str(uid)+":"+str(portage_gid)+" "+cachedir+"/dep",settings,free=1) - spawn("chmod -R u+rw,g+rw "+cachedir+"/dep",settings,free=1) - except OSError: - pass - -def flushmtimedb(record): - if mtimedb: - if record in mtimedb.keys(): - del mtimedb[record] - #print "mtimedb["+record+"] is cleared." - else: - writemsg("Invalid or unset record '"+record+"' in mtimedb.\n") - -#grab mtimes for eclasses and upgrades -mtimedb={} -mtimedbkeys=[ -"updates", "info", -"version", "starttime", -"resume", "ldpath" -] -mtimedbfile=root+"var/cache/edb/mtimedb" -try: - mypickle=cPickle.Unpickler(open(mtimedbfile)) - mypickle.find_global=None - mtimedb=mypickle.load() - if mtimedb.has_key("old"): - mtimedb["updates"]=mtimedb["old"] - del mtimedb["old"] - if mtimedb.has_key("cur"): - del mtimedb["cur"] -except SystemExit, e: - raise -except: - #print "!!!",e - mtimedb={"updates":{},"version":"","starttime":0} - -for x in mtimedb.keys(): - if x not in mtimedbkeys: - writemsg("Deleting invalid mtimedb key: "+str(x)+"\n") - del mtimedb[x] - -#,"porttree":portagetree(root,virts),"bintree":binarytree(root,virts)} -features=settings["FEATURES"].split() - -do_upgrade_packagesmessage=0 -def do_upgrade(mykey): - global do_upgrade_packagesmessage - writemsg("\n\n") - writemsg(green("Performing Global Updates: ")+bold(mykey)+"\n") - writemsg("(Could take a couple of minutes if you have a lot of binary packages.)\n") - writemsg(" "+bold(".")+"='update pass' "+bold("*")+"='binary update' "+bold("@")+"='/var/db move'\n"+" "+bold("s")+"='/var/db SLOT move' "+bold("S")+"='binary SLOT move' "+bold("p")+"='update /etc/portage/package.*'\n") - processed=1 - #remove stale virtual entries (mappings for packages that no longer exist) - - update_files={} - file_contents={} - myxfiles = ["package.mask","package.unmask","package.keywords","package.use"] - myxfiles = myxfiles + prefix_array(myxfiles, "profile/") - for x in myxfiles: - try: - myfile = open("/etc/portage/"+x,"r") - file_contents[x] = myfile.readlines() - myfile.close() - except IOError: - if file_contents.has_key(x): - del file_contents[x] - continue - - worldlist=grabfile("/"+WORLD_FILE) - myupd=grabfile(mykey) - db["/"]["bintree"]=binarytree("/",settings["PKGDIR"],virts) - for myline in myupd: - mysplit=myline.split() - if not len(mysplit): - continue - if mysplit[0]!="move" and mysplit[0]!="slotmove": - writemsg("portage: Update type \""+mysplit[0]+"\" not recognized.\n") - processed=0 - continue - if mysplit[0]=="move" and len(mysplit)!=3: - writemsg("portage: Update command \""+myline+"\" invalid; skipping.\n") - processed=0 - continue - if mysplit[0]=="slotmove" and len(mysplit)!=4: - writemsg("portage: Update command \""+myline+"\" invalid; skipping.\n") - processed=0 - continue - sys.stdout.write(".") - sys.stdout.flush() - - if mysplit[0]=="move": - db["/"]["vartree"].dbapi.move_ent(mysplit) - db["/"]["bintree"].move_ent(mysplit) - #update world entries: - for x in range(0,len(worldlist)): - #update world entries, if any. - worldlist[x]=dep_transform(worldlist[x],mysplit[1],mysplit[2]) - - #update /etc/portage/packages.* - for x in file_contents: - for mypos in range(0,len(file_contents[x])): - line=file_contents[x][mypos] - if line[0]=="#" or string.strip(line)=="": - continue - key=dep_getkey(line.split()[0]) - if key==mysplit[1]: - file_contents[x][mypos]=string.replace(line,mysplit[1],mysplit[2]) - update_files[x]=1 - sys.stdout.write("p") - sys.stdout.flush() - - elif mysplit[0]=="slotmove": - db["/"]["vartree"].dbapi.move_slot_ent(mysplit) - db["/"]["bintree"].move_slot_ent(mysplit,settings["PORTAGE_TMPDIR"]+"/tbz2") - - for x in update_files: - mydblink = dblink('','','/',settings) - if mydblink.isprotected("/etc/portage/"+x): - updating_file=new_protect_filename("/etc/portage/"+x)[0] - else: - updating_file="/etc/portage/"+x - try: - myfile=open(updating_file,"w") - myfile.writelines(file_contents[x]) - myfile.close() - except IOError: - continue - - # We gotta do the brute force updates for these now. - if (settings["PORTAGE_CALLER"] in ["fixpackages"]) or \ - ("fixpackages" in features): - db["/"]["bintree"].update_ents(myupd,settings["PORTAGE_TMPDIR"]+"/tbz2") - else: - do_upgrade_packagesmessage = 1 - - if processed: - #update our internal mtime since we processed all our directives. - mtimedb["updates"][mykey]=os.stat(mykey)[stat.ST_MTIME] - myworld=open("/"+WORLD_FILE,"w") - for x in worldlist: - myworld.write(x+"\n") - myworld.close() - print "" - -def portageexit(): - global uid,portage_gid,portdb,db - if secpass and not os.environ.has_key("SANDBOX_ACTIVE"): - # wait child process death - try: - while True: - os.wait() - except OSError: - #writemsg(">>> All child process are now dead.") - pass - - close_portdbapi_caches() - - if mtimedb: - # Store mtimedb - mymfn=mtimedbfile - try: - mtimedb["version"]=VERSION - cPickle.dump(mtimedb, open(mymfn,"w"), -1) - except SystemExit, e: - raise - except Exception, e: - pass - - try: - os.chown(mymfn,uid,portage_gid) - os.chmod(mymfn,0664) - except SystemExit, e: - raise - except Exception, e: - pass - -atexit.register(portageexit) - -if (secpass==2) and (not os.environ.has_key("SANDBOX_ACTIVE")): - if settings["PORTAGE_CALLER"] in ["emerge","fixpackages"]: - #only do this if we're root and not running repoman/ebuild digest - updpath=os.path.normpath(settings["PORTDIR"]+"///profiles/updates") - didupdate=0 - if not mtimedb.has_key("updates"): - mtimedb["updates"]={} - try: - mylist=listdir(updpath,EmptyOnError=1) - # resort the list - mylist=[myfile[3:]+"-"+myfile[:2] for myfile in mylist] - mylist.sort() - mylist=[myfile[5:]+"-"+myfile[:4] for myfile in mylist] - for myfile in mylist: - mykey=updpath+"/"+myfile - if not os.path.isfile(mykey): - continue - if (not mtimedb["updates"].has_key(mykey)) or \ - (mtimedb["updates"][mykey] != os.stat(mykey)[stat.ST_MTIME]) or \ - (settings["PORTAGE_CALLER"] == "fixpackages"): - didupdate=1 - do_upgrade(mykey) - portageexit() # This lets us save state for C-c. - except OSError: - #directory doesn't exist - pass - if didupdate: - #make sure our internal databases are consistent; recreate our virts and vartree - do_vartree(settings) - if do_upgrade_packagesmessage and \ - listdir(settings["PKGDIR"]+"/All/",EmptyOnError=1): - writemsg("\n\n\n ** Skipping packages. Run 'fixpackages' or set it in FEATURES to fix the") - writemsg("\n tbz2's in the packages directory. "+bold("Note: This can take a very long time.")) - writemsg("\n") - - - - - -#continue setting up other trees -db["/"]["porttree"]=portagetree("/",virts) -db["/"]["bintree"]=binarytree("/",settings["PKGDIR"],virts) -if root!="/": - db[root]["porttree"]=portagetree(root,virts) - db[root]["bintree"]=binarytree(root,settings["PKGDIR"],virts) -thirdpartymirrors=grabdict(settings["PORTDIR"]+"/profiles/thirdpartymirrors") - -if not os.path.exists(settings["PORTAGE_TMPDIR"]): - writemsg("portage: the directory specified in your PORTAGE_TMPDIR variable, \""+settings["PORTAGE_TMPDIR"]+",\"\n") - writemsg("does not exist. Please create this directory or correct your PORTAGE_TMPDIR setting.\n") - sys.exit(1) -if not os.path.isdir(settings["PORTAGE_TMPDIR"]): - writemsg("portage: the directory specified in your PORTAGE_TMPDIR variable, \""+settings["PORTAGE_TMPDIR"]+",\"\n") - writemsg("is not a directory. Please correct your PORTAGE_TMPDIR setting.\n") - sys.exit(1) - -# COMPATABILITY -- This shouldn't be used. -pkglines = settings.packages - -groups=settings["ACCEPT_KEYWORDS"].split() -archlist=[] -for myarch in grabfile(settings["PORTDIR"]+"/profiles/arch.list"): - archlist += [myarch,"~"+myarch] -for group in groups: - if not archlist: - writemsg("--- 'profiles/arch.list' is empty or not available. Empty portage tree?\n") - break - elif (group not in archlist) and group[0]!='-': - writemsg("\n"+red("!!! INVALID ACCEPT_KEYWORDS: ")+str(group)+"\n") - -# Clear the cache -dircache={} - -if not os.path.islink(PROFILE_PATH) and os.path.exists(settings["PORTDIR"]+"/profiles"): - writemsg(red("\a\n\n!!! "+PROFILE_PATH+" is not a symlink and will probably prevent most merges.\n")) - writemsg(red("!!! It should point into a profile within %s/profiles/\n" % settings["PORTDIR"])) - writemsg(red("!!! (You can safely ignore this message when syncing. It's harmless.)\n\n\n")) - time.sleep(3) - -# ============================================================================ -# ============================================================================ - |