public inbox for gentoo-dev@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-dev] [RFC] Initial python-r1.eclass & distutils-r1.eclass
@ 2012-09-29  8:53 Michał Górny
  2012-09-29 10:00 ` Tomáš Chvátal
                   ` (3 more replies)
  0 siblings, 4 replies; 48+ messages in thread
From: Michał Górny @ 2012-09-29  8:53 UTC (permalink / raw
  To: gentoo-dev; +Cc: python


[-- Attachment #1.1: Type: text/plain, Size: 272 bytes --]

Hello,

Instead of the floating patches and p-d-ng modifications I sent
earlier, here are the two complete (so far, well, initial :P) eclasses
for review.

They are designed as 'mostly' drop-in python-distutils-ng replacement.

-- 
Best regards,
Michał Górny

[-- Attachment #1.2: python-r1.eclass --]
[-- Type: text/plain, Size: 5952 bytes --]

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

# @ECLASS: python-r1
# @MAINTAINER:
# Python herd <python@gentoo.org>
# @AUTHOR:
# Author: Michał Górny <mgorny@gentoo.org>
# Based on work of: Krzysztof Pawlik <nelchael@gentoo.org>
# @BLURB: A common, simple eclass for Python packages.
# @DESCRIPTION:
# A common eclass providing helper functions to build and install
# packages supporting being installed for multiple Python
# implementations.
#
# This eclass sets correct IUSE and REQUIRED_USE. It exports PYTHON_DEPS
# and PYTHON_USEDEP so you can create correct dependencies for your
# package easily. It also provides methods to easily run a command for
# each enabled Python implementation and duplicate the sources for them.

case "${EAPI}" in
	0|1|2|3)
		die "Unsupported EAPI=${EAPI} (too old) for ${ECLASS}"
		;;
	4)
		# EAPI=4 needed for REQUIRED_USE
		;;
	*)
		die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
		;;
esac

# @ECLASS-VARIABLE: _PYTHON_ALL_IMPLS
# @INTERNAL
# @DESCRIPTION:
# All supported Python implementations, most preferred last.
_PYTHON_ALL_IMPLS=(
	jython2_5
	pypy1_8 pypy1_9
	python3_1 python3_2
	python2_5 python2_6 python2_7
)

# @ECLASS-VARIABLE: PYTHON_COMPAT
# @DESCRIPTION:
# This variable contains a space separated list of Python
# implementations a package supports. It must be set before
# the `inherit' call.  The default is to enable all implementations.
#
# PYTHON_COMPAT can be either a scalar or an array. If it's a scalar,
# the eclass will implicitly convert it to an array.
: ${PYTHON_COMPAT:=${_PYTHON_ALL_IMPLS[@]}}

# @ECLASS-VARIABLE: PYTHON_REQ_USE
# @DEFAULT_UNSET
# @DESCRIPTION:
# The list of USEflags required to be enabled on the chosen Python
# implementations, formed as a USE-dependency string. It should be valid
# for all implementations in PYTHON_COMPAT, so it may be necessary to
# use USE defaults.
#
# Example:
# @CODE
# PYTHON_REQ_USE="gdbm,ncurses(-)?"
# @CODE
#
# Will cause the Python dependencies to look like:
# @CODE
# python_targets_pythonX_Y? (
#   dev-lang/python:X_Y[gdbm,ncurses(-)?] )
# @CODE

# @ECLASS-VARIABLE: PYTHON_DEPS
# @DESCRIPTION:
# This is an eclass-generated Python dependency string for all
# implementations listed in PYTHON_COMPAT. It should be used
# in RDEPEND and/or DEPEND like:
#
# @CODE
# RDEPEND="${PYTHON_DEPS}
#   dev-foo/mydep"
# DEPEND="${RDEPEND}"
# @CODE

# @ECLASS-VARIABLE: PYTHON_USEDEP
# @DESCRIPTION:
# This is an eclass-generated USE-dependency string which can be used to
# depend on another Python package being built for the same Python
# implementations. It should be used like:
#
# @CODE
# RDEPEND="dev-python/foo[${PYTHON_USEDEP}]"
# @CODE

PYTHON_COMPAT=( ${PYTHON_COMPAT[@]} )

