Hi,

The ruby team is currently working on two new eclasses to better handle
our ruby packages. This first one is intended to be a replacement for
the current ruby.eclass. A second eclass is forthcoming and will provide
support for handling gems.

This new eclass has much better handling of multiple ruby target
implementations, fixing https://bugs.gentoo.org/show_bug.cgi?id=167029
and provides a better framework to include more functionality later.

We intend to move this eclass to the main tree and gradually move over
the packages currently using ruby.eclass. ruby.eclass will be deprecated
over time but we don't have a specific timeline for that yet.

There is a testbed with ebuilds here:
http://git.overlays.gentoo.org/gitweb/?p=proj/ruby-scripts.git;a=tree;f=ruby-ng-testbed;hb=HEAD

The eclass itself is attached to this message and here:
http://git.overlays.gentoo.org/gitweb/?p=proj/ruby-scripts.git;a=blob;f=ruby-ng-testbed/eclass/ruby-ng.eclass;h=ce9a37440600c7913a21b5780a18b5e8dd9d712f;hb=HEAD

Kind regards,

Hans

# Copyright 1999-2004 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: /var/cvsroot/gentoo-x86/eclass/ruby.eclass,v 1.75 2009/03/03 
15:51:54 a3li Exp $
#
# @ECLASS: ruby-ng.eclass
# @MAINTAINER:
# Ruby herd <r...@gentoo.org>
#
# Author: Diego E. Pettenò <flamee...@gentoo.org>
#
# Author: Alex Legler <a...@gentoo.org>
#
# @BLURB: An eclass for installing Ruby packages with proper support for 
multiple Ruby slots.
# @DESCRIPTION:
# The Ruby eclass is designed to allow an easier installation of Ruby packages
# and their incorporation into the Gentoo Linux system.
#
# Currently available targets are:
#  * ruby18 - Ruby (MRI) 1.8.x
#  * ruby19 - Ruby (MRI) 1.9.x
#  * ree18  - Ruby Enterprise Edition 1.8.x
#  * jruby  - JRuby
#
# This eclass does not define the implementation of the configure,
# compile, test, or install phases. Instead, the default phases are
# used.  Specific implementations of these phases can be provided in
# the ebuild either to be run for each Ruby implementation, or for all
# Ruby implementations, as follows:
#
#  * each_ruby_configure
#  * all_ruby_configure

# @ECLASS-VARIABLE: USE_RUBY
# @DESCRIPTION:
# This variable contains a space separated list of targets (see above) a package
# is compatible to. It must be set before the `inherit' call. There is no
# default. All ebuilds are expected to set this variable.

# @ECLASS-VARIABLE: PATCHES
# @DESCRIPTION:
# A String or Array of filenames of patches to apply to all implementations.

# @ECLASS-VARIABLE: RUBY_OPTIONAL
# @DESCRIPTION:
# Set the value to "yes" to make the dependency on a Ruby interpreter optional.

inherit eutils toolchain-funcs

EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_test 
src_install pkg_setup

case ${EAPI} in
        2) ;;
        *)
                die "Unsupported EAPI=${EAPI} for ruby-ng.eclass"
esac

# @FUNCTION: ruby_implementation_depend
# @USAGE: target [comparator [version]]
# @RETURN: Package atom of a Ruby implementation to be used in dependencies.
# @DESCRIPTION:
# This function returns the formal package atom for a Ruby implementation.
#
# `target' has to be one of the valid values for USE_RUBY (see above)
# 
# Set `comparator' and `version' to include a comparator (=, >=, etc.) and a
# version string to the returned string
ruby_implementation_depend() {
        local rubypn=
        local rubyslot=

        case $1 in
                ruby18)
                        rubypn="dev-lang/ruby"
                        rubyslot=":1.8"
                        ;;
                ruby19)
                        rubypn="dev-lang/ruby"
                        rubyslot=":1.9"
                        ;;
                ree18)
                        rubypn="dev-lang/ruby-enterprise"
                        rubyslot=":1.8"
                        ;;
                jruby)
                        rubypn="dev-java/jruby"
                        rubyslot=""
                        ;;
                *) die "$1: unknown Ruby implementation"
        esac

        echo "$2${rubypn}$3${rubyslot}"
}

# @FUNCTION: ruby_samelib
# @RETURN: use flag string with current ruby implementations
# @DESCRIPTION:
# Convenience function to output the use dependency part of a
# dependency. Used as a building block for ruby_add_rdepend() and
# ruby_add_bdepend(), but may also be useful in an ebuild to specify
# more complex dependencies.
ruby_samelib() {
        local res=
        for _ruby_implementation in $USE_RUBY; do
                has -${_ruby_implementation} $@ || \
                        res="${res}ruby_targets_${_ruby_implementation}?,"
        done

        echo "[${res%,}]"
}

_ruby_implementation_depend() {
        echo "ruby_targets_${1}? ( ${2}[ruby_targets_${1}] )"
}

_ruby_add_bdepend() {
        local atom=$1
        local conditions=$2

        for condition in $conditions; do
                atom="${condition}? ( ${atom} )"
        done

        DEPEND="${DEPEND} ${atom}"
        RDEPEND="${RDEPEND}"
}

