#!/bin/bash # Copyright 1999-2010 Gentoo Foundation # Distributed under the terms of the GNU General Public License v2 # We need this next line for "die" and "assert". It expands # It _must_ preceed all the calls to die and assert. shopt -s expand_aliases alias save_IFS='[ "${IFS:-unset}" != "unset" ] && old_IFS="${IFS}"' alias restore_IFS='if [ "${old_IFS:-unset}" != "unset" ]; then IFS="${old_IFS}"; unset old_IFS; else unset IFS; fi' assert() { local x pipestatus=${PIPESTATUS[*]} for x in $pipestatus ; do [[ $x -eq 0 ]] || die "$@" done } shopt -s extdebug # dump_trace([number of funcs on stack to skip], # [whitespacing for filenames], # [whitespacing for line numbers]) dump_trace() { local funcname="" sourcefile="" lineno="" s="yes" n p declare -i strip=${1:-1} local filespacing=$2 linespacing=$3 # The qa_call() function and anything before it are portage internals # that the user will not be interested in. Therefore, the stack trace # should only show calls that come after qa_call(). (( n = ${#FUNCNAME[@]} - 1 )) (( p = ${#BASH_ARGV[@]} )) while (( n > 0 )) ; do [ "${FUNCNAME[${n}]}" == "qa_call" ] && break (( p -= ${BASH_ARGC[${n}]} )) (( n-- )) done if (( n == 0 )) ; then (( n = ${#FUNCNAME[@]} - 1 )) (( p = ${#BASH_ARGV[@]} )) fi eerror "Call stack:" while (( n > ${strip} )) ; do funcname=${FUNCNAME[${n} - 1]} sourcefile=$(basename "${BASH_SOURCE[${n}]}") lineno=${BASH_LINENO[${n} - 1]} # Display function arguments args= if [[ -n "${BASH_ARGV[@]}" ]]; then for (( j = 1 ; j <= ${BASH_ARGC[${n} - 1]} ; ++j )); do newarg=${BASH_ARGV[$(( p - j - 1 ))]} args="${args:+${args} }'${newarg}'" done (( p -= ${BASH_ARGC[${n} - 1]} )) fi eerror " $(printf "%${filespacing}s" "${sourcefile}"), line $(printf "%${linespacing}s" "${lineno}"): Called ${funcname}${args:+ ${args}}" (( n-- )) done } nonfatal() { if has "${EAPI:-0}" 0 1 2 3 3_pre2 ; then die "$FUNCNAME() not supported in this EAPI" fi if [[ $# -lt 1 ]]; then die "$FUNCNAME(): Missing argument" fi PORTAGE_NONFATAL=1 "$@" } die() { if [[ $PORTAGE_NONFATAL -eq 1 ]]; then echo -e " $WARN*$NORMAL ${FUNCNAME[1]}: WARNING: $@" >&2 return 1 fi set +e if [ -n "${QA_INTERCEPTORS}" ] ; then # die was called from inside inherit. We need to clean up # QA_INTERCEPTORS since sed is called below. unset -f ${QA_INTERCEPTORS} unset QA_INTERCEPTORS fi local n filespacing=0 linespacing=0 # setup spacing to make output easier to read (( n = ${#FUNCNAME[@]} - 1 )) while (( n > 0 )) ; do [ "${FUNCNAME[${n}]}" == "qa_call" ] && break (( n-- )) done (( n == 0 )) && (( n = ${#FUNCNAME[@]} - 1 )) while (( n > 0 )); do sourcefile=${BASH_SOURCE[${n}]} sourcefile=${sourcefile##*/} lineno=${BASH_LINENO[${n}]} ((filespacing < ${#sourcefile})) && filespacing=${#sourcefile} ((linespacing < ${#lineno})) && linespacing=${#lineno} (( n-- )) done eerror "ERROR: $CATEGORY/$PF failed:" eerror " ${*:-(no error message)}" eerror dump_trace 2 ${filespacing} ${linespacing} eerror " $(printf "%${filespacing}s" "${BASH_SOURCE[1]##*/}"), line $(printf "%${linespacing}s" "${BASH_LINENO[0]}"): Called die" eerror "The specific snippet of code:" # This scans the file that called die and prints out the logic that # ended in the call to die. This really only handles lines that end # with '|| die' and any preceding lines with line continuations (\). # This tends to be the most common usage though, so let's do it. # Due to the usage of appending to the hold space (even when empty), # we always end up with the first line being a blank (thus the 2nd sed). sed -n \ -e "# When we get to the line that failed, append it to the # hold space, move the hold space to the pattern space, # then print out the pattern space and quit immediately ${BASH_LINENO[0]}{H;g;p;q}" \ -e '# If this line ends with a line continuation, append it # to the hold space /\\$/H' \ -e '# If this line does not end with a line continuation, # erase the line and set the hold buffer to it (thus # erasing the hold buffer in the process) /[^\]$/{s:^.*$::;h}' \ "${BASH_SOURCE[1]}" \ | sed -e '1d' -e 's:^:RETAIN-LEADING-SPACE:' \ | while read -r n ; do eerror " ${n#RETAIN-LEADING-SPACE}" ; done eerror eerror "If you need support, post the output of 'emerge --info =$CATEGORY/$PF'," eerror "the complete build log and the output of 'emerge -pqv =$CATEGORY/$PF'." if [[ -n ${EBUILD_OVERLAY_ECLASSES} ]] ; then eerror "This ebuild used the following eclasses from overlays:" local x for x in ${EBUILD_OVERLAY_ECLASSES} ; do eerror " ${x}" done fi if [ "${EMERGE_FROM}" != "binary" ] && \ ! hasq ${EBUILD_PHASE} prerm postrm && \ [ "${EBUILD#${PORTDIR}/}" == "${EBUILD}" ] ; then local overlay=${EBUILD%/*} overlay=${overlay%/*} overlay=${overlay%/*} if [[ -n $PORTAGE_REPO_NAME ]] ; then eerror "This ebuild is from an overlay named" \ "'$PORTAGE_REPO_NAME': '${overlay}/'" else eerror "This ebuild is from an overlay: '${overlay}/'" fi elif [[ -n $PORTAGE_REPO_NAME && -f "$PORTDIR"/profiles/repo_name ]] ; then local portdir_repo_name=$(<"$PORTDIR"/profiles/repo_name) if [[ -n $portdir_repo_name && \ $portdir_repo_name != $PORTAGE_REPO_NAME ]] ; then eerror "This ebuild is from a repository" \ "named '$PORTAGE_REPO_NAME'" fi fi if [[ "${EBUILD_PHASE/depend}" == "${EBUILD_PHASE}" ]] ; then local x for x in $EBUILD_DEATH_HOOKS; do ${x} "$@" >&2 1>&2 done > "$PORTAGE_BUILDDIR/.die_hooks" fi [[ -n ${PORTAGE_LOG_FILE} ]] \ && eerror "The complete build log is located at '${PORTAGE_LOG_FILE}'." if [ -f "${T}/environment" ] ; then eerror "The ebuild environment file is located at '${T}/environment'." elif [ -d "${T}" ] ; then { set export } > "${T}/die.env" eerror "The ebuild environment file is located at '${T}/die.env'." fi eerror "S: '${S}'" [ -n "$EBUILD_EXIT_STATUS_FILE" ] && > "$EBUILD_EXIT_STATUS_FILE" # subshell die support [[ $BASHPID = $EBUILD_MASTER_PID ]] || kill -s SIGTERM $EBUILD_MASTER_PID exit 1 } # We need to implement diefunc() since environment.bz2 files contain # calls to it (due to alias expansion). diefunc() { die "${@}" } quiet_mode() { [[ ${PORTAGE_QUIET} -eq 1 ]] } vecho() { quiet_mode || echo "$@" } # Internal logging function, don't use this in ebuilds elog_base() { local messagetype [ -z "${1}" -o -z "${T}" -o ! -d "${T}/logging" ] && return 1 case "${1}" in INFO|WARN|ERROR|LOG|QA) messagetype="${1}" shift ;; *) vecho -e " ${BAD}*${NORMAL} Invalid use of internal function elog_base(), next message will not be logged" return 1 ;; esac echo -e "$@" | while read -r ; do echo "$messagetype $REPLY" >> \ "${T}/logging/${EBUILD_PHASE:-other}" done return 0 } eqawarn() { elog_base QA "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do vecho " $WARN*$NORMAL $REPLY" >&2 done LAST_E_CMD="eqawarn" return 0 } elog() { elog_base LOG "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $GOOD*$NORMAL $REPLY" done LAST_E_CMD="elog" return 0 } esyslog() { local pri= local tag= if [ -x /usr/bin/logger ] then pri="$1" tag="$2" shift 2 [ -z "$*" ] && return 0 /usr/bin/logger -p "${pri}" -t "${tag}" -- "$*" fi return 0 } einfo() { elog_base INFO "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $GOOD*$NORMAL $REPLY" done LAST_E_CMD="einfo" return 0 } einfon() { elog_base INFO "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -ne " ${GOOD}*${NORMAL} $*" LAST_E_CMD="einfon" return 0 } ewarn() { elog_base WARN "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $WARN*$NORMAL $RC_INDENTATION$REPLY" >&2 done LAST_E_CMD="ewarn" return 0 } eerror() { elog_base ERROR "$*" [[ ${RC_ENDCOL} != "yes" && ${LAST_E_CMD} == "ebegin" ]] && echo echo -e "$@" | while read -r ; do echo " $BAD*$NORMAL $RC_INDENTATION$REPLY" >&2 done LAST_E_CMD="eerror" return 0 } ebegin() { local msg="$*" dots spaces=${RC_DOT_PATTERN//?/ } if [[ -n ${RC_DOT_PATTERN} ]] ; then dots=$(printf "%$(( COLS - 3 - ${#RC_INDENTATION} - ${#msg} - 7 ))s" '') dots=${dots//${spaces}/${RC_DOT_PATTERN}} msg="${msg}${dots}" else msg="${msg} ..." fi einfon "${msg}" [[ ${RC_ENDCOL} == "yes" ]] && echo LAST_E_LEN=$(( 3 + ${#RC_INDENTATION} + ${#msg} )) LAST_E_CMD="ebegin" return 0 } _eend() { local retval=${1:-0} efunc=${2:-eerror} msg shift 2 if [[ ${retval} == "0" ]] ; then msg="${BRACKET}[ ${GOOD}ok${BRACKET} ]${NORMAL}" else if [[ -n $* ]] ; then ${efunc} "$*" fi msg="${BRACKET}[ ${BAD}!!${BRACKET} ]${NORMAL}" fi if [[ ${RC_ENDCOL} == "yes" ]] ; then echo -e "${ENDCOL} ${msg}" else [[ ${LAST_E_CMD} == ebegin ]] || LAST_E_LEN=0 printf "%$(( COLS - LAST_E_LEN - 7 ))s%b\n" '' "${msg}" fi return ${retval} } eend() { local retval=${1:-0} shift _eend ${retval} eerror "$*" LAST_E_CMD="eend" return ${retval} } KV_major() { [[ -z $1 ]] && return 1 local KV=$@ echo "${KV%%.*}" } KV_minor() { [[ -z $1 ]] && return 1 local KV=$@ KV=${KV#*.} echo "${KV%%.*}" } KV_micro() { [[ -z $1 ]] && return 1 local KV=$@ KV=${KV#*.*.} echo "${KV%%[^[:digit:]]*}" } KV_to_int() { [[ -z $1 ]] && return 1 local KV_MAJOR=$(KV_major "$1") local KV_MINOR=$(KV_minor "$1") local KV_MICRO=$(KV_micro "$1") local KV_int=$(( KV_MAJOR * 65536 + KV_MINOR * 256 + KV_MICRO )) # We make version 2.2.0 the minimum version we will handle as # a sanity check ... if its less, we fail ... if [[ ${KV_int} -ge 131584 ]] ; then echo "${KV_int}" return 0 fi return 1 } _RC_GET_KV_CACHE="" get_KV() { [[ -z ${_RC_GET_KV_CACHE} ]] \ && _RC_GET_KV_CACHE=$(uname -r) echo $(KV_to_int "${_RC_GET_KV_CACHE}") return $? } unset_colors() { COLS=80 ENDCOL= GOOD= WARN= BAD= NORMAL= HILITE= BRACKET= } set_colors() { COLS=${COLUMNS:-0} # bash's internal COLUMNS variable (( COLS == 0 )) && COLS=$(set -- $(stty size 2>/dev/null) ; echo $2) (( COLS > 0 )) || (( COLS = 80 )) # Now, ${ENDCOL} will move us to the end of the # column; irregardless of character width ENDCOL=$'\e[A\e['$(( COLS - 8 ))'C' if [ -n "${PORTAGE_COLORMAP}" ] ; then eval ${PORTAGE_COLORMAP} else GOOD=$'\e[32;01m' WARN=$'\e[33;01m' BAD=$'\e[31;01m' HILITE=$'\e[36;01m' BRACKET=$'\e[34;01m' fi NORMAL=$'\e[0m' } RC_ENDCOL="yes" RC_INDENTATION='' RC_DEFAULT_INDENT=2 RC_DOT_PATTERN='' case "${NOCOLOR:-false}" in yes|true) unset_colors ;; no|false) set_colors ;; esac if [[ -z ${USERLAND} ]] ; then case $(uname -s) in *BSD|DragonFly) export USERLAND="BSD" ;; *) export USERLAND="GNU" ;; esac fi if [[ -z ${XARGS} ]] ; then case ${USERLAND} in BSD) export XARGS="xargs" ;; *) export XARGS="xargs -r" ;; esac fi has() { hasq "$@" } hasv() { if hasq "$@" ; then echo "$1" return 0 fi return 1 } hasq() { [[ " ${*:2} " == *" $1 "* ]] } # @FUNCTION: save_ebuild_env # @DESCRIPTION: # echo the current environment to stdout, filtering out redundant info. # # --exclude-init-phases causes pkg_nofetch and src_* phase functions to # be excluded from the output. These function are not needed for installation # or removal of the packages, and can therefore be safely excluded. # save_ebuild_env() { ( if hasq --exclude-init-phases $* ; then unset S _E_DOCDESTTREE_ _E_EXEDESTTREE_ if [[ -n $PYTHONPATH ]] ; then export PYTHONPATH=${PYTHONPATH/${PORTAGE_PYM_PATH}:} [[ -z $PYTHONPATH ]] && unset PYTHONPATH fi fi # misc variables inherited from the calling environment unset COLORTERM DISPLAY EDITOR LESS LESSOPEN LOGNAME LS_COLORS PAGER \ TERM TERMCAP USER # other variables inherited from the calling environment unset ECHANGELOG_USER GPG_AGENT_INFO \ SSH_AGENT_PID SSH_AUTH_SOCK STY WINDOW XAUTHORITY # CCACHE and DISTCC config unset ${!CCACHE_*} ${!DISTCC_*} # There's no need to bloat environment.bz2 with internally defined # functions and variables, so filter them out if possible. for x in pkg_setup pkg_nofetch src_unpack src_prepare src_configure \ src_compile src_test src_install pkg_preinst pkg_postinst \ pkg_prerm pkg_postrm ; do unset -f default_$x _eapi{0,1,2,3,4}_$x done unset x unset -f assert dump_trace die diefunc \ quiet_mode vecho elog_base eqawarn elog \ esyslog einfo einfon ewarn eerror ebegin _eend eend KV_major \ KV_minor KV_micro KV_to_int get_KV unset_colors set_colors has \ has_phase_defined_up_to \ hasg hasgq hasv hasq qa_source qa_call \ addread addwrite adddeny addpredict _sb_append_var \ lchown lchgrp esyslog use usev useq has_version portageq \ best_version use_with use_enable register_die_hook \ keepdir unpack strip_duplicate_slashes econf einstall \ dyn_setup dyn_unpack dyn_clean into insinto exeinto docinto \ insopts diropts exeopts libopts \ abort_handler abort_prepare abort_configure abort_compile \ abort_test abort_install dyn_prepare dyn_configure \ dyn_compile dyn_test dyn_install \ dyn_preinst dyn_help debug-print debug-print-function \ debug-print-section inherit EXPORT_FUNCTIONS remove_path_entry \ save_ebuild_env filter_readonly_variables preprocess_ebuild_env \ source_all_bashrcs ebuild_main \ ebuild_phase ebuild_phase_with_hooks \ _ebuild_arg_to_phase _ebuild_phase_funcs default \ _pipestatus \ ${QA_INTERCEPTORS} # portage config variables and variables set directly by portage unset ACCEPT_LICENSE BAD BRACKET BUILD_PREFIX COLS \ DISTCC_DIR DISTDIR DOC_SYMLINKS_DIR \ EBUILD_EXIT_STATUS_FILE EBUILD_FORCE_TEST EBUILD_MASTER_PID \ ECLASSDIR ECLASS_DEPTH ENDCOL FAKEROOTKEY \ GOOD HILITE HOME \ LAST_E_CMD LAST_E_LEN LD_PRELOAD MISC_FUNCTIONS_ARGS MOPREFIX \ NOCOLOR NORMAL PKGDIR PKGUSE PKG_LOGDIR PKG_TMPDIR \ PORTAGE_ACTUAL_DISTDIR PORTAGE_ARCHLIST \ PORTAGE_BASHRC PM_EBUILD_HOOK_DIR PORTAGE_BASHRCS_SOURCED \ PORTAGE_BINPKG_TAR_OPTS PORTAGE_BINPKG_TMPFILE PORTAGE_BUILDDIR \ PORTAGE_COLORMAP PORTAGE_CONFIGROOT PORTAGE_DEBUG \ PORTAGE_DEPCACHEDIR PORTAGE_GID \ PORTAGE_INST_GID \ PORTAGE_INST_UID PORTAGE_LOG_FILE PORTAGE_MASTER_PID \ PORTAGE_NONFATAL PORTAGE_QUIET \ PORTAGE_REPO_NAME PORTAGE_RESTRICT PORTAGE_UPDATE_ENV \ PORTAGE_VERBOSE PORTAGE_WORKDIR_MODE PORTDIR \ PORTDIR_OVERLAY ${!PORTAGE_SANDBOX_*} PREROOTPATH \ PROFILE_PATHS PWORKDIR QA_INTERCEPTORS \ RC_DEFAULT_INDENT RC_DOT_PATTERN RC_ENDCOL \ RC_INDENTATION READONLY_EBUILD_METADATA READONLY_PORTAGE_VARS \ REPLACING_VERSIONS REPLACED_BY_VERSION \ ROOT ROOTPATH RPMDIR TEMP TMP TMPDIR USE_EXPAND \ WARN XARGS _RC_GET_KV_CACHE # user config variables unset DOC_SYMLINKS_DIR INSTALL_MASK PKG_INSTALL_MASK declare -p declare -fp if [[ ${BASH_VERSINFO[0]} == 3 ]]; then export fi ) } true