_python_set_globals() {
	local flags=( "${PYTHON_COMPAT[@]/#/python_targets_}" )
	local optflags=${flags[@]/%/?}

	IUSE=${flags[*]}
	REQUIRED_USE="|| ( ${flags[*]} )"
	PYTHON_USEDEP=${optflags// /,}

	PYTHON_DEPS=
	local i
	for i in ${PYTHON_COMPAT[@]}; do
		local d
		case ${i} in
			python*)
				d='dev-lang/python';;
			jython*)
				d='dev-java/jython';;
			pypy*)
				d='dev-python/pypy';;
			*)
				die "Invalid implementation: ${i}"
		esac

		local v=${i##*[a-z]}
		local usestr
		[[ ${PYTHON_REQ_USE} ]] && usestr="[${PYTHON_REQ_USE}]"
		PYTHON_DEPS+=" python_targets_${i}? (
			${d}:${v/_/.}${usestr} )"
	done
}
_python_set_globals

# @FUNCTION: python_get_PYTHON
# @USAGE: <impl>
# @DESCRIPTION:
# Get the Python executable name for the given implementation. Please
# note that this this function returns the 'basename' only.
# If using it for a hashbang, please use #!/usr/bin/env.
python_get_PYTHON() {
	local impl=${1/_/.}

	case "${impl}" in
		python*|jython*)
			echo ${impl}
			;;
		pypy*)
			echo pypy-c${impl#pypy}
			;;
		*)
			die "Invalid argument to python_get_PYTHON: ${1}"
			;;
	esac
}

# @FUNCTION: python_copy_sources
# @DESCRIPTION:
# Create a single copy of the package sources (${S}) for each enabled
# Python implementation.
python_copy_sources() {
	local impl
	local bdir=${BUILD_DIR:-${S}}

	einfo "Will copy sources from ${S}"
	# the order is irrelevant here
	for impl in ${PYTHON_COMPAT[@]}; do
		if use python_targets_${impl}
		then
			local BUILD_DIR=${bdir%%/}-${impl}

			einfo "${impl}: copying to ${BUILD_DIR}"
			cp -pr "${S}" "${BUILD_DIR}" || die
		fi
	done
}

# @FUNCTION: python_foreach_impl
# @USAGE: <command> [<args>...]
# @DESCRIPTION:
# Run the given command for each of the enabled Python implementations.
# If additional parameters are passed, they will be passed through
# to the command. If the command fails, python_foreach_impl dies.
# If necessary, use ':' to force a successful return.
#
# Before the command is run, EPYTHON is set to the name of the current
# Python implementation, PYTHON is set to the correct Python executable
# name and exported, and BUILD_DIR is set to a 'default' build directory
# for given implementation (e.g. ${BUILD_DIR:-${S}}-python2_7).
#
# The command is run inside the build directory. If it doesn't exist
# yet, it is created (as an empty directory!). If your build system does
# not support out-of-source builds, you will likely want to use
# python_copy_sources first.
python_foreach_impl() {
	local impl
	local bdir=${BUILD_DIR:-${S}}

	for impl in ${_PYTHON_ALL_IMPLS[@]}; do
		if has ${impl} ${PYTHON_COMPAT[@]} && use python_targets_${impl}
		then
			local PYTHON=$(python_get_PYTHON "${impl}")
			local EPYTHON=${impl}
			local BUILD_DIR=${bdir%%/}-${impl}
			export PYTHON

			mkdir -p "${BUILD_DIR}" || die
			pushd "${BUILD_DIR}" &>/dev/null || die
			einfo "${EPYTHON}: running ${@}"
			"${@}" || die "${EPYTHON}: ${1} failed"
			popd || die
		fi
	done
}

