Hi all,

I have thought a bit more about how to better organize the bash-side of
portage and came to the conclusion that modularization of ebuild.sh (as
proposed in the recent thread "Refactoring ebuild.sh") can't be the only
and is not the best thing to do.

There is a fair amount of shell scripts and functions in the portage svn
repo that do not really belong there. For example all do*/new* scripts
in the bin/ directory. These are scripts that are not specific to
portage's implementation but the ebuilds that use it. That's why I think
we should move them more towards the ebuilds: Inside the tree.

This has the advantage that paludis/pkgcore don't have to keep their
helper scripts in sync with portages, that they get more visible to
ebuild devs (to some, especially the new ones, they seem like magic
commands that just come out of the middle of nowhere) and most
importantly, that they are where they belong. ;o)

Having them in the tree rather than portage would avoid bugs along the
lines of bug 121317 [1] and bug 136792 [2], or at least pull them off
portage's radar. As those functions are really the ebuild devs' area,
that's only a good thing, IMO.

As they reminded me very much of eclass functions, I converted them into
functions and put together an 'install-helpers.eclass'. Having them as
functions has the advantage of being able to create all of the new*
functions with zero redundancy and only few lines of code and being in
the same line as other helping utilities like the ones provided by
eutils and other eclasses. It has the disadvantage of not being able to
execute them with `find -exec' or `xargs'. However, that is not too much
of a problem in my eyes: I scanned the tree and out of the ~2400 ebuilds
that use find -exec/exec/xargs, none used it in combination with the
scripts I propose to convert to functions.

Having them in an eclass raises the problem of ebuilds having to inherit
said eclass, though. Even if it would be the correct way, I am not all
that keen on adding a 'inherit install-helpers' to ~15'000 ebuilds, so I
solved the problem this way:

--- ebuild.sh   2006-09-03 15:39:22 UTC
+++ ebuild.sh   2006-09-03 15:53:02 UTC
@@ -1350,6 +1350,9 @@
 # this can be left out of ebd variants, since they're unaffected.
 unset EBUILD_DEATH_HOOKS

+# let the profiles define eclasses to automatically load for every ebuild
+[[ -n ${PORTAGE_ECLASS_AUTOLOAD} ]] && inherit ${PORTAGE_ECLASS_AUTOLOAD}
+
 source ${EBUILD} || die "error sourcing ebuild"
 if ! hasq depend $EBUILD_PHASE; then
        RESTRICT="${PORTAGE_RESTRICT}"

Setting PORTAGE_ECLASS_AUTOLOAD enables every repository to define its
own set of "standard functions".

Note that I don't really care how the functions/scripts get into the
tree, it only matters to me *that* they are in the tree, so I'm open to
other suggestions. Also, this is probably not the only heap of functions
to move out of portage into the tree, I just didn't want to do more
before I know what way to choose.

Suggestions, comments, alternative approaches, flames, all are welcome.

[1] http://bugs.gentoo.org/show_bug.cgi?id=121317
[2] http://bugs.gentoo.org/show_bug.cgi?id=136792

-- 
Kind Regards,

Simon Stelling
Gentoo/AMD64 developer
# Copyright 1999-2006 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

#
# Original Author: Simon Stelling <[EMAIL PROTECTED]>
# Purpose: Install helpers to facilitate various actions performed in
# src_install
#

# Note: All of these were moved out of portage as they are only
# ebuild-specifc

ECLASS="install-helpers"

#
# into*/*opts section
#

# These functions control where and how files/directories given to do* and
# new* functions are installed.

into() {
        if [ "$1" == "/" ]; then
                export DESTTREE=""
        else
                export DESTTREE=$1
                if [ ! -d "${D}${DESTTREE}" ]; then
                        install -d "${D}${DESTTREE}"
                fi
        fi
}

insinto() {
        if [ "$1" == "/" ]; then
                export INSDESTTREE=""
        else
                export INSDESTTREE=$1
                if [ ! -d "${D}${INSDESTTREE}" ]; then
                        install -d "${D}${INSDESTTREE}"
                fi
        fi
}

exeinto() {
        if [ "$1" == "/" ]; then
                export EXEDESTTREE=""
        else
                export EXEDESTTREE="$1"
                if [ ! -d "${D}${EXEDESTTREE}" ]; then
                        install -d "${D}${EXEDESTTREE}"
                fi
        fi
}

