* New elog modules mail_summary and save_summary that act like the mail/save
modules except that they merge messages from multiple packages in a single
file/mail.
+* New QA loglevel and matching eqawarn function
+* `ebuild foo test` now always runs src_test if available
portage-2.1.1
------------
for arg in pargs:
try:
tmpsettings = portage.config(clone=portage.settings)
+ if arg == "test" and not "test" in tmpsettings.features:
+ print "Forcing test."
+ tmpsettings["EBUILD_FORCE_TEST"] = "1"
+ tmpsettings.backupenv["EBUILD_FORCE_TEST"] = "1"
if arg == "digest" and force:
discard_digests(ebuild, tmpsettings, portage.portdb)
a = portage.doebuild(ebuild, arg, portage.root, tmpsettings,
qa_source() {
local shopts=$(shopt) OLDIFS="$IFS"
- source "$@"
+ source "$@" || return 1
[[ $shopts != $(shopt) ]] &&
vecho "QA Notice: Global shell options were changed and not restored while sourcing $1"
[[ "$IFS" != "$OLDIFS" ]] &&
qa_call() {
local shopts=$(shopt) OLDIFS="$IFS"
- "$@"
+ "$@" || return 1
[[ $shopts != $(shopt) ]] &&
vecho "QA Notice: Global shell options were changed while calling $1"
[[ "$IFS" != "$OLDIFS" ]] &&
}
dyn_test() {
+ [ "${EBUILD_FORCE_TEST}" == "1" ] && rm -f "${PORTAGE_BUILDDIR}/.tested"
[ "$(type -t pre_src_test)" == "function" ] && qa_call pre_src_test
if [ "${PORTAGE_BUILDDIR}/.tested" -nt "${WORKDIR}" ]; then
vecho ">>> It appears that ${PN} has already been tested; skipping."
if [ -d "${S}" ]; then
cd "${S}"
fi
- if ! hasq test $FEATURES; then
+ if ! hasq test $FEATURES && [ "${EBUILD_FORCE_TEST}" != "1" ]; then
vecho ">>> Test phase [not enabled]: ${CATEGORY}/${PF}"
elif hasq test $RESTRICT; then
ewarn "Skipping make test/check due to ebuild restriction."
local messagetype
[ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1
case "${1}" in
- INFO|WARN|ERROR|LOG)
+ INFO|WARN|ERROR|LOG|QA)
messagetype="${1}"
shift
;;
return 0
}
+eqawarn() {
+ elog_base QA "$*"
+ echo -e " ${WARN}*${NORMAL} $*"
+ return 0
+}
+
elog() {
elog_base LOG "$*"
echo -e " ${GOOD}*${NORMAL} $*"
# logging related variables:
# PORTAGE_ELOG_CLASSES: selects messages to be logged, possible values are:
-# info, warn, error, log
+# info, warn, error, log, qa
# Warning: commenting this will disable elog
PORTAGE_ELOG_CLASSES="warn error log"
if not phase in logentries:
continue
for msgtype,msgcontent in logentries[phase]:
- pri = {"INFO": syslog.LOG_INFO, "WARN": syslog.LOG_WARNING, "ERROR": syslog.LOG_ERR, "LOG": syslog.LOG_NOTICE}
+ pri = {"INFO": syslog.LOG_INFO,
+ "WARN": syslog.LOG_WARNING,
+ "ERROR": syslog.LOG_ERR,
+ "LOG": syslog.LOG_NOTICE,
+ "QA": syslog.LOG_WARNING}
msgtext = "".join(msgcontent)
syslog.syslog(pri[msgtype], "%s: %s: %s" % (cpv, phase, msgtext))
syslog.closelog()
# exploit listdir() file order so we process log entries in chronological order
mylogfiles.reverse()
mylogentries = {}
+ my_elog_classes = set(mysettings.get("PORTAGE_ELOG_CLASSES", "").split())
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():
+ if msgtype.upper() not in my_elog_classes \
+ and msgtype.lower() not in my_elog_classes:
continue
if msgfunction not in portage_const.EBUILD_PHASES:
writemsg("!!! can't process invalid log file: %s\n" % f,
distfiles_map.setdefault(myfile, []).append(cpv)
mf = Manifest(mysettings["O"], mysettings["DISTDIR"],
fetchlist_dict=fetchlist_dict)
- missing_hashes = set(distfiles_map).difference(
- mf.fhashdict.get("DIST", {}))
+ required_hash_types = set(portage_const.MANIFEST1_HASH_FUNCTIONS)
+ required_hash_types.update(portage_const.MANIFEST2_HASH_FUNCTIONS)
+ required_hash_types.add("size")
+ dist_hashes = mf.fhashdict.get("DIST", {})
+ missing_hashes = set()
+ for myfile in distfiles_map:
+ myhashes = dist_hashes.get(myfile)
+ if not myhashes:
+ missing_hashes.add(myfile)
+ continue
+ if required_hash_types.difference(myhashes):
+ missing_hashes.add(myfile)
if missing_hashes:
missing_files = []
for myfile in missing_hashes:
os.chdir(srcroot)
mysymlinks = filter(os.path.islink, listdir(srcroot, recursive=1, filesonly=0, followSymlinks=False))
myfilelist.extend(mysymlinks)
+ mysymlinked_directories = [s + os.path.sep for s in mysymlinks]
+ del mysymlinks
+
stopmerge=False
starttime=time.time()
nocheck = False
# listdir isn't intelligent enough to exclude symlinked dirs,
# so we have to do it ourself
- for s in mysymlinks:
- # the length comparison makes sure that the symlink itself is checked
- if f[:len(s)] == s and len(f) > len(s):
+ for s in mysymlinked_directories:
+ if f.startswith(s):
nocheck = True
+ break
if nocheck:
continue
i=i+1
EAPI = "prefix"
-HASHING_BLOCKSIZE = 32768
+HASHING_BLOCKSIZE = 32768
MANIFEST1_HASH_FUNCTIONS = ["MD5","SHA256","RMD160"]
MANIFEST2_HASH_FUNCTIONS = ["SHA1","SHA256","RMD160"]