+In addition to the the long list of regular portage contributors, these folks have put their hard work into this.
+
+Michael Haubenwallner <michael.haubenwallner at salomon.at>
+Brian Harring <ferringb at gmail.com>
+Kito Dietrich <kito at gentoo.org>
+Fabian Groffen <grobian at gentoo.org>
+Emanuele Giaquinta <exg at gentoo.org>
+
echo "--localstatedir=${mylocalstatedir}"
return 0
}
-
+
+with_tmpdir() {
+ local mytmpdir
+ if [ -z "${1}" ]; then
+ if [ ! -z "${EPREFIX}" ]; then
+ mytmpdir="${EPREFIX}/tmp"
+ else
+ mytmpdir="/tmp"
+ fi
+ else
+ if [ ! -z "${EPREFIX}" ]; then
+ mytmpdir="${EPREFIX}${1}"
+ else
+ mytmpdir="${1}"
+ fi
+ fi
+ echo "--with-tmpdir=${mytmpdir}"
+ return 0
+}
+
use_with() {
if [ -z "$1" ]; then
echo "!!! use_with() called without a parameter." >&2
;;
esac
done
+ chmod -Rf a+rX,u+w,g-w,o-w .
}
strip_duplicate_slashes () {
print "emerge: wheel group use is being deprecated. Please update group and passwd to"
print " include the portage user as noted above, and then use group portage."
+if "--debug" in myopts:
+ print "myaction", myaction
+ print "myopts", myopts
+
# check if root user is the current user for the actions where emerge needs this
if portage.secpass < 2:
# We've already allowed "--version" and "--help" above.
if "--pretend" not in myopts and \
myaction not in ("search","info"):
- if "--debug" in myopts:
- print "myaction",myaction
- print "myopts",myopts
- print "emerge: root access required."
- sys.exit(1)
+ if portage.secpass >= 1:
+ if "--fetchonly" not in myopts and \
+ "--fetch-all-uri" not in myopts:
+ print "emerge: root access required."
+ sys.exit(1)
+ else:
+ print "emerge: root access required."
+ sys.exit(1)
if not "--pretend" in myopts:
emergelog("Started emerge on: "+time.strftime("%b %d, %Y %H:%M:%S", time.localtime()))
if portage.settings["RSYNC_TIMEOUT"] != "":
portage.writemsg("WARNING: usage of RSYNC_TIMEOUT is deprecated, " + \
- "use PORTAGE_RSYNC_OPTS instead\n")
+ "use PORTAGE_RSYNC_EXTRA_OPTS instead\n")
try:
mytimeout = int(portage.settings["RSYNC_TIMEOUT"])
rsync_opts.append("--timeout=%d" % mytimeout)
del myfiles[x]
mydone=[]
if repolevel==3: # In a package dir
- repoman_settings["O"]="./"
+ repoman_settings["O"]=os.getcwd()
portage.digestgen([],repoman_settings,manifestonly=1)
elif repolevel==2: # In a category dir
for x in myfiles:
if xs[0] in mydone:
continue
mydone.append(xs[0])
- repoman_settings["O"]="./"+xs[0]
+ repoman_settings["O"]=os.path.join(os.getcwd(), xs[0])
portage.digestgen([],repoman_settings,manifestonly=1)
elif repolevel==1: # repo-cvsroot
print green("RepoMan sez:"), "\"You're rather crazy... doing the entire repository.\"\n"
if string.join(xs[:2],"/") in mydone:
continue
mydone.append(string.join(xs[:2],"/"))
- repoman_settings["O"]="./"+string.join(xs[:2],"/")
+ repoman_settings["O"]=os.path.join(os.getcwd(), x[0], x[1])
portage.digestgen([],repoman_settings,manifestonly=1)
else:
print red("I'm confused... I don't know where I am!")
# PORTAGE_ELOG_SYSTEM: selects the module(s) to process the log messages. Modules
# included in portage are (empty means logging is disabled):
-# save (saves one log per package in $PORTAGE_TMPDIR/elogs)
+# save (saves one log per package in $PORT_LOGDIR/elog,
+# /var/log/portage/elog if $PORT_LOGDIR is unset)
# custom (passes all messages to $PORTAGE_LOG_COMMAND)
# syslog (sends all messages to syslog)
# mail (send all messages to the mailserver defined
#PORTAGE_ELOG_MAILURI="root@localhost localhost" (this is also the default setting)
#PORTAGE_ELOG_MAILURI="user@some.domain mail.some.domain" (sends mails to user@some.domain using the mailserver mail.some.domain)
#PORTAGE_ELOG_MAILURI="user@some.domain user:secret@mail.some.domain:100465" (this is left uncommented as a reader excercise ;)
+
+# PORTAGE_ELOG_MAILFROM: you can set the from-address of logmails with this variable,
+# if unset mails are sent by "portage" (this default may fail
+# in some environments).
+#PORTAGE_ELOG_MAILFROM="portage@some.domain"
+
+# PORTAGE_ELOG_MAILSUBJECT: template string to be used as subject for logmails. The following
+# variables are exanded:
+# ${PACKAGE} - see description of PORTAGE_ELOG_COMMAND
+# ${HOST} - FQDN of the host portage is running on
+#PORTAGE_ELOG_MAILSUBJECT="package ${PACKAGE} merged on ${HOST} with notice"
# Mode bits for ${WORKDIR} (see ebuild.5).
PORTAGE_WORKDIR_MODE="0700"
+# Some defaults for elog
+PORTAGE_ELOG_CLASSES="log warn error"
+
+PORTAGE_ELOG_MAILURI="@rootuser@"
+PORTAGE_ELOG_MAILSUBJECT="[portage] ebuild log for \${PACKAGE} on \${HOST}"
+PORTAGE_ELOG_MAILFROM="portage"
# *****************************
# ** DO NOT EDIT THIS FILE **
# passwd: password for smtp auth (defaults to none)
# mailserver: smtp server that should be used to deliver the mail (defaults to localhost)
# port: port to use on the given smtp server (defaults to 25, values > 100000 indicate that starttls should be used on (port-100000))
- if "PORTAGE_ELOG_MAILURI" in mysettings.keys():
- if " " in mysettings["PORTAGE_ELOG_MAILURI"]:
- myrecipient, mymailuri = mysettings["PORTAGE_ELOG_MAILURI"].split()
- if "@" in mymailuri:
- myauthdata, myconndata = mymailuri.rsplit("@", 1)
- try:
- mymailuser,mymailpasswd = myauthdata.split(":")
- except ValueError:
- print "!!! invalid SMTP AUTH configuration, trying unauthenticated ..."
- else:
- myconndata = mymailuri
- if ":" in myconndata:
- mymailhost,mymailport = myconndata.split(":")
- else:
- mymailhost = myconndata
+ if " " in mysettings["PORTAGE_ELOG_MAILURI"]:
+ myrecipient, mymailuri = mysettings["PORTAGE_ELOG_MAILURI"].split()
+ if "@" in mymailuri:
+ myauthdata, myconndata = mymailuri.rsplit("@", 1)
+ try:
+ mymailuser,mymailpasswd = myauthdata.split(":")
+ except ValueError:
+ print "!!! invalid SMTP AUTH configuration, trying unauthenticated ..."
else:
- myrecipient = mysettings["PORTAGE_ELOG_MAILURI"]
+ myconndata = mymailuri
+ if ":" in myconndata:
+ mymailhost,mymailport = myconndata.split(":")
+ else:
+ mymailhost = myconndata
+ else:
+ myrecipient = mysettings["PORTAGE_ELOG_MAILURI"]
try:
+ myfrom = mysettings["PORTAGE_ELOG_MAILFROM"]
+
mymessage = email.Message.Message()
- mymessage.set_unixfrom("portage")
+ mymessage.set_unixfrom(myfrom)
mymessage.set_payload(fulltext)
mymessage["To"] = myrecipient
- mymessage["Subject"] = "[portage] Ebuild log for %s" % cpv
+
+ mysubject = mysettings["PORTAGE_ELOG_MAILSUBJECT"]
+ mysubject = mysubject.replace("${PACKAGE}", cpv)
+ mysubject = mysubject.replace("${HOST}", socket.getfqdn())
+
+ mymessage["Subject"] = mysubject
if int(mymailport) > 100000:
myconn = smtplib.SMTP(mymailhost, int(mymailport) - 100000)
myconn = smtplib.SMTP(mymailhost, mymailport)
if mymailuser != "" and mymailpasswd != "":
myconn.login(mymailuser, mymailpasswd)
- myconn.sendmail("portage", myrecipient, mymessage.as_string())
+ myconn.sendmail(myfrom, myrecipient, mymessage.as_string())
myconn.quit()
except smtplib.SMTPException, e:
raise portage_exception.PortageException("!!! An error occured while trying to send logmail:\n"+str(e))
except socket.error, e:
- raise portage_exception.PortageException("!!! A network error occured while trying to send logmail:\n"+str(e)+"\nSure you configured PORTAGE_LOG_MAILURI correctly?")
+ raise portage_exception.PortageException("!!! A network error occured while trying to send logmail:\n"+str(e)+"\nSure you configured PORTAGE_ELOG_MAILURI correctly?")
return
def process(mysettings, cpv, logentries, fulltext):
cpv_path = cpv.replace("/", ":")
- elogdir = mysettings["PORTAGE_TMPDIR"]+"/elogs"
+ if mysettings["PORT_LOGDIR"] != "":
+ elogdir = os.path.join(mysettings["PORT_LOGDIR"], "elog")
+ else:
+ elogdir = os.path.join(os.sep, "var", "log", "portage", "elog")
if not os.path.exists(elogdir):
os.makedirs(elogdir)
os.chown(elogdir, portage_uid, portage_gid)
def resetColor():
return codes["reset"]
-def ctext(color,text):
- return codes[ctext]+text+codes["reset"]
-
-def bold(text):
- return codes["bold"]+text+codes["reset"]
-def white(text):
- return bold(text)
-
-def teal(text):
- return codes["teal"]+text+codes["reset"]
-def turquoise(text):
- return codes["turquoise"]+text+codes["reset"]
-def darkteal(text):
- return turquoise(text)
-
-def fuscia(text): # Don't use this one. It's spelled wrong!
- return codes["fuchsia"]+text+codes["reset"]
-def fuchsia(text):
- return codes["fuchsia"]+text+codes["reset"]
-def purple(text):
- return codes["purple"]+text+codes["reset"]
-
-def blue(text):
- return codes["blue"]+text+codes["reset"]
-def darkblue(text):
- return codes["darkblue"]+text+codes["reset"]
-
-def green(text):
- return codes["green"]+text+codes["reset"]
-def darkgreen(text):
- return codes["darkgreen"]+text+codes["reset"]
-
-def yellow(text):
- return codes["yellow"]+text+codes["reset"]
-def brown(text):
- return codes["brown"]+text+codes["reset"]
-def darkyellow(text):
- return brown(text)
-
-def red(text):
- return codes["red"]+text+codes["reset"]
-def darkred(text):
- return codes["darkred"]+text+codes["reset"]
-
+def colorize(color_key, text):
+ return codes[color_key] + text + codes["reset"]
+
+codes["darkteal"] = codes["turquoise"]
+codes["darkyellow"] = codes["brown"]
+codes["fuscia"] = codes["fuchsia"]
+codes["white"] = codes["bold"]
+
+compat_functions_colors = ["bold","white","teal","turquoise","darkteal",
+ "fuscia","fuchsia","purple","blue","darkblue","green","darkgreen","yellow",
+ "brown","darkyellow","red","darkred"]
+
+def create_color_func(color_key):
+ def derived_func(*args):
+ newargs = list(args)
+ newargs.insert(0, color_key)
+ return colorize(*newargs)
+ return derived_func
+
+for c in compat_functions_colors:
+ setattr(sys.modules[__name__], c, create_color_func(c))
if stat.S_ISDIR(pathstat[stat.ST_MODE]):
mtime = pathstat[stat.ST_MTIME]
else:
- raise portage_exception.PortageException
+ raise portage_exception.DirectoryNotFound(mypath)
except (IOError,OSError,portage_exception.PortageException):
if EmptyOnError:
return [], []
writemsg("File Not Found: '%s'\n" % str(e))
return 1
- if "ccache" in features:
- ccache_enabled = True
- if "CCACHE_DIR" not in mysettings or "" == mysettings["CCACHE_DIR"]:
- mysettings["CCACHE_DIR"] = os.path.join(mysettings["PORTAGE_TMPDIR"], "ccache")
-
- ccache_enabled = makedirs(mysettings["CCACHE_DIR"])
-
- if ccache_enabled:
- ccache_enabled = apply_recursive_permissions(
- mysettings["CCACHE_DIR"], gid=portage_gid,
- dirmode=02070, dirmask=02,
- filemode=060, filemask=02)
-
- if not ccache_enabled:
- writemsg("!!! Failed resetting perms on CCACHE_DIR='%s'\n" % mysettings["CCACHE_DIR"])
- features.remove("ccache")
- mysettings["FEATURES"] = " ".join(features)
-
- del ccache_enabled
-
- if "confcache" in features:
- confcache_enabled = True
- if "CONFCACHE_DIR" not in mysettings:
- mysettings["CONFCACHE_DIR"] = os.path.join(mysettings["PORTAGE_TMPDIR"], "confcache")
-
- confcache_enabled = makedirs(mysettings["CONFCACHE_DIR"])
-
- if confcache_enabled:
- confcache_enabled = apply_recursive_permissions(
- mysettings["CONFCACHE_DIR"], gid=portage_gid,
- dirmode=02070, dirmask=02,
- filemode=060, filemask=02)
-
- if not confcache_enabled:
- writemsg("!!! Failed resetting perms on confcachedir %s\n" % mysettings["CONFCACHE_DIR"])
- features.remove("confcache")
- mysettings["FEATURES"] = " ".join(features)
-
- del confcache_enabled
-
- if "distcc" in features:
-
- distcc_enabled = True
-
- if "DISTCC_DIR" not in mysettings or "" == mysettings["DISTCC_DIR"]:
- mysettings["DISTCC_DIR"] = os.path.join(mysettings["BUILD_PREFIX"], ".distcc")
- for x in ("", "lock", "state"):
- mydir = os.path.join(mysettings["DISTCC_DIR"], x)
- if not makedirs(mydir):
- distcc_enabled = False
- break
-
- if distcc_enabled:
- distcc_enabled = apply_recursive_permissions(
- mysettings["DISTCC_DIR"], gid=portage_gid,
- dirmode=02070, dirmask=02, filemode=060, filemask=02)
-
- if not distcc_enabled:
- writemsg("\n!!! File system problem when setting DISTCC_DIR directory permissions.\n")
- writemsg( "!!! DISTCC_DIR="+str(mysettings["DISTCC_DIR"]+"\n"))
- time.sleep(5)
- features.remove("distcc")
- mysettings["FEATURES"] = " ".join(features)
- mysettings["DISTCC_DIR"]=""
+ features_dirs = {
+ "ccache":{
+ "basedir_var":"CCACHE_DIR",
+ "default_dir":os.path.join(mysettings["PORTAGE_TMPDIR"], "ccache"),
+ "always_recurse":False},
+ "confcache":{
+ "basedir_var":"CONFCACHE_DIR",
+ "default_dir":os.path.join(mysettings["PORTAGE_TMPDIR"], "confcache"),
+ "always_recurse":True},
+ "distcc":{
+ "basedir_var":"DISTCC_DIR",
+ "default_dir":os.path.join(mysettings["BUILD_PREFIX"], ".distcc"),
+ "subdirs":("lock", "state"),
+ "always_recurse":True}
+ }
+ dirmode = 02070
+ filemode = 060
+ modemask = 02
+ for myfeature, kwargs in features_dirs.iteritems():
+ if myfeature in features:
+ basedir = mysettings[kwargs["basedir_var"]]
+ if basedir == "":
+ basedir = kwargs["default_dir"]
+ mysettings[kwargs["basedir_var"]] = basedir
+ try:
+ mydirs = [mysettings[kwargs["basedir_var"]]]
+ if "subdirs" in kwargs:
+ for subdir in kwargs["subdirs"]:
+ mydirs.append(os.path.join(basedir, subdir))
+ for mydir in mydirs:
+ if not makedirs(mydir):
+ raise portage_exception.DirectoryNotFound(
+ "Failed to create directory.")
+ try:
+ initial_stat = os.stat(mydir)
+ apply_secpass_permissions(mydir,
+ gid=portage_gid, mode=dirmode, mask=modemask, stat_cached=initial_stat)
+ result_stat = os.stat(mydir)
+ except OSError, oe:
+ if errno.EPERM == oe.errno:
+ writemsg("!!! %s\n" % oe)
+ raise portage_exception.OperationNotPermitted("stat('%s')" % mydir)
+ raise
+ # To avoid excessive recursive stat calls, we trigger
+ # recursion when the top level directory does not initially
+ # match our permission requirements.
+ if kwargs["always_recurse"] or \
+ result_stat.st_gid != initial_stat.st_gid or \
+ result_stat.st_mode & 07777 != initial_stat.st_mode & 07777:
+ if not kwargs["always_recurse"]:
+ writemsg("Adjusting permissions recursively: '%s'" % mydir)
+ def onerror(e):
+ raise # The feature is disabled if a single error
+ # occurs during permissions adjustment.
+ 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:
+ features.remove(myfeature)
+ mysettings["FEATURES"] = " ".join(features)
+ writemsg("!!! %s\n" % str(e))
+ writemsg("!!! Failed resetting perms on %s='%s'\n" % (kwargs["basedir_var"], basedir))
+ writemsg("!!! Disabled FEATURES='%s'\n" % myfeature)
+ time.sleep(5)
workdir_mode = 0700
try:
if self.pkg in otherversions:
otherversions.remove(self.pkg) # we already checked this package
+ myslot = self.settings["SLOT"]
for v in otherversions:
- # should we check for same SLOT here ?
- mypkglist.append(dblink(self.cat,v,destroot,self.settings))
+ # only allow versions with same slot to overwrite files
+ if myslot == db[self.myroot]["vartree"].dbapi.aux_get(self.mycpv, ["SLOT"])[0]:
+ mypkglist.append(dblink(self.cat,v,destroot,self.settings))
print green("*")+" checking "+str(len(myfilelist))+" files for package collisions"
for f in myfilelist:
-import os, sets
+import errno, os, sets
import portage, portage_exception, portage_versions, portage_const
from portage_checksum import *
from portage_exception import *
+from portage_util import write_atomic
class FileNotInManifestException(PortageException):
pass
def manifest2AuxfileFilter(filename):
filename = filename.strip(os.sep)
- return not (filename in ["CVS", ".svn"] or filename.startswith("digest-") or filename.startswith(".svn"))
+ return not (filename in [".svn", "CVS"] or filename.startswith("CVS"+os.sep) or filename.startswith(".svn"+os.sep) or filename.startswith("digest-"))
def manifest2MiscfileFilter(filename):
filename = filename.strip(os.sep)
mylines = fd.readlines()
fd.close()
mylines.extend(self._readDigests().split("\n"))
+ self._parseDigests(mylines, myhashdict=self.fhashdict)
+
+ def _parseDigests(self, mylines, myhashdict=None):
+ if myhashdict is None:
+ myhashdict = {}
for l in mylines:
myname = ""
mysplit = l.split()
myhashes = dict(zip(mysplit[3::2], mysplit[4::2]))
if len(myname) == 0:
continue
- if not self.fhashdict[mytype].has_key(myname):
- self.fhashdict[mytype][myname] = {}
- self.fhashdict[mytype][myname].update(myhashes)
- self.fhashdict[mytype][myname]["size"] = mysize
+ myhashdict.setdefault(mytype, {})
+ myhashdict[mytype].setdefault(myname, {})
+ myhashdict[mytype][myname].update(myhashes)
+ myhashdict[mytype][myname]["size"] = mysize
+ return myhashdict
- def _writeDigests(self):
+ def _writeDigests(self, force=False):
""" Create old style digest files for this Manifest instance """
cpvlist = [os.path.join(self.pkgdir.rstrip(os.sep).split(os.sep)[-2], x[:-7]) for x in portage.listdir(self.pkgdir) if x.endswith(".ebuild")]
rval = []
for cpv in cpvlist:
dname = os.path.join(self.pkgdir, "files", "digest-"+portage.catsplit(cpv)[1])
- mylines = []
distlist = self._getCpvDistfiles(cpv)
- for f in self.fhashdict["DIST"].keys():
- if f in distlist:
- for h in self.fhashdict["DIST"][f].keys():
- if h not in portage_const.MANIFEST1_HASH_FUNCTIONS:
- continue
- myline = " ".join([h, str(self.fhashdict["DIST"][f][h]), f, str(self.fhashdict["DIST"][f]["size"])])
- mylines.append(myline)
- fd = open(dname, "w")
- fd.write("\n".join(mylines))
- fd.write("\n")
- fd.close()
+ update_digest = True
+ if not force:
+ try:
+ f = open(dname, "r")
+ old_data = self._parseDigests(f.readlines())
+ f.close()
+ if len(old_data) == 1 and "DIST" in old_data:
+ new_data = self._getDigestData(distlist)
+ for myfile in new_data["DIST"]:
+ for hashname in new_data["DIST"][myfile].keys():
+ if hashname != "size" and \
+ hashname not in portage_const.MANIFEST1_HASH_FUNCTIONS:
+ del new_data["DIST"][myfile][hashname]
+ if new_data["DIST"] == old_data["DIST"]:
+ update_digest = False
+ except (IOError, OSError), e:
+ if errno.ENOENT == e.errno:
+ pass
+ else:
+ raise
+ if update_digest:
+ write_atomic(dname,
+ "\n".join(self._createDigestLines1(distlist, self.fhashdict))+"\n")
rval.append(dname)
return rval
+
+ def _getDigestData(self, distlist):
+ """create a hash dict for a specific list of files"""
+ myhashdict = {}
+ for myname in distlist:
+ for mytype in self.fhashdict:
+ if myname in self.fhashdict[mytype]:
+ myhashdict.setdefault(mytype, {})
+ myhashdict[mytype].setdefault(myname, {})
+ myhashdict[mytype][myname] = self.fhashdict[mytype][myname]
+ return myhashdict
+
+ def _createDigestLines1(self, distlist, myhashdict):
+ """ Create an old style digest file."""
+ mylines = []
+ myfiles = myhashdict["DIST"].keys()
+ myfiles.sort()
+ for f in myfiles:
+ if f in distlist:
+ myhashkeys = myhashdict["DIST"][f].keys()
+ myhashkeys.sort()
+ for h in myhashkeys:
+ if h not in portage_const.MANIFEST1_HASH_FUNCTIONS:
+ continue
+ myline = " ".join([h, str(myhashdict["DIST"][f][h]), f, str(myhashdict["DIST"][f]["size"])])
+ mylines.append(myline)
+ return mylines
def _addDigestsToManifest(self, digests, fd):
""" Add entries for old style digest files to Manifest file """
def _write(self, fd):
""" Actual Manifest file generator """
mylines = []
- for t in self.fhashdict.keys():
- for f in self.fhashdict[t].keys():
+ mytypes = self.fhashdict.keys()
+ mytypes.sort()
+ for t in mytypes:
+ myfiles = self.fhashdict[t].keys()
+ myfiles.sort()
+ for f in myfiles:
# compat hack for v1 manifests
if t == "AUX":
f2 = os.path.join("files", f)
f2 = f
myline = " ".join([t, f, str(self.fhashdict[t][f]["size"])])
myhashes = self.fhashdict[t][f]
- for h in myhashes.keys():
+ myhashkeys = myhashes.keys()
+ myhashkeys.sort()
+ for h in myhashkeys:
if h not in portage_const.MANIFEST2_HASH_FUNCTIONS:
continue
myline += " "+h+" "+str(myhashes[h])
mylines.append(myline)
if self.compat and t != "DIST":
- for h in myhashes.keys():
+ for h in myhashkeys:
if h not in portage_const.MANIFEST1_HASH_FUNCTIONS:
continue
mylines.append((" ".join([h, str(myhashes[h]), f2, str(myhashes["size"])])))