diff options
author | 2022-11-01 09:46:27 +0200 | |
---|---|---|
committer | 2022-11-01 18:49:10 +0200 | |
commit | 52a3d668722bedda48baaa054ed12e82335dcb42 (patch) | |
tree | 97ae1bf2691b433507deb63283507e3dd3b08559 /data | |
parent | tests: small cleanup (diff) | |
download | pkgcore-52a3d668722bedda48baaa054ed12e82335dcb42.tar.gz pkgcore-52a3d668722bedda48baaa054ed12e82335dcb42.tar.bz2 pkgcore-52a3d668722bedda48baaa054ed12e82335dcb42.zip |
setup.py: reorder data files
Store all data files (files that should be installed into `/usr` outside
python lib location) in one main "data" directory, with direct subdirs
matching the once installed on system. This is preparation for moving to
flit backend.
Signed-off-by: Arthur Zamarin <arthurzam@gentoo.org>
Diffstat (limited to 'data')
125 files changed, 5534 insertions, 0 deletions
diff --git a/data/lib/pkgcore/ebd/eapi/0/global.bash b/data/lib/pkgcore/ebd/eapi/0/global.bash new file mode 100644 index 000000000..e0365984f --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/0/global.bash @@ -0,0 +1,38 @@ +__phase_pkg_nofetch() { + [[ -z ${SRC_URI} ]] && return + + echo "!!! The following are listed in SRC_URI for ${PN}:" + local fp + __shopt_push -f + for fp in ${SRC_URI}; do + echo "!!! ${fp}" + done + __shopt_pop +} + +__phase_src_unpack() { [[ -n ${A} ]] && unpack ${A}; } + +__phase_src_compile() { + if [[ -x ./configure ]]; then + econf + fi + if [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + emake || die "emake failed" + fi +} + +__phase_src_test() { + addpredict / + local extra_args=( ${EXTRA_EMAKE} -j1 ) + if make check -n &> /dev/null; then + echo ">>> Test phase [check]: ${CATEGORY}/${PF}" + emake "${extra_args[@]}" check || die "make check failed, see above for details" + elif make test -n &> /dev/null; then + emake "${extra_args[@]}" test || die "make test failed, see above for details" + else + echo ">>> Test phase [none]: ${CATEGORY}/${PF}" + fi + SANDBOX_PREDICT=${SANDBOX_PREDICT%:/} +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/0/phase.bash b/data/lib/pkgcore/ebd/eapi/0/phase.bash new file mode 100644 index 000000000..b5ae8de13 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/0/phase.bash @@ -0,0 +1,93 @@ +## Package manager query commands + +has_version() { return $(__ebd_ipc_cmd ${FUNCNAME} "" "$@"); } +best_version() { __ebd_ipc_cmd ${FUNCNAME} "" "$@"; } + +## USE flag commands + +use() { + if [[ ! ${1#!} =~ ${PKGCORE_IUSE_EFFECTIVE} ]]; then + die "USE flag '${1#!}' not in IUSE for ${CATEGORY}/${PF}" + fi + + # Ensure USE is split on normal IFS. + local IFS=$' \t\n' + + if [[ ${1:0:1} == "!" ]]; then + ! __safe_has "${1#!}" ${USE} + else + __safe_has "$1" ${USE} + fi +} + +usev() { + if use "$1"; then + echo "${1#!}" + return 0 + fi + return 1 +} + +useq() { + use "$@" +} + +use_with() { + if [[ -z $1 ]]; then + echo "!!! use_with() called without a parameter." >&2 + echo "!!! use_with <USEFLAG> [<flagname> [value]]" >&2 + return + fi + + local uw_suffix="" + if __safe_has "${EAPI}" 0 1 2 3; then + uw_suffix=${3:+=$3} + else + uw_suffix=${3+=$3} + fi + + local uword=$2 + if [[ -z ${uword} ]]; then + uword=$1 + fi + + if use "$1"; then + echo "--with-${uword}${uw_suffix}" + return 0 + fi + echo "--without-${uword}" + return 1 +} + +use_enable() { + if [[ -z $1 ]]; then + echo "!!! use_enable() called without a parameter." >&2 + echo "!!! use_enable <USEFLAG> [<flagname> [value]]" >&2 + return + fi + + local ue_suffix="" + if __safe_has "${EAPI}" 0 1 2 3; then + ue_suffix=${3:+=$3} + else + ue_suffix=${3+=$3} + fi + + local uword=$2 + if [[ -z ${uword} ]]; then + uword=$1 + fi + + if use "$1"; then + echo "--enable-${uword}${ue_suffix}" + return 0 + fi + echo "--disable-${uword}" + return 1 +} + +## Misc commands + +unpack() { __ebd_ipc_cmd ${FUNCNAME} "" "$@"; } + +: diff --git a/data/lib/pkgcore/ebd/eapi/0/src_compile.bash b/data/lib/pkgcore/ebd/eapi/0/src_compile.bash new file mode 100644 index 000000000..feb82ef57 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/0/src_compile.bash @@ -0,0 +1,66 @@ +econf() { + local ret + ECONF_SOURCE=${ECONF_SOURCE:-.} + if [[ ! -x ${ECONF_SOURCE}/configure ]]; then + [[ -f ${ECONF_SOURCE}/configure ]] && die "configure script isn't executable" + die "no configure script found" + fi + + if [[ -d /usr/share/gnuconfig ]]; then + local x + find "${WORKDIR}" -type f \( -name config.guess -o -name config.sub \) | \ + while read x; do + echo "econf: replacing ${x} with /usr/share/gnuconfig/${x##*/}" + cp -f "/usr/share/gnuconfig/${x##*/}" "${x}" + done + fi + + # if the profile defines a location to install libs to aside from default, pass it on. + # if the ebuild passes in --libdir, they're responsible for the conf_libdir fun. + local CONF_LIBDIR=$(__get_libdir) + if [[ -n ${CONF_LIBDIR} && $* != *"--libdir="* ]]; then + if [[ $* == *"--exec-prefix="* ]]; then + local args=$(echo $*) + local -a prefix=( $(echo ${args/*--exec-prefix[= ]}) ) + CONF_PREFIX=${prefix/--*} + [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX=/${CONF_PREFIX} + elif [[ $* == *"--prefix="* ]]; then + local args=$(echo $*) + local -a pref=( $(echo ${args/*--prefix[= ]}) ) + CONF_PREFIX=${prefix/--*} + [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX=/${CONF_PREFIX} + else + CONF_PREFIX=/usr + fi + export CONF_PREFIX + [[ ${CONF_LIBDIR} != /* ]] && CONF_LIBDIR=/${CONF_LIBDIR} + set -- --libdir="$(__strip_duplicate_slashes "${CONF_PREFIX}${CONF_LIBDIR}")" "$@" + fi + + # Reset IFS since we're interpreting user supplied EXTRA_ECONF. + local IFS=$' \t\n' + set -- "${ECONF_SOURCE}/configure" \ + --prefix="${EPREFIX}"/usr \ + ${CBUILD:+--build="${CBUILD}"} \ + --host="${CHOST}" \ + ${CTARGET:+--target="${CTARGET}"} \ + --mandir="${EPREFIX}"/usr/share/man \ + --infodir="${EPREFIX}"/usr/share/info \ + --datadir="${EPREFIX}"/usr/share \ + --sysconfdir="${EPREFIX}"/etc \ + --localstatedir="${EPREFIX}"/var/lib \ + "$@" \ + ${EXTRA_ECONF} + + echo "$@" + + if ! "$@"; then + if [[ -s config.log ]]; then + echo + echo "!!! Please attach the config.log to your bug report:" + echo "!!! ${PWD}/config.log" + fi + die "econf failed" + fi + return $? +} diff --git a/data/lib/pkgcore/ebd/eapi/0/src_install.bash b/data/lib/pkgcore/ebd/eapi/0/src_install.bash new file mode 100644 index 000000000..c8c036405 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/0/src_install.bash @@ -0,0 +1,100 @@ +# Install destination commands + +into() { + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + if [[ $1 == "/" ]]; then + export PKGCORE_DESTTREE="" + else + export PKGCORE_DESTTREE=$1 + fi + + # only EAPI <= 6 supports DESTTREE + ${PKGCORE_HAS_DESTTREE} && export DESTTREE=${PKGCORE_DESTTREE} +} + +insinto() { + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + if [[ $1 == "/" ]]; then + export PKGCORE_INSDESTTREE="" + else + export PKGCORE_INSDESTTREE=$1 + fi + + # only EAPI <= 6 supports INSDESTTREE + ${PKGCORE_HAS_DESTTREE} && export INSDESTTREE=${PKGCORE_INSDESTTREE} +} + +exeinto() { + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + if [[ $1 == "/" ]]; then + export PKGCORE_EXEDESTTREE="" + else + export PKGCORE_EXEDESTTREE=$1 + fi +} + +docinto() { + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + if [[ $1 == "/" ]]; then + export PKGCORE_DOCDESTTREE="" + else + export PKGCORE_DOCDESTTREE=$1 + fi +} + +# Install options commands + +insopts() { + { has -s "$@" || has --strip "$@"; } && \ + ewarn "insopts shouldn't be given -s; stripping should be left to the manager." + export INSOPTIONS=$@ +} + +diropts() { + export DIROPTIONS=$@ +} + +exeopts() { + { has -s "$@" || has --strip "$@"; } && \ + ewarn "exeopts shouldn't be given -s; stripping should be left to the manager." + export EXEOPTIONS=$@ +} + +libopts() { + { has -s "$@" || has --strip "$@"; } && \ + ewarn "libopts shouldn't be given -s; stripping should be left to the manager." + export LIBOPTIONS=$@ +} + +# Install command + +einstall() { + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + # CONF_PREFIX is only set if they didn't pass in libdir above + local LOCAL_EXTRA_EINSTALL=( ${EXTRA_EINSTALL} ) + local CONF_LIBDIR=$(__get_libdir) + if [[ -n ${CONF_LIBDIR} && ${CONF_PREFIX:-unset} != "unset" ]]; then + local EI_DESTLIBDIR=${ED%%/}/${CONF_PREFIX%%/}/${CONF_LIBDIR%%/}/ + LOCAL_EXTRA_EINSTALL+=( libdir=${EI_DESTLIBDIR} ) + unset -v EI_DESTLIBDIR + fi + + if ! [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + die "no Makefile found" + fi + + # Reset IFS for LOCAL_EXTRA_EINSTALL, should users be up to something. + local IFS=$' \t\n' + set -- \ + ${MAKE:-make} \ + prefix="${ED}/usr" \ + datadir="${ED}/usr/share" \ + infodir="${ED}/usr/share/info" \ + localstatedir="${ED}/var/lib" \ + mandir="${ED}/usr/share/man" \ + sysconfdir="${ED}/etc" \ + ${LOCAL_EXTRA_EINSTALL[@]} \ + "$@" install + [[ ${PKGCORE_DEBUG} != 0 ]] && "$@" -n + "$@" || die "einstall failed" +} diff --git a/data/lib/pkgcore/ebd/eapi/1/global.bash b/data/lib/pkgcore/ebd/eapi/1/global.bash new file mode 100644 index 000000000..34f6b1a40 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/1/global.bash @@ -0,0 +1,10 @@ +__phase_src_compile() { + if [[ -x ${ECONF_SOURCE:-.}/configure ]]; then + econf + fi + if [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + emake || die "emake failed" + fi +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/2/global.bash b/data/lib/pkgcore/ebd/eapi/2/global.bash new file mode 100644 index 000000000..74dd78858 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/global.bash @@ -0,0 +1,15 @@ +__phase_src_prepare() { :; } + +__phase_src_configure() { + if [[ -x ${ECONF_SOURCE:-.}/configure ]]; then + econf + fi +} + +__phase_src_compile() { + if [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + emake || die "emake failed" + fi +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/2/phase.bash b/data/lib/pkgcore/ebd/eapi/2/phase.bash new file mode 100644 index 000000000..b5c2c80b4 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/phase.bash @@ -0,0 +1,11 @@ +default() { + if __is_function default_pkg_${EBUILD_PHASE}; then + default_pkg_${EBUILD_PHASE} + elif __is_function default_src_${EBUILD_PHASE}; then + default_src_${EBUILD_PHASE} + else + die "default is not available in ebuild phase '${EBUILD_PHASE}'" + fi +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/2/pkg_nofetch.bash b/data/lib/pkgcore/ebd/eapi/2/pkg_nofetch.bash new file mode 100644 index 000000000..542968cb1 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/pkg_nofetch.bash @@ -0,0 +1 @@ +default_pkg_nofetch() { __phase_pkg_nofetch; } diff --git a/data/lib/pkgcore/ebd/eapi/2/src_compile.bash b/data/lib/pkgcore/ebd/eapi/2/src_compile.bash new file mode 100644 index 000000000..787714d89 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/src_compile.bash @@ -0,0 +1,4 @@ +# moved to src_configure +unset -f econf + +default_src_compile() { __phase_src_compile; } diff --git a/data/lib/pkgcore/ebd/eapi/2/src_configure.bash b/data/lib/pkgcore/ebd/eapi/2/src_configure.bash new file mode 100644 index 000000000..e0067312d --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/src_configure.bash @@ -0,0 +1,73 @@ +econf() { + local ret + ECONF_SOURCE=${ECONF_SOURCE:-.} + if [[ ! -x ${ECONF_SOURCE}/configure ]]; then + [[ -f ${ECONF_SOURCE}/configure ]] && die "configure script isn't executable" + die "no configure script found" + fi + + if [[ -d /usr/share/gnuconfig ]]; then + local x + find "${WORKDIR}" -type f \( -name config.guess -o -name config.sub \) | \ + while read x; do + echo "econf: replacing ${x} with /usr/share/gnuconfig/${x##*/}" + cp -f "/usr/share/gnuconfig/${x##*/}" "${x}" + done + fi + + # if the profile defines a location to install libs to aside from default, pass it on. + # if the ebuild passes in --libdir, they're responsible for the conf_libdir fun. + local CONF_LIBDIR=$(__get_libdir) + if [[ -n ${CONF_LIBDIR} && $* != *"--libdir="* ]]; then + if [[ $* == *"--exec-prefix="* ]]; then + local args=$(echo $*) + local -a prefix=( $(echo ${args/*--exec-prefix[= ]}) ) + CONF_PREFIX=${prefix/--*} + [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX=/${CONF_PREFIX} + elif [[ $* == *"--prefix="* ]]; then + local args=$(echo $*) + local -a prefix=( $(echo ${args/*--prefix[= ]}) ) + CONF_PREFIX=${prefix/--*} + [[ ${CONF_PREFIX} != /* ]] && CONF_PREFIX=/${CONF_PREFIX} + else + CONF_PREFIX=/usr + fi + export CONF_PREFIX + [[ ${CONF_LIBDIR} != /* ]] && CONF_LIBDIR=/${CONF_LIBDIR} + set -- --libdir="$(__strip_duplicate_slashes "${CONF_PREFIX}${CONF_LIBDIR}")" "$@" + fi + + # get EAPI specific arguments + local help_text=$("${ECONF_SOURCE}/configure" --help 2> /dev/null) + set -- $(__run_eapi_funcs --override __econf_options "${help_text}") "$@" + + # Reset IFS since we're interpreting user supplied EXTRA_ECONF. + local IFS=$' \t\n' + set -- "${ECONF_SOURCE}/configure" \ + --prefix="${EPREFIX}"/usr \ + ${CBUILD:+--build="${CBUILD}"} \ + --host="${CHOST}" \ + ${CTARGET:+--target="${CTARGET}"} \ + --mandir="${EPREFIX}"/usr/share/man \ + --infodir="${EPREFIX}"/usr/share/info \ + --datadir="${EPREFIX}"/usr/share \ + --sysconfdir="${EPREFIX}"/etc \ + --localstatedir="${EPREFIX}"/var/lib \ + "$@" \ + ${EXTRA_ECONF} + + echo "$@" + + if ! "$@"; then + if [[ -s config.log ]]; then + echo + echo "!!! Please attach the config.log to your bug report:" + echo "!!! ${PWD}/config.log" + fi + die "econf failed" + fi + return $? +} + + +default_src_configure() { __phase_src_configure; } diff --git a/data/lib/pkgcore/ebd/eapi/2/src_prepare.bash b/data/lib/pkgcore/ebd/eapi/2/src_prepare.bash new file mode 100644 index 000000000..0038c6159 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/src_prepare.bash @@ -0,0 +1 @@ +default_src_prepare() { __phase_src_prepare; } diff --git a/data/lib/pkgcore/ebd/eapi/2/src_test.bash b/data/lib/pkgcore/ebd/eapi/2/src_test.bash new file mode 100644 index 000000000..e1b0749a4 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/src_test.bash @@ -0,0 +1 @@ +default_src_test() { __phase_src_test; } diff --git a/data/lib/pkgcore/ebd/eapi/2/src_unpack.bash b/data/lib/pkgcore/ebd/eapi/2/src_unpack.bash new file mode 100644 index 000000000..684d0b437 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/2/src_unpack.bash @@ -0,0 +1 @@ +default_src_unpack() { __phase_src_unpack; } diff --git a/data/lib/pkgcore/ebd/eapi/4/global.bash b/data/lib/pkgcore/ebd/eapi/4/global.bash new file mode 100644 index 000000000..c8ca5d110 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/4/global.bash @@ -0,0 +1,19 @@ +__phase_src_install() { + if [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + emake DESTDIR="${D}" install + fi + + local docs PKGCORE_DOCDESTTREE= + if ! docs=$(declare -p DOCS 2> /dev/null); then + for docs in README* ChangeLog AUTHORS NEWS TODO CHANGES \ + THANKS BUGS FAQ CREDITS CHANGELOG; do + [[ -s ${docs} ]] && dodoc "${docs}" + done + elif [[ ${docs} == "declare -a "* ]]; then + dodoc "${DOCS[@]}" + else + dodoc ${DOCS} + fi +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/4/phase.bash b/data/lib/pkgcore/ebd/eapi/4/phase.bash new file mode 100644 index 000000000..f075cb485 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/4/phase.bash @@ -0,0 +1,3 @@ +nonfatal() { PKGCORE_NONFATAL=true "$@"; } + +: diff --git a/data/lib/pkgcore/ebd/eapi/4/src_configure.bash b/data/lib/pkgcore/ebd/eapi/4/src_configure.bash new file mode 100644 index 000000000..5f859526a --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/4/src_configure.bash @@ -0,0 +1,5 @@ +__econf_options_eapi4() { + if [[ $1 == *"--disable-dependency-tracking"* ]]; then + echo --disable-dependency-tracking + fi +} diff --git a/data/lib/pkgcore/ebd/eapi/4/src_install.bash b/data/lib/pkgcore/ebd/eapi/4/src_install.bash new file mode 100644 index 000000000..50918ed02 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/4/src_install.bash @@ -0,0 +1,3 @@ +default_src_install() { __phase_src_install; } + +docompress() { __ebd_ipc_cmd ${FUNCNAME} "" "$@"; } diff --git a/data/lib/pkgcore/ebd/eapi/5/global.bash b/data/lib/pkgcore/ebd/eapi/5/global.bash new file mode 100644 index 000000000..c9dfe178d --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/5/global.bash @@ -0,0 +1,16 @@ +# parallel tests are allowed (no forced -j1) +__phase_src_test() { + addpredict / + local extra_args=( ${EXTRA_EMAKE} ) + if make check -n &> /dev/null; then + echo ">>> Test phase [check]: ${CATEGORY}/${PF}" + emake "${extra_args[@]}" check || die "make check failed, see above for details" + elif make test -n &> /dev/null; then + emake "${extra_args[@]}" test || die "make test failed, see above for details" + else + echo ">>> Test phase [none]: ${CATEGORY}/${PF}" + fi + SANDBOX_PREDICT=${SANDBOX_PREDICT%:/} +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/5/phase.bash b/data/lib/pkgcore/ebd/eapi/5/phase.bash new file mode 100644 index 000000000..8fe6ab01b --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/5/phase.bash @@ -0,0 +1,6 @@ +usex() { + use "$1" && echo "${2-yes}$4" || echo "${3-no}$5" + return 0 +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/5/src_configure.bash b/data/lib/pkgcore/ebd/eapi/5/src_configure.bash new file mode 100644 index 000000000..5d3c9c390 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/5/src_configure.bash @@ -0,0 +1,5 @@ +__econf_options_eapi5() { + if [[ $1 == *"--disable-silent-rules"* ]]; then + echo --disable-silent-rules + fi +} diff --git a/data/lib/pkgcore/ebd/eapi/6/global.bash b/data/lib/pkgcore/ebd/eapi/6/global.bash new file mode 100644 index 000000000..3766014c3 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/6/global.bash @@ -0,0 +1,22 @@ +__phase_src_prepare() { + local patches + if patches=$(declare -p PATCHES 2> /dev/null); then + if [[ ${patches} == "declare -a "* ]]; then + [[ ${#PATCHES[@]} -gt 0 ]] && eapply "${PATCHES[@]}" + else + [[ -n ${PATCHES} ]] && eapply ${PATCHES} + fi + fi + + eapply_user +} + +__phase_src_install() { + if [[ -f Makefile || -f GNUmakefile || -f makefile ]]; then + emake DESTDIR="${D}" install + fi + + einstalldocs +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/6/phase.bash b/data/lib/pkgcore/ebd/eapi/6/phase.bash new file mode 100644 index 000000000..bbdb3ac3e --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/6/phase.bash @@ -0,0 +1,5 @@ +in_iuse() { [[ $1 =~ ${PKGCORE_IUSE_EFFECTIVE} ]]; } + +get_libdir() { __get_libdir lib; } + +: diff --git a/data/lib/pkgcore/ebd/eapi/6/src_configure.bash b/data/lib/pkgcore/ebd/eapi/6/src_configure.bash new file mode 100644 index 000000000..4385001cc --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/6/src_configure.bash @@ -0,0 +1,8 @@ +__econf_options_eapi6() { + if [[ $1 == *"--docdir"* ]]; then + echo --docdir="${EPREFIX}"/usr/share/doc/${PF} + fi + if [[ $1 == *"--htmldir"* ]]; then + echo --htmldir="${EPREFIX}"/usr/share/doc/${PF}/html + fi +} diff --git a/data/lib/pkgcore/ebd/eapi/6/src_install.bash b/data/lib/pkgcore/ebd/eapi/6/src_install.bash new file mode 100644 index 000000000..ad9d26b12 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/6/src_install.bash @@ -0,0 +1,34 @@ +PKGCORE_BANNED_FUNCS=( einstall ) + +einstalldocs() { + local docs PKGCORE_DOCDESTTREE= + if ! docs=$(declare -p DOCS 2> /dev/null); then + local -a DOCS + for docs in README* ChangeLog AUTHORS NEWS TODO CHANGES \ + THANKS BUGS FAQ CREDITS CHANGELOG; do + [[ -s ${docs} ]] && DOCS+=( ${docs} ) + done + if [[ ${#DOCS[@]} -gt 0 ]]; then + dodoc "${DOCS[@]}" || return $? + fi + elif [[ ${docs} == "declare -a "* ]]; then + if [[ ${#DOCS[@]} -gt 0 ]]; then + dodoc -r "${DOCS[@]}" || return $? + fi + elif [[ -n ${DOCS} ]]; then + dodoc -r ${DOCS} || return $? + fi + + PKGCORE_DOCDESTTREE=html + if ! docs=$(declare -p HTML_DOCS 2> /dev/null); then + : + elif [[ ${docs} == "declare -a "* ]]; then + if [[ ${#HTML_DOCS[@]} -gt 0 ]]; then + dodoc -r "${HTML_DOCS[@]}" || return $? + fi + elif [[ -n ${HTML_DOCS} ]]; then + dodoc -r ${HTML_DOCS} || return $? + fi + + return 0 +} diff --git a/data/lib/pkgcore/ebd/eapi/6/src_prepare.bash b/data/lib/pkgcore/ebd/eapi/6/src_prepare.bash new file mode 100644 index 000000000..0e07021c9 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/6/src_prepare.bash @@ -0,0 +1,8 @@ +eapply() { __ebd_ipc_cmd ${FUNCNAME} "" "$@"; } + +eapply_user() { + [[ -f ${T}/.user_patches_applied ]] && return + __ebd_ipc_cmd ${FUNCNAME} "" "$@" +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/7/global.bash b/data/lib/pkgcore/ebd/eapi/7/global.bash new file mode 100644 index 000000000..8fb3a5260 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/7/global.bash @@ -0,0 +1,187 @@ +__ver_parse_range() { + local range=${1} + local max=${2} + + [[ ${range} == [0-9]* ]] || die "${FUNCNAME}: range must start with a number" + start=${range%-*} + [[ ${range} == *-* ]] && end=${range#*-} || end=${start} + if [[ ${end} ]]; then + [[ ${start} -le ${end} ]] || die "${FUNCNAME}: end of range must be >= start" + [[ ${end} -le ${max} ]] || end=${max} + else + end=${max} + fi +} + +__ver_split() { + local v=${1} LC_ALL=C + + comp=() + + # get separators and components + local s c + while [[ ${v} ]]; do + # cut the separator + s=${v%%[a-zA-Z0-9]*} + v=${v:${#s}} + # cut the next component; it can be either digits or letters + [[ ${v} == [0-9]* ]] && c=${v%%[^0-9]*} || c=${v%%[^a-zA-Z]*} + v=${v:${#c}} + + comp+=( "${s}" "${c}" ) + done +} + +ver_cut() { + local range=${1} + local v=${2:-${PV}} + local start end + local -a comp + + __ver_split "${v}" + local max=$((${#comp[@]}/2)) + __ver_parse_range "${range}" "${max}" + + local IFS= + if [[ ${start} -gt 0 ]]; then + start=$(( start*2 - 1 )) + fi + echo "${comp[*]:start:end*2-start}" +} + +ver_rs() { + local v + (( ${#} & 1 )) && v=${@: -1} || v=${PV} + local start end i + local -a comp + + __ver_split "${v}" + local max=$((${#comp[@]}/2 - 1)) + + while [[ ${#} -ge 2 ]]; do + __ver_parse_range "${1}" "${max}" + for (( i = start*2; i <= end*2; i+=2 )); do + [[ ${i} -eq 0 && -z ${comp[i]} ]] && continue + comp[i]=${2} + done + shift 2 + done + + local IFS= + echo "${comp[*]}" +} + +__ver_compare_int() { + local a=$1 b=$2 d=$(( ${#1}-${#2} )) + + # Zero-pad to equal length if necessary. + if [[ ${d} -gt 0 ]]; then + printf -v b "%0${d}d%s" 0 "${b}" + elif [[ ${d} -lt 0 ]]; then + printf -v a "%0$(( -d ))d%s" 0 "${a}" + fi + + [[ ${a} > ${b} ]] && return 3 + [[ ${a} == "${b}" ]] +} + +__ver_compare() { + local va=${1} vb=${2} a an al as ar b bn bl bs br re LC_ALL=C + + re="^([0-9]+(\.[0-9]+)*)([a-z]?)((_(alpha|beta|pre|rc|p)[0-9]*)*)(-r[0-9]+)?$" + + [[ ${va} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${va}" + an=${BASH_REMATCH[1]} + al=${BASH_REMATCH[3]} + as=${BASH_REMATCH[4]} + ar=${BASH_REMATCH[7]} + + [[ ${vb} =~ ${re} ]] || die "${FUNCNAME}: invalid version: ${vb}" + bn=${BASH_REMATCH[1]} + bl=${BASH_REMATCH[3]} + bs=${BASH_REMATCH[4]} + br=${BASH_REMATCH[7]} + + # Compare numeric components (PMS algorithm 3.2) + # First component + __ver_compare_int "${an%%.*}" "${bn%%.*}" || return + + while [[ ${an} == *.* && ${bn} == *.* ]]; do + # Other components (PMS algorithm 3.3) + an=${an#*.} + bn=${bn#*.} + a=${an%%.*} + b=${bn%%.*} + if [[ ${a} == 0* || ${b} == 0* ]]; then + # Remove any trailing zeros + [[ ${a} =~ 0+$ ]] && a=${a%"${BASH_REMATCH[0]}"} + [[ ${b} =~ 0+$ ]] && b=${b%"${BASH_REMATCH[0]}"} + [[ ${a} > ${b} ]] && return 3 + [[ ${a} < ${b} ]] && return 1 + else + __ver_compare_int "${a}" "${b}" || return + fi + done + [[ ${an} == *.* ]] && return 3 + [[ ${bn} == *.* ]] && return 1 + + # Compare letter components (PMS algorithm 3.4) + [[ ${al} > ${bl} ]] && return 3 + [[ ${al} < ${bl} ]] && return 1 + + # Compare suffixes (PMS algorithm 3.5) + as=${as#_}${as:+_} + bs=${bs#_}${bs:+_} + while [[ -n ${as} && -n ${bs} ]]; do + # Compare each suffix (PMS algorithm 3.6) + a=${as%%_*} + b=${bs%%_*} + if [[ ${a%%[0-9]*} == "${b%%[0-9]*}" ]]; then + __ver_compare_int "${a##*[a-z]}" "${b##*[a-z]}" || return + else + # Check for p first + [[ ${a%%[0-9]*} == p ]] && return 3 + [[ ${b%%[0-9]*} == p ]] && return 1 + # Hack: Use that alpha < beta < pre < rc alphabetically + [[ ${a} > ${b} ]] && return 3 || return 1 + fi + as=${as#*_} + bs=${bs#*_} + done + if [[ -n ${as} ]]; then + [[ ${as} == p[_0-9]* ]] && return 3 || return 1 + elif [[ -n ${bs} ]]; then + [[ ${bs} == p[_0-9]* ]] && return 1 || return 3 + fi + + # Compare revision components (PMS algorithm 3.7) + __ver_compare_int "${ar#-r}" "${br#-r}" || return + + return 2 +} + +ver_test() { + local va op vb + + if [[ $# -eq 3 ]]; then + va=${1} + shift + else + va=${PVR} + fi + + [[ $# -eq 2 ]] || die "${FUNCNAME}: bad number of arguments" + + op=${1} + vb=${2} + + case ${op} in + -eq|-ne|-lt|-le|-gt|-ge) ;; + *) die "${FUNCNAME}: invalid operator: ${op}" ;; + esac + + __ver_compare "${va}" "${vb}" + test $? "${op}" 2 +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/7/src_configure.bash b/data/lib/pkgcore/ebd/eapi/7/src_configure.bash new file mode 100644 index 000000000..1ff999c65 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/7/src_configure.bash @@ -0,0 +1,7 @@ +__econf_options_eapi7() { + if [[ $1 == *"--with-sysroot"* ]]; then + echo --with-sysroot="${ESYSROOT:-/}" + fi +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/7/src_install.bash b/data/lib/pkgcore/ebd/eapi/7/src_install.bash new file mode 100644 index 000000000..5e7337046 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/7/src_install.bash @@ -0,0 +1,3 @@ +PKGCORE_BANNED_FUNCS=( libopts ) + +dostrip() { __ebd_ipc_cmd ${FUNCNAME} "" "$@"; } diff --git a/data/lib/pkgcore/ebd/eapi/8/global.bash b/data/lib/pkgcore/ebd/eapi/8/global.bash new file mode 100644 index 000000000..574e071c9 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/8/global.bash @@ -0,0 +1,14 @@ +__phase_src_prepare() { + local patches + if patches=$(declare -p PATCHES 2> /dev/null); then + if [[ ${patches} == "declare -a "* ]]; then + [[ ${#PATCHES[@]} -gt 0 ]] && eapply -- "${PATCHES[@]}" + else + [[ -n ${PATCHES} ]] && eapply -- ${PATCHES} + fi + fi + + eapply_user +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/8/phase.bash b/data/lib/pkgcore/ebd/eapi/8/phase.bash new file mode 100644 index 000000000..efeccd889 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/8/phase.bash @@ -0,0 +1,9 @@ +PKGCORE_BANNED_FUNCS=( hasq hasv useq ) + +usev() { + if use "$1"; then + echo "${2:-${1#!}}" + return 0 + fi + return 1 +} diff --git a/data/lib/pkgcore/ebd/eapi/8/src_configure.bash b/data/lib/pkgcore/ebd/eapi/8/src_configure.bash new file mode 100644 index 000000000..ed94b52bf --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/8/src_configure.bash @@ -0,0 +1,8 @@ +__econf_options_eapi8() { + if [[ $1 == *"--datarootdir"* ]]; then + echo "--datarootdir=${EPREFIX}/usr/share" + fi + if [[ $1 == *"--disable-static"* || $1 == *"--enable-static"* ]]; then + echo "--disable-static" + fi +} diff --git a/data/lib/pkgcore/ebd/eapi/common.bash b/data/lib/pkgcore/ebd/eapi/common.bash new file mode 100644 index 000000000..daff5b2f0 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/common.bash @@ -0,0 +1,153 @@ +# Common EAPI functionality (mainly phase related) + +# debug-print() gets called from many places with verbose status information useful +# for tracking down problems. The output is in ${T}/eclass-debug.log. +# You can set ECLASS_DEBUG_OUTPUT to redirect the output somewhere else as well. +# The special "on" setting echoes the information, mixing it with the rest of the +# emerge output. +# You can override the setting by exporting a new one from the console, or you can +# set a new default in make.*. Here the default is "" or unset. + +# in the future might use e* from /etc/init.d/functions.sh if i feel like it +debug-print() { + if __safe_has ${EBUILD_PHASE} depend nofetch pretend config info postinst; then + return + fi + # if ${T} isn't defined, we're in dep calculation mode and + # shouldn't do anything + [[ -z ${T} ]] && return 0 + + local _item + for _item in "$@"; do + # extra user-configurable targets + if [[ ${ECLASS_DEBUG_OUTPUT} == "on" ]]; then + echo "debug: ${_item}" + elif [[ -n ${ECLASS_DEBUG_OUTPUT} ]]; then + echo "debug: ${_item}" >> "${ECLASS_DEBUG_OUTPUT}" + fi + + # default target + echo "${_item}" >> "${T}"/eclass-debug.log + chmod g+w "${T}"/eclass-debug.log &> /dev/null + done + # let the portage user own/write to this file +} + +# The following 2 functions are debug-print() wrappers + +debug-print-function() { + local str="$1: entering function" + shift + debug-print "${str}, parameters: $*" +} + +debug-print-section() { + debug-print "now in section $*" +} + +__get_libdir() { + local libdir=$1 libdir_var="LIBDIR_${ABI}" + [[ -n ${ABI} && -n ${!libdir_var} ]] && libdir=${!libdir_var} + echo "${libdir}" +} + +__phase_pre_phase() { + if [[ -d ${S} ]]; then + cd "${S}" + elif __safe_has "${EAPI}" 0 1 2 3; then + cd "${WORKDIR}" + elif [[ -n ${A} ]]; then + die "source directory '${S}' doesn't exist, but \${A} isn't empty (see S-WORKDIR-FALLBACK in PMS)" + else + local phase + # eapi4 blatant idiocy... + for phase in unpack prepare configure compile test install; do + [[ ${phase} == ${EBUILD_PHASE} ]] && break + __is_function src_${phase} || continue + # to reach here means that (for example), we're doing src_install, and src_compile was defined + # but S doesn't exist. + die "source directory '${S}' doesn't exist, \${A} is defined, and there was a defined " \ + "phase function '${phase}' prior to '${EBUILD_PHASE}'; please see S-WORKDIR-FALLBACK " \ + "in pms for the details of what is allowed for eapi4 and later" + done + cd "${WORKDIR}" + fi +} + +__phase_pre_src_unpack() { cd "${WORKDIR}"; } +__phase_pre_src_prepare() { __phase_pre_phase; } +__phase_pre_src_test() { __phase_pre_phase; } + +__phase_pre_src_configure() { + local var + for var in C{BUILD,HOST,TARGET,C,XX} {AS,LD,{,LIB}C{,XX}}FLAGS CCACHE_DIR; do + [[ -n ${!var+set} ]] && export ${var}="${!var}" + done + __phase_pre_phase +} + +__phase_pre_src_compile() { + # just reuse the default_pre_src_configure; this means we don't have to care + # if the eapi has configure or not. + __phase_pre_src_configure + + if __feature_is_enabled distcc; then + [[ -n ${DISTCC_DIR} ]] && addwrite "${DISTCC_DIR}" + if __feature_is_enabled distcc-pump; then + eval $(pump --startup) || echo "Warning: Failed starting pump" >&2 + trap 'pump --shutdown' EXIT + fi + fi +} + +__phase_post_src_compile() { + if __feature_is_enabled distcc && __feature_is_enabled distcc-pump; then + pump --shutdown + trap - EXIT + fi +} + +__phase_pre_src_install() { + export PKGCORE_DESTTREE=/usr PKGCORE_INSDESTTREE='' \ + PKGCORE_EXEDESTTREE='' PKGCORE_DOCDESTTREE='' + if ${PKGCORE_HAS_DESTTREE}; then + export DESTTREE=${PKGCORE_DESTTREE} + export INSDESTTREE=${PKGCORE_INSDESTTREE} + fi + export INSOPTIONS="-m0644" EXEOPTIONS="-m0755" + export LIBOPTIONS="-m0644" DIROPTIONS="-m0755" + export PORTAGE_COMPRESS=${PORTAGE_COMPRESS:-bzip2} + export PORTAGE_COMPRESS_FLAGS=${PORTAGE_COMPRESS_FLAGS:--9} + export D + rm -rf "${D}" + if ${PKGCORE_PREFIX_SUPPORT}; then + [[ -n ${ED+set} ]] || \ + die "variable ED is unset, but prefix mode is enabled, internal error?" + export ED=${ED} + mkdir -p "${ED}" + else + mkdir "${D}" + fi + __phase_pre_phase +} + +# Iterate over the inherited EAPI stack running all EAPI specific functions +# starting with a defined prefix. Defaults to running in inherited order from +# the current package's EAPI to the oldest inherited EAPI. To run in overriding +# order (the reverse direction), pass '--override' as the first argument. +__run_eapi_funcs() { + local eapis=( ${PKGCORE_EAPI_INHERITS} ) + if [[ $1 == --override ]]; then + eapis=( $(__reverse_array eapis) ) + shift + fi + local func_prefix=$1 + shift + + local eapi + for eapi in "${eapis[@]}"; do + __qa_run_function_if_exists ${func_prefix}_eapi${eapi} "$@" + done +} + +: diff --git a/data/lib/pkgcore/ebd/eapi/depend.bash b/data/lib/pkgcore/ebd/eapi/depend.bash new file mode 100644 index 000000000..286bb5b95 --- /dev/null +++ b/data/lib/pkgcore/ebd/eapi/depend.bash @@ -0,0 +1,116 @@ +# Common EAPI functions + +has() { + local needle=$1 + shift + + local IFS=$'\001' + + # try fast mode first; no IFS match is guaranteed that the needle isn't there. + [[ "${IFS}${*}${IFS}" != *"${IFS}${needle}${IFS}"* ]] && return 1 + + # If we have a match, ensure it's not due to $@ already having \001 in it. + # unlikely, but better safe than sorry. + IFS=' ' + [[ *$'\001'* != $* ]] && return 0 + + # \001 for some insane reason was in $@; fallback to the slow for loop. + # Suppress debug output for this part however. + __shopt_push +x + local x + for x in "$@"; do + if [[ ${x} == ${needle} ]]; then + __shopt_pop + return 0 + fi + done + __shopt_pop + return 1 +} + +hasq() { + has ${EBUILD_PHASE} prerm postrm || eqawarn \ + "QA Notice: The 'hasq' function is deprecated (replaced by 'has')" + has "$@" +} + +hasv() { + has "$@" && echo "$1" +} + +# stubbed debug commands to avoid debug output during metadata generation +debug-print() { :; } +debug-print-function() { :; } +debug-print-section() { :; } + +# output commands +eqawarn() { + __elog_base QA "$*" + printf " ${PKGCORE_RC_WARN}*${PKGCORE_RC_NORMAL} %b\n" "${*}" >&2 + PKGCORE_RC_LAST_CMD="eqawarn" + return 0 +} + +elog() { + __elog_base LOG "$*" + printf " ${PKGCORE_RC_GOOD}*${PKGCORE_RC_NORMAL} %b\n" "${*}" >&2 + PKGCORE_RC_LAST_CMD="elog" + return 0 +} + +einfo() { + printf " ${PKGCORE_RC_GOOD}*${PKGCORE_RC_NORMAL} %b\n" "${*}" >&2 + PKGCORE_RC_LAST_CMD="einfo" + return 0 +} + +einfon() { + __elog_base INFO "$*" + printf " ${PKGCORE_RC_GOOD}*${PKGCORE_RC_NORMAL} %b" "${*}" >&2 + PKGCORE_RC_LAST_CMD="einfon" + return 0 +} + +ewarn() { + __elog_base WARN "$*" + printf " ${PKGCORE_RC_WARN}*${PKGCORE_RC_NORMAL} %b\n" "${*}" >&2 + PKGCORE_RC_LAST_CMD="ewarn" + return 0 +} + +eerror() { + __elog_base ERROR "$*" + printf " ${PKGCORE_RC_BAD}*${PKGCORE_RC_NORMAL} %b\n" "${*}" >&2 + PKGCORE_RC_LAST_CMD="eerror" + return 0 +} + +ebegin() { + local msg="$* ..." + einfon "${msg}" + echo + PKGCORE_RC_LAST_CMD="ebegin" + return 0 +} + +eend() { + local retval=${1:-0} + shift + + local msg + + if [[ ${retval} == 0 ]]; then + msg="${PKGCORE_RC_BRACKET}[ ${PKGCORE_RC_GOOD}ok${PKGCORE_RC_BRACKET} ]${PKGCORE_RC_NORMAL}" + else + if [[ $# -ne 0 ]]; then + eerror "$*" + fi + msg="${PKGCORE_RC_BRACKET}[ ${PKGCORE_RC_BAD}!!${PKGCORE_RC_BRACKET} ]${PKGCORE_RC_NORMAL}" + fi + + echo -e "${PKGCORE_RC_ENDCOL} ${msg}" >&2 + + return ${retval} +} + +: diff --git a/data/lib/pkgcore/ebd/ebuild-daemon-lib.bash b/data/lib/pkgcore/ebd/ebuild-daemon-lib.bash new file mode 100644 index 000000000..77819947f --- /dev/null +++ b/data/lib/pkgcore/ebd/ebuild-daemon-lib.bash @@ -0,0 +1,148 @@ +# ebuild daemon lib code + +PKGCORE_EBD_PID=${BASHPID} +# Use ebd_read/ebd_write for talking to the running pkgcore instance instead of +# echo'ing to the fd yourself. This allows us to move the open fd's w/out +# issues down the line. +__ebd_read_line_nonfatal() { + read -u ${PKGCORE_EBD_READ_FD} $1 +} + +__ebd_read_line() { + __ebd_read_line_nonfatal "$@" + local ret=$? + [[ ${ret} -ne 0 ]] && \ + die "coms error in ${PKGCORE_EBD_PID}, read_line $@ failed w/ ${ret}" +} + +# Read a line into an array using a bell char as a delimiter since the null char +# can't be assigned to variables. +__ebd_read_array() { + IFS=$'\07' read -u ${PKGCORE_EBD_READ_FD} -a $1 + [[ $? -ne 0 ]] && \ + die "coms error in ${PKGCORE_EBD_PID}, read_array $@ failed" +} + +# read -N usage requires bash-4.1 or so (EAPI 6 requires >= 4.2) +__ebd_read_size() { + read -u ${PKGCORE_EBD_READ_FD} -r -N $1 $2 + local ret=$? + [[ ${ret} -ne 0 ]] && \ + die "coms error in ${PKGCORE_EBD_PID}, read_size $@ failed w/ ${ret}" +} + +__ebd_read_cat_size() { + dd bs=$1 count=1 <&${PKGCORE_EBD_READ_FD} +} + +# Write arg list as a single string using a null char delimiter terminated by a newline. +# Note that this requires printf as echo doesn't appear to respect IFS=$'\0'. +__ebd_write_array() { + printf "%s\0" "$@" >&${PKGCORE_EBD_WRITE_FD} + __ebd_write_line +} + +__ebd_write_line() { + echo "$*" >&${PKGCORE_EBD_WRITE_FD} + local ret=$? + [[ ${ret} -ne 0 ]] && \ + die "coms error, write failed w/ ${ret}" +} + +__ebd_write_raw() { + echo -n "$*" >&${PKGCORE_EBD_WRITE_FD} || die "coms error, __ebd_write_raw failed" +} + +__ipc_exit() { + # exit in a helper compatible way when running IPC command from a helper + [[ -n ${HELPER_ERROR_PREFIX} ]] && __helper_exit "$@" + + local ret=$1 + shift + if [[ ${ret} == 0 ]]; then + [[ -n $@ ]] && echo "$@" + return 0 + fi + + local error_msg="${IPC_CMD}: exitcode ${ret}" + [[ -n $@ ]] && error_msg+=": $@" + + if ${PKGCORE_NONFATAL}; then + eerror "${error_msg}" + return ${ret} + fi + + die "${error_msg}" +} + +# run an ebuild command on the python side and return its status +__ebd_ipc_cmd() { + local IPC_CMD=$1 opts=$2 ret_str + local -a ret + shift 2 + + __ebd_write_line ${IPC_CMD} + __ebd_write_line ${PKGCORE_NONFATAL:-false} + __ebd_write_line ${PWD} + __ebd_write_line ${EBUILD_PHASE} + __ebd_write_line ${opts} + __ebd_write_array "$@" + __ebd_read_array ret + __ipc_exit "${ret[@]}" +} + +# ask the python side to display sandbox complaints +__request_sandbox_summary() { + local line + __ebd_write_line "__request_sandbox_summary ${SANDBOX_LOG}" + __ebd_read_line line + while [[ ${line} != "end_sandbox_summary" ]]; do + echo "${line}" + __ebd_read_line line + done +} + +__internal_inherit() { + local line + if [[ $# -ne 1 ]]; then + die "internal_inherit accepts an eclass name arg, got $*" + fi + if [[ -n ${PKGCORE_PRELOADED_ECLASSES[$1]} ]]; then + __qa_invoke "${PKGCORE_PRELOADED_ECLASSES[$1]}" + return + fi + __ebd_write_line "request_inherit $1" + __ebd_read_line line + if [[ ${line} == "path" ]]; then + __ebd_read_line line + __qa_invoke source "${line}" >&2 || die "failed eclass inherit: $1" + elif [[ ${line} == "transfer" ]]; then + __ebd_read_line line + __qa_invoke eval "${line}" || die "failed evaluating eclass $1 on transfer" + else + die "unknown inherit command from python for eclass $1: '${line}'" + fi +} + +__source_bashrcs() { + ${PKGCORE_SUPPRESS_BASHRCS:-false} && return + local line + __ebd_write_line "request_bashrcs" + __ebd_read_line line + while [[ ${line} != "end_request" ]]; do + if [[ ${line} == "path" ]]; then + __ebd_read_line line + source "${line}" >&2 + elif [[ ${line} == "transfer" ]]; then + __ebd_read_line line + eval "${line}" || die "failed evaluating profile bashrc: ${line}" + else + __ebd_write_line "failed" + die "unknown profile bashrc transfer mode from python: '${line}'" + fi + __ebd_write_line "next" + __ebd_read_line line + done +} + +: diff --git a/data/lib/pkgcore/ebd/ebuild-daemon.bash b/data/lib/pkgcore/ebd/ebuild-daemon.bash new file mode 100644 index 000000000..354f7ff0c --- /dev/null +++ b/data/lib/pkgcore/ebd/ebuild-daemon.bash @@ -0,0 +1,405 @@ +# core ebuild processor handling code + +# These are functions that shouldn't be marked readonly, since they're runtime +# switchable. +PKGCORE_RUNTIME_FUNCS=( '__timed_call' ) + +PKGCORE_EBD_PATH=${BASH_SOURCE[0]%/*} + +__set_perf_debug() { + if [[ ${PKGCORE_DEBUG} -ge 4 || -n ${PKGCORE_PERF_DEBUG} ]]; then + __timed_call() { + echo "timing $*" >&2 + time "$@" + local __ret=$? + echo "timed $*" >&2 + return ${__ret} + } + else + __timed_call() { + "$@" + } + fi +} + +__set_perf_debug + +# Temporary function used by the daemon, till proper die implementation is loaded. +die() { + echo "$@" >&2 + exit 1 +} + +declare -rf __set_perf_debug +declare -r PKGCORE_EBD_WRITE_FD PKGCORE_EBD_READ_FD + +__ebd_sigint_handler() { + EBD_DISABLE_DIEFUNC="yes" + # silence ourselves as everything shuts down. + exec 2>/dev/null + exec 1>/dev/null + # suppress sigpipe; if we can't tell the parent to die, + # it's already shutting us down. + trap "exit 2" SIGPIPE + __ebd_write_line "SIGINT" + trap - SIGINT + # this relies on the python side to *not* discard the killed + exit 2 +} + +__ebd_sigterm_handler() { + EBD_DISABLE_DIEFUNC="yes" + # silence ourselves as everything shuts down. + exec 2>/dev/null + exec 1>/dev/null + # suppress sigpipe; if we can't tell the parent to die, + # it's already shutting us down. + trap "exit 15" SIGPIPE + __ebd_write_line "SIGTERM" + trap - SIGTERM + exit 15 +} + +__ebd_exec_main() { + if ! source "${PKGCORE_EBD_PATH}"/ebuild-daemon-lib.bash; then + die "failed sourcing ${PKGCORE_EBD_PATH}/ebuild-daemon-lib.bash" + fi + + # Ensure the other side is still there, well, this moreso is for the python + # side to ensure loading up the intermediate funcs succeeded. + local com + __ebd_read_line com + if [[ ${com} != "ebd?" ]]; then + die "serv init coms failed, received '${com}' when expecting 'ebd?'" + fi + __ebd_write_line "ebd!" + + # get our die functionality now. + if ! source "${PKGCORE_EBD_PATH}"/exit-handling.bash; then + __ebd_write_line "failed sourcing exit handling functionality" + exit 2 + fi + + if ! source "${PKGCORE_EBD_PATH}"/isolated-functions.bash; then + __ebd_write_line "failed sourcing isolated-functions.bash" + exit 2 + fi + + # enable colored support as early as possible for early die() usage + [[ -z ${NO_COLOR} ]] && __colored_output_enable + + if ! source "${PKGCORE_EBD_PATH}"/ebuild.bash; then + __ebd_write_line "failed" + die "failed sourcing ${PKGCORE_EBD_PATH}/ebuild.bash" + fi + + __ebd_read_line com + case ${com} in + "sandbox_log?") + if [[ ! ${SANDBOX_LOG} ]]; then + die "sandbox enabled but no SANDBOX_LOG?!" + fi + __ebd_write_line "${SANDBOX_LOG}" + declare -rx SANDBOX_LOG=${SANDBOX_LOG} + addwrite "${SANDBOX_LOG}" + ;; + no_sandbox) + ;; + *) + die "unknown sandbox com: '${com}'" + ;; + esac + + __IFS_push $'\n' + readonly_vars=( $(readonly) ) + __IFS_pop + # extract variable names from declarations + readonly_vars=( "${readonly_vars[@]/%=*/}" ) + readonly_vars=( "${readonly_vars[@]/#* * /}" ) + + for x in "${readonly_vars[@]}"; do + if ! __safe_has "${x}" "${PKGCORE_BLACKLIST_VARS[@]}"; then + PKGCORE_BLACKLIST_VARS+=( ${x} ) + fi + done + __ebd_write_line ${readonly_vars[@]} + unset -v x readonly_vars + + # protect ourselves + declare -rx PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH} + + declare -A PKGCORE_PRELOADED_ECLASSES + + trap __ebd_sigint_handler SIGINT + trap __ebd_sigterm_handler SIGTERM + + # finally, load the master list of pkgcore funcs. fallback to + # regenerating it if needed. + if [[ -f ${PKGCORE_EBD_PATH}/generated/funcs/global ]]; then + PKGCORE_BLACKLIST_FUNCS+=( $(<"${PKGCORE_EBD_PATH}"/generated/funcs/global) ) + else + PKGCORE_BLACKLIST_FUNCS+=( $("${PKGCORE_EBD_PATH}"/generate_global_func_list 2> /dev/null) ) + fi + [[ $? -eq 0 ]] || die "failed reading the global function skip list" + + for x in "${PKGCORE_BLACKLIST_FUNCS[@]}"; do + __is_function "${x}" || continue + if ! __safe_has "${x}" "${PKGCORE_RUNTIME_FUNCS[@]}"; then + declare -fr ${x} &> /dev/null + fi + done + unset -v x + + source "${PKGCORE_EBD_PATH}"/eapi/depend.bash || die "failed sourcing eapi/depend.bash" + __ebd_main_loop + exit 0 +} + +__ebd_process_sandbox_results() { + if [[ -z ${SANDBOX_LOG} || ! -e ${SANDBOX_LOG} ]]; then + return 0; + fi + echo "sandbox exists- ${SANDBOX_LOG}" >&2 + __request_sandbox_summary >&2 + echo "SANDBOX_ON:=${SANDBOX_ON:-unset}" >&2 + echo "SANDBOX_DISABLED:=${SANDBOX_DISABLED:-unset}" >&2 + echo "SANDBOX_READ:=${SANDBOX_READ:-unset}" >&2 + echo "SANDBOX_WRITE:=${SANDBOX_WRITE:-unset}" >&2 + echo "SANDBOX_PREDICT:=${SANDBOX_PREDICT:-unset}" >&2 + echo "SANDBOX_DEBUG:=${SANDBOX_DEBUG:-unset}" >&2 + echo "SANDBOX_DEBUG_LOG:=${SANDBOX_DEBUG_LOG:-unset}" >&2 + echo "SANDBOX_LOG:=${SANDBOX_LOG:-unset}" >&2 + echo "SANDBOX_ARMED:=${SANDBOX_ARMED:-unset}" >&2 + return 1 +} + +__ebd_process_ebuild_phases() { + # note that this is entirely subshelled; as such exit is used rather than returns + ( + declare -r PKGCORE_QA_SUPPRESSED=false + local phases=$@ + local is_depends=true + if [[ ${phases/depend} == ${phases} ]]; then + is_depends=false + fi + local cont=0 + + while [[ ${cont} == 0 ]]; do + local line='' + __ebd_read_line line + case ${line} in + start_receiving_env*) + line=${line#start_receiving_env } + case ${line} in + file*) + line=${line#file } + source "${line}" + cont=$? + ;; + bytes*) + line=${line#bytes } + __ebd_read_size "${line}" line + __IFS_push $'\0' + eval "${line}" + cont=$? + __IFS_pop + ;; + lines|*) + while __ebd_read_line line && [[ ${line} != "end_receiving_env" ]]; do + __IFS_push $'\0' + eval "${line}" + cont=$? + __IFS_pop + if [[ ${cont} != 0 ]]; then + echo "err, env receiving threw an error for '${line}': $?" >&2 + break + fi + done + ;; + esac + if [[ ${cont} != 0 ]]; then + __ebd_write_line "env_receiving_failed" + exit 1 + fi + __set_perf_debug + __ebd_write_line "env_received" + ;; + logging*) + PORTAGE_LOGFILE=${line#logging } + __ebd_write_line "logging_ack" + ;; + set_sandbox_state*) + if [[ $(( ${line:18} )) -eq 0 ]]; then + export SANDBOX_DISABLED=1 + else + export SANDBOX_DISABLED=0 + export SANDBOX_VERBOSE="no" + fi + ;; + start_processing) + if ${is_depends} && [[ -n ${PKGCORE_METADATA_PATH} ]]; then + export PATH=${PKGCORE_METADATA_PATH} + fi + cont=2 + ;; + shutdown_daemon) + break + ;; + alive) + __ebd_write_line "yep!" + ;; + *) + die "unknown phase processing com: '${line}'" + ;; + esac + done + if [[ ${cont} != 2 ]]; then + exit ${cont} + fi + + [[ -n ${PORTAGE_LOGFILE} ]] && addwrite "$(readlink -f "${PORTAGE_LOGFILE}")" + + [[ -n ${PORTAGE_TMPDIR} ]] && { + addpredict "${PORTAGE_TMPDIR}" + addwrite "${PORTAGE_TMPDIR}" + addread "${PORTAGE_TMPDIR}" + } + + local ret + umask 0022 + + if [[ -z ${PORTAGE_LOGFILE} ]]; then + __execute_phases ${phases} + ret=$? + else + __execute_phases ${phases} &> >(umask 0002; tee -i -a "${PORTAGE_LOGFILE}") + ret=$? + fi + + if [[ ${ret} -ne 0 ]]; then + __ebd_process_sandbox_results + exit ${ret} + fi + exit 0 + ) +} + +__ebd_process_metadata() { + # protect the env. + # note the local usage is redundant in light of it, but prefer to write it this + # way so that if someone ever drops the (), it'll still not bleed out. + ( + # Heavy QA checks (IFS, shopt, etc) are suppressed for speed + declare -r PKGCORE_QA_SUPPRESSED=false + # Wipe __mode; it bleeds from our parent. + unset -v __mode + local __data + local __ret + __ebd_read_size "$1" __data + local IFS=$'\0' + eval "$__data" + __ret=$? + unset -v __data + [[ ${__ret} -ne 0 ]] && exit 1 + unset -v __ret + local IFS=$' \t\n' + + if [[ -n ${PKGCORE_METADATA_PATH} ]]; then + export PATH=${PKGCORE_METADATA_PATH} + fi + + # invoked internally by bash on PATH search failure, see the bash man + # page section on command execution for details + command_not_found_handle() { + die "external commands disallowed during metadata regen: '${*}'" + } + + __execute_phases "${2:-depend}" && exit 0 + __ebd_process_sandbox_results + exit 1 + ) +} + +__make_preloaded_eclass_func() { + eval "__preloaded_eclass_$1() { + $2 + }" + PKGCORE_PRELOADED_ECLASSES[$1]=__preloaded_eclass_$1 +} + +__ebd_main_loop() { + PKGCORE_BLACKLIST_VARS+=( __mode com is_depends phases line cont ) + SANDBOX_ON=1 + while :; do + local com='' + # If we don't manage to read, this means that the other end hung up. + # exit. + __ebd_read_line_nonfatal com || com="shutdown_daemon" + case ${com} in + process_ebuild*) + # cleanse whitespace. + local phases=$(echo ${com#process_ebuild}) + __ebd_process_ebuild_phases ${phases} + if [[ $? -eq 0 ]]; then + __ebd_write_line "phases succeeded" + else + __ebd_write_line "phases failed ebd::${com% *} failed" + fi + ;; + shutdown_daemon) + break + ;; + preload_eclass\ *) + success="succeeded" + com=${com#preload_eclass } + for e in ${com}; do + x=${e##*/} + x=${x%.eclass} + if ! $(type -P bash) -n "${e}"; then + echo "errors detected in '${e}'" >&2 + success='failed' + break + fi + __make_preloaded_eclass_func "${x}" "$(< "${e}")" + done + __ebd_write_line "preload_eclass ${success}" + unset -v e x success + ;; + clear_preloaded_eclasses) + unset -v PKGCORE_PRELOADED_ECLASSES + declare -A PKGCORE_PRELOADED_ECLASSES + __ebd_write_line "clear_preloaded_eclasses succeeded" + ;; + set_metadata_path\ *) + line=${com#set_metadata_path } + __ebd_read_size "${line}" PKGCORE_METADATA_PATH + __ebd_write_line "metadata_path_received" + ;; + gen_metadata\ *|gen_ebuild_env\ *) + local __mode="depend" + local error_output + [[ ${com} == gen_ebuild_env* ]] && __mode="generate_env" + line=${com#* } + # capture sourcing stderr output + error_output=$(__ebd_process_metadata "${line}" "${__mode}" 2>&1 1>/dev/null) + if [[ $? -eq 0 ]]; then + __ebd_write_line "phases succeeded" + else + [[ -n ${error_output} ]] || error_output="ebd::${com% *} failed" + __ebd_write_line "phases failed ${error_output}" + fi + ;; + alive) + __ebd_write_line "yep!" + ;; + *) + die "unknown ebd com: '${com}'" + ;; + esac + done +} + +# start the daemon if requested +[[ $1 == "daemonize" ]] && __ebd_exec_main + +: diff --git a/data/lib/pkgcore/ebd/ebuild-default-functions.bash b/data/lib/pkgcore/ebd/ebuild-default-functions.bash new file mode 100644 index 000000000..48bad0c10 --- /dev/null +++ b/data/lib/pkgcore/ebd/ebuild-default-functions.bash @@ -0,0 +1,247 @@ +# default functions for ebuild env that aren't saved- specific to the portage instance. + +# sandbox support functions +addread() { + export SANDBOX_READ=${SANDBOX_READ}:$1 +} + +addwrite() { + export SANDBOX_WRITE=${SANDBOX_WRITE}:$1 +} + +adddeny() { + export SANDBOX_DENY=${SANDBOX_DENY}:$1 +} + +addpredict() { + export SANDBOX_PREDICT=${SANDBOX_PREDICT}:$1 +} + +__dyn_src_install() { + if __is_function src_install; then + __qa_invoke src_install + else + __qa_run_function_if_exists __phase_src_install + fi + + "${PKGCORE_EBD_PATH}"/helpers/internals/prepall + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + cd "${ED}" + + if type -p scanelf > /dev/null; then + # Make sure we disallow insecure RUNPATH/RPATH's + # Don't want paths that point to the tree where the package was built + # (older, broken libtools would do this). Also check for null paths + # because the loader will search $PWD when it finds null paths. + local f=$(scanelf -qyRF '%r %p' "${ED}" | grep -E "(${WORKDIR}|${ED}|: |::|^ )") + if [[ -n ${f} ]]; then + echo -ne '\a\n' + echo "QA Notice: the following files contain insecure RUNPATH's" + echo " Please file a bug about this at http://bugs.gentoo.org/" + echo " For more information on this issue, kindly review:" + echo " http://bugs.gentoo.org/81745" + echo "${f}" + echo -ne '\a\n' + __feature_is_enabled stricter && die "Insecure binaries detected" + echo "autofixing rpath..." + TMPDIR=${WORKDIR} scanelf -BXr ${f} -o /dev/null + fi + + # Check for setid binaries but are not built with BIND_NOW + f=$(scanelf -qyRF '%b %p' "${ED}") + if [[ -n ${f} ]]; then + echo -ne '\a\n' + echo "QA Notice: the following files are setXid, dyn linked, and using lazy bindings" + echo " This combination is generally discouraged. Try forcing via bashrc" + echo " LDFLAGS='-Wl,-z,now' for the pkg, or disable FEATURES=stricter" + echo "${f}" + echo -ne '\a\n' + __feature_is_enabled stricter && die "Aborting due to lazy bindings" + sleep 1 + fi + + # TEXTREL's are baaaaaaaad + f=$(scanelf -qyRF '%t %p' "${ED}") + if [[ -n ${f} ]]; then + echo -ne '\a\n' + echo "QA Notice: the following files contain runtime text relocations" + echo " Text relocations require a lot of extra work to be preformed by the" + echo " dynamic linker which will cause serious performance impact on IA-32" + echo " and might not function properly on other architectures hppa for example." + echo " If you are a programmer please take a closer look at this package and" + echo " consider writing a patch which addresses this problem." + echo "${f}" + echo -ne '\a\n' + __feature_is_enabled stricter && die "Aborting due to textrels" + sleep 1 + fi + + # Check for files with executable stacks + f=$(scanelf -qyRF '%e %p' "${ED}") + if [[ -n ${f} ]]; then + echo -ne '\a\n' + echo "QA Notice: the following files contain executable stacks" + echo " Files with executable stacks will not work properly (or at all!)" + echo " on some architectures/operating systems. A bug should be filed" + echo " at http://bugs.gentoo.org/ to make sure the file is fixed." + echo "${f}" + echo -ne '\a\n' + __feature_is_enabled stricter && die "Aborting due to +x stack" + sleep 1 + fi + + # Create NEEDED and NEEDED.ELF.2 files required for things like preserve-libs + # TODO: someday find a way to move this to the triggers implementation to allow + # for parallelization of the scanning- if useful. + scanelf -qyRF '%a;%p;%S;%r;%n' "${ED}" | { while IFS= read -r l; do + arch=${l%%;*}; l=${l#*;} + obj="/${l%%;*}"; l=${l#*;} + soname=${l%%;*}; l=${l#*;} + rpath=${l%%;*}; l=${l#*;}; [[ ${rpath} == " - " ]] && rpath="" + needed=${l%%;*}; l=${l#*;} + echo "${obj} ${needed}" >> "${T}"/NEEDED + echo "${arch:3};${obj};${soname};${rpath};${needed}" >> "${T}"/NEEDED.ELF.2 + done } + fi +} + +__dyn_pkg_preinst() { + if __is_function pkg_preinst; then + __qa_invoke pkg_preinst + else + __qa_run_function_if_exists __phase_pkg_preinst + fi + + ${PKGCORE_PREFIX_SUPPORT} || local ED=${D} + + # total suid control. + if __feature_is_enabled suidctl > /dev/null; then + sfconf=/etc/portage/suidctl.conf + echo ">>> Performing suid scan in ${ED}" + local i + for i in $(find "${ED}" -type f \( -perm -4000 -o -perm -2000 \) ); do + if [[ -s ${sfconf} ]]; then + suid=$(grep ^${i/${ED}/}$ "${sfconf}") + if [[ ${suid} == ${i/${ED}/} ]]; then + echo "- ${i/${ED}/} is an approved suid file" + else + echo ">>> Removing sbit on non registered ${i/${ED}/}" + chmod ugo-s "${i}" + grep ^#${i/${ED}/}$ ${sfconf} > /dev/null || { + # sandbox prevents us from writing directly + # to files outside of the sandbox, but this + # can easly be bypassed using the addwrite() function + addwrite "${sfconf}" + echo ">>> Appending commented out entry to ${sfconf} for ${PF}" + ls_ret=$(ls -ldh "${i}") + echo "## ${ls_ret%${ED}*}${ls_ret#*${ED}}" >> "${sfconf}" + echo "#${i/${ED}/}" >> "${sfconf}" + # no delwrite() eh? + # delwrite ${sconf} + } + fi + else + echo "suidctl feature set but you are lacking a ${sfconf}" + fi + done + fi + + # SELinux file labeling (needs to always be last in dyn_preinst) + if __feature_is_enabled selinux; then + # only attempt to label if setfiles is executable + # and 'context' is available on selinuxfs. + if [[ -f /selinux/context && -x /usr/sbin/setfiles ]]; then + echo ">>> Setting SELinux security labels" + if [[ -f ${POLICYDIR}/file_contexts/file_contexts ]]; then + cp -f "${POLICYDIR}"/file_contexts/file_contexts "${T}" + else + make -C "${POLICYDIR}" FC=${T}/file_contexts "${T}"/file_contexts + fi + + addwrite /selinux/context + /usr/sbin/setfiles -r "${ED}" "${T}"/file_contexts "${ED}" \ + || die "failed to set SELinux security labels" + else + # nonfatal, since merging can happen outside a SE kernel + # like during a recovery situation + echo "!!! Unable to set SELinux security labels" + fi + fi +} + +inherit() { + [[ -z $@ ]] && die "${FUNCNAME}: missing eclass argument" + local INHERIT_DEPTH=$(( ${INHERIT_DEPTH-0} + 1 )) + + if [[ ${INHERIT_DEPTH} -gt 1 ]]; then + debug-print "*** Multiple Inheritance (level: ${INHERIT_DEPTH})" + fi + + local location olocation + local ECLASS + + # note that this ensures any later unsets/mangling, the ebuilds original + # setting is protected. + local IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND BDEPEND IDEPEND + if ${PKGCORE_ACCUMULATE_PROPERTIES_RESTRICT}; then + local PROPERTIES RESTRICT + fi + + # keep track of direct ebuild inherits + [[ ${INHERIT_DEPTH} -eq 1 ]] && INHERIT+=" $@" + + for ECLASS in "$@"; do + if [[ ${EBUILD_PHASE} != "depend" ]]; then + if ! __safe_has "${ECLASS}" ${INHERITED}; then + echo + echo "QA Notice: ECLASS '${ECLASS}' illegal conditional inherit in ${CATEGORY}/${PF}" >&2 + echo + fi + fi + + unset -v IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND BDEPEND IDEPEND + if ${PKGCORE_ACCUMULATE_PROPERTIES_RESTRICT}; then + unset -v PROPERTIES RESTRICT + fi + + __internal_inherit "$1" || die "${FUNCNAME}: failed sourcing $1" + + # If each var has a value, append it to the global variable E_* to + # be applied after everything is finished. New incremental behavior. + [[ -n ${IUSE} ]] && E_IUSE+=${E_IUSE:+ }${IUSE} + [[ -n ${REQUIRED_USE} ]] && E_REQUIRED_USE+=${E_REQUIRED_USE:+ }${REQUIRED_USE} + [[ -n ${DEPEND} ]] && E_DEPEND+=${E_DEPEND:+ }${DEPEND} + [[ -n ${RDEPEND} ]] && E_RDEPEND+=${E_RDEPEND:+ }${RDEPEND} + [[ -n ${PDEPEND} ]] && E_PDEPEND+=${E_PDEPEND:+ }${PDEPEND} + [[ -n ${BDEPEND} ]] && E_BDEPEND+=${E_BDEPEND:+ }${BDEPEND} + [[ -n ${IDEPEND} ]] && E_IDEPEND+=${E_IDEPEND:+ }${IDEPEND} + if ${PKGCORE_ACCUMULATE_PROPERTIES_RESTRICT}; then + [[ -n ${PROPERTIES} ]] && E_PROPERTIES+=${E_PROPERTIES:+ }${PROPERTIES} + [[ -n ${RESTRICT} ]] && E_RESTRICT+=${E_RESTRICT:+ }${RESTRICT} + fi + + # while other PMs have checks to keep this unique, we don't; no need, + # further up the stack (python side) we uniquify this. + # if you try to do it in bash rather than python, it's ~10% slower regen + INHERITED+=" ${ECLASS}" + + shift + done +} + +# Exports stub functions that call the eclass's functions, thereby making them default. +# For example, if ECLASS="base" and you call "EXPORT_FUNCTIONS src_unpack", the following +# code will be eval'd: +# src_unpack() { base_src_unpack; } +EXPORT_FUNCTIONS() { + if [[ -z ${ECLASS} ]]; then + die "EXPORT_FUNCTIONS without a defined ECLASS" + fi + local phase_func + for phase_func in $*; do + debug-print "EXPORT_FUNCTIONS: ${phase_func} -> ${ECLASS}_${phase_func}" + eval "${phase_func}() { ${ECLASS}_${phase_func} "\$@" ; }" > /dev/null + done +} + +: diff --git a/data/lib/pkgcore/ebd/ebuild-env-utils.bash b/data/lib/pkgcore/ebd/ebuild-env-utils.bash new file mode 100644 index 000000000..04e99c3c3 --- /dev/null +++ b/data/lib/pkgcore/ebd/ebuild-env-utils.bash @@ -0,0 +1,136 @@ +# this functionality is all related to saving/loading environmental dumps for ebuilds + +__regex_filter_input() { + # We don't need to reset IFS in this context, thus skip the pop. + local IFS='|' + local regex="^(${*})$" + # use egrep if possible... tis faster. + local l ret=0 + if l=$(type -P gsed || type -P sed); then + "${l}" -re "/${regex}/d" + ret=$? + [[ ${ret} != 0 ]] && die "got failing return code (${ret}) invoking ${l} -e '/${regex}/d'" + elif l=$(type -P egrep); then + # use type -p; qa_interceptors may be active. + "${l}" -v "${regex}" + ret=$? + # return status is 1 for no matches and 2 for errors + [[ ${ret} -gt 1 ]] && die "got failing return code (${ret}) ${l} -v '${regex}'" + ret=0 # reset the return status if there are no matches, it isn't an error + else + while read l; do + [[ ${l} =~ ${regex} ]] || echo "${l}" + done + fi + return ${ret} +} + +__escape_regex_array() { + local __tmp_array + # Need to get the content of the original array... + eval "__tmp_array=( \"\${$1[@]}\" )" + __tmp_array=( "${__tmp_array[@]//\+/\\+}" ) + __tmp_array=( "${__tmp_array[@]//\./\\.}" ) + __tmp_array=( "${__tmp_array[@]//\*/\\*}" ) + # Now transfer the content back. + eval $1='( "${__tmp_array[@]}" )' +} &> /dev/null + +__filter_env() { + local opts + [[ ${PKGCORE_DEBUG} -ge 1 ]] && opts="--debug" + __ebd_ipc_cmd "filter_env" "${opts}" "$@" +} + +# selectively saves the environ- specifically removes things that have been marked to not be exported. +# dump the environ to stdout. +__environ_dump() { + __shopt_push -f + + # dump variables first so no local variables get picked up + local exported_vars=( $(compgen -v | __regex_filter_input ${PKGCORE_BLACKLIST_VARS[@]}) ) + if [[ ${#exported_vars[@]} -ne 0 ]]; then + declare -p "${exported_vars[@]}" || die "failed outputting env vars ${exported_vars[@]}" + fi + + local func_filters=( "${PKGCORE_BLACKLIST_FUNCS[@]}" ${PKGCORE_EAPI_FUNCS} "${PKGCORE_PRELOADED_ECLASSES[@]}" ) + + # Punt any regex chars... + __escape_regex_array func_filters + local exported_funcs=( $(compgen -A function | __regex_filter_input "${func_filters[@]}" ) ) + if [[ ${#exported_funcs[@]} -ne 0 ]]; then + declare -f "${exported_funcs[@]}" || die "failed outputting funcs ${exported_funcs[@]}" + fi + + __shopt_pop +} + +# dump environ to $1, optionally piping it through $2 and redirecting $2's output to $1. +__environ_save_to_file() { + if [[ $# -ne 1 && $# -ne 2 ]]; then + die "${FUNCNAME}: requires at least one argument, two max; got $@" + fi + + if [[ $# -eq 1 ]]; then + __environ_dump > "$1" + else + __environ_dump | $2 > "$1" + fi + chown portage:portage "$1" &> /dev/null + chmod 0664 "$1" &> /dev/null +} + +# reload a saved env, applying usual filters to the env prior to eval'ing it. +__environ_sanitize_saved_env() { + if [[ $# -ne 1 ]]; then + die "scrub_environ called with wrong args, only one can be given: $@" + fi + + [[ ! -f $1 ]] && die "${FUNCNAME}: called with a nonexist env: $1" + + # here's how this goes; we do an eval'd loadup of the target env w/in a subshell.. + # declares and such will slide past filter-env (so it goes). we then use our own + # __environ_dump from within to get a clean dump from that env, and load it into + # the parent eval. + ( + # protect the core vars and functions needed to do a __environ_dump + # some of these are already readonly- we still are forcing it to be safe. + readonly PKGCORE_EXISTING_PATH SANDBOX_ON T + readonly -a PKGCORE_BLACKLIST_VARS PKGCORE_BLACKLIST_FUNCS + readonly -f __filter_env __environ_dump __regex_filter_input + + __shopt_push -f + IFS=$' \t\n' + declare -a PKGCORE_FUNC_ARRAY=( "${PKGCORE_BLACKLIST_FUNCS[@]}" ) + declare -a PKGCORE_VAR_ARRAY=( "${PKGCORE_BLACKLIST_VARS[@]}" ) + IFS=, + PKGCORE_FUNC_ARRAY=${PKGCORE_FUNC_ARRAY[*]} + PKGCORE_VAR_ARRAY=${PKGCORE_VAR_ARRAY[*]} + IFS=$' \t\n' + __shopt_pop + + rm -f "${T}"/.pre-scrubbed-env || die "failed rm'ing" + # run the filtered env. + __filter_env \ + --funcs "${PKGCORE_FUNC_ARRAY}" \ + --vars "${PKGCORE_VAR_ARRAY}" \ + "$1" "${T}"/.pre-scrubbed-env \ + || die "failed first step of scrubbing the env to load" + + [[ -s ${T}/.pre-scrubbed-env ]] || die "empty pre-scrubbed-env file, pkgcore bug?" + source "${T}"/.pre-scrubbed-env >&2 || die "failed sourcing scrubbed env" + + # ok. it's loaded into this subshell... now we use our dump mechanism (which we trust) + # to output it- this mechanism is far more bulletproof then the load filtering (since + # declare and friends can set vars via many, many different ways), thus we use it + # as the final filtering. + rm -f "${T}"/.scrubbed-env + __environ_dump > "${T}"/.scrubbed-env || die "dumping environment failed" + ) && return + + echo "die 'failed parsing the env dump'" # yep, we're injecting code into the eval. + exit 1 + # note no die usage here... exit instead, since we don't want another tb thrown +} + +: diff --git a/data/lib/pkgcore/ebd/ebuild.bash b/data/lib/pkgcore/ebd/ebuild.bash new file mode 100644 index 000000000..9bcabd48d --- /dev/null +++ b/data/lib/pkgcore/ebd/ebuild.bash @@ -0,0 +1,531 @@ +# ebuild phase processing, env handling + +# general phase execution path- __execute_phases is called, which sets EBUILD_PHASE, and then +# depending on the phase, loads or initializes. Env is init'd for non src based stages if the env +# isn't found- otherwise it loads the environ via __load_environ call. In cases where env isn't +# found for phases setup -> merge, it bails (theres no way the env should be missing- exemption is +# setup phase). +# +# for env filtering for restoration and reloading, note the updates to PKGCORE_BLACKLIST_(VARS|FUNCS). +# those vars are basically used to track what shouldn't be saved/restored. Whitespace separated, +# those vars can support posix (think egrep) regex. They should hold all vars/funcs that are +# internal ebd vars. Basically, filter all vars/funcs that are specific to ebd, not the ebuild. +# +# after loading the env, user defined pre hooks are executed, __dyn_${EBUILD_PHASE} is executed, and +# the post hooks are executed. If the env needs to be flushed to disk, PKGCORE_MUST_EXPORT_ENV is +# set to "yes", and __execute_phases will dump it to ${T}/environment. +# +# few notes on general env stuff- if it's not ebuild specific or a user option, it's typically +# marked readonly. This limits users, but also helps to ensure that reloaded envs from older +# portages don't overwrite an internal ebd.sh function that has since changed. + +PKGCORE_BLACKLIST_VARS=( + # bash-related + $(compgen -v) "BASH_.*" COLUMNS OLDPWD + + # external programs + "SANDBOX_.*" "CCACHE.*" "DISTCC.*" "SUDO_.*" + + # internals + "___.*" "PKGCORE_.*" ret + + # portage-compat + "PORTAGE_.*" "EMERGE_.*" FEATURES EMERGE_FROM + "RSYNC_.*" GENTOO_MIRRORS + "(DIST|FILES|RPM|ECLASS)DIR" + "ACCEPT_(PROPERTIES|RESTRICT)" + "(RESUME|FETCH)COMMAND(_.*)?" XARGS SYNC DIR + "ACCEPT_(KEYWORDS|LICENSE)" + "PORT(_LOGDIR|DIR(_OVERLAY)?)" "PROFILE_.*" ECLASS TMP + + # PMS + CATEGORY PF P PN PV PR PVR EBUILD A EBUILD_PHASE + T WORKDIR D ED ROOT EROOT EPREFIX HOME "USE_EXPAND_.*" + MERGE_TYPE REPLACING_VERSIONS REPLACED_BY_VERSION +) + +if [[ -z ${PKGCORE_EBD_PATH} ]]; then + echo "PKGCORE_EBD_PATH is unset!" + exit 1 +fi + +# knock the sandbox vars back to the pkgs defaults. +__reset_sandbox() { + export SANDBOX_ON=1 + export SANDBOX_PREDICT=${SANDBOX_PREDICT:+${SANDBOX_PREDICT}:}/proc/self/maps:/dev/console:/dev/random:${PORTAGE_TMPDIR} + export SANDBOX_WRITE=${SANDBOX_WRITE:+${SANDBOX_WRITE}:}/dev/shm:${PORTAGE_TMPDIR} + export SANDBOX_READ=${SANDBOX_READ:+${SANDBOX_READ}:}/dev/shm:${PORTAGE_TMPDIR} + local var + for var in CCACHE_DIR DISTCC_DIR D WORKDIR T; do + if [[ -n ${!var} ]]; then + addread "${!var}" + addwrite "${!var}" + fi + done +} + +# Prevent aliases from causing portage to act inappropriately. +# Make sure it's before everything so we don't mess aliases that follow. +unalias -a + +# This is needed for calling __load_environ, __load_safe_environ, and +# __init_environ. If those can ever be moved into functions this can be +# dropped. +shopt -s expand_aliases + +# Unset some variables that break things. +unset -v GZIP BZIP BZIP2 CDPATH GREP_OPTIONS GREP_COLOR GLOB_IGNORE + +# gentoo bug 309369; nasty alias, but it exists due to portage using declare's +# in env dumping. declare statements are implicitly local. as such, the +# sourcing statement has to be in the same scope as the invoker of +# __load_environ for that scope to get the changes +alias __load_environ='{ + [[ -z ${PKGCORE_TARGET_ENV} ]] && die "__load_environ was invoked w/out PKGCORE_TARGET_ENV set"; + [[ -z ${T} ]] && die "__load_environ requires \$T to be set"; + PKGCORE_EXISTING_PATH=${PATH}; + __timed_call __environ_sanitize_saved_env "${PKGCORE_TARGET_ENV}" + if [[ -n ${PKGCORE_PERF_DEBUG} ]]; then + echo "timing source ${PKGCORE_TARGET_ENV}" >&2 + time source "${PKGCORE_TARGET_ENV}" >&2 + echo "timed source ${PKGCORE_TARGET_ENV}" >&2 + else + source "${PKGCORE_TARGET_ENV}" >&2 + fi + [[ $? == 0 ]] || die "sourcing saved env failed"; + __ensure_PATH "${PKGCORE_EXISTING_PATH}"; + __timed_call __load_eapi_libs + __timed_call __source_bashrcs + unset -v PKGCORE_EXISTING_PATH; +}' + +# Invoke this when we know that this version of pkgcore generated the env dump; +# this bypasses the safeties in loading. +alias __load_safe_environ='{ + [[ -z ${PKGCORE_TARGET_ENV} ]] && die "__load_safe_environ was invoked w/out PKGCORE_TARGET_ENV set"; + [[ -z ${T} ]] && die "__load_safe_environ requires \$T to be set"; + PKGCORE_EXISTING_PATH=${PATH}; + if [[ -n ${PKGCORE_PERF_DEBUG} ]]; then + echo "timing source ${PKGCORE_TARGET_ENV}" >&2 + time source "${PKGCORE_TARGET_ENV}" >&2 + echo "timed source ${PKGCORE_TARGET_ENV}" >&2 + else + source "${PKGCORE_TARGET_ENV}" >&2 + fi + [[ $? == 0 ]] || die "sourcing saved env failed"; + __ensure_PATH "${PKGCORE_EXISTING_PATH}"; + __timed_call __load_eapi_libs + __timed_call __source_bashrcs + unset -v PKGCORE_EXISTING_PATH; +}' + +alias __init_environ='{ + PKGCORE_EXISTING_PATH=${PATH}; + __timed_call __load_eapi_libs + if [[ -n ${PKGCORE_PERF_DEBUG} ]]; then + echo "timing eval \$(__generate_initial_ebuild_environ)" >&2 + time eval "$(__timed_call __generate_initial_ebuild_environ)" >&2 + echo "timed eval \$(__generate_initial_ebuild_environ)" >&2 + else + eval "$(__generate_initial_ebuild_environ)" + fi + [[ $? == 0 ]] || die "failed loading initialized environment"; + __ensure_PATH "${PKGCORE_EXISTING_PATH}"; + __timed_call __source_bashrcs + unset -v PKGCORE_EXISTING_PATH; +}' + +shopt -s extdebug &> /dev/null + +# if no perms are specified, dirs/files will have decent defaults +# (not secretive, but not stupid) +umask 022 + +# the sandbox is disabled by default except when overridden in the relevant stages +export SANDBOX_ON=0 + +# Used to track if we're subshelled w/in the main ebd instance, or if we're in +# a literal child process. +PKGCORE_IS_NOT_HELPER=1 + +# ensure the passed in PATH has its components in $PATH and that they aren't +# overridden by new entries +__ensure_PATH() { + local existing_path=$1 + local adds + # note this isolates the adds in the same order they appear in + # the passed in path, maintaining that order. + if [[ ${existing_path} != ${PATH} ]]; then + local IFS=: + local p + for p in ${existing_path}; do + # keep in mind PATH=":foon" is a valid way to say "cwd" + [[ -z ${p} ]] && continue + if ! __safe_has "${p}" ${PATH} && ! __safe_has "${p}" ${adds}; then + adds=${adds:+${adds}:}${p} + fi + done + [[ -n ${adds} ]] && PATH=${adds}${PATH:+:${PATH}} + fi + export PATH +} + +__load_eapi_libs() { + # reload depend; while it may've been loaded already, reload it so that callers can + # rely on this setting the env up as necessary + # finally, update the filters with functionality loaded from here- + # always, always, *always* use our own functionality + source "${PKGCORE_EBD_PATH}"/eapi/common.bash \ + || die "failed sourcing eapi/common.bash" + + # load global scope EAPI functions + source "${PKGCORE_EBD_PATH}"/.generated/libs/${EAPI}/global \ + || die "failed sourcing EAPI ${EAPI} global scope lib" +} + +# do all profile, bashrc's, and ebuild sourcing. Should only be called in setup phase, unless the +# env is *completely* missing, as it is occasionally for ebuilds during prerm/postrm. +__generate_initial_ebuild_environ() { + local ORIG_CC=${CC} + local ORIG_CXX=${CXX} + local PKGCORE_EXISTING_PATH=${PATH} + local T=${T} + + if [[ ${EBUILD_PHASE} == "setup" ]]; then + # we specifically save the env so it's not stomped on by sourcing. + # bug 51552 + __timed_call __environ_save_to_file "${T}"/.temp_env + + # restore the saved env vars. + PKGCORE_SUPPRESS_BASHRCS=true + PKGCORE_TARGET_ENV=${T}/.temp_env + if ! __load_environ; then + # this shouldn't happen. + die "failed to load '${T}/.temp_env' -- fs is readonly?" + fi + unset -v PKGCORE_SUPPRESS_BASHRCS + + rm "${T}"/.temp_env + fi + + [[ -n ${EBUILD} ]] && __timed_call __load_ebuild "${EBUILD}" + + if [[ ${EBUILD_PHASE} != "depend" ]]; then + RESTRICT=${PKGCORE_FINALIZED_RESTRICT} + unset -v PKGCORE_FINALIZED_RESTRICT + unset -v CC CXX + [[ -n ${ORIG_CC} ]] && export CC=${ORIG_CC} + [[ -n ${ORIG_CXX} ]] && export CXX=${ORIG_CXX} + unset -v ORIG_CC ORIG_CXX + fi + + __ensure_PATH "${PKGCORE_EXISTING_PATH}" + if [[ -n ${T} && ${EBUILD_PHASE} != "pretend" ]]; then + # Use a file if possible; faster since bash does this lovely byte by + # byte reading if it's a pipe. Having the file around is useful for + # debugging also. + __timed_call __environ_save_to_file "${T}"/.initial_environ || die "failed dumping env to '${T}/.initial_environ'" + echo "source \"${T}\"/.initial_environ" + else + __timed_call __environ_dump || die "failed dumping env" + fi +} + +# Set up the bash version compatibility level. This does not disable features +# when running with a newer version, but makes it so that when bash changes +# behavior in an incompatible way, the older behavior is used instead. +__export_bash_compat() { + [[ -z ${PKGCORE_BASH_COMPAT} ]] && die "PKGCORE_BASH_COMPAT isn't set!" + + # Set compat level only for the ebuild environment, this won't affect + # external shell scripts. + __var_push -n BASH_COMPAT=${PKGCORE_BASH_COMPAT} + + # BASH_COMPAT was introduced in bash-4.3, for older versions a compat + # option must be used. + if [[ ${PKGCORE_BASH_COMPAT} == "3.2" && ${BASH_VERSINFO[0]} -gt 3 ]]; then + __shopt_push -s compat32 + fi + + # Explicitly set shell option (it's automatically enabled by setting + # BASH_COMPAT) so it gets properly disabled once leaving scope. Otherwise, + # __qa_invoke() can throw warnings when the compat42 option enabled + # internally by bash bleeds out of scope which seems to be caused when + # ebuilds or eclasses alter shopt options. + [[ ${PKGCORE_BASH_COMPAT} == "4.2" ]] && __shopt_push -s compat42 +} + +__load_ebuild() { + local EBUILD=$1 + [[ -f ${EBUILD} ]] || die "nonexistent ebuild: '${EBUILD}'" + shift + + SANDBOX_ON=1 + export S=${WORKDIR}/${P} + + unset -v IUSE REQUIRED_USE DEPEND RDEPEND PDEPEND BDEPEND IDEPEND + local E_IUSE E_REQUIRED_USE E_DEPEND E_RDEPEND E_PDEPEND E_BDEPEND E_IDEPEND + if ${PKGCORE_ACCUMULATE_PROPERTIES_RESTRICT}; then + unset -v PROPERTIES RESTRICT + local E_PROPERTIES E_RESTRICT + fi + + __env_push + __export_bash_compat + + # EAPI 6 and up raise expansion errors on failed globbing in global scope. + ${PKGCORE_GLOBAL_FAILGLOB} && __shopt_push -s failglob + + __qa_invoke source "${EBUILD}" + if [[ $? != 0 ]]; then + # rerun source in a subshell to capture stderr + local error_msg="error sourcing ebuild" + local source_err=$(__qa_invoke source "${EBUILD}" 2>&1) + [[ -n ${source_err} ]] && error_msg+="\n\n${source_err}" + die "${error_msg}" + fi + + __env_pop + + # a reasonable default for $S + if [[ -z ${S} ]]; then + export S=${WORKDIR}/${P} + fi + + # Note that this is not the same as `export RDEPEND=${RDEPEND:-${DEPEND}}` + # That will test for unset *or* NULL (""), we want just to set if unset. + if __safe_has "${EAPI}" 0 1 2 3; then + if [[ ${RDEPEND-unset} == "unset" ]]; then + export RDEPEND=${DEPEND} + fi + fi + + # add in dependency info from eclasses + IUSE+=${IUSE:+ }${E_IUSE} + REQUIRED_USE+=${REQUIRED_USE:+ }${E_REQUIRED_USE} + DEPEND+=${DEPEND:+ }${E_DEPEND} + RDEPEND+=${RDEPEND:+ }${E_RDEPEND} + PDEPEND+=${PDEPEND:+ }${E_PDEPEND} + BDEPEND+=${BDEPEND:+ }${E_BDEPEND} + IDEPEND+=${IDEPEND:+ }${E_IDEPEND} + if ${PKGCORE_ACCUMULATE_PROPERTIES_RESTRICT}; then + PROPERTIES+=${PROPERTIES:+ }${E_PROPERTIES} + RESTRICT+=${RESTRICT:+ }${E_RESTRICT} + fi +} + +# short version. think these should be sourced via at the daemon's choice, rather then defacto. +# note that exit-handling loads the die functions, thus the custom failure there. +source "${PKGCORE_EBD_PATH}"/exit-handling.bash >&2 || { echo "ERROR: failed sourcing exit-handling.bash"; exit -1; } +source "${PKGCORE_EBD_PATH}"/ebuild-default-functions.bash >&2 || die "failed sourcing ebuild-default-functions.bash" +source "${PKGCORE_EBD_PATH}"/ebuild-env-utils.bash >&2 || die "failed sourcing ebuild-env-utils.bash" + +__run_ebuild_phase() { + [[ ${PKGCORE_DEBUG} -ge 2 ]] && set -x + + # some users have $TMP/$TMPDIR to a custom dir in their home ... + # this will cause sandbox errors with some ./configure + # scripts, so set it to $T. + local -x TMP=${T} + local -x TMPDIR=${T} + + __env_push + __export_bash_compat + ${PKGCORE_EBUILD_PHASE_FUNC} && __var_push -n EBUILD_PHASE_FUNC=$1 + + # die when encountering unknown commands + command_not_found_handle() { + local msg="${EBUILD_PHASE_FUNC}(): unknown command '$1'" + [[ $# -gt 1 ]] && msg+=" when executing: '$*'" + if ${PKGCORE_NONFATAL}; then + eerror "${msg}" + return 1 + fi + die "${msg}" + } + + # load phase scope EAPI functions + source "${PKGCORE_EBD_PATH}"/.generated/libs/${EAPI}/$1 \ + || die "failed sourcing EAPI ${EAPI} $1 phase scope lib" + + cd "${PKGCORE_EMPTYDIR}" || die "unable to cd into ${PKGCORE_EMPTYDIR}" + __qa_run_function_if_exists __phase_pre_$1 + __qa_run_function_if_exists pre_$1 + + if __is_function __dyn_$1; then + __dyn_$1 + elif __is_function $1; then + __qa_invoke $1 + else + __qa_run_function_if_exists __phase_$1 + fi + + __qa_run_function_if_exists post_$1 + __qa_run_function_if_exists __phase_post_$1 + + __env_pop + + # don't leak func to exported env + unset -f command_not_found_handle + + [[ ${PKGCORE_DEBUG} -lt 4 ]] && set +x +} + +# general func to call for phase execution. this handles necessary env +# loading/dumping, and executing pre/post/dyn calls. +__execute_phases() { + local PKGCORE_DIE_OUTPUT_DETAILS PKGCORE_SUPPRESS_BASHRCS + local PKGCORE_SAVE_ENV PKGCORE_TARGET_ENV PKGCORE_MUST_EXPORT_ENV=false + + # give us pretty tracebacks. + shopt -s extdebug + + trap "exit 2" SIGINT + trap "exit 9" SIGQUIT + trap "exit 1" SIGTERM + declare -rx PKGCORE_EBUILD_PROCESS_PID=${BASHPID} + + local ret + for EBUILD_PHASE in $*; do + PKGCORE_SAVE_ENV=true + PKGCORE_DIE_OUTPUT_DETAILS=true + PKGCORE_SUPPRESS_BASHRCS=false + + case ${EBUILD_PHASE} in + nofetch|pretend) + PKGCORE_SUPPRESS_BASHRCS=true + __init_environ + + PKGCORE_DIE_OUTPUT_DETAILS=false + __run_ebuild_phase pkg_${EBUILD_PHASE} + PKGCORE_SAVE_ENV=false + ret=0 + ;; + prerm|postrm|preinst|postinst|config) + [[ ${EBUILD_PHASE} == postrm ]] && PKGCORE_SAVE_ENV=false + export SANDBOX_ON=0 + + PKGCORE_TARGET_ENV=${T}/environment + __load_environ || die "failed loading env during ${EBUILD_PHASE} phase" + + __run_ebuild_phase pkg_${EBUILD_PHASE} + ret=0 + ;; + unpack|prepare|configure|compile|test|install) + if [[ ${SANDBOX_DISABLED=0} == 0 ]]; then + export SANDBOX_ON=1 + else + export SANDBOX_ON=0 + fi + + [[ ${PKGCORE_DEBUG} -ge 3 ]] && set -x + PKGCORE_TARGET_ENV=${T}/environment + __load_safe_environ || die "failed loading env during ${EBUILD_PHASE} phase" + [[ -z ${S} ]] && die "\$S was null, path=${PATH}" + + __run_ebuild_phase src_${EBUILD_PHASE} + ret=0 + ;; + setup|setup-binpkg) + EBUILD_PHASE="setup" + + # binpkgs don't need to reinitialize the env. + if [[ ${EBUILD_PHASE} == "setup" ]]; then + [[ -n ${DISTCC_LOG} ]] && addwrite "$(dirname ${DISTCC_LOG})" + + if __feature_is_enabled ccache; then + export CCACHE_DIR + [[ -n ${CCACHE_SIZE} ]] && ccache -M ${CCACHE_SIZE} &> /dev/null + fi + + [[ ${PKGCORE_DEBUG} -ge 2 ]] && set -x + __init_environ + else + PKGCORE_TARGET_ENV=${T}/environment + __load_environ || die "failed loading env during ${EBUILD_PHASE} phase" + fi + + # pkg_setup needs to be run outside the sandbox for tmp file + # creation; for example, awking and piping a file in /tmp + # requires a temp file to be created in /etc. If pkg_setup is + # in the sandbox, both our lilo and apache ebuilds break. + export SANDBOX_ON=0 + + __run_ebuild_phase pkg_${EBUILD_PHASE} + ret=0; + ;; + depend|generate_env) + SANDBOX_ON=1 + PKGCORE_SAVE_ENV=false + + PKGCORE_DIE_OUTPUT_DETAILS=false + + __timed_call __load_eapi_libs + __load_ebuild "${EBUILD}" + + if [[ ${EBUILD_PHASE} == depend ]]; then + __dump_metadata_keys + else + # Use gawk if at possible; it's a fair bit faster since + # bash likes to do byte by byte reading. + local __path + __path=$(PATH=/usr/bin:/bin type -P gawk) + if [[ $? == 0 ]]; then + { unset -v __path; __environ_dump; } | \ + LC_ALL=C "${__path}" -F $'\0' 'BEGIN { content="";chars=0;RS="\0";ORS=""} {chars += length($0);content = content $0} END {printf("receive_env %i\n%s",chars, content)}' >&${PKGCORE_EBD_WRITE_FD} + else + local my_env=$(__environ_dump) + __ebd_write_line "receive_env ${#my_env}" + __ebd_write_raw "${my_env}" + unset -v my_env __path + fi + fi + ;; + *) + die "invalid command: ${EBUILD_PHASE}" + ;; + esac + + ${PKGCORE_SAVE_ENV} && PKGCORE_MUST_EXPORT_ENV=true + [[ ${PKGCORE_DEBUG} -lt 4 ]] && set +x + done + + if ${PKGCORE_MUST_EXPORT_ENV}; then + __timed_call __environ_save_to_file "${T}"/environment + fi + return ${ret:-0} +} + +__dump_metadata_keys() { + # note this function does /not/ use shopt pushing/popping; it should only + # be invoked after ebuild code has done it's thing, as such we no longer care, + # and directly screw w/ it for speed reasons- about 5% speedup in metadata regen. + set -f + local key phases phase + for key in "${PKGCORE_METADATA_KEYS[@]}"; do + if [[ ${key} == DEFINED_PHASES ]]; then + for phase in "${PKGCORE_EBUILD_PHASES[@]}"; do + __is_function "${phase}" && phases+=( ${phase} ) + done + __ebd_write_line "key DEFINED_PHASES=${phases[@]:--}" + else + # deref the val, if it's not empty/unset, then spit a key command to EBD + # after using echo to normalize whitespace (specifically removal of newlines) + if [[ ${!key:-unset} != "unset" ]]; then + # note that we explicitly bypass the normal functions, and directly + # write to the FD. This is done since it's about 25% faster for our usage; + # if we used the functions, we'd have to subshell the 'echo ${!key}', which + # because of bash behaviour, means the content would be read byte by byte. + echo -n "key ${key}=" >&${PKGCORE_EBD_WRITE_FD} + echo ${!key} >&${PKGCORE_EBD_WRITE_FD} + fi + fi + done + set +f +} + +set +f + +export XARGS +set +H -h +: diff --git a/data/lib/pkgcore/ebd/exit-handling.bash b/data/lib/pkgcore/ebd/exit-handling.bash new file mode 100644 index 000000000..cecbbab49 --- /dev/null +++ b/data/lib/pkgcore/ebd/exit-handling.bash @@ -0,0 +1,122 @@ +# Exit handling functions for the ebuild environment + +# Check whether any command in the most recently executed foreground pipe +# returned non-zero and if so calls die passing along any given parameters. +assert() { + local pipestatus=${PIPESTATUS[*]} + [[ -z ${pipestatus//[ 0]*/} ]] || die "$@ (pipestatus: ${pipestatus})" +} + +# Abort the current build process (see PMS for details). +die() { + set +x + # if we were signaled to die... + if [[ -n ${EBD_DISABLE_DIEFUNC} ]]; then + return + fi + + if [[ ${PKGCORE_NONFATAL_DIE} && $1 == "-n" ]]; then + shift + if ${PKGCORE_NONFATAL}; then + [[ $# -gt 0 ]] && eerror "$*" + return 1 + fi + fi + + # Notify the python side we're dying so it should handle cleanup, + # this forces die() to work in subshell environments. + __ebd_write_line "dying ${PORTAGE_LOGFILE}" + + # Send any error messages back to python for output. + exec 2>&${PKGCORE_EBD_WRITE_FD} + + local n filespacing=0 linespacing=0 sourcefile lineno + # setup spacing to make output easier to read + for (( n = ${#FUNCNAME[@]} - 1 ; n >= 0 ; --n )); do + sourcefile=${BASH_SOURCE[${n}]} sourcefile=${sourcefile##*/} + lineno=${BASH_LINENO[${n}]} + (( filespacing < ${#sourcefile} )) && filespacing=${#sourcefile} + (( linespacing < ${#lineno} )) && linespacing=${#lineno} + done + + local phase_str= + [[ -n ${EBUILD_PHASE} ]] && phase_str=" (${EBUILD_PHASE} phase)" + eerror "ERROR: ${CATEGORY}/${PF}::${PKGCORE_PKG_REPO} failed${phase_str}:" + + # split error message by newline so every line gets prefixed properly + local line + echo -e "${@:-(no error message)}" | while IFS= read -r line; do + eerror " ${line}" + done + + if [[ -n ${PKGCORE_IS_NOT_HELPER} ]]; then + eerror + __dump_trace 2 ${filespacing} ${linespacing} >&2 + eerror " $(printf "%${filespacing}s" "${BASH_SOURCE[1]##*/}"), line $(printf "%${linespacing}s" "${BASH_LINENO[0]}"): called die" + fi + if ${PKGCORE_DIE_OUTPUT_DETAILS-true}; then + if [[ -n ${PKGCORE_IS_NOT_HELPER} ]]; then + eerror + eerror "If you need support, post the topmost build error, and the call stack if relevant." + fi + local hook + for hook in ${EBUILD_DEATH_HOOKS}; do + ${hook} >&2 1>&2 + done + fi + + local working_dir=$(pwd) + if [[ ${PKGCORE_EBD_PATH} != ${working_dir} ]]; then + eerror + eerror "Working directory: '${working_dir}'" + fi + + __ebd_write_line "dead" + exit 1 +} + +# usage- first arg is the number of funcs on the stack to ignore. +# defaults to 1 (ignoring __dump_trace) +# whitespacing for filenames +# whitespacing for line numbers +__dump_trace() { + declare -i strip=${1:-1} + local filespacing=$2 linespacing=$3 + local n p + + (( n = ${#FUNCNAME[@]} - 1 )) + (( p = ${#BASH_ARGV[@]} )) + # Drop internals up to the __qa_invoke() call when debugging isn't enabled. + if [[ -z ${PKGCORE_DEBUG} ]]; then + while (( n > 0 )); do + [[ ${FUNCNAME[${n}]} == __qa_invoke ]] && break + (( p -= ${BASH_ARGC[${n} - 1]} )) + (( n-- )) + done + if (( n == 0 )); then + (( n = ${#FUNCNAME[@]} - 1 )) + (( p = ${#BASH_ARGV[@]} )) + fi + fi + + eerror "Call stack:" + local funcname= sourcefile= lineno= + for (( n; n > ${strip}; n-- )); do + funcname=${FUNCNAME[${n} - 1]} + sourcefile=${BASH_SOURCE[${n}]##*/} + lineno=${BASH_LINENO[${n} - 1]} + # Display function arguments + local args= newargs= + local j + if [[ ${#BASH_ARGV[@]} -gt 0 ]]; then + for (( j = 0 ; j < ${BASH_ARGC[${n} - 1]} ; ++j )); do + newargs=${BASH_ARGV[$(( p - j - 1 ))]} + args="${args:+${args} }'${newargs}'" + done + (( p -= ${BASH_ARGC[${n} - 1]} )) + fi + eerror " $(printf "%${filespacing}s" "${sourcefile}"), line $(printf "%${linespacing}s" "${lineno}"): called ${funcname}${args:+ ${args}}" + done +} + +: diff --git a/data/lib/pkgcore/ebd/generate_eapi_cmd_list b/data/lib/pkgcore/ebd/generate_eapi_cmd_list new file mode 100755 index 000000000..f8e49404c --- /dev/null +++ b/data/lib/pkgcore/ebd/generate_eapi_cmd_list @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +# +# Generate the list of banned or deprecated commands specific to an EAPI version. +# +# Outputs the list of banned commands for a given EAPI by default. The -b and +# -d options can be used to output only the banned or deprecated commands, +# respectively. The -o option limits command scanning to the single, specified +# EAPI instead of cumulatively building up the command list from inherited +# EAPIs. + +ONLY=false +BANNED=false +DEPRECATED=false +INTERNAL=false + +while getopts "bdio" opt; do + case ${opt} in + b) BANNED=true ;; + d) DEPRECATED=true ;; + i) INTERNAL=true ;; + o) ONLY=true ;; + *) ;; + esac +done + +# default to outputting banned list +if ! ${BANNED} && ! ${DEPRECATED} && ! ${INTERNAL}; then + BANNED=true +fi + +shift $((OPTIND-1)) +EAPI=${1:-0} +${ONLY} && INITIAL_EAPI=${EAPI} || INITIAL_EAPI=0 +export PKGCORE_EBD_PATH=${BASH_SOURCE[0]%/*} + +BANNED_CMDS=() +DEPRECATED_CMDS=() +INTERNAL_CMDS=() +BANNED_HELPER=${PKGCORE_EBD_PATH}/helpers/internals/banned +DEPRECATED_HELPER=${PKGCORE_EBD_PATH}/helpers/internals/deprecated + +shopt -s nullglob +for (( eapi=${INITIAL_EAPI} ; eapi<=${EAPI} ; eapi++ )) ; do + # scan for banned/deprecated shell functions + for file in "${PKGCORE_EBD_PATH}/eapi/${eapi}"/*.bash; do + source "${file}" || { echo "failed loading ${file}" >&2; exit 1; } + BANNED_CMDS+=( "${PKGCORE_BANNED_FUNCS[@]}" ) + unset PKGCORE_BANNED_FUNCS + DEPRECATED_CMDS+=( "${PKGCORE_DEPRECATED_FUNCS[@]}" ) + unset PKGCORE_DEPRECATED_FUNCS + done + # scan for banned/deprecated helpers + if [[ -d "${PKGCORE_EBD_PATH}/helpers/${eapi}" ]]; then + for file in $(find "${PKGCORE_EBD_PATH}/helpers/${eapi}" ! -type d); do + cmd=${file##*/} + if $(cmp -s "${file}" "${BANNED_HELPER}"); then + BANNED_CMDS+=( "${cmd}" ) + # remove deprecated entry if one exists + for i in "${!DEPRECATED_CMDS[@]}"; do + [[ ${DEPRECATED_CMDS[i]} == ${cmd} ]] && unset 'DEPRECATED_CMDS[i]' + done + elif $(cmp -s "${file}" "${DEPRECATED_HELPER}"); then + DEPRECATED_CMDS+=( "${cmd}" ) + else + INTERNAL_CMDS+=( "${cmd}" ) + fi + done + fi +done + +if ${BANNED} && [[ -n ${BANNED_CMDS[@]} ]]; then + printf '%s\n' ${BANNED_CMDS[@]} | sort -u +fi +if ${DEPRECATED} && [[ -n ${DEPRECATED_CMDS[@]} ]]; then + printf '%s\n' ${DEPRECATED_CMDS[@]} | sort -u +fi +if ${INTERNAL} && [[ -n ${INTERNAL_CMDS[@]} ]]; then + printf '%s\n' ${INTERNAL_CMDS[@]} | sort -u +fi diff --git a/data/lib/pkgcore/ebd/generate_eapi_func_list b/data/lib/pkgcore/ebd/generate_eapi_func_list new file mode 100755 index 000000000..e2bcebb9d --- /dev/null +++ b/data/lib/pkgcore/ebd/generate_eapi_func_list @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# +# Generate the list of functions specific to an EAPI version. +# +# This script is run dynamically in a repo or tarball layout on initialization +# of the build environment for each ebuild since different EAPIs require +# different lists of functions to be skipped. For installed versions, static +# function lists are generated at install time and used instead. + +ONLY=false +VISIBLE=false + +while getopts "ov" opt; do + case ${opt} in + o) ONLY=true ;; + v) VISIBLE=true ;; + *) ;; + esac +done + +shift $((OPTIND-1)) +EAPI=${1:-0} +${ONLY} && INITIAL_EAPI=${EAPI} || INITIAL_EAPI=0 +export PKGCORE_EBD_PATH=${BASH_SOURCE[0]%/*} + +shopt -s nullglob +for (( eapi=${INITIAL_EAPI} ; eapi<=${EAPI} ; eapi++ )) ; do + for file in "${PKGCORE_EBD_PATH}/eapi/${eapi}"/*.bash; do + source "${file}" || { echo "failed loading ${file}" >&2; exit 1; } + done +done + +${VISIBLE} || INTERNAL_FUNCS=( $(compgen -A function __) ) + +# Sorting order; put PMS functionality first, then our internals. +printf '%s\n' $(compgen -X '__*' -A function) ${INTERNAL_FUNCS[@]} | sort -u diff --git a/data/lib/pkgcore/ebd/generate_eapi_lib b/data/lib/pkgcore/ebd/generate_eapi_lib new file mode 100755 index 000000000..aaacf4e3f --- /dev/null +++ b/data/lib/pkgcore/ebd/generate_eapi_lib @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# +# Generate EAPI specific bash libraries for various scopes. +# +# This script is run dynamically in a repo or tarball layout on initialization +# of the build environment for each ebuild since different EAPIs require +# different support to be enabled or overridden. For installed versions, static +# function lists are generated at install time and used instead. + +load_eapi_libs() { + local scope="global" + local -a skip_funcs=( $(compgen -A function) ) + local skip_regex=$(IFS='|'; echo "^(${skip_funcs[*]})$") + + while getopts "s:" opt; do + case ${opt} in + s) scope=${OPTARG} ;; + *) exit 1 ;; + esac + done + shift $((OPTIND-1)) + local EAPI=${1:-0} + local selected_func=$2 + + local eapi file func + for (( eapi=0 ; eapi<=${EAPI} ; eapi++ )) ; do + # load phase libs when not targeting global scope + if [[ ${scope} != global ]]; then + source "${PKGCORE_EBD_PATH}"/eapi/depend.bash || { echo "failed loading depend.bash" >&2; exit 1; } + if [[ ${scope} != phase ]]; then + file=${PKGCORE_EBD_PATH}/eapi/${eapi}/phase.bash + if [[ -f ${file} ]]; then + source "${file}" || { echo "failed loading ${file}" >&2; exit 1; } + fi + fi + fi + + file=${PKGCORE_EBD_PATH}/eapi/${eapi}/${scope}.bash + if [[ -f ${file} ]]; then + source "${file}" || { echo "failed loading ${file}" >&2; exit 1; } + fi + + # replace EAPI banned functions if any exist + for func in "${PKGCORE_BANNED_FUNCS[@]}"; do + if declare -F ${func} &>/dev/null; then + eval "${func}() { die \"\${FUNCNAME}: banned in EAPI ${eapi}\"; }" + else + echo "EAPI ${eapi}: undefined banned func: '${func}'" >&2 + exit 1 + fi + done + unset PKGCORE_BANNED_FUNCS + + # replace EAPI deprecated functions if any exist + for func in "${PKGCORE_DEPRECATED_FUNCS[@]}"; do + if declare -F ${func} &>/dev/null; then + local func_src=$(declare -f ${func}) + local warning="QA Notice: ${func}: deprecated in EAPI ${eapi}" + # rename deprecated function + eval "${func_src/#${func}/__deprecated_${func}}" + # replace deprecated function with QA warning + renamed function + eval "${func}() { eqawarn \"${warning}\"; __deprecated_${func}; }" + else + echo "EAPI ${eapi}: undefined deprecated func: '${func}'" >&2 + exit 1 + fi + done + unset PKGCORE_DEPRECATED_FUNCS + done + + local -a eapi_funcs + for func in $(compgen -A function); do + [[ ! ${func} =~ ${skip_regex} ]] && eapi_funcs+=( ${func} ) + done + + if [[ -n ${selected_func} && ! ${selected_func} =~ ${skip_regex} ]]; then + declare -f ${selected_func} + else + declare -f ${eapi_funcs[@]} + fi +} + +# output values if being run as a script +if [[ ${BASH_SOURCE[0]} == $0 ]]; then + export PKGCORE_EBD_PATH=${BASH_SOURCE[0]%/*} + load_eapi_libs "$@" +fi diff --git a/data/lib/pkgcore/ebd/generate_global_func_list b/data/lib/pkgcore/ebd/generate_global_func_list new file mode 100755 index 000000000..1a0cdc644 --- /dev/null +++ b/data/lib/pkgcore/ebd/generate_global_func_list @@ -0,0 +1,72 @@ +#!/usr/bin/env bash +# +# Generate the list of globally defined functions. +# +# This script is run dynamically in a repo or tarball layout on initialization +# of the build environment. For installed versions, a static function list is +# generated at install time and used instead. + +export PKGCORE_EBD_PATH=${BASH_SOURCE[0]%/*} + +# re-exec ourselves inside an empty environment +if [[ -z ${PKGCORE_CLEAN_ENV} ]]; then + exec env -i \ + PATH="${PATH}" \ + PKGCORE_CLEAN_ENV=1 \ + "$0" "$@" +fi + +# avoid any potential issues of unicode sorting for whacked func names +export LC_ALL=C +DEBUG=false + +while getopts ":d" opt; do + case $opt in + d) DEBUG=true ;; + *) ;; + esac +done + +# use seen array to only source files once +declare -A seen +source() { + local fp=$(readlink -f "$1") + ${seen[${fp}]:-false} && return 0 + # die relies on these vars; we reuse them. + local CATEGORY=${PKGCORE_EBD_PATH} + local PF=$1 + ${DEBUG} && echo "sourcing ${x}" >&2 + . "$@" || { echo "!!! failed sourcing ${x}; exit $?" >&2; exit 3; } + seen[${fp}]=true + return 0 +} + +# proper sourcing order to satisfy dependencies +forced_order_source=( + isolated-functions.bash + exit-handling.bash + eapi/depend.bash + eapi/common.bash + ebuild-daemon-lib.bash + ebuild-daemon.bash +) + +# prefix all paths with ebd directory +forced_order_source=( "${forced_order_source[@]/#/${PKGCORE_EBD_PATH}\/}" ) + +# Source everything that requires a certain order first, then reload all libs +# including any ones that were skipped the first time. +# +# EAPI specific libs are skipped since those need be sourced on demand +# depending on an ebuild's EAPI. +for x in "${forced_order_source[@]}" "${PKGCORE_EBD_PATH}"/*.bash; do + source "${x}" +done + +# wipe our custom funcs +unset -f source + +${DEBUG} && echo >&2 +# Sorting order; put PMS functionality first, then our internals. +printf '%s\n' $(compgen -X '__*' -A function) $(compgen -A function __) | + sort -u diff --git a/data/lib/pkgcore/ebd/helpers/0/dosed b/data/lib/pkgcore/ebd/helpers/0/dosed new file mode 100755 index 000000000..6cdec3cf0 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/dosed @@ -0,0 +1,22 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +check_args 1 - + +pattern="s:${ED}::g" + +for x in "$@"; do + trg=${ED}/${x} + if [[ ! -e ${trg} ]]; then + pattern=${x} + continue + fi + if [[ ! -f ${trg} ]]; then + error "'${trg}' is not a regular file!"; + continue + fi + tmp_file=${T}/${trg##*/} + if check_command cp "${trg}" "${tmp_file}"; then + check_command sed -e "${pattern}" "${tmp_file}" > "${trg}" + rm -f "${tmp_file}" + fi +done diff --git a/data/lib/pkgcore/ebd/helpers/0/emake b/data/lib/pkgcore/ebd/helpers/0/emake new file mode 100755 index 000000000..41abc1bbc --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/emake @@ -0,0 +1,4 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +info "${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} $@" +check_command ${MAKE:-make} ${MAKEOPTS} ${EXTRA_EMAKE} "$@" diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fowners b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fowners new file mode 120000 index 000000000..b139f9174 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fowners @@ -0,0 +1 @@ +../src_install/fowners
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fperms b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fperms new file mode 120000 index 000000000..78b020190 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/fperms @@ -0,0 +1 @@ +../src_install/fperms
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/keepdir b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/keepdir new file mode 120000 index 000000000..56cfcbd3c --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_postinst/keepdir @@ -0,0 +1 @@ +../src_install/keepdir
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/dodir b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/dodir new file mode 120000 index 000000000..c10af926d --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/dodir @@ -0,0 +1 @@ +../src_install/dodir
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fowners b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fowners new file mode 120000 index 000000000..b139f9174 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fowners @@ -0,0 +1 @@ +../src_install/fowners
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fperms b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fperms new file mode 120000 index 000000000..78b020190 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/fperms @@ -0,0 +1 @@ +../src_install/fperms
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/keepdir b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/keepdir new file mode 120000 index 000000000..56cfcbd3c --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/pkg_preinst/keepdir @@ -0,0 +1 @@ +../src_install/keepdir
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dobin b/data/lib/pkgcore/ebd/helpers/0/src_install/dobin new file mode 100755 index 000000000..ef534d424 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dobin @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=\"${PKGCORE_DESTTREE}/bin\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doconfd b/data/lib/pkgcore/ebd/helpers/0/src_install/doconfd new file mode 100755 index 000000000..27a780e9f --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doconfd @@ -0,0 +1,4 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/etc/conf.d +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dodir b/data/lib/pkgcore/ebd/helpers/0/src_install/dodir new file mode 100755 index 000000000..a1d7b41b8 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dodir @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--diroptions=\"${DIROPTIONS}\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dodoc b/data/lib/pkgcore/ebd/helpers/0/src_install/dodoc new file mode 100755 index 000000000..d6320d15a --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dodoc @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=\"/usr/share/doc/${PF}/${PKGCORE_DOCDESTTREE}\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doenvd b/data/lib/pkgcore/ebd/helpers/0/src_install/doenvd new file mode 100755 index 000000000..a6f2871a2 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doenvd @@ -0,0 +1,4 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/etc/env.d +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doexe b/data/lib/pkgcore/ebd/helpers/0/src_install/doexe new file mode 100755 index 000000000..fabd55bc1 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doexe @@ -0,0 +1,6 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( + "--dest=\"${PKGCORE_EXEDESTTREE}\"" + "--insoptions=\"${EXEOPTIONS}\"" +) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dohard b/data/lib/pkgcore/ebd/helpers/0/src_install/dohard new file mode 100755 index 000000000..251498da2 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dohard @@ -0,0 +1 @@ +#!/usr/bin/env pkgcore-ipc-helper diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dohtml b/data/lib/pkgcore/ebd/helpers/0/src_install/dohtml new file mode 100755 index 000000000..35f6ed605 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dohtml @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=\"/usr/share/doc/${PF}/${PKGCORE_DOCDESTTREE:-html}\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doinfo b/data/lib/pkgcore/ebd/helpers/0/src_install/doinfo new file mode 100755 index 000000000..0ea3de53a --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doinfo @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=/usr/share/info" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doinitd b/data/lib/pkgcore/ebd/helpers/0/src_install/doinitd new file mode 100755 index 000000000..9ed3f6339 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doinitd @@ -0,0 +1,4 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_EXEDESTTREE=/etc/init.d +IPC_CMD=doexe diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doins b/data/lib/pkgcore/ebd/helpers/0/src_install/doins new file mode 100755 index 000000000..5cf5f6a03 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doins @@ -0,0 +1,11 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( + "--dest=\"${PKGCORE_INSDESTTREE}\"" + "--insoptions=\"${INSOPTIONS}\"" + "--diroptions=\"${DIROPTIONS}\"" +) + +if [[ -n ${PKGCORE_INSDESTTREE} && -z ${PKGCORE_INSDESTTREE%${ED}*} ]]; then + __helper_exit 2 "do not give \${D} or \${ED} as part of the path arguments to doins" +fi diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dolib b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib new file mode 100755 index 000000000..4a901f1dd --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib @@ -0,0 +1,12 @@ +#!/usr/bin/env pkgcore-ipc-helper + +if [[ ${HELPER_NAME} == "dolib.so" ]]; then + LIBOPTIONS="-m0755" +elif [[ ${HELPER_NAME} == "dolib.a" ]]; then + LIBOPTIONS="-m0644" +fi + +OPTIONS=( + "--dest=\"${PKGCORE_DESTTREE}/$(__get_libdir lib)\"" + "--insoptions=\"${LIBOPTIONS}\"" +) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.a b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.a new file mode 120000 index 000000000..c013e45e8 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.a @@ -0,0 +1 @@ +dolib
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.so b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.so new file mode 120000 index 000000000..c013e45e8 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dolib.so @@ -0,0 +1 @@ +dolib
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/doman b/data/lib/pkgcore/ebd/helpers/0/src_install/doman new file mode 100755 index 000000000..4e15ab225 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/doman @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=/usr/share/man" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/domo b/data/lib/pkgcore/ebd/helpers/0/src_install/domo new file mode 100755 index 000000000..22dce4892 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/domo @@ -0,0 +1,7 @@ +#!/usr/bin/env pkgcore-ipc-helper + +if ${PKGCORE_HAS_DESTREE}; then + OPTIONS=( "--dest=\"${PKGCORE_DESTTREE}/share/locale\"" ) +else + OPTIONS=( "--dest=/usr/share/locale" ) +fi diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dosbin b/data/lib/pkgcore/ebd/helpers/0/src_install/dosbin new file mode 100755 index 000000000..4b9eafb21 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dosbin @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--dest=\"${PKGCORE_DESTTREE}/sbin\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/dosym b/data/lib/pkgcore/ebd/helpers/0/src_install/dosym new file mode 120000 index 000000000..dacdb2f13 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/dosym @@ -0,0 +1 @@ +dohard
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/fowners b/data/lib/pkgcore/ebd/helpers/0/src_install/fowners new file mode 100755 index 000000000..2b91950dd --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/fowners @@ -0,0 +1,7 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +# at least two args are required- the owner/group chunk, and the target +check_args 2 - + +# pathway must be absolute. +check_command chown "${@/#\//${ED}/}" diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/fperms b/data/lib/pkgcore/ebd/helpers/0/src_install/fperms new file mode 100755 index 000000000..bbc6719de --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/fperms @@ -0,0 +1,7 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +# at least two args are required- the owner/group chunk, and the target +check_args 2 - + +# pathway must be absolute. +check_command chmod "${@/#\//${ED}/}" diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/keepdir b/data/lib/pkgcore/ebd/helpers/0/src_install/keepdir new file mode 100755 index 000000000..a1d7b41b8 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/keepdir @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ipc-helper + +OPTIONS=( "--diroptions=\"${DIROPTIONS}\"" ) diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newbin b/data/lib/pkgcore/ebd/helpers/0/src_install/newbin new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newbin @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newconfd b/data/lib/pkgcore/ebd/helpers/0/src_install/newconfd new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newconfd @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newdoc b/data/lib/pkgcore/ebd/helpers/0/src_install/newdoc new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newdoc @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newenvd b/data/lib/pkgcore/ebd/helpers/0/src_install/newenvd new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newenvd @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newexe b/data/lib/pkgcore/ebd/helpers/0/src_install/newexe new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newexe @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newinitd b/data/lib/pkgcore/ebd/helpers/0/src_install/newinitd new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newinitd @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newins b/data/lib/pkgcore/ebd/helpers/0/src_install/newins new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newins @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.a b/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.a new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.a @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.so b/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.so new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newlib.so @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newman b/data/lib/pkgcore/ebd/helpers/0/src_install/newman new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newman @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/0/src_install/newsbin b/data/lib/pkgcore/ebd/helpers/0/src_install/newsbin new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/0/src_install/newsbin @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/4/dosed b/data/lib/pkgcore/ebd/helpers/4/dosed new file mode 120000 index 000000000..22465e004 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/4/dosed @@ -0,0 +1 @@ +../internals/banned
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/4/src_install/dohard b/data/lib/pkgcore/ebd/helpers/4/src_install/dohard new file mode 120000 index 000000000..8c40f6117 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/4/src_install/dohard @@ -0,0 +1 @@ +../../internals/banned
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/5/src_install/doheader b/data/lib/pkgcore/ebd/helpers/5/src_install/doheader new file mode 100755 index 000000000..17f473b4a --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/5/src_install/doheader @@ -0,0 +1,4 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/usr/include +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/5/src_install/newheader b/data/lib/pkgcore/ebd/helpers/5/src_install/newheader new file mode 120000 index 000000000..26d671d49 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/5/src_install/newheader @@ -0,0 +1 @@ +../../internals/_generic_new
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/6/src_install/dohtml b/data/lib/pkgcore/ebd/helpers/6/src_install/dohtml new file mode 120000 index 000000000..02d54a782 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/6/src_install/dohtml @@ -0,0 +1 @@ +../../internals/deprecated
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/7/nonfatal b/data/lib/pkgcore/ebd/helpers/7/nonfatal new file mode 100755 index 000000000..941998fe1 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/7/nonfatal @@ -0,0 +1,5 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +check_args 1 - + +PKGCORE_NONFATAL=true "$@" diff --git a/data/lib/pkgcore/ebd/helpers/7/src_install/dohtml b/data/lib/pkgcore/ebd/helpers/7/src_install/dohtml new file mode 120000 index 000000000..8c40f6117 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/7/src_install/dohtml @@ -0,0 +1 @@ +../../internals/banned
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/7/src_install/dolib b/data/lib/pkgcore/ebd/helpers/7/src_install/dolib new file mode 120000 index 000000000..8c40f6117 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/7/src_install/dolib @@ -0,0 +1 @@ +../../internals/banned
\ No newline at end of file diff --git a/data/lib/pkgcore/ebd/helpers/8/src_install/doconfd b/data/lib/pkgcore/ebd/helpers/8/src_install/doconfd new file mode 100755 index 000000000..296a48827 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/8/src_install/doconfd @@ -0,0 +1,5 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/etc/conf.d +INSOPTIONS=-m0644 +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/8/src_install/doenvd b/data/lib/pkgcore/ebd/helpers/8/src_install/doenvd new file mode 100755 index 000000000..140b894d5 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/8/src_install/doenvd @@ -0,0 +1,5 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/etc/env.d +INSOPTIONS=-m0644 +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/8/src_install/doheader b/data/lib/pkgcore/ebd/helpers/8/src_install/doheader new file mode 100755 index 000000000..086b406d3 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/8/src_install/doheader @@ -0,0 +1,5 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_INSDESTTREE=/usr/include +INSOPTIONS=-m0644 +IPC_CMD=doins diff --git a/data/lib/pkgcore/ebd/helpers/8/src_install/doinitd b/data/lib/pkgcore/ebd/helpers/8/src_install/doinitd new file mode 100755 index 000000000..0b6aa9c97 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/8/src_install/doinitd @@ -0,0 +1,5 @@ +#!/usr/bin/env pkgcore-ipc-helper + +PKGCORE_EXEDESTTREE=/etc/init.d +EXEOPTIONS=-m0755 +IPC_CMD=doexe diff --git a/data/lib/pkgcore/ebd/helpers/common/pkgcore-ebuild-helper b/data/lib/pkgcore/ebd/helpers/common/pkgcore-ebuild-helper new file mode 100755 index 000000000..ad5943ead --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/pkgcore-ebuild-helper @@ -0,0 +1,75 @@ +#!/usr/bin/env bash + +# protect against env screwups. +if [[ -z ${PKGCORE_EBD_PATH} ]]; then + PKGCORE_EBD_PATH=$(readlink -f "${0}") + # and go up 3, out of helpers. + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} +fi +export PKGCORE_EBD_PATH + +source "${PKGCORE_EBD_PATH}"/exit-handling.bash || { + echo "failed to load exit-handling library: PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH}" >&2 + exit -127 +} + +if [[ $# -lt 1 ]]; then + die "ebuild-helper invoked without a target helper arg" +fi + +source "${PKGCORE_EBD_PATH}"/ebuild-daemon-lib.bash || \ + die "failed to load ebuild-daemon-lib.bash" +source "${PKGCORE_EBD_PATH}"/isolated-functions.bash || \ + die "failed to load isolated-functions.bash" +source "${PKGCORE_EBD_PATH}"/eapi/depend.bash >&2 || \ + die "failed sourcing eapi/depend.bash" +source "${PKGCORE_EBD_PATH}"/eapi/common.bash >&2 || \ + die "failed sourcing eapi/common.bash" +source "${PKGCORE_EBD_PATH}"/helpers/internals/helper-lib.bash >&2 || \ + die "failed sourcing helpers/internals/helper-lib.bash" + +failed=false + +MASTER_HELPER_NAME=${1##*/} +HELPER_ERROR_PREFIX= + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + export ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + error "The variable ED is missing from the environment, but is required for prefix mode." + exit -1 +fi + +invoke_script() { + [[ $# -eq 0 ]] && die "${FUNCNAME}: missing required arguments" + local HELPER_PATH=$1 + local HELPER_NAME=${1##*/} + local HELPER_EAPI=${1%/*} + HELPER_EAPI=${HELPER_EAPI##*/} + shift + local HELPER_ARG_COUNT=$# + if [[ ! -e ${HELPER_PATH} ]]; then + HELPER_PATH=$(type -p "${HELPER_NAME}") + [[ -z ${HELPER_PATH} ]] && die "${HELPER_NAME} command not found" + fi + + local OLD_ERROR_PREFIX=${HELPER_ERROR_PREFIX} + local HELPER_ERROR_PREFIX=${OLD_ERROR_PREFIX:+${OLD_ERROR_PREFIX}: }${HELPER_NAME} + + source "${HELPER_PATH}" + + if ${failed}; then + if ${PKGCORE_NONFATAL}; then + echo "WARNING: nonzero exitcode from ${HELPER_ERROR_PREFIX}" >&2 + # need to track the exit code here... + return 1 + fi + die "helper failed: ${HELPER_NAME} $@" + exit 1 + fi + return 0 +} +invoke_script "$@" +exit $(( $? )) diff --git a/data/lib/pkgcore/ebd/helpers/common/pkgcore-ipc-helper b/data/lib/pkgcore/ebd/helpers/common/pkgcore-ipc-helper new file mode 100755 index 000000000..dcde1f945 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/pkgcore-ipc-helper @@ -0,0 +1,71 @@ +#!/usr/bin/env bash + +# protect against env screwups. +if [[ -z ${PKGCORE_EBD_PATH} ]]; then + PKGCORE_EBD_PATH=$(readlink -f "${0}") + # and go up 3, out of helpers. + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} + PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH%/*} +fi +export PKGCORE_EBD_PATH + +source "${PKGCORE_EBD_PATH}"/exit-handling.bash || { + echo "failed to load exit-handling library: PKGCORE_EBD_PATH=${PKGCORE_EBD_PATH}" >&2 + exit -127 +} + +if [[ $# -lt 1 ]]; then + die "ipc-helper invoked without a target helper arg" +fi + +source "${PKGCORE_EBD_PATH}"/ebuild-daemon-lib.bash || \ + die "failed to load ebuild-daemon-lib.bash" +source "${PKGCORE_EBD_PATH}"/isolated-functions.bash || \ + die "failed to load isolated-functions.bash" +source "${PKGCORE_EBD_PATH}"/eapi/depend.bash >&2 || \ + die "failed sourcing eapi/depend.bash" +source "${PKGCORE_EBD_PATH}"/eapi/common.bash >&2 || \ + die "failed sourcing eapi/common.bash" +source "${PKGCORE_EBD_PATH}"/helpers/internals/helper-lib.bash >&2 || \ + die "failed sourcing helpers/internals/helper-lib.bash" + +HELPER_ERROR_PREFIX= + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + export ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + error "The variable ED is missing from the environment, but is required for prefix mode." + exit -1 +fi + +run_ipc_helper() { + [[ $# -eq 0 ]] && die "${FUNCNAME}: missing required arguments" + local HELPER_PATH=$1 + local HELPER_NAME=${1##*/} + local HELPER_EAPI=${1%/*} + HELPER_EAPI=${HELPER_EAPI##*/} + shift + local HELPER_ARG_COUNT=$# + if [[ ! -e ${HELPER_PATH} ]]; then + HELPER_PATH=$(type -p "${HELPER_NAME}") + [[ -z ${HELPER_PATH} ]] && die "${HELPER_NAME} command not found" + fi + + local OLD_ERROR_PREFIX=${HELPER_ERROR_PREFIX} + local HELPER_ERROR_PREFIX=${OLD_ERROR_PREFIX:+${OLD_ERROR_PREFIX}: }${HELPER_NAME} + + local IPC_CMD=${HELPER_NAME} + source "${HELPER_PATH}" + + # load all parent command opts when running a subcommand that is possibly nested + local orig_cmd=${HELPER_NAME} + while [[ ${orig_cmd} != ${IPC_CMD} ]]; do + orig_cmd=${IPC_CMD} + source "$(type -p ${IPC_CMD})" >&2 || die "failed sourcing ${IPC_CMD}" + done + + __ebd_ipc_cmd ${IPC_CMD} "${OPTIONS[*]}" "$@" +} +run_ipc_helper "$@" +exit $(( $? )) diff --git a/data/lib/pkgcore/ebd/helpers/common/prepalldocs b/data/lib/pkgcore/ebd/helpers/common/prepalldocs new file mode 100755 index 000000000..552f73d58 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/prepalldocs @@ -0,0 +1,67 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +shopt -s extdebug extglob + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + __helper_exit -1 "The variable ED is missing from the environment, but is required for prefix mode; failing." +fi + +dir=${ED}/usr/share/doc/${PF} + +[[ ! -d ${dir} ]] && return + +z=$(find "${dir}" \ + '(' -type f -or -type l ')' \ + -not -name '*.gz' \ + -not -name '*.bz2' \ + -not -name '*.xz' \ + -not -name '*.Z' \ + -not -name '*.js' \ + -not -path "${ED}/usr/share/doc/${PF}/html/*" \ + -print \ + 2>/dev/null) + +[[ -z ${z} ]] && return + +if [[ -z ${PORTAGE_COMPRESS_SUFFIX} ]]; then + case ${PORTAGE_COMPRESS} in + gzip) suffix="gz";; + bzip2) suffix="bz2";; + xz) suffix="xz";; + (p?)zstd suffix="zst";; + *) die "prepalldocs error: please set PORTAGE_COMPRESS_SUFFIX in make.conf";; + esac +fi + +IFS=$'\n' +echo "doc: ${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS}" +for y in ${z}; do + if [[ -L ${y} ]]; then + # Symlink ... + mylink=${y} + linkto=$(readlink "${y}") + + if [[ ${linkto##*.} != ${suffix} ]]; then + linkto=${linkto}.${suffix} + fi + if [[ ${mylink##*.} != ${suffix} ]]; then + mylink=${mylink}.${suffix} + fi + + echo " link fixed ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [[ ${y} != ${mylink} ]]; then + echo " link removed ${y##*/}" + rm -f "${y}" + fi + else + if [[ ${y##*.} != ${suffix} ]]; then + echo " compressing ${y##*/}" >&2 + "${PORTAGE_COMPRESS}" ${PORTAGE_COMPRESS_FLAGS} -f "${y}" + fi + fi +done + +: diff --git a/data/lib/pkgcore/ebd/helpers/common/prepallstrip b/data/lib/pkgcore/ebd/helpers/common/prepallstrip new file mode 100755 index 000000000..d17004e9f --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/prepallstrip @@ -0,0 +1,7 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +check_args 0 0 + +if ! __feature_is_enabled prepstrip && ! __safe_has nostrip ${RESTRICT}; then + check_command_or_stop prepstrip "${ED}" +fi diff --git a/data/lib/pkgcore/ebd/helpers/common/prepinfo b/data/lib/pkgcore/ebd/helpers/common/prepinfo new file mode 100755 index 000000000..b1466f26e --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/prepinfo @@ -0,0 +1,64 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +shopt -s extdebug extglob + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + __helper_exit -1 "The variable ED is missing from the environment, but is required for prefix mode; failing." +fi + +if [[ -z $1 ]]; then + z=${ED}/usr/share/info +else + if [[ -d ${ED}/$1/share/info ]]; then + z=${ED}/$1/share/info + else + z=${ED}/$1/info + fi +fi + +[[ ! -d ${z} ]] && return + +rm -f "${z}"/dir{,.old}{,.info{,.gz,.bz2,.xz,.Z}} + +if [[ -z ${PORTAGE_COMPRESS_SUFFIX} ]]; then + case ${PORTAGE_COMPRESS} in + gzip) suffix="gz";; + bzip2) suffix="bz2";; + xz) suffix="xz";; + (p?)zstd suffix="zst";; + *) die "prepinfo: error fixing links: please set PORTAGE_COMPRESS_SUFFIX in make.conf";; + esac +fi + +echo "info: ${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS}" + +for x in $(find "${z}"/ \( -type f -or -type l \) -maxdepth 1 -mindepth 1 2>/dev/null); do + if [[ -L ${x} ]]; then + # Symlink ... + mylink=${x} + linkto=$(readlink "${x}") + + if [[ ${linkto##*.} != ${suffix} ]]; then + linkto=${linkto}.${suffix} + fi + if [[ ${mylink##*.} != ${suffix} ]]; then + mylink=${mylink}.${suffix} + fi + + echo " fixing GNU info symlink: ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [[ ${x} != ${mylink} ]]; then + echo " removing old symlink: ${x##*/}" + rm -f "${x}" + fi + else + if [[ ${x##*.} != ${suffix} ]]; then + echo " compressing GNU info page: ${x##*/}" + "${PORTAGE_COMPRESS}" ${PORTAGE_COMPRESS_FLAGS} -f "${x}" + fi + fi +done + +: diff --git a/data/lib/pkgcore/ebd/helpers/common/prepman b/data/lib/pkgcore/ebd/helpers/common/prepman new file mode 100755 index 000000000..9cc5755db --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/prepman @@ -0,0 +1,63 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +shopt -s extdebug extglob + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + __helper_exit -1 "The variable ED is missing from the environment, but is required for prefix mode; failing." +fi + +if [[ -z $1 ]]; then + z=${ED}/usr/share/man +else + z=${ED}/$1/man +fi + +[[ ! -d ${z} ]] && return + +if [[ -z ${PORTAGE_COMPRESS_SUFFIX} ]]; then + case ${PORTAGE_COMPRESS} in + gzip) suffix="gz";; + bzip2) suffix="bz2";; + xz) suffix="xz";; + (p?)zstd suffix="zst";; + *) die "prepman error: please set PORTAGE_COMPRESS_SUFFIX in make.conf";; + esac +fi + +echo "man: ${PORTAGE_COMPRESS} ${PORTAGE_COMPRESS_FLAGS}" + +for x in $(find "${z}"/ -type d 2>/dev/null); do + for y in $(find "${x}"/ \( -type f -or -type l \) ! -name '.keep*' -maxdepth 1 -mindepth 1 2>/dev/null); do + if [[ -L ${y} ]]; then + # Symlink ... + mylink=${y} + linkto=$(readlink "${y}") + + # Do NOT change links to directories + if [[ -d ${z}/${linkto} ]]; then + continue + fi + + if [[ ${linkto##*.} != ${suffix} ]]; then + linkto=${linkto}.${suffix} + fi + if [[ ${mylink##*.} != ${suffix} ]]; then + mylink=${mylink}.${suffix} + fi + + echo " link fixed ${mylink##*/}" + ln -snf "${linkto}" "${mylink}" + if [[ ${y} != ${mylink} ]]; then + echo " link removed ${y##*/}" + rm -f "${y}" + fi + else + if [[ ${y##*.} != ${suffix} && ! -d ${y} ]]; then + echo " compressing ${y##*/}" + "${PORTAGE_COMPRESS}" ${PORTAGE_COMPRESS_FLAGS} -f "${y}" + fi + fi + done +done diff --git a/data/lib/pkgcore/ebd/helpers/common/prepstrip b/data/lib/pkgcore/ebd/helpers/common/prepstrip new file mode 100755 index 000000000..8547d259c --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/common/prepstrip @@ -0,0 +1,66 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +shopt -s extdebug + +# exit if the feature isn't requested, or the restrict isn't there. +__feature_is_enabled installsources || return +__safe_has installsources ${RESTRICT} && return + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + __helper_exit -1 "The variable ED is missing from the environment, but is required for prefix mode; failing." +fi + +for x in debugedit scanelf rsync; do + if ! type -P ${x} >/dev/null; then + ewarn "FEATURES=installsources is enabled but the ${x} binary could not" + ewarn "be found. This feature will not work unless ${x} is installed!" + return + fi +done + +save_elf_sources() { + local x=$1 + local sources_dir=/usr/src/debug/${CATEGORY}/${PF} + debugedit -b "${WORKDIR}" -d "${sources_dir}" \ + -l "${T}"/debug.sources "${x}" + if [[ -s ${T}/debug.sources ]]; then + [[ -d ${ED}/${sources_dir} ]] || mkdir -p "${ED}/${sources_dir}" + grep -zv '/<built-in>$' "${T}"/debug.sources | \ + (cd "${WORKDIR}"; LANG=C sort -z -u | \ + rsync -rtL0 --files-from=- "${WORKDIR}/" "${ED}/${sources_dir}/" ) + fi +} + +# The existence of the section .symtab tells us that a binary is stripped. +# We want to log already stripped binaries, as this may be a QA violation. +# They prevent us from getting the splitdebug data. +if ! __safe_has binchecks ${RESTRICT} && ! __safe_has strip ${RESTRICT}; then + f=$(scanelf -yqRBF '#k%F' -k '!.symtab' "$@") + if [[ -n ${f} ]]; then + echo -e "\a\n" + ewarn "QA Notice: Pre-stripped files found:" + ewarn "${f}" + echo "${f}" > "${T}"/scanelf-already-stripped.log + fi +fi + +# Now we look for unstripped binaries. +for x in $(scanelf -yqRBF '#k%F' -k '.symtab' "$@"); do + f=$(file "${x}") || continue + [[ -z ${f} ]] && continue + + # only split debug info for final linked objects + # or kernel modules as debuginfo for intermediatary + # files (think crt*.o from gcc/glibc) is useless and + # actually causes problems. install sources for all + # elf types though cause that stuff is good. + + if [[ ${f} == *"SB executable"* || ${f} == *"SB pie executable"* || + ${f} == *"SB shared object"* ]]; then + save_elf_sources "${x}" + elif [[ ${f} == *"SB relocatable"* ]]; then + save_elf_sources "${x}" + fi +done diff --git a/data/lib/pkgcore/ebd/helpers/internals/_generic_new b/data/lib/pkgcore/ebd/helpers/internals/_generic_new new file mode 100755 index 000000000..1e15106eb --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/internals/_generic_new @@ -0,0 +1,22 @@ +#!/usr/bin/env pkgcore-ipc-helper + +check_args 2 + +if [[ -z ${T} ]]; then + __helper_exit 2 "environment issue (ebuild commands somehow filtered the env for ${HELPER_NAME} call)- \${T} was empty" +fi + +TMP=$(mktemp -d -p "${T}" ".${HELPER_NAME}_XXXXXX") +trap 'rm -rf "${TMP}"' EXIT + +if ${PKGCORE_NEW_READS_STDIN} && [[ $1 == "-" ]]; then + if [[ -t 0 ]]; then + __helper_exit 1 "no input data available, stdin is a tty" + fi + check_command_or_stop cat > "${TMP}/$2" +else + check_command_or_stop cp -- "$1" "${TMP}/$2" +fi + +set -- "${TMP}/$2" +IPC_CMD=do${HELPER_NAME#new} diff --git a/data/lib/pkgcore/ebd/helpers/internals/banned b/data/lib/pkgcore/ebd/helpers/internals/banned new file mode 100755 index 000000000..a9ecde875 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/internals/banned @@ -0,0 +1,3 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +die "${HELPER_NAME}: banned in EAPI ${HELPER_EAPI}" diff --git a/data/lib/pkgcore/ebd/helpers/internals/deprecated b/data/lib/pkgcore/ebd/helpers/internals/deprecated new file mode 100755 index 000000000..7fd964c5f --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/internals/deprecated @@ -0,0 +1,15 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +eqawarn "QA Notice: ${HELPER_NAME}: deprecated in EAPI ${HELPER_EAPI}" + +# remove deprecated location from PATH and run original helper +deprecated_path=$(__which ${HELPER_NAME}) +__var_push PATH=${PATH/${deprecated_path%/*}:/} +ORIG_HELPER=$(__which ${HELPER_NAME}) +__var_pop + +if [[ ${deprecated_path} == ${ORIG_HELPER} ]]; then + die "couldn't find original '${HELPER_NAME}' helper, internal error" +fi + +"${ORIG_HELPER}" "$@" diff --git a/data/lib/pkgcore/ebd/helpers/internals/helper-lib.bash b/data/lib/pkgcore/ebd/helpers/internals/helper-lib.bash new file mode 100644 index 000000000..886232777 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/internals/helper-lib.bash @@ -0,0 +1,80 @@ +# various helper functionality + +error() { + echo "${HELPER_ERROR_PREFIX}: ${@-no message given}" >&2 + failed=true +} + +warn() { + echo "${HELPER_ERROR_PREFIX}: warning, ${@-no message given}" >&2 +} + +info() { + echo "${HELPER_ERROR_PREFIX}: $@" >&2 +} + +check_args() { + local tense="argument" + local min=$(( $1 )) + local max + [[ ${min} -gt 1 ]] && tense="arguments" + if [[ $2 == '-' ]]; then + max=${HELPER_ARG_COUNT} + elif [[ -z $2 ]]; then + max=$1 + fi + max=$(( max )) + + if [[ ${HELPER_ARG_COUNT} -ge ${min} && ${HELPER_ARG_COUNT} -le ${max} ]]; then + return 0 + fi + if [[ ${min} -eq ${max} ]]; then + die "${HELPER_ERROR_PREFIX}: requires exactly ${min} ${tense}, got ${HELPER_ARG_COUNT}" + elif [[ $2 == '-' ]]; then + die "${HELPER_ERROR_PREFIX}: requires at least ${min} ${tense}, got ${HELPER_ARG_COUNT}" + else: + die "${HELPER_ERROR_PREFIX}: requires at least ${min} ${tense}, and at most ${max} arguments, got ${HELPER_ARG_COUNT}" + fi +} + +check_command() { + local ret + "$@" + ret=$? + [[ ${ret} == 0 ]] && return 0 + error "exitcode ${ret} from $*" + return $(( ret )) +} + +check_command_or_stop() { + check_command "$@" + __helper_check_exit $? "$@ failed, cannot continue" + return 0 +} + +__helper_exit() { + local ret=$1 + shift + [[ ${ret} == 0 ]] && exit 0 + + local error_msg="${HELPER_ERROR_PREFIX}: exitcode ${ret}" + [[ -n $@ ]] && error_msg+=": $@" + + if ${PKGCORE_NONFATAL}; then + eerror "${error_msg}" + exit ${ret} + fi + + die "${error_msg}" +} + +__helper_failed() { + PKGCORE_IS_NOT_HELPER= + die "helper failed: ${BASH_COMMAND}" +} + +__helper_check_exit() { + [[ $1 == 0 ]] && return + shift + __helper_exit "$@" +} diff --git a/data/lib/pkgcore/ebd/helpers/internals/prepall b/data/lib/pkgcore/ebd/helpers/internals/prepall new file mode 100755 index 000000000..3a9840275 --- /dev/null +++ b/data/lib/pkgcore/ebd/helpers/internals/prepall @@ -0,0 +1,88 @@ +#!/usr/bin/env pkgcore-ebuild-helper + +prepman +prepinfo +prepalldocs +prepallstrip + +if ! ${PKGCORE_PREFIX_SUPPORT:=false}; then + ED=${D} +elif [[ ${ED:-unset} == "unset" ]]; then + __helper_exit -1 "The variable ED is missing from the environment, but is required for prefix mode; failing." +fi + +# this should help to ensure that all (most?) shared libraries are executable +# and that all libtool scripts / static libraries are not executable +for i in "${ED}"/opt/*/lib{,32,64} \ + "${ED}"/lib{,32,64} \ + "${ED}"/usr/lib{,32,64} \ + "${ED}"/usr/X11R6/lib{,32,64}; do + [[ ! -d ${i} ]] && continue + + for j in "${i}"/*.so.* "${i}"/*.so; do + [[ ! -e ${j} ]] && continue + [[ -L ${j} ]] && continue + [[ -x ${j} ]] && continue + echo "making executable: /${j/${ED}/}" + chmod +x "${j}" + done + + for j in "${i}"/*.a "${i}"/*.la; do + [[ ! -e ${j} ]] && continue + [[ -L ${j} ]] && continue + [[ ! -x ${j} ]] && continue + echo "removing executable bit: /${j/${ED}/}" + chmod -x "${j}" + done +done + +# When installing static libraries into /usr/lib and shared libraries into +# /lib, we have to make sure we have a linker script in /usr/lib along side +# the static library, or gcc will utilize the static lib when linking :(. +# http://bugs.gentoo.org/4411 +for a in "${ED}"/usr/lib*/*.a; do + s=${a%.a}.so + if [[ ! -e ${s} ]]; then + s=${s%usr/*}${s##*/usr/} + if [[ -e ${s} ]]; then + echo -e "\aQA Notice: missing gen_usr_ldscript for ${s##*/}\a" + sleep 1 + fi + fi +done + +# Make sure people don't store libtool files or static libs in /lib +f=$(ls "${ED}"/lib*/*.{a,la} 2>/dev/null) +if [[ -n ${f} ]]; then + echo -e "\n\aQA Notice: excessive files found in the / partition\a" + echo "${f}" + sleep 1 +fi + +# Verify that the libtool files don't contain bogus $ED entries. +for a in "${ED}"/usr/lib*/*.la; do + s=${a##*/} + if grep -qs "${ED}" "${a}"; then + echo -e "\n\aQA Notice: ${s} appears to contain PORTAGE_TMPDIR paths\a" + sleep 1 + fi +done + +if type -p scanelf > /dev/null; then + # Run some sanity checks on shared libraries + for d in "${ED}"/lib* "${ED}"/usr/lib*; do + f=$(scanelf -ByF '%S %p' "${d}"/lib*.so* | gawk '$2 == "" { print }') + if [[ -n ${f} ]]; then + echo -e "\n\aQA Notice: the following shared libraries lack a SONAME\a" + echo "${f}" + sleep 1 + fi + + f=$(scanelf -ByF '%n %p' "${d}"/lib*.so* | gawk '$2 == "" { print }') + if [[ -n ${f} ]]; then + echo -e "\n\aQA Notice: the following shared libraries lack NEEDED entries\a" + echo "${f}" + sleep 1 + fi + done +fi diff --git a/data/lib/pkgcore/ebd/isolated-functions.bash b/data/lib/pkgcore/ebd/isolated-functions.bash new file mode 100644 index 000000000..1723cdc0f --- /dev/null +++ b/data/lib/pkgcore/ebd/isolated-functions.bash @@ -0,0 +1,366 @@ +# Various internal functions + +# Internal logging function, don't use this in ebuilds. +__elog_base() { + local messagetype + [[ -z $1 || -z ${T} || ! -d ${T}/logging ]] && return 1 + case $1 in + INFO|WARN|ERROR|LOG|QA) + messagetype=$1 + shift + ;; + *) + echo -e " ${PKGCORE_RC_BAD}*${PKGCORE_RC_NORMAL} Invalid use of internal function __elog_base(), next message will not be logged" >&2 + return 1 + ;; + esac + echo "$*" >> "${T}/logging/${EBUILD_PHASE}.${messagetype}" + return 0 +} + +__colored_output_disable() { + PKGCORE_RC_COLS="25 80" + PKGCORE_RC_ENDCOL= + PKGCORE_RC_GOOD= + PKGCORE_RC_WARN= + PKGCORE_RC_BAD= + PKGCORE_RC_NORMAL= + PKGCORE_RC_HILITE= + PKGCORE_RC_BRACKET= +} &> /dev/null + +__colored_output_enable() { + # try setting the column width to bash's internal COLUMNS variable, + # then try to get it via stty. no go? hardcode it to 80. + PKGCORE_RC_COLS=${COLUMNS:-0} + if (( PKGCORE_RC_COLS <= 0 )); then + PKGCORE_RC_COLS=$(set -- $(stty size 2>/dev/null) ; echo ${2:-0}) + if (( PKGCORE_RC_COLS <= 0 )); then + PKGCORE_RC_COLS=80 + fi + fi + export COLUMNS=${PKGCORE_RC_COLS} + + # Use PKGCORE_RC_PREFIX in build env to avoid clipping when capturing the + # output and displaying with a custom prefix. + PKGCORE_RC_COLS=$(( PKGCORE_RC_COLS - 8 - PKGCORE_RC_PREFIX )) # width of [ ok ] == 7 + + # Now, ${PKGCORE_RC_ENDCOL} will move us to the end of the column; + # irregardless of character width. + export PKGCORE_RC_ENDCOL=$'\e[A\e['${PKGCORE_RC_COLS}'C' + + export PKGCORE_RC_GOOD=$'\e[32;01m' + export PKGCORE_RC_WARN=$'\e[33;01m' + export PKGCORE_RC_BAD=$'\e[31;01m' + export PKGCORE_RC_HILITE=$'\e[36;01m' + export PKGCORE_RC_BRACKET=$'\e[34;01m' + export PKGCORE_RC_NORMAL=$'\e[0m' +} &> /dev/null + +# Version of has, only to be used when the invoker knows that the targets will +# never have \001 in them. +__safe_has() { + local needle=$1 + shift + local IFS=$'\001' + [[ "${IFS}${*}${IFS}" == *"${IFS}${needle}${IFS}"* ]] +} + +__feature_is_enabled() { + local IFS=$' \t\n' + __safe_has "$1" ${FEATURES} +} &> /dev/null + +__which() { + [[ $# -ne 1 ]] && die "${FUNCNAME}: requires a single command name arg, got $@" + type -P "$1" || die "'$1' not found in PATH" +} + +__is_function() { + declare -F "$1" &> /dev/null +} &> /dev/null + +__run_function_if_exists() { + __is_function "$1" || return 0 + "$@" +} + +__qa_run_function_if_exists() { + __is_function "$1" || return 0 + __qa_invoke "$@" +} + +# Check if a directory is empty. +# Returns: 0 if empty, 1 otherwise. +__directory_is_empty() { + __shopt_push -s dotglob nullglob + local files=( ${1}/* ) + __shopt_pop + [[ ${#files[@]} -gt 0 ]] && return 1 + return 0 +} + +# Reverse a given array. +# Example: +# $ a=(1 2 3 4 5) +# $ a=( $(__reverse_array a) ) +# $ echo ${a[@]} +# 5 4 3 2 1 +__reverse_array() { + local _array_ref="$1"[@] + local -a array=( "${!_array_ref}" ) + local i + for (( i=${#array[@]}-1 ; i>=0 ; i-- )) ; do + echo "${array[i]}" + done +} + +__strip_duplicate_slashes() { + if [[ -n $1 ]]; then + local removed=$1 + while [[ ${removed} == *//* ]]; do + removed=${removed//\/\///} + done + echo "${removed}" + fi +} + +declare -a PKGCORE_SHOPT_STACK + +# Save the current shell option state and set a shell option. +# Returns: 0 on success, dies on failure. +__shopt_push() { + PKGCORE_SHOPT_STACK[${#PKGCORE_SHOPT_STACK[@]}]=${BASHOPTS} + PKGCORE_SHOPT_STACK[${#PKGCORE_SHOPT_STACK[@]}]=$- + if [[ $1 == -[su] ]]; then + # shopt modification + shopt "$@" || die "bad shopt options: $@" + elif [[ -n $@ ]]; then + set "$@" || die "bad set invocation: $@" + fi + return 0 +} &> /dev/null + +# Revert to the most recent shell option state. +# Returns: 0 on success, dies on failure. +__shopt_pop() { + [[ $# -ne 0 ]] && die "${FUNCNAME}: accepts no args, got $@" + local count=$(( ${#PKGCORE_SHOPT_STACK[@]} - 1 )) + [[ ${count} -le 0 ]] && die "${FUNCNAME}: invoked with nothing on the stack" + + local set_val=${PKGCORE_SHOPT_STACK[${count}]} + if [[ $- != ${set_val} ]]; then + set ${-:++${-}} ${set_val:+-${set_val}} || die "failed enforcing set state of ${set_val}" + fi + unset -v PKGCORE_SHOPT_STACK\[${count}\] || die "${FUNCNAME}: readonly shopt stack" + + count=$(( count - 1 )) + + local previous=${PKGCORE_SHOPT_STACK[${count}]} + unset -v PKGCORE_SHOPT_STACK\[${count}\] || die "${FUNCNAME}: readonly shopt stack" + [[ ${BASHOPTS} == ${previous} ]] && return 0 + + local IFS=' ' + local current=${BASHOPTS} + if [[ -n ${current} ]]; then + shopt -u ${current//:/ } >&2 || die "failed wiping current shopt settings of ${current}" + fi + if [[ -n ${previous} ]]; then + shopt -s ${previous//:/ } >&2 || die "failed forcing old shopt settings to ${previous}" + fi + return 0 +} &> /dev/null + +declare -a PKGCORE_SAVED_IFS + +# Save the current IFS value and set a new one. +# Returns: 0 on success, dies on failure. +__IFS_push() { + PKGCORE_SAVED_IFS[${#PKGCORE_SAVED_IFS[@]}]=${IFS-unset} + if [[ $1 == unset ]]; then + unset -v IFS || die "${FUNCNAME}: IFS is readonly" + else + IFS=$1 + fi + : +} + +# Revert to the most recent IFS setting. +# Returns: 0 on success, dies on failure. +__IFS_pop() { + if [[ ${#PKGCORE_SAVED_IFS[@]} -eq 0 ]]; then + die "${FUNCNAME}: invoked with nothing on the stack" + fi + IFS=${PKGCORE_SAVED_IFS[$(( ${#PKGCORE_SAVED_IFS[@]} - 1 ))]} + if [[ ${IFS} == unset ]]; then + unset -v IFS || die "${FUNCNAME}: IFS is readonly" + fi + unset -v PKGCORE_SAVED_IFS\[$(( ${#PKGCORE_SAVED_IFS[@]} - 1 ))\] || die "${FUNCNAME}: readonly IFS stack" + : +} + +declare -a PKGCORE_VAR_STACK + +# Save the given variable's value and set a new one. +# Returns: 0 on success, dies on failure. +__var_push() { + local export_opts + if [[ $1 == -n ]]; then + export_opts="-n" + shift + fi + [[ $# -eq 0 ]] && die "${FUNCNAME}: invoked with no arguments" + + local arg var orig_val + for arg in "$@"; do + var=${arg%%=*} + + # If the specified variable currently has a value we save it; + # otherwise, just push the variable name onto the stack. + if orig_val=$(declare -p ${var} 2>/dev/null); then + orig_val=${orig_val/declare *${var}=[\'\"]/${var}=} + orig_val=${orig_val%[\'\"]} + else + orig_val=${var} + fi + + # toss the current value + unset -v ${var} 2>/dev/null || die "${FUNCNAME}: '${var}' is readonly" + + # export a new value if one was specified + if [[ ${arg} == *=* ]]; then + export ${export_opts} "${arg}" || die "${FUNCNAME}: failed to export '${arg}'" + fi + + PKGCORE_VAR_STACK[${#PKGCORE_VAR_STACK[@]}]=${orig_val} + done +} + +# Revert the most recent variable value change. +# Returns: 0 on success, dies on failure. +__var_pop() { + [[ ${#PKGCORE_VAR_STACK[@]} -gt 0 ]] \ + || die "${FUNCNAME}: invoked with nothing on the stack" + + local count=$1 + case $# in + 0) count=1;; + 1) [[ ${count} == *[!0-9]* ]] && die "${FUNCNAME}: arg must be a number: $*";; + *) die "${FUNCNAME}: only accepts one arg: $*";; + esac + + local var arg + while (( count-- )); do + arg=${PKGCORE_VAR_STACK[$(( ${#PKGCORE_VAR_STACK[@]} - 1 ))]} + var=${arg%%=*} + + # unset the variable on the top of the stack + unset -v ${var} 2>/dev/null || die "${FUNCNAME}: '${var}' is readonly" + + # reset its value if one was stored + if [[ ${arg} == *=* ]]; then + export "${arg}" || die "${FUNCNAME}: failed to export '${arg}'" + fi + + unset -v PKGCORE_VAR_STACK\[$(( ${#PKGCORE_VAR_STACK[@]} - 1 ))\] || die "${FUNCNAME}: readonly variable stack" + done +} + +declare -a PKGCORE_RESET_STACK + +# Save the current shell option and variable stack states. +# Returns: 0 +__env_push() { + PKGCORE_RESET_STACK[${#PKGCORE_RESET_STACK[@]}]=${#PKGCORE_SHOPT_STACK[@]} + PKGCORE_RESET_STACK[${#PKGCORE_RESET_STACK[@]}]=${#PKGCORE_VAR_STACK[@]} +} + +# Revert to the last marked shell option and variable stack states. +# Returns: 0 on success, dies on failure. +__env_pop() { + if [[ ${#PKGCORE_RESET_STACK[@]} -lt 2 ]]; then + die "${FUNCNAME}: not enough values on the stack" + fi + + local var_stack_reset=${PKGCORE_RESET_STACK[$(( ${#PKGCORE_RESET_STACK[@]} - 1 ))]} + unset -v PKGCORE_RESET_STACK\[$(( ${#PKGCORE_RESET_STACK[@]} - 1 ))\] || die "${FUNCNAME}: readonly env stack" + local shopt_stack_reset=${PKGCORE_RESET_STACK[$(( ${#PKGCORE_RESET_STACK[@]} - 1 ))]} + unset -v PKGCORE_RESET_STACK\[$(( ${#PKGCORE_RESET_STACK[@]} - 1 ))\] || die "${FUNCNAME}: readonly env stack" + + while [[ ${#PKGCORE_VAR_STACK[@]} -gt ${var_stack_reset} ]]; do + __var_pop + done + while [[ ${#PKGCORE_SHOPT_STACK[@]} -gt ${shopt_stack_reset} ]]; do + __shopt_pop + done +} + +declare -a PKGCORE_STDOUT +declare -a PKGCORE_STDERR + +# Echo a given command to stderr if debugging is enabled then run it while +# capturing stdout/stderr to PKGCORE_STDOUT/PKGCORE_STDERR arrays. +__run() { + [[ ${PKGCORE_DEBUG} -ge 1 ]] && echo $1 >&2 + local ret stdout stderr + source <({ stderr=( "$({ mapfile -t stdout< <(eval $1; ret=$?; declare -p ret >&3); } 3>&2 2>&1; declare -p stdout >&2)" ); declare -p stderr; } 2>&1) + PKGCORE_STDOUT=( "${stdout[@]}" ) + PKGCORE_STDERR=( "${stderr[@]}" ) + [[ ${PKGCORE_DEBUG} -ge 1 ]] && printf '%b\n' "${PKGCORE_STDERR[@]}" >&2 + return ${ret} +} + +# Echo a given command to stderr and then run it. +__echo_and_run() { + [[ ! ${PKGCORE_DEBUG} -ge 1 ]] && local -x PKGCORE_DEBUG=1 + __run "$1" +} + +__qa_invoke() { + if ${PKGCORE_QA_SUPPRESSED:-false}; then + "$@" + return $(( $? )) + fi + local pkgcore_should_fail=false + # save env and shopt settings. + # in addition, protect the stack from bad pkgcore calls, or bad consumers accessing internals + local PKGCORE_SAVED_IFS=() + local PKGCORE_SHOPT_STACK=() + + __IFS_push "${IFS}" + __shopt_push + + "$@" + local ret=$? + + if [[ ${#PKGCORE_SAVED_IFS[@]} -ne 1 ]]; then + echo "QA warning: unbalanced __IFS_push/__IFS_pop detected. internal error? count was ${#PKGCORE_SAVED_IFS[@]}" + pkgcore_should_fail=true + fi + if [[ ${#PKGCORE_SHOPT_STACK[@]} -ne 2 ]]; then + echo "QA warning: unbalanced __shopt_push/__shopt_pop detected. internal error? count was ${#PKGCORE_SHOPT_STACK[@]}" + pkgcore_should_fail=true + fi + + if [[ ${PKGCORE_SAVED_IFS[0]} != ${IFS-unset} ]]; then + echo "QA WARNING: invocation $@ manipulated IFS to ${IFS}, but didn't restore it to its original value!" + fi + __IFS_pop + + # While these echo statements are ugly, written this way to ensure bash + # does it as a single write- aka, keep it within the size of atomic writes + # for pipes, relevant for threaded output straight to term. + if [[ ${PKGCORE_SHOPT_STACK[0]} != ${BASHOPTS} ]]; then + echo "QA warning: shopt modification bled out of invocation $@"$'\n'" : was ${PKGCORE_SHOPT_STACK[0]}"$'\n'" : now ${BASHOPTS}" >&2 + fi + + if [[ ${PKGCORE_SHOPT_STACK[1]} != $- ]]; then + echo "QA warning: set modification bled out of invocation $@"$'\n'" : was ${PKGCORE_SHOPT_STACK[1]}"$'\n'" : now $-" >&2 + fi + __shopt_pop + + ${pkgcore_should_fail} && die "invocation $@ modified globals and didn't clean up" + return $(( ret )) +} + +: diff --git a/data/lib/pkgcore/shell/bash/pkgcore.bash b/data/lib/pkgcore/shell/bash/pkgcore.bash new file mode 100644 index 000000000..fcca094a9 --- /dev/null +++ b/data/lib/pkgcore/shell/bash/pkgcore.bash @@ -0,0 +1,91 @@ +# Common library of shell functions for parsing various Gentoo-related data +# and leveraging pkgcore functionality. + +# get an attribute for a given package +_pkgattr() { + local prog=$(_get_caller) + local pkg_attr=$1 pkg_atom=$2 repo=$3 + local ret=0 pid fdout fderr + local -a pkg error + + if [[ -z ${pkg_atom} ]]; then + echo "${prog}: enter a valid package name or repo path" >&2 + return 1 + fi + + # setup pipes for stdout/stderr capture + local tmpdir=$(mktemp -d) + trap "rm -rf '${tmpdir}'" EXIT HUP INT TERM + mkfifo "${tmpdir}"/{stdout,stderr} + + if [[ -n ${repo} ]]; then + pquery -r "${repo}" --raw --unfiltered --cpv -R --one-attr "${pkg_attr}" \ + -n -- "${pkg_atom}" >"${tmpdir}"/stdout 2>"${tmpdir}"/stderr & + else + pquery --ebuild-repos --raw --unfiltered --cpv -R --one-attr "${pkg_attr}" \ + -n -- "${pkg_atom}" >"${tmpdir}"/stdout 2>"${tmpdir}"/stderr & + fi + + # capture pquery stdout/stderr into separate vars + pid=$! + exec {fdout}<"${tmpdir}"/stdout {fderr}<"${tmpdir}"/stderr + rm -rf "${tmpdir}" + mapfile -t -u ${fdout} pkg + mapfile -t -u ${fderr} error + wait ${pid} + ret=$? + exec {fdout}<&- {fderr}<&- + + if [[ ${ret} != 0 ]]; then + # re-prefix the main pquery error message with the shell function name + echo "${prog}: ${error[0]#pquery: error: }" >&2 + # output the remaining portion of the error message + local line + for line in "${error[@]:1}"; do + echo -E "${line}" >&2 + done + return 1 + fi + + local choice + if [[ -z ${pkg[@]} ]]; then + echo "${prog}: no matches found: ${pkg_atom}" >&2 + return 1 + elif [[ ${#pkg[@]} > 1 ]]; then + echo "${prog}: multiple matches found: ${pkg_atom}" >&2 + choice=$(_choose "${pkg[@]%%|*}") + [[ $? -ne 0 ]] && return 1 + else + choice=-1 + fi + echo ${pkg[${choice}]#*|} +} + +# get the caller of the current function +_get_caller() { + local caller + if [[ ${FUNCNAME[-1]} == "source" ]]; then + caller=$(basename ${BASH_SOURCE[-1]}) + else + caller=${FUNCNAME[-1]} + fi + echo ${caller} +} + +# cross-shell compatible PATH searching +_which() { + type -P "$1" >/dev/null +} + +# cross-shell compatible read num chars +_read_nchars() { + local var + read -n $1 var + echo ${var} +} + +# cross-shell compatible array index helper +# bash arrays start at 0 +_array_index() { + echo $1 +} diff --git a/data/lib/pkgcore/shell/bin/pkgcore-sh-helper b/data/lib/pkgcore/shell/bin/pkgcore-sh-helper new file mode 100755 index 000000000..96e2a03fd --- /dev/null +++ b/data/lib/pkgcore/shell/bin/pkgcore-sh-helper @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +# exit out if not running via an external script +[ -z "$1" ] && exit 1 + +SCRIPT_PATH=$1 +SCRIPT=$(basename ${SCRIPT_PATH}) +shift + +SHELL=$(ps -p $(ps -p $$ -o ppid=) -o comm=) +if [ "${SHELL}" != "bash" ] && [ "${SHELL}" != "zsh" ]; then + echo "${SCRIPT}: unsupported shell: ${SHELL}" >&2 + exit 1 +fi + +exec ${SHELL} -c "source \"$(dirname ${0})\"/../pkgcore.sh && SCRIPT=${SCRIPT} source \"${SCRIPT_PATH}\" $@" diff --git a/data/lib/pkgcore/shell/bin/psite b/data/lib/pkgcore/shell/bin/psite new file mode 100755 index 000000000..6d200c5f8 --- /dev/null +++ b/data/lib/pkgcore/shell/bin/psite @@ -0,0 +1,47 @@ +#!/usr/bin/env pkgcore-sh-helper +# open a package's homepage in a browser +# +# For queries returning multiple packages, a list of options is presented to +# the user to choose from. In the same manner, if a package has multiple +# homepages listed, a list of homepages is outputted for selection. +# +# Note that this requires xdg-utils to be installed for xdg-open. + +# Default to the current working directory if no argument is passed so this can +# be run with no arguments from within an ebuild's directory. +if [[ $# -eq 0 ]]; then + set -- "${PWD}" "$@" +elif [[ $1 == "-h" || $1 == "--help" ]]; then + cat <<-EOF + ${SCRIPT}: open a package's homepage in a browser + usage: ${SCRIPT} pkg [repo] + example: ${SCRIPT} gcc -- open gcc's homepage + example: ${SCRIPT} coreutils gentoo -- open the coreutils::gentoo homepage + EOF + exit +fi + +homepage=( $(_pkgattr homepage "$@") ) +[[ $? -ne 0 ]] && exit 1 + +if [[ -z ${homepage[@]} ]]; then + echo "${SCRIPT}: no homepage found: $1" >&2 + exit 1 +elif [[ ${#homepage[@]} -gt 1 ]]; then + echo "${SCRIPT}: multiple homepages found:" >&2 + choice=$(_choose "${homepage[@]}") + [[ $? -ne 0 ]] && exit 1 + homepage=${homepage[choice]} +fi + +# fallback to xdg-open if $BROWSER is unset +if [[ -z ${BROWSER} ]]; then + BROWSER=xdg-open +fi + +if ! _which ${BROWSER}; then + echo "${SCRIPT}: ${BROWSER} not available" >&2 + return 1 +fi + +${BROWSER} "${homepage}" &>/dev/null & diff --git a/data/lib/pkgcore/shell/pkgcore.sh b/data/lib/pkgcore/shell/pkgcore.sh new file mode 100644 index 000000000..74581c025 --- /dev/null +++ b/data/lib/pkgcore/shell/pkgcore.sh @@ -0,0 +1,90 @@ +# Common library of useful shell functions leveraging pkgcore functionality. +# Source this file from your .bashrc, .zshrc, or similar. +# +# Only bash and zsh are currently supported. + +# determine interactive parent shell +PKGSHELL=$(ps -p $$ -ocomm=) +if [[ ${PKGSHELL} != "bash" && ${PKGSHELL} != "zsh" ]]; then + echo "pkgcore.sh: unsupported shell: ${PKGSHELL}" >&2 + return 1 +fi + +# determine the directory path where this script exists +if [[ ${PKGSHELL} == "bash" ]]; then + SCRIPTDIR=$(dirname $(realpath ${BASH_SOURCE[0]})) +else + SCRIPTDIR=${${(%):-%x}:A:h} +fi + +# source bash/zsh specific support +source "${SCRIPTDIR}"/${PKGSHELL}/pkgcore.${PKGSHELL} +export PATH=${SCRIPTDIR}/bin:${PATH} +unset PKGSHELL SCRIPTDIR + +# interactively choose a value from an array +# +# usage: _choose "${array[@]}" +# returns: index of array choice (assuming array indexing starts at 1) +_choose() { + local choice num_opts=$# + + # show available choices + local x i=0 + for x in $@; do + echo " $(( ++i )): ${x}" >&2 + done + + # read user choice, checking for invalid values + local invalid=0 + while true; do + echo -n "Please select one: " >&2 + choice=$(_read_nchars ${#num_opts}) + if [[ ! ${choice} =~ [0-9]+ || ${choice} -lt 1 || ${choice} -gt ${num_opts} ]]; then + (( invalid++ )) + echo " -- Invalid choice!" >&2 + # three invalids seen, giving up + [[ ${invalid} -gt 2 ]] && break + continue + fi + echo >&2 + break + done + + # default to array indexes starting at 0 + (( choice-- )) + echo $(_array_index ${choice}) +} + +# change to a package directory +# +# This will change the current working directory to the sys-devel/gcc directory +# in the gentoo repo. Note that pkgcore's extended atom syntax is supported so +# one can also abbreviate the command to `pcd gcc gentoo` assuming there is +# only one package with a name of 'gcc' in the gentoo repo. In the case where +# multiple matches are found the list of choices is returned to select from. +# +# This should work for any local repo type on disk, e.g. one can also use this +# to enter the repos for installed or binpkgs via 'vdb' or 'binpkg' repo +# arguments, respectively. +pcd() { + if [[ $1 == "-h" || $1 == "--help" ]]; then + cat <<-EOF + pcd: change to a package directory + usage: pcd pkg [repo] + example: pcd gcc gentoo -- change to the sys-devel/gcc directory in the gentoo repo + example: pcd coreutils vdb -- change to the sys-apps/coreutils dir in the vdb + EOF + return 0 + fi + + local pkgpath=$(_pkgattr path "$@") + [[ -z ${pkgpath} ]] && return 1 + + # find the nearest parent directory + while [[ ! -d ${pkgpath} ]]; do + pkgpath=$(dirname "${pkgpath}") + done + + pushd "${pkgpath}" >/dev/null +} diff --git a/data/lib/pkgcore/shell/zsh/pkgcore.zsh b/data/lib/pkgcore/shell/zsh/pkgcore.zsh new file mode 100644 index 000000000..0ee9cd9d6 --- /dev/null +++ b/data/lib/pkgcore/shell/zsh/pkgcore.zsh @@ -0,0 +1,348 @@ +# Common library of shell functions for parsing various Gentoo-related data +# and leveraging pkgcore functionality. + +# get an attribute for a given package +_pkgattr() { + local prog=$(_get_caller) + local pkg_attr=$1 pkg_atom=$2 repo=$3 + local ret=0 pid fdout fderr + local -a pkg error + + if [[ -z ${pkg_atom} ]]; then + echo "${prog}: enter a valid package name or repo path" >&2 + return 1 + fi + + # setup pipes for stdout/stderr capture + local tmpdir=$(mktemp -d) + trap "rm -rf '${tmpdir}'" EXIT HUP INT TERM + mkfifo "${tmpdir}"/{stdout,stderr} + + if [[ -n ${repo} ]]; then + pquery -r "${repo}" --raw --unfiltered --cpv -R --one-attr "${pkg_attr}" \ + -n -- "${pkg_atom}" >"${tmpdir}"/stdout 2>"${tmpdir}"/stderr & + else + pquery --ebuild-repos --raw --unfiltered --cpv -R --one-attr "${pkg_attr}" \ + -n -- "${pkg_atom}" >"${tmpdir}"/stdout 2>"${tmpdir}"/stderr & + fi + + # capture pquery stdout/stderr into separate vars + pid=$! + exec {fdout}<"${tmpdir}"/stdout {fderr}<"${tmpdir}"/stderr + rm -rf "${tmpdir}" + pkg=("${(@f)$(<&${fdout})}") + error=("${(@f)$(<&${fderr})}") + wait ${pid} + ret=$? + exec {fdout}<&- {fderr}<&- + + if [[ ${ret} != 0 ]]; then + # re-prefix the main pquery error message with the shell function name + echo "${prog}: ${error[1]#pquery: error: }" >&2 + # output the remaining portion of the error message + local line + for line in "${error[@]:1}"; do + echo -E "${line}" >&2 + done + return 1 + fi + + local choice + if [[ -z ${pkg[@]} ]]; then + echo "${prog}: no matches found: ${pkg_atom}" >&2 + return 1 + elif [[ ${#pkg[@]} > 1 ]]; then + echo "${prog}: multiple matches found: ${pkg_atom}" >&2 + choice=$(_choose "${pkg[@]%%|*}") + [[ $? -ne 0 ]] && return 1 + else + choice=-1 + fi + echo ${pkg[${choice}]#*|} +} + +# get the caller of the current function +_get_caller() { + echo ${${funcstack[-1]}:t} +} + +# cross-shell compatible PATH searching +_which() { + whence -p "$1" >/dev/null +} + +# cross-shell compatible read num chars +_read_nchars() { + local var + read -k $1 var + echo ${var} +} + +# cross-shell compatible array index helper +# zsh arrays start at 1 +_array_index() { + index=$1 + echo $(( ++index )) +} + +## Completion related functions ## + +# configured repo info +# +# Note that this only supports the repos.conf format, +# PORTDIR/PORTDIR_OVERLAY in make.conf are not supported. +# +# optional args: +# -t repo_types -- show specific repo types (defaults to showing source repos) +# The repo_types parameter can be any of the following characters in combination: +# e: package.provided "repo" +# i: vdb "repo" +# s: all source repos (default if the -t option isn't passed) +# b: all binary repos +# a: repo-stack "repo" +# For example, `_repos -t sbi` will return the list of source, binary, and +# installed repos. +# -v section:key +# -p print the output instead of using completion +# -l use repo locations instead of repo_ids +_repos() { + typeset -A opts + zparseopts -E -A opts t: l p v: + + local repo_name output_type + typeset -a repos repo_types output + + # verify selected repo types + if [[ -n ${opts[(I)-t]} ]]; then + local -a supported_repo_types=(e i s b a) + repo_types=(${(s::)opts[-t]}) + for type in ${repo_types[@]}; do + if [[ ! ${type} =~ [${supported_repo_types[@]}] ]]; then + echo "${funcstack[1]}: invalid repo type: ${type}" >&2 + echo "supported types: ${supported_repo_types[@]} (see docs)" >&2 + return 1 + fi + done + else + # default to showing source repos + repo_types=(s) + fi + + if [[ -e /etc/portage/repos.conf ]]; then + repos_conf_files=( /etc/portage/repos.conf /etc/portage/repos.conf/** ) + else + repos_conf_files=( /usr/share/pkgcore/config/repos.conf ) + fi + + IFS='= ' + + local file + for file in "${repos_conf_files[@]}"; do + [[ -f ${file} ]] || continue + while read -r name value; do + # skip comments and empty lines + [[ -z ${name} || ${name} == '#'* ]] && continue + if [[ (${name} == '['*']') && -z ${value} ]]; then + repo_name=${name//[\[\]]} + [[ ${repo_name} != "DEFAULT" ]] && repos+=(${repo_name}) + typeset -A ${repo_name} + else + eval "${repo_name}[${name}]=\"${value}\"" + fi + done < ${file} + done + + if [[ -n ${opts[(I)-v]} ]]; then + section=${opts[-v]%%:*} + value=${opts[-v]##*:} + eval "output=\${${section}[${value}]}" + elif [[ -n ${opts[(I)-l]} ]]; then + # repo paths + output_type="repo paths" + for repo in ${repos[@]}; do + eval "output+=(\${${repo}[location]})" + done + else + # repo names + output_type="repos" + + [[ ${repo_types} =~ "s" ]] && output+=(${repos[@]}) + [[ ${repo_types} =~ "e" ]] && output+=( provided ) + [[ ${repo_types} =~ "i" ]] && output+=( vdb ) + [[ ${repo_types} =~ "b" ]] && output+=( binpkg ) + [[ ${repo_types} =~ "a" ]] && output+=( repo-stack ) + fi + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t repos ${output_type} output + else + print ${output} + fi +} + +# available licenses +# +# optional args: +# -r repo specify the repo to use; otherwise the default repo is used +# -p print the output instead of using completion +_licenses() { + typeset -A opts + zparseopts -E -A opts p r: + + typeset -a licenses + + if [[ -n ${opts[(I)-r]} ]]; then + repo=${opts[-r]} + else + repo=$(_repos -p -v DEFAULT:main-repo) + fi + + repo_path=${$(_repos -p -v "${repo}:location")%/} + licenses=("${repo_path}"/licenses/*(.:t)) + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t licenses 'licenses' licenses + else + print ${licenses} + fi +} + +# global/local USE flag info +# +# optional args +# -r repo specify the repo to use; otherwise the default repo is used +# -p print the output instead of using completion +# -g only show global use flags +# -l only show local use flags +# -o don't show use flag descriptions +_use() { + typeset -A opts + zparseopts -E -A opts o p r: + + local desc + typeset -a use use_global use_local + + if [[ -n ${opts[(I)-r]} ]]; then + repo=${opts[-r]} + else + repo=$(_repos -p -v DEFAULT:main-repo) + fi + + repo_path=${$(_repos -p -v "${repo}:location")%/} + [[ -f ${repo_path}/profiles/use.desc ]] && use_global=(${(S)${${(f)"$(<${repo_path}/profiles/use.desc)"}:#\#*}/ - /:}) + [[ -f ${repo_path}/profiles/use.local.desc ]] && use_local=(${(S)${(S)${${(f)"$(<${repo_path}/profiles/use.local.desc)"}:#\#*}/*:/}/ - /:}) + + if [[ -z ${opts[(I)-g]} && -z ${opts[(I)-l]} ]]; then + # both global and local use flags are shown by default + use=( ${use_global} ${use_local} ) + elif [[ -n ${opts[(I)-g]} ]]; then + use=${use_global} + desc='global ' + elif [[ -n ${opts[(I)-l]} ]]; then + use=${use_local} + desc='local ' + fi + + # strip use flag descriptions + if [[ -n ${opts[(I)-o]} ]]; then + use=(${^use/:*/}) + fi + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t use "${desc}use flag" use + else + print ${use} + fi +} + +# package categories provided by repos +# +# optional args +# -r repo specify the repo to use; otherwise the default repo is used +# -p print the output instead of using completion +_categories() { + typeset -A opts + zparseopts -E -A opts p r: + + typeset -a categories + + if [[ -n ${opts[(I)-r]} ]]; then + repo=${opts[-r]} + else + repo=$(_repos -p -v DEFAULT:main-repo) + fi + + repo_path=${$(_repos -p -v "${repo}:location")%/} + [[ -f ${repo_path}/profiles/categories ]] && categories=(${${(f)"$(<${repo_path}/profiles/categories)"}:#\#*}) + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t categories 'categories' categories + else + print ${categories} + fi +} + +# arches provided by repos +# +# optional args +# -r repo specify the repo to use; otherwise the default repo is used +# -p print the output instead of using completion +_arches() { + typeset -A opts + zparseopts -E -A opts p r: + + typeset -a arches + + if [[ -n ${opts[(I)-r]} ]]; then + repo=${opts[-r]} + else + repo=$(_repos -p -v DEFAULT:main-repo) + fi + + repo_path=${$(_repos -p -v "${repo}:location")%/} + [[ -f ${repo_path}/profiles/arch.list ]] && arches=(${${(f)"$(<${repo_path}/profiles/arch.list)"}:#\#*}) + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t arches 'arches' arches + else + print ${arches} + fi +} + +# profiles provided by repos +# +# optional args +# -r repo specify the repo to use; otherwise the default repo is used +# -p print the output instead of using completion +# -f output full, absolute profile paths +_profiles() { + typeset -A opts + zparseopts -E -A opts a p f r: + + local file repo repo_path arch path pstatus + typeset -a profiles + + if [[ -n ${opts[(I)-r]} ]]; then + repo=${opts[-r]} + else + repo=$(_repos -p -v DEFAULT:main-repo) + fi + + repo_path=${$(_repos -p -v "${repo}:location")%/} + file=${repo_path}/profiles/profiles.desc + + if [[ -f ${file} ]]; then + while read -r arch path pstatus; do + # skip comments and empty lines + [[ -z ${arch} || ${arch} == '#'* ]] && continue + [[ -n ${opts[(I)-f]} ]] && path=${repo_path}/profiles/${path} + profiles+=(${path}) + done < ${file} + fi + + if [[ -n ${compstate} ]] && [[ -z ${opts[(I)-p]} ]]; then + _describe -t profiles 'profiles' profiles $* + else + print ${profiles} + fi +} diff --git a/data/share/bash-completion/completions/pquery b/data/share/bash-completion/completions/pquery new file mode 100644 index 000000000..6bc0cbdf0 --- /dev/null +++ b/data/share/bash-completion/completions/pquery @@ -0,0 +1,153 @@ +# bash completion for pquery + +source "/usr/share/bash-completion/helpers/gentoo-common.sh" + +_pquery() { + local i cmd cur prev words cword split + _init_completion || return + + local base_options=( + -h --help + --version + --debug + -q --quiet + -v --verbose + --color + + # config options + --config + --domain + + # repository matching options + --raw + --unfiltered + --virtuals + -r --repo + -E --ebuild-repos + -B --binary-repos + -I --installed + -A --all-repos + + # package matching options + --all + --has-use + --license + --revdep + --revdep-pkgs + --restrict-revdep + --restrict-revdep-pkgs + -S --description + --eapi + --owns + --owns-re + --maintainer + --maintainer-name + --maintainer-email + --environment + --pkgset + -u --upgrade + + # output options + -1, --first + -a, --atom + --cpv + -R + --slot + -n --no-version + --min + --max + --blame + --size + --contents + --highlight-dep + --print-revdep + --attr + --force-attr + --one-attr + --force-one-attr + ) + + local boolean_options=( + true + false + ) + + local attributes=( + all allmetadata + + path repo source_repository + longdescription maintainers + category package fullver revision version + environment cbuild chost ctarget + inherited defined_phases + + eapi description homepage + distfiles files uris fetchables + license slot subslot keywords iuse required_use use restrict properties + + alldepends depend bdepend idepend pdepend rdepend + raw_alldepends raw_depend raw_bdepend raw_idepend raw_pdepend raw_rdepend + ) + + # find repo location + local REPO="$(git rev-parse --show-toplevel)" + for ((i = 1; i < ${COMP_CWORD}; i++)); do + case "${COMP_WORDS[i]}" in + -r | --repo) + REPO=$(_parsereposconf "${COMP_WORDS[i+1]}" location) + : ${REPO:=${COMP_WORDS[i+1]}} + ;; + esac + done + + case ${prev} in + --color) + COMPREPLY=($(compgen -W "${boolean_options[*]}" -- "${cur}")) + ;; + --config) + COMPREPLY=($(compgen -f -- "${cur}")) + ;; + --domain) + COMPREPLY=() + ;; + --has-use | --license | --revdep | --revdep-pkgs | --restrict-revdep | --restrict-revdep-pkgs | \ + -S | --description | --eapi | --owns | --owns-re | --environment | --pkgset | \ + --maintainer | --maintainer-name | --maintainer-email) + COMPREPLY=() + ;; + --virtuals) + COMPREPLY=($(compgen -W "only disable" -- "${cur}")) + ;; + -r | --repo) + COMPREPLY=($(compgen -W "$(_parsereposconf -l)" -- "${cur}")) + COMPREPLY+=($(compgen -d -- "${cur}")) + ;; + --highlight-dep | --print-revdep) + COMPREPLY=() + ;; + --attr | --force-attr | --one-attr | --force-one-attr) + COMPREPLY=($(compgen -W "${attributes[*]}" -- "${cur}")) + ;; + --highlight-dep | --print-revdep) + COMPREPLY=() + ;; + *) + if [[ ${cur} == -* ]]; then + COMPREPLY+=($(compgen -W "${base_options[*]}" -- "${cur}")) + else + _list_repo_atoms() { + eval cd "${REPO}" || return + if [[ $cur == */* ]]; then + compgen -W "$(compgen -G "${cur}*" )" -- "${cur}" + else + compgen -W "$(compgen -G "${cur}*" -S / )" -- "${cur}" + fi + } + COMPREPLY+=( $(_list_repo_atoms) ) + fi + ;; + esac +} +complete -F _pquery pquery + +# vim: set ft=bash sw=4 et sts=4 : diff --git a/data/config/make.globals b/data/share/pkgcore/config/make.globals index baf85593f..baf85593f 100644 --- a/data/config/make.globals +++ b/data/share/pkgcore/config/make.globals diff --git a/data/config/repos.conf b/data/share/pkgcore/config/repos.conf index ecc8e8412..ecc8e8412 100644 --- a/data/config/repos.conf +++ b/data/share/pkgcore/config/repos.conf diff --git a/data/stubconfig/repos.conf b/data/share/pkgcore/stubconfig/repos.conf index 61c65b2d4..61c65b2d4 100644 --- a/data/stubconfig/repos.conf +++ b/data/share/pkgcore/stubconfig/repos.conf diff --git a/data/stubrepo/metadata/layout.conf b/data/share/pkgcore/stubrepo/metadata/layout.conf index dae6b4b06..dae6b4b06 100644 --- a/data/stubrepo/metadata/layout.conf +++ b/data/share/pkgcore/stubrepo/metadata/layout.conf diff --git a/data/stubrepo/profiles/arch.list b/data/share/pkgcore/stubrepo/profiles/arch.list index 21d5bd8c7..21d5bd8c7 100644 --- a/data/stubrepo/profiles/arch.list +++ b/data/share/pkgcore/stubrepo/profiles/arch.list diff --git a/data/stubrepo/profiles/default/make.defaults b/data/share/pkgcore/stubrepo/profiles/default/make.defaults index 12024de7b..12024de7b 100644 --- a/data/stubrepo/profiles/default/make.defaults +++ b/data/share/pkgcore/stubrepo/profiles/default/make.defaults diff --git a/data/stubrepo/profiles/profiles.desc b/data/share/pkgcore/stubrepo/profiles/profiles.desc index 09e4e5a13..09e4e5a13 100644 --- a/data/stubrepo/profiles/profiles.desc +++ b/data/share/pkgcore/stubrepo/profiles/profiles.desc diff --git a/data/stubrepo/profiles/repo_name b/data/share/pkgcore/stubrepo/profiles/repo_name index af495602f..af495602f 100644 --- a/data/stubrepo/profiles/repo_name +++ b/data/share/pkgcore/stubrepo/profiles/repo_name diff --git a/data/xml-schema/metadata.xsd b/data/share/pkgcore/xml-schema/metadata.xsd index 3812045a6..3812045a6 100644 --- a/data/xml-schema/metadata.xsd +++ b/data/share/pkgcore/xml-schema/metadata.xsd diff --git a/data/share/zsh/site-functions/_pkgcore b/data/share/zsh/site-functions/_pkgcore new file mode 100644 index 000000000..3e2aed84a --- /dev/null +++ b/data/share/zsh/site-functions/_pkgcore @@ -0,0 +1,725 @@ +#compdef pclean pconfig pebuild pinspect pmaint pmerge pquery psite pcd + +SHELL_LIB=$(python -c 'from pkgcore import const; print(const.LIBDIR_PATH)')/shell/zsh/pkgcore.zsh +source "${SHELL_LIB}" || print "$0: failed to load '${SHELL_LIB}'" >&2 +unset SHELL_LIB + +common_main_args=( + '(- :)'--version'[show version information and exit]' + '--config[use config config or skip loading system config]:config path:_files' + "--color[Color output]:yes/no:((y\:'yes' n\:'no'))" +) + +common_output_args=( + '(- :)'{-h,--help}'[show help information and exit]' + '(--debug --help -h)--debug[enable debugging output]' + '(--quiet -q --verbose -v)'{-q,--quiet}'[suppress non-error output]' + '(--verbose -v --quiet -q)'{-v,--verbose}'[show verbose output]' +) + +common_args=( + $common_main_args + $common_output_args +) + +domain_common_args=( + $common_args + '--domain[domain to use for this operation]' +) + +_pclean() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + $common_args \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + dist:'remove distfiles' + pkg:'remove binpkgs' + tmp:'remove tmpdir entries' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + typeset -a shared_opts file_opts repo_opts + + shared_opts=( + {'(--pretend)-p','(-p)--pretend'}'[dry run without performing any changes]' + {'(--exclude)-x','(-x)--exclude'}'[list of packages to exclude from removal]' + {'(--exclude-file)-X','(-X)--exclude-file'}'[path to exclusion file]' + '*:target:' + ) + + file_opts=( + {'(--modified)-m','(-m)--modified'}'[skip files that have been modified since a given time]' + {'(--size)-s','(-s)--size'}'[skip files bigger than a given size]' + ) + + repo_opts=( + {'(--installed)-I','(-I)--installed'}'[skip files for packages that are currently installed]' + {'(--fetch-restricted)-f','(-f)--fetch-restricted'}'[skip fetch-restricted files]' + ) + + pkg_opts=( + '--source-repo[remove binpkgs with matching source repo]' + ) + + case $line[1] in + (dist) + _arguments -C -A '-*' \ + $domain_common_args \ + $shared_opts \ + $file_opts \ + $repo_opts \ + {'(--ignore-failures)-i','(-i)--ignore-failures'}'[ignore checksum parsing errors]' \ + && ret=0 + ;; + (pkg) + _arguments -C -A '-*' \ + $domain_common_args \ + $shared_opts \ + $file_opts \ + $repo_opts \ + $pkg_opts \ + && ret=0 + ;; + (tmp) + _arguments -C -A '-*' \ + $domain_common_args \ + $shared_opts \ + {'(--all)-a','(-a)--all'}'[wipe the entire tmpdir]' \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac + + return ret +} + +_pconfig() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + $common_args \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + classes:'list all classes referenced by the config' + describe_class:'describe the arguments a class needs, how to use it in a config' + uncollapsable:'show configuration objects that could not be collapsed/instantiated' + dump:'dump the entire configuration' + configurables:'list registered configurables (may not be complete)' + dump-uncollapsed:'dump the configuration in a raw, uncollapsed form' + package:"invoke a package's custom configuration scripts" + world:'inspect and modify the world file' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (classes|uncollapsable|dump-uncollapsed) + _arguments -C -A '-*' \ + $common_output_args \ + && ret=0 + ;; + (describe_class) + _arguments -C -A '-*' \ + $common_output_args \ + '*:classes' \ + && ret=0 + ;; + (dump|configurables) + _arguments -C -A '-*' \ + $common_output_args \ + '*:type' \ + && ret=0 + ;; + (package) + _arguments -C -A '-*' \ + $domain_common_args \ + '*:restriction or atom' \ + && ret=0 + ;; + (world) + _arguments -C -A '-*' \ + $domain_common_args \ + '(- :)'{-l,--list}'[list the current world file contents for this domain]' \ + '*'{-r,--remove}'[remove an entry from the world file]:package atom:' \ + '*'{-a,--add}'[add an entry to the world file]:package atom:' \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac + + return ret +} + +_pebuild() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + $domain_common_args \ + "--no-auto[run just the specified phases; it's up to the invoker to get the order right]" \ + '(-): :->atom-or-ebuild' \ + '(-)*:: :->phase' \ + && ret=0 + + case $state in + (atom-or-ebuild) + # complete ebuilds before directories + zstyle ':completion:*' file-patterns '*%p(^-/):other-files:ebuilds *(-/):directories:directories' + + _arguments \ + '*:ebuilds:_files -g \*.ebuild' \ + && ret=0 + ;; + (phase) + typeset -a phases + + phases=( + setup:'run package specific setup actions or checks' + unpack:'unpack all the sources to the workdir' + prepare:'preparation of all sources such as applying patches' + configure:'run configuration steps' + compile:'run compilation steps' + test:'run test steps' + install:'install the package to the temp directory' + clean:"remove the package's temporary directory" + ) + + _describe -V -t phases phase phases && ret=0 + ;; + + (*) + _nothing + ;; + esac + + return ret +} + +_pinspect() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + $common_args \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + pkgsets:'pkgset related introspection' + eapi_usage:'report of eapi usage for targeted repos' + license_usage:'report of license usage for targeted repos' + eclass_usage:'report of eclass usage for targeted repos' + mirror_usage:'report of SRC_URI mirror usage for targeted repos' + distfiles_usage:'report detailing distfiles space usage for targeted repos' + query:'auxiliary access to ebuild/repository info via portageq akin API' + portageq:'portageq compatible interface to query commands' + profile:'profile related querying' + digests:'identify what packages are missing digest info' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + + typeset -a historical_repo_data_opts + historical_repo_data_opts=( + '(- :)'{-h,--help}'[show help information and exit]' + '--no-final-summary[disable outputting a summary of data across all repos]' + '--sort-by-name[sort output by name, rather then by frequency]' + '--first[show only the first N detail items]:number' + '--last[show only the last N detail items]:number' + '*:repo:_repos -t siab' + ) + + case $line[1] in + (pkgsets) + _arguments -C -A '-*' \ + '(- :)'{-h,--help}'[show help information and exit]' \ + '--all[display info on all pkgsets]' \ + ':pkgset:' \ + && ret=0 + ;; + ((eapi|license|eclass|mirror)_usage) + _arguments -C -A '-*' \ + $historical_repo_data_opts \ + && ret=0 + ;; + (distfiles_usage) + _arguments -C -A '-*' \ + '--no-repo-summary[disable outputting repo summaries]' \ + '--no-detail[disable outputting a detail view of all repos]' \ + '--include-nonmirrored[if set, nonmirrored distfiles will be included in the total]' \ + '--include-restricted[if set, fetch restricted distfiles will be included in the total]' \ + $historical_repo_data_opts \ + && ret=0 + ;; + (query) + _arguments -C \ + '(- :)'{-h,--help}'[show help information and exit]' \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + best_version:'return the maximum visble version for a given atom' + env_var:'return configuration defined variables' + get_profiles:'show available profiles for a given repo' + get_repo_path:'show repo path for a given repo' + get_repos:'return list of configured repos' + has_version:'return 0 if an atom is merged, 1 if not' + mass_best_version:'multiple best_version calls' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + + typeset -a subcmd_opts + query_subcmd_opts=( + '(- :)'{-h,--help}'[show help information and exit]' + '--eapi[limit all operations to just what the given EAPI supports]:EAPI' + '--use[override the use flags used for transitive USE deps]:USE' + '--domain[domain to use for this operation]:domain' + '--domain-at-root[specify the domain to use via its root path]:root path:_path_files -/' + ) + + case $line[1] in + (best_version|has_version|mass_best_version) + _arguments -C -A '-*' \ + $subcmd_opts \ + '*:package atom' \ + && ret=0 + ;; + (env_var) + _arguments -C -A '-*' \ + $subcmd_opts \ + '*:variable' \ + && ret=0 + ;; + (get_profiles|get_repo_path) + _arguments -C -A '-*' \ + $subcmd_opts \ + ':repo:_repos' \ + && ret=0 + ;; + (get_repos) + _arguments -C -A '-*' \ + $subcmd_opts \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + (*) + _nothing + ;; + esac + ;; + (portageq) + _arguments -C \ + '(- :)'{-h,--help}'[show help information and exit]' \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + best_version:'return the maximum visble version for a given atom' + envvar:'return configuration defined variables (deprecated)' + envvar2:'return configuration defined variables' + get_repo_news_path:'show the news path for a given repo' + get_repo_path:'show repo path for a given repo' + get_repos:'return list of configured repos' + has_version:'return 0 if an atom is merged, 1 if not' + mass_best_version:'multiple best_version calls' + match:'shorthand for `pquery --installed`' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + + typeset -a portageq_subcmd_opts + subcmd_opts=( + '(- :)'{-h,--help}'[show help information and exit]' + '--eapi[limit all operations to just what the given EAPI supports]:EAPI' + '--use[override the use flags used for transitive USE deps]:USE' + ) + + case $line[1] in + (best_version|has_version|mass_best_version|match) + _arguments -C -A '-*' \ + $subcmd_opts \ + '1:root path:_path_files -/' \ + '2:package atom' \ + && ret=0 + ;; + (envvar|envvar2) + _arguments -C -A '-*' \ + $subcmd_opts \ + '1:root path:_path_files -/' \ + '2:variable' \ + && ret=0 + ;; + (get_repo_path|get_repo_news_path) + _arguments -C -A '-*' \ + $subcmd_opts \ + '1:root path:_path_files -/' \ + '2:repo:_repos' \ + && ret=0 + ;; + (get_repos) + _arguments -C -A '-*' \ + $subcmd_opts \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + (*) + _nothing + ;; + esac + ;; + (profile) + typeset -a profile_attrs + local profile_opts='-f' + + profile_attrs=( + parent:'output the linearized tree of inherited parents' + eapi:'output EAPI support required for reading this profile' + deprecated:'dump deprecation notices, if any' + provided:'list all package.provided packages' + system:'output the system package set' + use_expand:'output the USE_EXPAND configuration for this profile' + iuse_effective:'output the IUSE_EFFECTIVE value for this profile' + masks:'inspect package masks' + unmasks:'inspect package unmasks' + bashrcs:'inspect bashrcs' + keywords:'inspect package.keywords' + accept_keywords:'inspect package.accept_keywords' + use:'inspect package.use' + masked_use:'inspect masked use flags' + stable_masked_use:'inspect stable masked use flags' + forced_use:'inspect forced use flags' + stable_forced_use:'inspect stable forced use flags' + defaults:'inspect defined configuration for this profile' + arch:'output the arch defined for this profile' + status:'output the status of this profile' + ) + + # only complete profiles from the specified repo + if (( words[(I)-r|--repo] )); then + local repo=${words[(( $words[(I)-r|--repo] + 1 ))]} + profile_opts="-r ${repo}" + fi + + _arguments -C -A '-*' \ + '(- :)'{-h,--help}'[show help information and exit]' \ + {'(--repo)-r','(-r)--repo'}'[target repository]:repo:_repos' \ + '1:profile attribute:(($profile_attrs))' \ + "2:profile:_profiles ${profile_opts}" \ + && ret=0 + ;; + (digests) + _arguments -C -A '-*' \ + '(- :)'{-h,--help}'[show help information and exit]' \ + ':repo:_repos' \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac + return ret +} + +_pmaint() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + $common_args \ + '(-): :->command' \ + '(-)*:: :->subcommand' \ + && ret=0 + + case $state in + (command) + typeset -a subcommands + + subcommands=( + sync:'synchronize a local repository with its defined remote' + copy:'copy binpkgs between repositories; primarily useful for quickpkging a livefs pkg' + regen:'regenerate repository caches' + env-update:'update env.d and ldconfig' + mirror:'mirror the sources for a package in full' + ) + + _describe -t subcommands subcommand subcommands && ret=0 + ;; + (subcommand) + curcontext=${curcontext%:*}-$line[1]: + + case $line[1] in + (sync) + _arguments -C -w -S -s -A '-*' \ + $common_output_args \ + '*:repo:_repos' \ + && ret=0 + ;; + (copy) + _arguments -C -w -S -s -A '-*' \ + $common_output_args \ + {'(--source-repo)-s','(-s)--source-repo'}'[copy strictly from the supplied repository]:repo:_repos' \ + {'(--ignore-missing)-i','(-i)--ignore-missing'}"[if a matching pkg already exists in the target, don't update it]" \ + ':target repo:_repos' \ + ':query:' \ + && ret=0 + ;; + (regen) + _arguments -C -w -S -s -A '-*' \ + $common_output_args \ + '--disable-eclass-caching[disable caching eclasses into functions (results in a ~2x slower regen process, only disable when debugging)]' \ + {'(--threads)-t','(-t)--threads'}'[number of threads to use for regeneration (defaults to using all available processors]:number' \ + '--force[force regeneration to occur regardless of staleness checks]' \ + '--rsync[update timestamps for rsync repos]' \ + '--use-local-desc[update local USE flag description cache (profiles/use.local.desc)]' \ + '--pkg-desc-index[update package description cache (metadata/pkg_desc_index)]' \ + '*:repo:_repos' \ + && ret=0 + ;; + (env-update) + _arguments -C -w -S -s -A '-*' \ + $common_output_args \ + '--skip-ldconfig[do not update etc/ldso.conf and ld.so.cache]' \ + && ret=0 + ;; + (mirror) + _arguments -C -w -S -s -A '-*' \ + $common_output_args \ + {'(--ignore-failures)-f','(-f)--ignore-failures'}'[if a failure occurs, keep going]' \ + ':query:' \ + && ret=0 + ;; + (*) + _nothing + ;; + esac + ;; + esac + + return ret +} + +_pmerge() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + typeset -a pkg ops resolver output + + pkg=( + {'(--newuse)-N','(-N)--newuse'}'[check for changed useflags in installed packages (implies -1)]' + ) + + ops=( + {'(--unmerge)-C','(-C)--unmerge'}'[unmerge a package]' + '--clean[remove installed packages not referenced by any target packages/sets]' + {'(--pretend)-p','(-p)--pretend'}"[do the resolution, but don't merge/fetch anything]" + '--ignore-failures[ignore failures while running all types of tasks]' + {'(--ask)-a','(-a)--ask'}'[do the resolution, but ask to merge/fetch anything]' + "--force[force merging to a repo, regardless of if it's frozen]" + {'(--fetchonly)-f','(-f)--fetchonly'}'[do only the fetch steps of the resolved plan]' + {'(--oneshot)-1','(-1)--oneshot'}'[do not record changes in the world file]' + ) + + resolver=( + {'(--upgrade)-u','(-u)--upgrade'}'[try to upgrade already installed packages/dependencies]' + {'(--downgrade)-d','(-d)--downgrade'}'[try to downgrade already installed packages/dependencies]' + {'(--deep)-D','(-D)--deep'}'[force the resolver to verify already installed dependencies]' + '--preload-vdb-state[enable preloading of the installed packages database]' + {'(--ignore-cycles)-i','(-i)--ignore-cycles'}"[ignore cycles if they're found to be unbreakable]" + "--with-bdeps[process build dependencies for built packages (by default they're ignored]" + {'(--nodeps)-O','(-O)--nodeps'}'[disable dependency resolution]' + {'(--noreplace)-n','(-n)--noreplace'}"[don't reinstall target atoms if they're already installed]" + {'(--buildpkg)-b','(-b)--buildpkg'}'[build binpkgs]' + {'(--usepkg)-k','(-k)--usepkg'}'[prefer to use binpkgs]' + {'(--usepkgonly)-K','(-K)--usepkgonly'}'[use only binpkgs]' + {'(--source-only)-S','(-S)--source-only'}'[use only source packages, no binpkgs]' + {'(--empty)-e','(-e)--empty'}'[force rebuilding of all involved packages]' + ) + + output=( + "--quiet-repo-display[use numbers to indicate repos instead of ::repo output in the package merge list]" + {'(--formatter)-F','(-F)--formatter'}'[output formatter to use]:formatter:((basic pkgcore portage portage-verbose))' + ) + + _arguments -C -w -S -s -A '-*' \ + $domain_common_args \ + $pkg \ + $ops \ + $resolver \ + $output \ + '*:target:' \ + && ret=0 + + return ret +} + +_pquery() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + typeset -a repo pkg output + + repo=( + '--raw[disable configuration and filtering]' + '--no-filters[disable all license filtering and visibility filtering]' + "--virtuals[specific virtuals handling (everything is matched by default)]:options:((only\:'only match virtuals' disable\:'no matching virtuals'))" + {'(--repo)-r','(-r)--repo'}'[target repository]:repo:_repos -t seib' + {'(--ebuild-repos)-E','(-E)--ebuild-repos'}'[search all ebuild repos]' + {'(--binary-repos)-B','(-B)--binary-repos'}'[search all binary repos]' + {'(--installed)-I','(-I)--installed'}'[search installed pkgs]' + {'(--all-repos)-A','(-A)--all-repos'}'[search all repos including the vdb]' + ) + + pkg=( + '--all[match all packages (equivalent to "pquery *")]' + '--has-use[exact string match on a USE flag]:use flag:_use -o' + '--license[exact match on a license]:license:_licenses' + '--revdep[shorthand for --restrict-revdep atom --print-revdep atom]:pkg atom:' + '--revdep-pkgs[shorthand for --restrict-revdep-pkgs atom --print-revdep atom]:pkg atom:' + '--restrict-revdep[dependency on an atom]:pkg atom:' + '--restrict-revdep-pkgs[dependency on pkgs that match a specific atom]:pkg atom:' + {'(--description)-S','(-S)--description'}'[regexp search on description and longdescription]:description regex' + '--eapi[match packages using a given EAPI]' + '--owns[exact match on an owned file/dir]:path:_files' + '--owns-re[like "owns" but using a regexp for matching]:path regex:_files' + '--maintainer[comma-separated list of regexes to search for maintainers]' + '--maintainer-name[comma-separated list of maintainer name regexes to search for]' + '--maintainer-email[comma-separated list of maintainer email regexes to search for]' + '--maintainer-needed[match packages without a maintainer]' + '--environment[regexp search in environment.bz2]' + '--pkgset[find packages that match the given package set]' + {'(--upgrade)-u','(-u)--upgrade'}'[matched installed packages without best slotted version]' + ) + + output=( + {'(--first)-1','(-1)--first'}'[stop when first match is found]' + {'(--no-version)-n','(-n)--no-version'}'[collapse multiple matching versions together]' + '--min[show only the lowest version for each package]' + '--max[show only the highest version for each package]' + '--cpv[print the category/package-version]' + {'(--atom)-a','(-a)--atom'}'[print =cat/pkg-3 instead of cat/pkg-3 (implies --cpv, has no effect with --no-version)]' + "--attr[print this attribute's value (can be specified more than once)]" + '--force-attr[like --attr but accepts any string as attribute name instead of only explicitly supported names]' + '--one-attr[print one attribute, suppresses other output]' + '--force-one-attr[like --one-attr but accepts any string as attribute name instead of only explicitly supported names]' + '--one-attr[print one attribute, suppresses other output]' + '--size[display size of all files owned by the package]' + '--contents[list files owned by the package]' + '--highlight-dep[highlight dependencies matching this atom]' + '--blame[shorthand for --attr maintainers]' + '--print-revdep[print what condition(s) trigger a dep]' + ) + + _arguments -C \ + $domain_common_args \ + $repo \ + $pkg \ + $output \ + '*:target:' \ + && ret=0 + + return ret +} + +_pcd() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + '(- :)'{-h,--help}'[show help information and exit]' \ + '1:package atom' \ + '2:repo:_repos -t sib' \ + && ret=0 + + return ret +} + +_psite() { + local curcontext=$curcontext state state_descr line ret=1 + typeset -A opt_args + + _arguments -C \ + '(- :)'{-h,--help}'[show help information and exit]' \ + '1:package atom' \ + '2:repo:_repos -t sib' \ + && ret=0 + + return ret +} + +_pkgcore() { + local ret=1 + _call_function ret _$service + return ret +} + +_pkgcore + +# vim: set et sw=2 ts=2 ft=zsh: |