[-- Attachment #1.3: distutils-r1.eclass --]
[-- Type: text/plain, Size: 6367 bytes --]

# Copyright 1999-2012 Gentoo Foundation
# Distributed under the terms of the GNU General Public License v2
# $Header: $

# @ECLASS: distutils-r1
# @MAINTAINER:
# Python herd <python@gentoo.org>
# @AUTHOR:
# Author: Michał Górny <mgorny@gentoo.org>
# Based on the work of: Krzysztof Pawlik <nelchael@gentoo.org>
# @BLURB: A simple eclass to build Python packages using distutils.
# @DESCRIPTION:
# A simple eclass providing functions to build Python packages using
# the distutils build system. It exports phase functions for all
# the src_* phases. Each of the phases runs two pseudo-phases:
# python_..._all() (e.g. python_prepare_all()) once in ${S}, then
# python_...() (e.g. python_prepare()) for each implementation
# (see: python_foreach_impl() in python-r1).
#
# In distutils-r1_src_prepare(), the 'all' function is run before
# per-implementation ones (because it creates the implementations),
# per-implementation functions are run in a random order.
#
# In remaining phase functions, the per-implementation functions are run
# before the 'all' one, and they are ordered from the least to the most
# preferred implementation (so that 'better' files overwrite 'worse'
# ones).
#
# If the ebuild doesn't specify a particular pseudo-phase function,
# the default one will be used (distutils-r1_...). Defaults are provided
# for all per-implementation pseudo-phases, python_prepare_all()
# and python_install_all(); whenever writing your own pseudo-phase
# functions, you should consider calling the defaults (and especially
# distutils-r1_python_prepare_all).
#
# Please note that distutils-r1 sets RDEPEND and DEPEND for you.

case "${EAPI}" in
	0|1|2|3)
		die "Unsupported EAPI=${EAPI} (too old) for ${ECLASS}"
		;;
	4)
		;;
	*)
		die "Unsupported EAPI=${EAPI} (unknown) for ${ECLASS}"
		;;
esac

inherit eutils python-r1

EXPORT_FUNCTIONS src_prepare src_configure src_compile src_test src_install

RDEPEND=${PYTHON_DEPS}
DEPEND=${PYTHON_DEPS}

# @FUNCTION: distutils-r1_python_prepare_all
# @DESCRIPTION:
# The default python_prepare_all(). It applies the patches from PATCHES
# array, then user patches and finally calls python_copy_sources to
# create copies of resulting sources for each Python implementation.
distutils-r1_python_prepare_all() {
	[[ ${PATCHES} ]] && epatch "${PATCHES[@]}"

	epatch_user

	# create source copies for each implementation
	python_copy_sources
}

# @FUNCTION: distutils-r1_python_prepare
# @DESCRIPTION:
# The default python_prepare(). Currently it is a no-op
# but in the future it may apply implementation-specific quirks
# to the build system.
distutils-r1_python_prepare() {
	:
}

# @FUNCTION: distutils-r1_python_configure
# @DESCRIPTION:
# The default python_configure(). Currently a no-op.
distutils-r1_python_configure() {
	:
}

# @FUNCTION: distutils-r1_python_compile
# @DESCRIPTION:
# The default python_compile(). Runs 'setup.py build' using the correct
# Python implementation.
distutils-r1_python_compile() {
	cd "${BUILD_DIR}" || die
	"${PYTHON}" setup.py build || die
}

# @FUNCTION: distutils-r1_python_test
# @DESCRIPTION:
# The default python_test(). Currently a no-op.
distutils-r1_python_test() {
	:
}

# @FUNCTION: distutils-r1_rename_scripts
# @DESCRIPTION:
# Renames installed Python scripts to be implementation-suffixed.
# ${PYTHON} has to be set to the expected Python executable (which
# hashbang will be grepped for), and ${EPYTHON} to the implementation
# name (for new name).
distutils-r1_rename_scripts() {
	local dir f
	local wrapdir=${T}/distutils_wrappers

	# XXX: change this if we ever allow directories in bin/sbin
	for dir in bin sbin usr/bin usr/sbin; do
		for f in "${D}"/${dir}/*; do
			if [[ -x ${f} ]]; then
				if [[ "$(head -n 1 "${f}")" == '#!'*${PYTHON}* ]]
				then
					local newf=${f}-${EPYTHON}
					mv "${f}" "${newf}" || die

					mkdir -p "${wrapdir}"/${dir}
					ln -fs "${newf##*/}" \
						"${wrapdir}"/${dir}/"${f##*/}" || die
				fi
			fi
		done
	done
}

# @FUNCTION: distutils-r1_python_install
# @DESCRIPTION:
# The default python_install(). Runs 'setup.py install' using
# the correct Python implementation, and appending the optimization
# flags. Then calls distutils-r1_rename_scripts.
distutils-r1_python_install() {
	local flags

	case "${EPYTHON}" in
		jython*)
			flags='--compile';;
		*)
			flags='--compile -O2';;
	esac

	# XXX: where does it come from?!
	unset PYTHONDONTWRITEBYTECODE

	cd "${BUILD_DIR}" || die
	"${PYTHON}" setup.py install ${flags} --root="${D}" || die

	distutils-r1_rename_scripts
}