docinto() {
        if [ "$1" == "/" ]; then
                export DOCDESTTREE=""
        else
                export DOCDESTTREE="$1"
                if [ ! -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}" ]; then
                        install -d "${D}usr/share/doc/${PF}/${DOCDESTTREE}"
                fi
        fi
}

insopts() {
        export INSOPTIONS="$@"

        # `install` should never be called with '-s' ...
        hasq -s ${INSOPTIONS} && die "Never call insopts() with -s"
}

diropts() {
        export DIROPTIONS="$@"
}

exeopts() {
        export EXEOPTIONS="$@"

        # `install` should never be called with '-s' ...
        hasq -s ${EXEOPTIONS} && die "Never call exeopts() with -s"
}

libopts() {
        export LIBOPTIONS="$@"

        # `install` should never be called with '-s' ...
        hasq -s ${LIBOPTIONS} && die "Never call libopts() with -s"
}

# if no perms are specified, dirs/files will have decent defaults
# (not secretive, but not stupid)
umask 022
export DESTTREE=/usr
export INSDESTTREE=""
export EXEDESTTREE=""
export DOCDESTTREE=""
export INSOPTIONS="-m0644"
export EXEOPTIONS="-m0755"
export LIBOPTIONS="-m0644"
export DIROPTIONS="-m0755"
export MOPREFIX=${PN}

#
# do* section
#

dobin() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        if [[ ! -d ${D}${DESTTREE}/bin ]] ; then
                install -d "${D}${DESTTREE}/bin" || return 2
        fi

        ret=0

        for x in "$@" ; do
                if [[ -e ${x} ]] ; then
                        install -m0755 -o ${PORTAGE_INST_UID:-0} -g \
                        ${PORTAGE_INST_GID:-0} "${x}" "${D}${DESTTREE}/bin"
                else
                        echo "!!! ${0##*/}: ${x} does not exist" 1>&2
                        false
                fi
                ((ret+=$?))
        done

        return ${ret}
}

doconfd() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        env \
        INSDESTTREE="/etc/conf.d/" \
        doins "$@"
}

dodir() {
        slash=/
        install -d ${DIROPTIONS} "${@/#${slash}/${D}${slash}}"
}

dodoc() {
        if [ $# -lt 1 ] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1        
        fi

        dir="${D}usr/share/doc/${PF}/${DOCDESTTREE}"
        if [ ! -d "${dir}" ] ; then
                install -d "${dir}"
        fi

        ret=0
        for x in "$@" ; do
                if [ -s "${x}" ] ; then
                        install -m0644 "${x}" "${dir}"
                        gzip -f -9 "${dir}/${x##*/}"
                elif [ ! -e "${x}" ] ; then
                        echo "dodoc: ${x} does not exist" 1>&2
                        ((++ret))
                fi
        done

        return ${ret}
}

doenvd() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        env \
        INSDESTTREE="/etc/env.d/" \
        doins "$@"
}

doexe() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        if [[ ! -d ${D}${EXEDESTTREE} ]] ; then
                install -d "${D}${EXEDESTTREE}"
        fi

        for x in "$@" ; do
                if [ -L "${x}" ] ; then
                        cp "${x}" "${T}"
                        mysrc="${T}"/$(/usr/bin/basename "${x}")
                elif [ -d "${x}" ] ; then
                        echo "doexe: warning, skipping directory ${x}"
                        continue
                else
                        mysrc="${x}"
                fi
                install ${EXEOPTIONS} "${mysrc}" "${D}${EXEDESTTREE}"
        done
}