_ruby_add_rdepend() {
        local atom=$1
        local conditions=$2

        for condition in $conditions; do
                atom="${condition}? ( ${atom} )"
        done

        RDEPEND="${RDEPEND} ${atom}"
        _ruby_add_bdepend "$atom" test
}

# @FUNCTION: ruby_add_rdepend
# @USAGE: [conditions] atom
# @DESCRIPTION:
# Adds the specified atom(s) with optional use condition(s) to
# RDEPEND, taking the current set of ruby targets into account. This
# makes sure that all ruby dependencies of the package are installed
# for the same ruby targets. Use this function for all ruby
# dependencies instead of setting RDEPEND yourself. Both atom and
# conditions can be a space-separated list of atoms or conditions.
ruby_add_rdepend() {
        local atoms=
        local conditions=
        case $# in
                1)
                        atoms=$1
                        ;;
                2)
                        conditions=$1
                        atoms=$2
                        ;;
                *)
                        die "bad number of arguments to $0"
                        ;;
        esac

        for atom in $atoms; do
                _ruby_add_rdepend "${atom}$(ruby_samelib)" "$conditions"
        done
}

# @FUNCTION: ruby_add_bdepend
# @USAGE: [conditions] atom
# @DESCRIPTION:
# Adds the specified atom(s) with optional use condition(s) to both
# DEPEND and RDEPEND, taking the current set of ruby targets into
# account. This makes sure that all ruby dependencies of the package
# are installed for the same ruby targets. Use this function for all
# ruby dependencies instead of setting DEPEND and RDEPEND
# yourself. Both atom and conditions can be a space-separated list of
# atoms or conditions.
ruby_add_bdepend() {
        local atoms=
        local conditions=
        case $# in
                1)
                        atoms=$1
                        ;;
                2)
                        conditions=$1
                        atoms=$2
                        ;;
                *)
                        die "bad number of arguments to $0"
                        ;;
        esac

        for atom in $atoms; do
                _ruby_add_bdepend "${atom}$(ruby_samelib)" "$conditions"
        done
}

for _ruby_implementation in $USE_RUBY; do
        IUSE="${IUSE} ruby_targets_${_ruby_implementation}"

        # If you specify RUBY_OPTIONAL you also need to take care of
        # ruby useflag and dependency.
        if [[ ${RUBY_OPTIONAL} != "yes" ]]; then
                DEPEND="${DEPEND} ruby_targets_${_ruby_implementation}? ( 
$(ruby_implementation_depend $_ruby_implementation) )"
                RDEPEND="${RDEPEND} ruby_targets_${_ruby_implementation}? ( 
$(ruby_implementation_depend $_ruby_implementation) )"
        fi
done