# @FUNCTION: distutils-r1_python_install_all
# @DESCRIPTION:
# The default python_install_all(). It creates wrappers
# for the implementation-suffixed executables.
distutils-r1_python_install_all() {
	local wrapdir=${T}/distutils_wrappers

	if [[ -d ${wrapdir} ]]; then
		cp -r "${wrapdir}/." "${D}" || die
	fi
}

distutils-r1_src_prepare() {
	# common preparations
	if declare -f python_prepare_all >/dev/null; then
		python_prepare_all
	else
		distutils-r1_python_prepare_all
	fi

	if declare -f python_prepare >/dev/null; then
		python_foreach_impl python_prepare
	else
		distutils-r1_python_prepare
	fi
}

distutils-r1_src_configure() {
	if declare -f python_configure >/dev/null; then
		python_foreach_impl python_configure
	else
		distutils-r1_python_configure
	fi

	if declare -f python_configure_all >/dev/null; then
		python_configure_all
	fi
}

distutils-r1_src_compile() {
	if declare -f python_compile >/dev/null; then
		python_foreach_impl python_compile
	else
		python_foreach_impl distutils-r1_python_compile
	fi

	if declare -f python_compile_all >/dev/null; then
		python_compile_all
	fi
}

distutils-r1_src_test() {
	if declare -f python_test >/dev/null; then
		python_foreach_impl python_test
	else
		distutils-r1_python_test
	fi

	if declare -f python_test_all >/dev/null; then
		python_test_all
	fi
}

distutils-r1_src_install() {
	if declare -f python_install >/dev/null; then
		python_foreach_impl python_install
	else
		python_foreach_impl distutils-r1_python_install
	fi

	if declare -f python_install_all >/dev/null; then
		python_install_all
	else
		distutils-r1_python_install_all
	fi
}

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 316 bytes --]

^ permalink raw reply	[flat|nested] 48+ messages in thread

end of thread, other threads:[~2012-10-26 18:29 UTC | newest]

Thread overview: 48+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-29  8:53 [gentoo-dev] [RFC] Initial python-r1.eclass & distutils-r1.eclass Michał Górny
2012-09-29 10:00 ` Tomáš Chvátal
2012-09-29 10:23   ` Michał Górny
2012-09-29 10:45   ` Michał Górny
2012-09-29 19:34     ` Luca Barbato
2012-09-29 10:20 ` Markos Chandras
2012-09-29 10:49   ` Michał Górny
2012-09-29 13:49     ` hasufell
2012-09-29 14:19       ` Ian Stakenvicius
2012-09-29 14:26         ` hasufell
2012-09-29 14:37           ` Dirkjan Ochtman
2012-09-29 18:39             ` Michał Górny
2012-09-29 20:48               ` hasufell
2012-09-30 14:01                 ` Michał Górny
2012-09-29 15:37           ` Ian Stakenvicius
2012-09-29 15:45             ` hasufell
2012-09-29 15:50               ` Ian Stakenvicius
2012-09-29 15:54                 ` hasufell
2012-09-29 15:54               ` Ciaran McCreesh
2012-09-29 18:40               ` Michał Górny
2012-09-29 19:20                 ` Pacho Ramos
2012-09-29 20:34                   ` Michał Górny
2012-09-30  8:31                     ` Pacho Ramos
2012-09-30  8:58                       ` Fabian Groffen
2012-09-30  9:47                         ` Pacho Ramos
2012-09-30 13:28                         ` Michał Górny
2012-09-30 13:47                           ` Fabian Groffen
2012-09-30 13:57                         ` Michał Górny
2012-09-30 14:12                           ` Fabian Groffen
2012-09-30 18:15                             ` Zac Medico
2012-09-30 21:47                         ` Brian Harring
2012-10-01  6:36                           ` Fabian Groffen
2012-10-01  7:19                             ` Brian Harring
2012-10-01 15:17                             ` Marien Zwart
2012-10-01 15:44                               ` Fabian Groffen
2012-09-29 15:47             ` hasufell
2012-09-29 18:35       ` Michał Górny
2012-09-30  5:09   ` Ben de Groot
2012-10-05 12:42 ` Michał Górny
2012-10-25 16:41 ` hasufell
2012-10-25 17:10   ` Ian Stakenvicius
2012-10-25 17:43   ` Michał Górny
2012-10-25 18:55     ` hasufell
2012-10-25 20:13       ` Michał Górny
2012-10-26 18:28         ` hasufell
2012-10-25 20:37       ` Michał Górny
2012-10-25 19:19   ` hasufell
2012-10-25 20:40     ` Michał Górny

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox