blob: e51f2ee157020ab8c246ae723bd626e3a127b090 [file] [log] [blame]
# 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.76 2005/05/29 12:40:08 jstubbs Exp $
VERSION="$Rev$"[6:-2] + "-svn"
# ===========================================================================
# START OF IMPORTS -- START OF IMPORTS -- START OF IMPORTS -- START OF IMPORT
# ===========================================================================
try:
import sys
except ImportError:
print "Failed to import sys! Something is _VERY_ wrong with python."
raise
try:
import os,string,types,signal,fcntl,errno
import time,traceback,copy
import re,pwd,grp,commands
import shlex,shutil
try:
import cPickle
except ImportError:
import pickle as cPickle
import stat
import commands
from time import sleep
from random import shuffle
import UserDict
if getattr(__builtins__, "set", None) is None:
from sets import Set as set
except ImportError, e:
sys.stderr.write("\n\n")
sys.stderr.write("!!! Failed to complete python imports. These 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 not 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");
raise
try:
# XXX: This should get renamed to bsd_chflags, I think.
import chflags
bsd_chflags = chflags
except ImportError:
bsd_chflags = None
try:
from cache.cache_errors import CacheError
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, 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, CONFIG_MEMORY_FILE,\
INCREMENTALS, EAPI, MISC_SH_BINARY
from portage_data import ostype, lchown, userland, secpass, uid, wheelgid, \
portage_uid, portage_gid
from portage_manifest import Manifest
import portage_util
from portage_util import atomic_ofstream, apply_secpass_permissions, apply_recursive_permissions, \
dump_traceback, getconfig, grabdict, grabdict_package, grabfile, grabfile_package, \
map_dictlist_vals, pickle_read, pickle_write, stack_dictlist, stack_dicts, stack_lists, \
unique_array, varexpand, writedict, writemsg, writemsg_stdout, write_atomic
import portage_exception
import portage_gpg
import portage_locks
import portage_exec
from portage_exec import atexit_register, run_exitfuncs
from portage_locks import unlockfile,unlockdir,lockfile,lockdir
import portage_checksum
from portage_checksum import perform_md5,perform_checksum,prelink_capable
import eclass_cache
from portage_localization import _
from portage_update import fixdbentries, update_dbentries, grab_updates
# Need these functions directly in portage namespace to not break every external tool in existence
from portage_versions import ververify,vercmp,catsplit,catpkgsplit,pkgsplit,pkgcmp
# endversion and endversion_keys are for backward compatibility only.
from portage_versions import endversion_keys
from portage_versions import suffix_value as endversion
except ImportError, 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")
raise
try:
import portage_selinux as selinux
except OSError, e:
writemsg("!!! SELinux not loaded: %s\n" % str(e), noiselevel=-1)
del e
except ImportError:
pass
# ===========================================================================
# 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
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 portage_exception.DirectoryNotFound(mypath)
except (IOError,OSError,portage_exception.PortageException):
if EmptyOnError:
return [], []
return None, None
# Python retuns mtime in seconds, so if it was changed in the last few seconds, it could be invalid
if mtime != cached_mtime or time.time() - mtime < 4:
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 (IOError, OSError):
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, dirsonly=False):
list, ftype = cacheddir(mypath, ignorecvs, ignorelist, EmptyOnError, followSymlinks)
if list is None:
list=[]
if ftype is None:
ftype=[]
if not (filesonly or dirsonly or 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','SCCS')):
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]]
elif dirsonly:
rlist = []
for x in range(0, len(ftype)):
if ftype[x] == 1:
rlist = rlist + [list[x]]
else:
rlist=list
return rlist
starttime=long(time.time())
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 portage_dep.paren_reduce
writemsg( output.red("!!! Tokenize is deprecated, please use portage_dep.paren_reduce.\n") )
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 is 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
def elog_process(cpv, mysettings):
mylogfiles = listdir(mysettings["T"]+"/logging/")
# shortcut for packages without any messages
if len(mylogfiles) == 0:
return
# exploit listdir() file order so we process log entries in chronological order
mylogfiles.reverse()
mylogentries = {}
for f in mylogfiles:
msgfunction, msgtype = f.split(".")
if not msgtype.upper() in mysettings["PORTAGE_ELOG_CLASSES"].split() \
and not msgtype.lower() in mysettings["PORTAGE_ELOG_CLASSES"].split():
continue
if msgfunction not in portage_const.EBUILD_PHASES:
print "!!! can't process invalid log file: %s" % f
continue
if not msgfunction in mylogentries:
mylogentries[msgfunction] = []
msgcontent = open(mysettings["T"]+"/logging/"+f, "r").readlines()
mylogentries[msgfunction].append((msgtype, msgcontent))
# in case the filters matched all messages
if len(mylogentries) == 0:
return
# generate a single string with all log messages
fulllog = ""
for phase in portage_const.EBUILD_PHASES:
if not phase in mylogentries:
continue
for msgtype,msgcontent in mylogentries[phase]:
fulllog += "%s: %s\n" % (msgtype, phase)
for line in msgcontent:
fulllog += line
fulllog += "\n"
# pass the processing to the individual modules
logsystems = mysettings["PORTAGE_ELOG_SYSTEM"].split()
for s in logsystems:
try:
# FIXME: ugly ad.hoc import code
# TODO: implement a common portage module loader
logmodule = __import__("elog_modules.mod_"+s)
m = getattr(logmodule, "mod_"+s)
m.process(mysettings, cpv, mylogentries, fulllog)
except (ImportError, AttributeError), e:
print "!!! Error while importing logging modules while loading \"mod_%s\":" % s
print e
except portage_exception.PortageException, e:
print e
#parse /etc/env.d and generate /etc/profile.env
def env_update(makelinks=1, target_root=None, prev_mtimes=None):
if target_root is None:
global root
target_root = root
if prev_mtimes is None:
global mtimedb
prev_mtimes = mtimedb["ldpath"]
envd_dir = os.path.join(target_root, "etc", "env.d")
portage_util.ensure_dirs(envd_dir, mode=0755)
fns = listdir(envd_dir, 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", "PYTHONPATH"
]
env={}
for x in fns:
# don't process backup files
if x[-1]=='~' or x[-4:]==".bak":
continue
file_path = os.path.join(envd_dir, x)
myconfig = getconfig(file_path)
if myconfig is None:
writemsg("!!! Parsing error in '%s'\n" % file_path, noiselevel=-1)
#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(myconfig[myspec].split(":"))
else:
specials[myspec].append(myconfig[myspec])
del myconfig[myspec]
# process all other variables
for myenv in myconfig.keys():
env[myenv]=myconfig[myenv]
ldsoconf_path = os.path.join(target_root, "etc", "ld.so.conf")
try:
myld = open(ldsoconf_path)
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])
except (IOError, OSError), e:
if e.errno != errno.ENOENT:
raise
oldld = None
ld_cache_update=False
newld=specials["LDPATH"]
if (oldld!=newld):
#ld.so.conf needs updating and ldconfig needs to be run
myfd = atomic_ofstream(ldsoconf_path)
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 = atomic_ofstream(
os.path.join(target_root, "etc", "prelink.conf"))
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()
for lib_dir in portage_util.unique_array(specials["LDPATH"]+['usr/lib','usr/lib64','usr/lib32','lib','lib64','lib32']):
x = os.path.join(target_root, lib_dir.lstrip(os.sep))
try:
newldpathtime = os.stat(x)[stat.ST_MTIME]
except OSError, oe:
if oe.errno == errno.ENOENT:
try:
del prev_mtimes[x]
except KeyError:
pass
# ignore this path because it doesn't exist
continue
raise
mtime_changed = False
if x in prev_mtimes:
if prev_mtimes[x] == newldpathtime:
pass
else:
prev_mtimes[x] = newldpathtime
mtime_changed = True
else:
prev_mtimes[x] = newldpathtime
mtime_changed = True
if mtime_changed:
ld_cache_update = True
# Only run ldconfig as needed
if (ld_cache_update or makelinks):
# ldconfig has very different behaviour between FreeBSD and Linux
if ostype=="Linux" or ostype.lower().endswith("gnu"):
# 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 %setc/ld.so.cache...\n" % target_root)
if makelinks:
commands.getstatusoutput("cd / ; /sbin/ldconfig -r '%s'" % target_root)
else:
commands.getstatusoutput("cd / ; /sbin/ldconfig -X -r '%s'" % target_root)
elif ostype in ("FreeBSD","DragonFly"):
writemsg(">>> Regenerating %svar/run/ld-elf.so.hints...\n" % target_root)
commands.getstatusoutput(
"cd / ; /sbin/ldconfig -elf -i -f '%svar/run/ld-elf.so.hints' '%setc/ld.so.conf'" % \
(target_root, target_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 = atomic_ofstream(os.path.join(target_root, "etc", "profile.env"))
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 = atomic_ofstream(os.path.join(target_root, "etc", "csh.env"))
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()
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,recursive=0):
pkgs=grabdict(myfilename, juststrings=juststrings, empty=1,recursive=recursive)
for x in pkgs.keys():
if not isvalidatom(x):
del(pkgs[x])
writemsg("--- Invalid atom in %s: %s\n" % (myfilename, x),
noiselevel=-1)
return pkgs
def grabfile_package(myfilename,compatlevel=0,recursive=0):
pkgs=grabfile(myfilename,compatlevel,recursive=recursive)
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]),
noiselevel=-1)
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, mysettings=None):
"returns set of USE variables auto-enabled due to packages being installed"
global autouse_val
if mysettings is None:
global settings
mysettings = settings
if autouse_val is not None:
return autouse_val
if mysettings.profile_path is None:
autouse_val = ""
return ""
myusevars=""
usedefaults = mysettings.use_defs
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, config_root="/", target_root="/"):
self.already_in_regenerate = 0
self.locked = 0
self.mycpv = None
self.puse = []
self.modifiedkeys = []
self.virtuals = {}
self.virts_p = {}
self.dirVirtuals = None
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)
config_root = self.backupenv["PORTAGE_CONFIGROOT"]
target_root = self.backupenv["ROOT"]
else:
# backupenv is for calculated incremental variables.
self.backupenv = os.environ.copy()
config_root = \
os.path.normpath(config_root).rstrip(os.path.sep) + os.path.sep
target_root = \
os.path.normpath(target_root).rstrip(os.path.sep) + os.path.sep
for k, v in (("PORTAGE_CONFIGROOT", config_root),
("ROOT", target_root)):
if not os.path.isdir(v):
writemsg("!!! Error: %s='%s' is not a directory. Please correct this.\n" % (k, v),
noiselevel=-1)
raise portage_exception.DirectoryNotFound(v)
self.depcachedir = DEPCACHE_PATH
if not config_profile_path:
config_profile_path = \
os.path.join(config_root, PROFILE_PATH.lstrip(os.path.sep))
if os.path.isdir(config_profile_path):
self.profile_path = config_profile_path
else:
self.profile_path = None
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(
os.path.join(config_root, MODULES_FILE_PATH.lstrip(os.path.sep)))
if self.modules["user"] is None:
self.modules["user"] = {}
self.modules["default"] = {
"portdbapi.metadbmodule": "cache.metadata.database",
"portdbapi.auxdbmodule": "cache.flat_hash.database",
}
self.usemask=[]
self.configlist=[]
# 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.
if self.profile_path is None:
self.profiles = []
else:
self.profiles = [os.path.realpath(self.profile_path)]
mypath = self.profiles[0]
while os.path.exists(os.path.join(mypath, "parent")):
parents_file = os.path.join(mypath, "parent")
parents = grabfile(parents_file)
if len(parents) != 1:
raise portage_exception.ParseError(
"Expected 1 parent and got %i: '%s'" % \
(len(parents), parents_file))
mypath = os.path.normpath(os.path.join(
mypath, parents[0]))
if os.path.exists(mypath):
self.profiles.insert(0, mypath)
else:
raise portage_exception.ParseError(
"Specified parent not found: '%s'" % parents_file)
if os.environ.has_key("PORTAGE_CALLER") and os.environ["PORTAGE_CALLER"] == "repoman":
pass
else:
custom_prof = os.path.join(
config_root, CUSTOM_PROFILE_PATH.lstrip(os.path.sep))
if os.path.exists(custom_prof):
self.user_profile_dir = custom_prof
self.profiles.append(custom_prof)
del custom_prof
self.packages_list = [grabfile_package(os.path.join(x, "packages")) for x in self.profiles]
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 = [grabfile(os.path.join(x, "use.mask")) for x in self.profiles]
self.usemask = stack_lists(usemask_lists, incremental=True)
del usemask_lists
use_defs_lists = [grabdict(os.path.join(x, "use.defaults")) for x in self.profiles]
self.use_defs = stack_dictlist(use_defs_lists, incremental=True)
del use_defs_lists
try:
mygcfg_dlists = [getconfig(os.path.join(x, "make.globals")) \
for x in self.profiles + [os.path.join(config_root, "etc")]]
self.mygcfg = stack_dicts(mygcfg_dlists, incrementals=portage_const.INCREMENTALS, ignore_none=1)
if self.mygcfg is None:
self.mygcfg = {}
except SystemExit, e:
raise
except Exception, e:
writemsg("!!! %s\n" % (e), noiselevel=-1)
writemsg("!!! Incorrect multiline literals can cause this. Do not use them.\n", noiselevel=-1)
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 = [getconfig(os.path.join(x, "make.defaults")) for x in self.profiles]
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 is None:
self.mygcfg = {}
except SystemExit, e:
raise
except Exception, e:
writemsg("!!! %s\n" % (e), noiselevel=-1)
writemsg("!!! 'rm -Rf /usr/portage/profiles; emerge sync' may fix this. If it does\n",
noiselevel=-1)
writemsg("!!! not then please report this to bugs.gentoo.org and, if possible, a dev\n",
noiselevel=-1)
writemsg("!!! on #gentoo (irc.freenode.org)\n",
noiselevel=-1)
sys.exit(1)
self.configlist.append(self.mygcfg)
self.configdict["defaults"]=self.configlist[-1]
try:
self.mygcfg = getconfig(
os.path.join(config_root, MAKE_CONF_FILE.lstrip(os.path.sep)),
allow_sourcing=True)
if self.mygcfg is None:
self.mygcfg = {}
except SystemExit, e:
raise
except Exception, e:
writemsg("!!! %s\n" % (e), noiselevel=-1)
writemsg("!!! Incorrect multiline literals can cause this. Do not use them.\n",
noiselevel=-1)
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]
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()
if os.environ.get("PORTAGE_CALLER","") == "repoman" and \
os.environ.get("PORTDIR_OVERLAY","") == "":
# repoman shouldn't use local settings.
locations = [self["PORTDIR"] + "/profiles"]
else:
abs_user_config = os.path.join(config_root,
USER_CONFIG_PATH.lstrip(os.path.sep))
locations = [os.path.join(self["PORTDIR"], "profiles"),
abs_user_config]
for ov in self["PORTDIR_OVERLAY"].split():
ov = os.path.normpath(ov)
if os.path.isdir(ov+"/profiles"):
locations.append(ov+"/profiles")
if os.environ.get("PORTAGE_CALLER","") == "repoman":
self.pusedict = {}
self.pkeywordsdict = {}
self.punmaskdict = {}
else:
pusedict = grabdict_package(
os.path.join(abs_user_config, "package.use"), recursive=1)
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(
os.path.join(abs_user_config, "package.keywords"),
recursive=1)
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(
os.path.join(abs_user_config, "package.unmask"),
recursive=1)
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 = [grabfile(os.path.join(x, "categories")) for x in locations]
self.categories = stack_lists(categories, incremental=1)
del categories
archlist = [grabfile(os.path.join(x, "arch.list")) for x in locations]
archlist = stack_lists(archlist, incremental=1)
self.configdict["conf"]["PORTAGE_ARCHLIST"] = " ".join(archlist)
#package.mask
pkgmasklines = [grabfile_package(os.path.join(x, "package.mask")) for x in self.profiles]
for l in locations:
pkgmasklines.append(grabfile_package(l+os.path.sep+"package.mask", recursive=1))
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 = [grabfile(os.path.join(x, "package.provided")) for x in self.profiles]
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",
noiselevel=-1)
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:defaults"
self.backupenv["USE_ORDER"] = useorder
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",
noiselevel=-1)
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"),
noiselevel=-1)
self["PORTDIR_OVERLAY"] = string.join(new_ov)
self.backup_changes("PORTDIR_OVERLAY")
if clone is None:
self.regenerate()
self.features = portage_util.unique_array(self["FEATURES"].split())
else:
# XXX
# The below self.regenerate() causes previous changes to FEATURES
# (and other incrementals) to be reverted. If this instance is a
# clone, we need to take the cloned FEATURES from backupenv and
# save them where the regenerate() call will not destroy them.
# Later, we use backup_changes() to restore the cloned FEATURES
# into the backupenv once again.
self.features = portage_util.unique_array(
self.backupenv["FEATURES"].split())
self.regenerate()
#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",
noiselevel=-1)
self.features.remove("gpg")
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"),
noiselevel=-1)
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"]) and len(self["CHOST"]):
self["CBUILD"] = self["CHOST"]
self.backup_changes("CBUILD")
if mycpv:
self.setcpv(mycpv)
self.backupenv["PORTAGE_BIN_PATH"] = PORTAGE_BIN_PATH
self.backupenv["PORTAGE_PYM_PATH"] = PORTAGE_PYM_PATH
self["PORTAGE_CONFIGROOT"] = config_root
self.backup_changes("PORTAGE_CONFIGROOT")
self["ROOT"] = target_root
self.backup_changes("ROOT")
self._init_dirs()
def _init_dirs(self):
"""Create tmp, var/tmp and var/lib/portage (relative to $ROOT)."""
dir_mode_map = {
"tmp" :(-1, 01777, 0),
"var/tmp" :(-1, 01777, 0),
"var/lib/portage" :(portage_gid, 02750, 02),
"var/cache/edb" :(portage_gid, 0755, 02)
}
for mypath, (gid, mode, modemask) in dir_mode_map.iteritems():
try:
mydir = os.path.join(self["ROOT"], mypath)
portage_util.ensure_dirs(mydir, gid=gid, mode=mode, mask=modemask)
except portage_exception.PortageException, e:
writemsg("!!! Directory initialization failed: '%s'\n" % mydir,
noiselevel=-1)
writemsg("!!! %s\n" % str(e),
noiselevel=-1)
def validate(self):
"""Validate miscellaneous settings and display warnings if necessary.
(This code was previously in the global scope of portage.py)"""
groups = self["ACCEPT_KEYWORDS"].split()
archlist = self.archlist()
if not archlist:
writemsg("--- 'profiles/arch.list' is empty or not available. Empty portage tree?\n")
else:
for group in groups:
if group not in archlist and group[0] != '-':
writemsg("!!! INVALID ACCEPT_KEYWORDS: %s\n" % str(group),
noiselevel=-1)
abs_profile_path = os.path.join(self["PORTAGE_CONFIGROOT"],
PROFILE_PATH.lstrip(os.path.sep))
if not os.path.islink(abs_profile_path) and \
os.path.exists(os.path.join(self["PORTDIR"], "profiles")):
writemsg("\a\n\n!!! %s is not a symlink and will probably prevent most merges.\n" % abs_profile_path,
noiselevel=-1)
writemsg("!!! It should point into a profile within %s/profiles/\n" % self["PORTDIR"])
writemsg("!!! (You can safely ignore this message when syncing. It's harmless.)\n\n\n")
abs_user_virtuals = os.path.join(self["PORTAGE_CONFIGROOT"],
USER_VIRTUALS_FILE.lstrip(os.path.sep))
if os.path.exists(abs_user_virtuals):
writemsg("\n!!! /etc/portage/virtuals is deprecated in favor of\n")
writemsg("!!! /etc/portage/profile/virtuals. Please move it to\n")
writemsg("!!! this new location.\n\n")
def loadVirtuals(self,root):
"""Not currently used by portage."""
writemsg("DEPRECATED: portage.config.loadVirtuals\n")
self.getvirtuals(root)
def load_best_module(self,property_string):
best_mod = best_from_dict(property_string,self.modules,self.module_priority)
try:
mod = load_mod(best_mod)
except:
dump_traceback(red("Error: Failed to import module '%s'") % best_mod, noiselevel=0)
sys.exit(1)
return 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",
noiselevel=-1)
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
# CATEGORY is important because it's used in doebuild
# to infer the cpv. If it's corrupted, it leads to
# strange errors later on, so we'll validate it and
# print a warning if necessary.
if filename == "CATEGORY":
matchobj = re.match("[-a-zA-Z0-9_.+]+", mydata)
if not matchobj or matchobj.start() != 0 or \
matchobj.end() != len(mydata):
writemsg("!!! CATEGORY file is corrupt: %s\n" % \
os.path.join(infodir, filename), noiselevel=-1)
except (OSError, IOError):
writemsg("!!! Unable to read file: %s\n" % infodir+"/"+filename,
noiselevel=-1)
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):
if len(self.virtuals) == 0:
self.getvirtuals()
# 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
if cp not in self.treeVirtuals[virt]:
self.treeVirtuals[virt].append(cp)
self.virtuals = self.__getvirtuals_compile()
def regenerate(self,useonly=0,use_cache=1):
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 = self.incrementals
# If self.features exists, it has already been stacked and may have
# been mutated, so don't stack it again or else any mutations will be
# reverted.
if "FEATURES" in myincrementals and hasattr(self, "features"):
myincrementals = set(myincrementals)
myincrementals.remove("FEATURES")
for mykey in myincrementals:
if mykey=="USE":
mydbs=self.uvlist
if "auto" in self["USE_ORDER"].split(":") and "settings" in globals():
self.configdict["auto"]["USE"] = autouse(
vartree(root=self["ROOT"], categories=self.categories),
use_cache=use_cache, mysettings=self)
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),
noiselevel=-1)
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
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 and mystr not in self.usemask:
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 get_virts_p(self, myroot):
if self.virts_p:
return self.virts_p
virts = self.getvirtuals(myroot)
if virts:
myvkeys = virts.keys()
for x in myvkeys:
vkeysplit = x.split("/")
if not self.virts_p.has_key(vkeysplit[1]):
self.virts_p[vkeysplit[1]] = virts[x]
return self.virts_p
def getvirtuals(self, myroot="/"):
#XXX: due to caching, myroot is ignored on all but the first call
if self.virtuals:
return self.virtuals
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 = [grabdict(os.path.join(x, "virtuals")) for x in myvirtdirs]
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())
self.virtuals = self.__getvirtuals_compile()
return self.virtuals
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 is None:
writemsg("!!! lookuplist is null.\n")
elif x.has_key(mykey):
match = x[mykey]
break
return match
def has_key(self,mykey):
for x in self.lookuplist:
if x.has_key(mykey):
return 1
return 0
def __contains__(self, mykey):
"""Called to implement membership test operators (in and not in)."""
return bool(self.has_key(mykey))
def setdefault(self, k, x=None):
if k in self:
return self[k]
else:
self[k] = x
return x
def get(self, k, x=None):
if k in self:
return self[k]
else:
return x
def keys(self):
return unique_array(flatten([x.keys() for x in self.lookuplist]))
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
def thirdpartymirrors(self):
if getattr(self, "_thirdpartymirrors", None) is None:
profileroots = [os.path.join(self["PORTDIR"], "profiles")]
for x in self["PORTDIR_OVERLAY"].split():
profileroots.insert(0, os.path.join(x, "profiles"))
thirdparty_lists = [grabdict(os.path.join(x, "thirdpartymirrors")) for x in profileroots]
self._thirdpartymirrors = stack_dictlist(thirdparty_lists, incremental=True)
return self._thirdpartymirrors
def archlist(self):
return flatten([[myarch, "~" + myarch] \
for myarch in self["PORTAGE_ARCHLIST"].split()])
def selinux_enabled(self):
if getattr(self, "_selinux_enabled", None) is None:
self._selinux_enabled = 0
if "selinux" in self["USE"].split():
if "selinux" in globals():
if selinux.is_selinux_enabled() == 1:
self._selinux_enabled = 1
else:
self._selinux_enabled = 0
else:
writemsg("!!! SELinux module not found. Please verify that it was installed.\n",
noiselevel=-1)
self._selinux_enabled = 0
if self._selinux_enabled == 0:
try:
del sys.modules["selinux"]
except KeyError:
pass
return self._selinux_enabled
# 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,sesandbox=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"]
features = mysettings.features
# 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 droppriv and not uid and portage_gid and portage_uid:
keywords.update({"uid":portage_uid,"gid":portage_gid,"groups":[portage_gid],"umask":002})
if not free:
free=((droppriv and "usersandbox" not in features) or \
(not droppriv and "sandbox" not in features and "usersandbox" not in features))
if free:
keywords["opt_name"] += " bash"
spawn_func = portage_exec.spawn_bash
else:
keywords["opt_name"] += " sandbox"
spawn_func = portage_exec.spawn_sandbox
if sesandbox:
con = selinux.getcontext()
con = string.replace(con, mysettings["PORTAGE_T"], mysettings["PORTAGE_SANDBOX_T"])
selinux.setexec(con)
retval = spawn_func(mystring, env=env, **keywords)
if sesandbox:
selinux.setexec(None)
return retval
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."
features = mysettings.features
# '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
thirdpartymirrors = mysettings.thirdpartymirrors()
check_config_instance(mysettings)
custommirrors = grabdict(os.path.join(mysettings["PORTAGE_CONFIGROOT"],
CUSTOM_MIRRORS_FILE.lstrip(os.path.sep)), recursive=1)
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"),
noiselevel=-1)
writemsg("!!! This can be done by adding -distlocks to FEATURES in /etc/make.conf",
noiselevel=-1)
# 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:
mymirrors += [x.rstrip("/") for x in mysettings["GENTOO_MIRRORS"].split() if x]
mydigests = Manifest(
mysettings["O"], mysettings["DISTDIR"]).getTypeDigests("DIST")
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
try:
apply_secpass_permissions(os.path.join(mysettings["DISTDIR"], myfile), gid=portage_gid,
mode=0664, mask=02)
except portage_exception.FileNotFound:
pass
except portage_exception.PortageException, e:
if not os.access(os.path.join(mysettings["DISTDIR"], myfile), os.R_OK):
writemsg("!!! Failed to adjust permissions: %s\n" % str(e), noiselevel=-1)
except (OSError,IOError),e:
# file does not exist
writemsg(_("!!! %(file)s not found in %(dir)s\n") % {"file":myfile, "dir":mysettings["DISTDIR"]},
noiselevel=-1)
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"]},
noiselevel=-1)
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"), noiselevel=-1)
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", noiselevel=-1)
writemsg(" %s\n" % (myuri), noiselevel=-1)
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),
noiselevel=-1)
missingSourceHost = True
if missingSourceHost:
return 0
del missingSourceHost
can_fetch=True
if not listonly:
dirmode = 02070
filemode = 060
modemask = 02
distdir_dirs = ["", "cvs-src"]
if "distlocks" in features:
distdir_dirs.append(".locks")
try:
for x in distdir_dirs:
mydir = os.path.join(mysettings["DISTDIR"], x)
if portage_util.ensure_dirs(mydir, gid=portage_gid, mode=dirmode, mask=modemask):
writemsg("Adjusting permissions recursively: '%s'\n" % mydir,
noiselevel=-1)
def onerror(e):
raise # bail out on the first error that occurs during recursion
if not apply_recursive_permissions(mydir,
gid=portage_gid, dirmode=dirmode, dirmask=modemask,
filemode=filemode, filemask=modemask, onerror=onerror):
raise portage_exception.OperationNotPermitted(
"Failed to apply recursive permissions for the portage group.")
except portage_exception.PortageException, e:
if not os.path.isdir(mysettings["DISTDIR"]):
writemsg("!!! %s\n" % str(e), noiselevel=-1)
writemsg("!!! Directory Not Found: DISTDIR='%s'\n" % mysettings["DISTDIR"], noiselevel=-1)
writemsg("!!! Fetching will fail!\n", noiselevel=-1)
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:
if use_locks and locks_in_subdir:
distlocks_subdir = os.path.join(mysettings["DISTDIR"], locks_in_subdir)
if not os.access(distlocks_subdir, os.W_OK):
writemsg("!!! No write access to write to %s. Aborting.\n" % distlocks_subdir,
noiselevel=-1)
return 0
del distlocks_subdir
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:
# Verify checksums at each fetch for fetchonly.
verified_ok,reason = portage_checksum.verify_all(mysettings["DISTDIR"]+"/"+myfile, mydigests[myfile])
if not verified_ok:
print reason
writemsg("!!! Previously fetched file: "+str(myfile)+"\n", noiselevel=-1)
writemsg("!!! Reason: "+reason[0]+"\n", noiselevel=-1)
writemsg("!!! Got: %s\n!!! Expected: %s\n" % \
(reason[0], reason[1]), noiselevel=-1)
writemsg("Refetching...\n\n", noiselevel=-1)
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:
# ENOENT is expected from the stat call at the beginning of
# this try block.
if e.errno != errno.ENOENT:
writemsg("An exception was caught(1)...\nFailing the download: %s.\n" % (str(e)),
noiselevel=-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,
noiselevel=-1)
else:
writemsg("!!! File %s isn't fully fetched, but unable to complete it\n" % myfile,
noiselevel=-1)
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" % \
os.path.join(mysettings["DISTDIR"], myfile),
noiselevel=-1)
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)
spawn_keywords = {}
if "userfetch" in mysettings.features and \
os.getuid() == 0 and portage_gid and portage_uid:
spawn_keywords.update({
"uid" : portage_uid,
"gid" : portage_gid,
"groups" : [portage_gid],
"umask" : 002})
try:
if mysettings.selinux_enabled():
con = selinux.getcontext()
con = string.replace(con, mysettings["PORTAGE_T"], mysettings["PORTAGE_FETCH_T"])
selinux.setexec(con)
myret = portage_exec.spawn_bash(myfetch,
env=mysettings.environ(), **spawn_keywords)
if mysettings.selinux_enabled():
selinux.setexec(None)
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),
noiselevel=-1)
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 checksum 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 checksums 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:
print reason
writemsg("!!! Fetched file: "+str(myfile)+" VERIFY FAILED!\n",
noiselevel=-1)
writemsg("!!! Reason: "+reason[0]+"\n",
noiselevel=-1)
writemsg("!!! Got: %s\n!!! Expected: %s\n" % \
(reason[0], reason[1]), noiselevel=-1)
writemsg("Removing corrupt distfile...\n", noiselevel=-1)
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:
# ENOENT is expected from the stat call at the
# beginning of this try block.
if e.errno != errno.ENOENT:
writemsg("An exception was caught(2)...\nFailing the download: %s.\n" % (str(e)),
noiselevel=-1)
fetched=0
else:
if not myret:
fetched=2
break
elif mydigests!=None:
writemsg("No digest file available and download failed.\n\n",
noiselevel=-1)
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",
noiselevel=-1)
return 0
return 1
def digestgen(myarchives, mysettings, overwrite=1, manifestonly=0, myportdb=None):
"""Generates a digest file if missing. Assumes all files are available.
DEPRECATED: this now only is a compability wrapper for
portage_manifest.Manifest()
NOTE: manifestonly and overwrite are useless with manifest2 and
are therefore ignored."""
if myportdb is None:
writemsg("Warning: myportdb not specified to digestgen\n")
global portdb
myportdb = portdb
mf = Manifest(mysettings["O"], mysettings["DISTDIR"],
fetchlist_dict=FetchlistDict(mysettings["O"], mysettings, myportdb))
writemsg_stdout(">>> Creating Manifest for %s\n" % mysettings["O"])
try:
mf.create(requiredDistfiles=myarchives, assumeDistHashesSometimes=True,
assumeDistHashesAlways=("assume-digests" in mysettings.features))
except portage_exception.FileNotFound, e:
writemsg("!!! File %s doesn't exist, can't update Manifest\n" % str(e),
noiselevel=-1)
return 0
mf.write(sign=False)
if "assume-digests" not in mysettings.features:
distlist = mf.fhashdict.get("DIST", {}).keys()
distlist.sort()
auto_assumed = []
for filename in distlist:
if not os.path.exists(os.path.join(mysettings["DISTDIR"], filename)):
auto_assumed.append(filename)
if auto_assumed:
mytree = os.path.realpath(
os.path.dirname(os.path.dirname(mysettings["O"])))
cp = os.path.sep.join(mysettings["O"].split(os.path.sep)[-2:])
pkgs = myportdb.cp_list(cp, mytree=mytree)
pkgs.sort()
writemsg_stdout(" digest.assumed" + \
output.colorize("WARN", str(len(auto_assumed)).rjust(18)) + "\n")
for pkg_key in pkgs:
fetchlist = myportdb.getfetchlist(pkg_key,
mysettings=mysettings, all=True, mytree=mytree)[1]
pv = pkg_key.split("/")[1]
for filename in auto_assumed:
if filename in fetchlist:
writemsg_stdout(" digest-%s::%s\n" % (pv, filename))
return 1
def digestParseFile(myfilename, mysettings=None):
"""(filename) -- Parses a given file for entries matching:
<checksumkey> <checksum_hex_string> <filename> <filesize>
Ignores lines that don't start with a valid checksum identifier
and returns a dict with the filenames as keys and {checksumkey:checksum}
as the values.
DEPRECATED: this function is now only a compability wrapper for
portage_manifest.Manifest()."""
mysplit = myfilename.split(os.sep)
if mysplit[-2] == "files" and mysplit[-1].startswith("digest-"):
pkgdir = os.sep + os.sep.join(mysplit[:-2]).strip(os.sep)
elif mysplit[-1] == "Manifest":
pkgdir = os.sep + os.sep.join(mysplit[:-1]).strip(os.sep)
if mysettings is None:
global settings
mysettings = config(clone=settings)
return Manifest(pkgdir, mysettings["DISTDIR"]).getDigests()
# 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 checksums.
DEPRECATED: this function isn't compatible with manifest2, use
portage_manifest.Manifest() instead for any digest related tasks.
"""
print "!!! use of deprecated function digestCheckFiles(), use portage_manifest instead"""
return 0
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(os.path.realpath(myfile))
print red("!!! Reason: ")+reason[0]
print red("!!! Got: ")+str(reason[1])
print red("!!! Expected: ")+str(reason[2])
print
return 0
else:
writemsg_stdout(">>> checksums "+note+" ;-) %s\n" % x)
return 1
def digestcheck(myfiles, mysettings, strict=0, justmanifest=0):
"""Verifies checksums. Assumes all files have been downloaded.
DEPRECATED: this is now only a compability wrapper for
portage_manifest.Manifest()."""
if not strict:
return 1
pkgdir = mysettings["O"]
manifest_path = os.path.join(pkgdir, "Manifest")
if not os.path.exists(manifest_path):
writemsg("!!! Manifest file not found: '%s'\n" % manifest_path,
noiselevel=-1)
if strict:
return 0
mf = Manifest(pkgdir, mysettings["DISTDIR"])
okaymsg = " ;-)\n"
try:
writemsg_stdout(">>> checking ebuild checksums")
mf.checkTypeHashes("EBUILD")
writemsg_stdout(okaymsg)
writemsg_stdout(">>> checking auxfile checksums")
mf.checkTypeHashes("AUX")
writemsg_stdout(okaymsg)
writemsg_stdout(">>> checking miscfile checksums")
mf.checkTypeHashes("MISC", ignoreMissingFiles=True)
writemsg_stdout(okaymsg)
for f in myfiles:
writemsg_stdout(">>> checking %s" % f)
mf.checkFileHashes(mf.findFile(f), f)
writemsg_stdout(okaymsg)
except KeyError, e:
writemsg("\n!!! Missing digest for %s\n" % str(e), noiselevel=-1)
return 0
except portage_exception.FileNotFound, e:
writemsg("\n!!! A file listed in the Manifest could not be found: %s\n" % str(e),
noiselevel=-1)
return 0
except portage_exception.DigestException, e:
writemsg("\n!!! Digest verification failed:\n", noiselevel=-1)
writemsg("!!! %s\n" % e.value[0], noiselevel=-1)
writemsg("!!! Reason: %s\n" % e.value[1], noiselevel=-1)
writemsg("!!! Got: %s\n" % e.value[2], noiselevel=-1)
writemsg("!!! Expected: %s\n" % e.value[3], noiselevel=-1)
return 0
return 1
# 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 mysettings.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
kwargs = actionmap[mydo]["args"]
mysettings["EBUILD_PHASE"] = mydo
phase_retval = spawn(actionmap[mydo]["cmd"] % mydo, mysettings, debug=debug, logfile=logfile, **kwargs)
del mysettings["EBUILD_PHASE"]
if phase_retval == os.EX_OK:
if mydo == "install":
mycommand = " ".join([MISC_SH_BINARY, "install_qa_check"])
qa_retval = spawn(mycommand, mysettings, debug=debug, logfile=logfile, **kwargs)