dohard() {
        if [[ $# -ne 2 ]] ; then
                echo "$0: two arguments needed" 1>&2
                return 1
        fi

        target=$1
        linkname=$2
        ln -f "${D}${target}" "${D}${linkname}"
}

doinfo() {
        if [ ${#} -lt 1 ] ; then
                echo "doinfo: at least one argument needed"
                return 1        
        fi
        if [ ! -d "${D}usr/share/info" ] ; then
                install -d "${D}usr/share/info"
        fi

        for x in "$@" ; do
                if [ -e "${x}" ] ; then
                        install -m0644 "${x}" "${D}usr/share/info"
                        gzip -f -9 "${D}usr/share/info/${x##*/}"
                else
                        echo "doinfo: ${x} does not exist"
                fi
        done
}

doinitd() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        env \
        EXEDESTTREE="/etc/init.d/" \
        doexe "$@"
}

doins() {
        if [ $# -lt 1 ] ; then
                echo "${0}: at least one argument needed"
                return 1
        fi

        if [ "${1}" == "-r" ] ; then
                DOINSRECUR=y
                shift
        else
                DOINSRECUR=n
        fi
        [ -z "${INSDEPTH}" ] && declare -i INSDEPTH=0
        if [ ${INSDEPTH} -gt 30 ] ; then
                echo "${0}: sanity check ... 30 directories is too much :("
                return 1
        fi

        if [ "${INSDESTTREE%${D}*}" == "" ]; then
                echo "-------------------------------------------------------" 
1>&2
                echo "You should not use \${D} with helpers." 1>&2
                echo "  --> ${INSDESTTREE}" 1>&2
                echo "-------------------------------------------------------" 
1>&2
                #return 1
        fi

        [ ! -d "${D}${INSDESTTREE}" ] && dodir "${INSDESTTREE}"

        for x in "$@" ; do
                if [ -L "$x" ] ; then
                        cp "$x" "${T}"
                        mysrc="${T}/$(/usr/bin/basename "${x}")"
                elif [ -d "$x" ] ; then
                        if [ "${DOINSRECUR}" == "n" ] ; then
                                continue
                        fi

                        mydir="${INSDESTTREE}/$(basename "${x}")"
                        find "${x}" -mindepth 1 -maxdepth 1 -exec \
                                env \
                                        INSDESTTREE="${mydir}" \
                                        INSDEPTH=$((INSDEPTH+1)) \
                                        doins -r {} \;
                        continue
                else
                        mysrc="${x}"
                fi
                install ${INSOPTIONS} "${mysrc}" "${D}${INSDESTTREE}"
        done
}

dolib() {
        # Setup ABI cruft
        LIBDIR_VAR="LIBDIR_${ABI}"
        if [[ -n ${ABI} && -n ${!LIBDIR_VAR} ]] ; then
                CONF_LIBDIR=${!LIBDIR_VAR}
        fi
        unset LIBDIR_VAR
        # we need this to default to lib so that things dont break
        CONF_LIBDIR=${CONF_LIBDIR:-lib}
        libdir="${D}${DESTTREE}/${CONF_LIBDIR}"


        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi
        if [[ ! -d ${libdir} ]] ; then
                install -d "${libdir}" || return 1
        fi

        ret=0

        for x in "$@" ; do
                if [[ -e ${x} ]] ; then
                        if [[ ! -L ${x} ]] ; then
                                install ${LIBOPTIONS} "${x}" "${libdir}"
                        else
                                ln -s "$(readlink "${x}")" "${libdir}/${x##*/}"
                        fi
                else
                        echo "!!! ${0##*/}: ${x} does not exist" 1>&2
                        false
                fi
                ((ret+=$?))
        done

        return ${ret}
}

dolib.a() {
        env LIBOPTIONS="-m0644" \
        dolib "$@"
}

dolib.so() {
        env LIBOPTIONS="-m0755" \
        dolib "$@"
}

doman() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        i18n=""

        ret=0

        for x in "$@" ; do
                if [[ ${x:0:6} == "-i18n=" ]] ; then
                        i18n=${x:6}/
                        continue
                fi
                if [[ ${x:0:6} == ".keep_" ]] ; then
                        continue
                fi

                suffix=${x##*.}

                if [[ ${suffix} == "gz" ]] ; then
                        realname=${x%.*}
                        suffix=${realname##*.}
                        echo "QA Notice: you should let portage compress 
'${realname}' for you" 2>&1
                fi

                mandir=${i18n}man${suffix:0:1}

                if echo ${mandir} | egrep -q 'man[0-9n](|f|p|pm)$' -; then
                        if [[ -s ${x} ]] ; then
                                if [[ ! -d ${D}/usr/share/man/${mandir} ]] ; 
then
                                        install -d 
"${D}/usr/share/man/${mandir}"
                                fi

                                install -m0644 "${x}" 
"${D}/usr/share/man/${mandir}"
                                ((ret+=$?))
                        elif [[ ! -e ${x} ]] ; then
                                echo "doman: ${x} does not exist" 1>&2
                                ((++ret))
                        fi
                else
                        echo "doman: '${x}' is probably not a man page; 
skipping" 1>&2
                        ((++ret))
                fi
        done

        return ${ret}
}

domo() {
        mynum=${#}
        if [ ${mynum} -lt 1 ] ; then
                echo "${0}: at least one argument needed"
                return 1
        fi
        if [ ! -d "${D}${DESTTREE}/share/locale" ] ; then
                install -d "${D}${DESTTREE}/share/locale/"
        fi

        for x in "$@" ; do
                if [ -e "${x}" ] ; then
                        mytiny="${x##*/}"
                        
mydir="${D}${DESTTREE}/share/locale/${mytiny%.*}/LC_MESSAGES"
                        if [ ! -d "${mydir}" ] ; then
                                install -d "${mydir}"
                        fi
                        install -m0644 "${x}" "${mydir}/${MOPREFIX}.mo"
                else
                        echo "${0}: ${x} does not exist"
                fi
        done
}

dosbin() {
        if [[ $# -lt 1 ]] ; then
                echo "$0: at least one argument needed" 1>&2
                return 1
        fi

        if [[ ! -d ${D}${DESTTREE}/sbin ]] ; then
                install -d "${D}${DESTTREE}/sbin" || return 2
        fi

        ret=0

        for x in "$@" ; do
                if [[ -e ${x} ]] ; then
                        install -m0755 -o ${PORTAGE_INST_UID:-0} -g \
                        ${PORTAGE_INST_GID:-0} "${x}" "${D}${DESTTREE}/sbin"
                else
                        echo "!!! ${0##*/}: ${x} does not exist" 1>&2
                        false
                fi
                ((ret+=$?))
        done

        return ${ret}
}

dosed() {
        mysed="s:${D}::g"

        for x in "$@" ; do
                y="${D}${x}"
                if [ -a "${y}" ] ; then
                        if [ -f "${y}" ] ; then
                                mysrc="${T}/${y##*/}"
                                cp "${y}" "${mysrc}"
                                sed -e "${mysed}" "${mysrc}" > "${y}"
                        else
                                echo "${y} is not a regular file!"
                                return 1
                        fi
                else
                        mysed="${x}"
                fi
        done
}

dosym() {
        if [[ $# -ne 2 ]] ; then
                echo "$0: two arguments needed" 1>&2
                return 1
        fi

        destdir=${2%/*}
        [[ ! -d ${D}${destdir} ]] && dodir "${destdir}"

        ln -snf "$1" "${D}$2"
}

#
# new* section
#

# This code creates a bunch of new* functions that do basically the same as
# their do* relatives, but rename the file before putting it into the final
# location. They take exactly two arguments.

for act in bin confd doc envd exe initd ins lib.a lib.so man sbin ; do
        eval "new${act}() { \
                if [[ -z \${T} ]] || [[ -z \${2} ]] ; then \
                        echo \"\$0: Need two arguments, old file and new file\" 
1>&2 ; \
                        return 1 ; \
                fi ; \
                \
                rm -rf \"\${T}/\${2}\" && \
                cp -f \"\${1}\" \"\${T}/\${2}\" && \
                do${act} \"\${T}/\${2}\" ; \
        }"
done

#
# misc section
#

fowners() {
        slash=/
        chown "${@/#${slash}/${D}${slash}}"
}

fperms() {
        slash=/
        chmod "${@/#${slash}/${D}${slash}}"
}

# adds ".keep" files so that dirs aren't auto-cleaned
keepdir() {
        dodir "$@"
        local x
        if [ "$1" == "-R" ] || [ "$1" == "-r" ]; then
                shift
                find "$@" -type d -printf 
"${D}/%p/.keep_${CATEGORY}_${PN}-${SLOT}\n" | tr "\n" "\0" | $XARGS -0 -n100 
touch || die "Failed to recursive create .keep files"
        else
                for x in "$@"; do
                        touch "${D}/${x}/.keep_${CATEGORY}_${PN}-${SLOT}" || 
die "Failed to create .keep in ${D}/${x}"
                done
        fi
}

Reply via email to