+++ /dev/null
-# 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)
-
-# ============================================================================
-# ============================================================================
-