_ruby_invoke_environment() {
        old_S=${S}
        sub_S=${S#${WORKDIR}}

        environment=$1; shift

        my_WORKDIR="${WORKDIR}"/${environment}
        S="${my_WORKDIR}"/"${sub_S}"

        if [[ -d "${S}" ]]; then
                pushd "$S" &>/dev/null
        elif [[ -d "${my_WORKDIR}" ]]; then
                pushd "${my_WORKDIR}" &>/dev/null
        else
                pushd "${WORKDIR}" &>/dev/null
        fi

        ebegin "Running ${_PHASE:-${EBUILD_PHASE}} phase for $environment"
        "$@"
        popd &>/dev/null

        S=${old_S}
}

_ruby_each_implementation() {
        local invoked=no
        for _ruby_implementation in ${USE_RUBY}; do
                # only proceed if it's requested
                use ruby_targets_${_ruby_implementation} || continue

                RUBY=$(type -p $_ruby_implementation 2>/dev/null)
                invoked=yes

                if [[ -n "$1" ]]; then
                        _ruby_invoke_environment $_ruby_implementation "$@"
                fi

                unset RUBY
        done

        [[ ${invoked} == "no" ]] && die "You need to select at least one Ruby 
implementation by setting RUBY_TARGETS in /etc/make.conf."
}

# @FUNCTION: ruby-ng_pkg_setup
# @DESCRIPTION:
# Check whether at least one ruby target implementation is present.
ruby-ng_pkg_setup() {
        # This only checks that at least one implementation is present
        # before doing anything; by leaving the parameters empty we know
        # it's a special case.
        _ruby_each_implementation
}

# @FUNCTION: ruby-ng_src_unpack
# @DESCRIPTION:
# Unpack the source archive, including gems.
ruby-ng_src_unpack() {
        mkdir "${WORKDIR}"/all
        pushd "${WORKDIR}"/all &>/dev/null

        # We don't support an each-unpack, it's either all or nothing!
        if type all_ruby_unpack &>/dev/null; then
                _ruby_invoke_environment all all_ruby_unpack
        else
                [[ -n ${A} ]] && unpack ${A}
        fi

        popd &>/dev/null
}

_ruby_apply_patches() {
        for x in "${patch...@]}"; do
                epatch "${x}"
        done

        # This is a special case: instead of executing just in the special
        # "all" environment, this will actually copy the effects on _all_
        # the other environments, and is thus executed before the copy
        type all_ruby_prepare &>/dev/null && all_ruby_prepare
}

_ruby_source_copy() {
        # Until we actually find a reason not to, we use hardlinks, this
        # should reduce the amount of disk space that is wasted by this.
        cp -prl all ${_ruby_implementation} \
                || die "Unable to copy ${_ruby_implementation} environment"
}

# @FUNCTION: ruby-ng_src_prepare
# @DESCRIPTION:
# Apply patches and prepare versions for each ruby target
# implementation. Also carry out common clean up tasks.
ruby-ng_src_prepare() {
        # Way too many Ruby packages are prepared on OSX without removing
        # the extra data forks, we do it here to avoid repeating it for
        # almost every other ebuild.
        find . -name '._*' -delete

        _ruby_invoke_environment all _ruby_apply_patches

        _ruby_each_implementation _ruby_source_copy

        if type each_ruby_prepare &>/dev/null; then
                _ruby_each_implementation each_ruby_prepare
        fi
}

# @FUNCTION: ruby-ng_src_configure
# @DESCRIPTION:
# Configure the package.
ruby-ng_src_configure() {
        if type each_ruby_configure &>/dev/null; then
                _ruby_each_implementation each_ruby_configure
        fi

        type all_ruby_configure &>/dev/null && \
                _ruby_invoke_environment all all_ruby_configure
}

# @FUNCTION: ruby-ng_src_compile
# @DESCRIPTION:
# Compile the package.
ruby-ng_src_compile() {
        if type each_ruby_compile &>/dev/null; then
                _ruby_each_implementation each_ruby_compile
        fi

        type all_ruby_compile &>/dev/null && \
                _ruby_invoke_environment all all_ruby_compile
}

# @FUNCTION: ruby-ng_src_test
# @DESCRIPTION:
# Run tests for the package.
ruby-ng_src_test() {
        if type each_ruby_test &>/dev/null; then
                _ruby_each_implementation each_ruby_test
        fi

        type all_ruby_test &>/dev/null && \
                _ruby_invoke_environment all all_ruby_test
}

_each_ruby_check_install() {
        local libruby_basename=$(${RUBY} -rrbconfig -e 'puts 
Config::CONFIG["LIBRUBY_SO"]')
        local libruby_soname=$(scanelf -qS 
"/usr/$(get_libdir)/${libruby_basename}" | awk '{ print $1 }')

        # The current implementation lacks libruby (i.e.: jruby)
        [[ -z ${libruby_soname} ]] && return 0

        scanelf -qnR "${D}"/$(dirname $(${RUBY} -rrbconfig -e 'puts 
Config::CONFIG["sitedir"]')) \
                | fgrep -v "${libruby_soname}" \
                > "${T}"/ruby-ng-${_ruby_implementation}-mislink.log

        if [[ -s "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ]]; then
                ewarn "Extensions installed for ${_ruby_implementation} with 
missing links to ${libruby}"
                ewarn $(< "${T}"/ruby-ng-${_ruby_implementation}-mislink.log )
                die "Missing links to ${libruby}"
        fi
}

# @FUNCTION: ruby-ng_src_install
# @DESCRIPTION:
# Install the package for each ruby target implementation.
ruby-ng_src_install() {
        if type each_ruby_install &>/dev/null; then
                _ruby_each_implementation each_ruby_install
        fi

        type all_ruby_install &>/dev/null && \
                _ruby_invoke_environment all all_ruby_install

        _PHASE="check install" \
                _ruby_each_implementation _each_ruby_check_install
}

# @FUNCTION: doruby
# @USAGE: file [file...]
# @DESCRIPTION:
# Installs the specified file(s) into the sitelibdir of the Ruby interpreter in 
${RUBY}. 
doruby() {
        ( # don't want to pollute calling env
                insinto $(${RUBY} -r rbconfig -e 'print 
Config::CONFIG["sitelibdir"]')
                insopts -m 0644
                doins "$@"
        ) || die "failed to install $@"
}

# @FUNCTION: ruby_get_libruby
# @RETURN: The location of libruby*.so belonging to the Ruby interpreter in 
${RUBY}.
ruby_get_libruby() {
        ${RUBY} -rrbconfig -e 'puts File.join(Config::CONFIG["libdir"], 
Config::CONFIG["LIBRUBY"])'
}

# @FUNCTION: ruby_get_hdrdir
# @RETURN: The location of the header files belonging to the Ruby interpreter 
in ${RUBY}.
ruby_get_hdrdir() {
        local rubyhdrdir=$(${RUBY} -rrbconfig -e 'puts 
Config::CONFIG["rubyhdrdir"]')

        if [[ "${rubyhdrdir}" = "nil" ]] ; then
                rubyhdrdir=$(${RUBY} -rrbconfig -e 'puts 
Config::CONFIG["archdir"]')
        fi

        echo "${rubyhdrdir}"
}

Attachment: signature.asc
Description: This is a digitally signed message part

Reply via email to