1 |
# Copyright 1999-2009 Gentoo Foundation |
2 |
# Distributed under the terms of the GNU General Public License v2 |
3 |
# $Header: /var/cvsroot/gentoo-x86/eclass/ruby-ng.eclass,v 1.9 2010/04/02 20:26:21 a3li Exp $ |
4 |
# |
5 |
# @ECLASS: ruby-ng.eclass |
6 |
# @MAINTAINER: |
7 |
# Ruby herd <ruby@gentoo.org> |
8 |
# |
9 |
# Author: Diego E. Pettenò <flameeyes@gentoo.org> |
10 |
# |
11 |
# Author: Alex Legler <a3li@gentoo.org> |
12 |
# |
13 |
# Author: Hans de Graaff <graaff@gentoo.org> |
14 |
# |
15 |
# @BLURB: An eclass for installing Ruby packages with proper support for multiple Ruby slots. |
16 |
# @DESCRIPTION: |
17 |
# The Ruby eclass is designed to allow an easier installation of Ruby packages |
18 |
# and their incorporation into the Gentoo Linux system. |
19 |
# |
20 |
# Currently available targets are: |
21 |
# * ruby18 - Ruby (MRI) 1.8.x |
22 |
# * ruby19 - Ruby (MRI) 1.9.x |
23 |
# * ree18 - Ruby Enterprise Edition 1.8.x |
24 |
# * jruby - JRuby |
25 |
# |
26 |
# This eclass does not define the implementation of the configure, |
27 |
# compile, test, or install phases. Instead, the default phases are |
28 |
# used. Specific implementations of these phases can be provided in |
29 |
# the ebuild either to be run for each Ruby implementation, or for all |
30 |
# Ruby implementations, as follows: |
31 |
# |
32 |
# * each_ruby_configure |
33 |
# * all_ruby_configure |
34 |
|
35 |
# @ECLASS-VARIABLE: USE_RUBY |
36 |
# @DESCRIPTION: |
37 |
# This variable contains a space separated list of targets (see above) a package |
38 |
# is compatible to. It must be set before the `inherit' call. There is no |
39 |
# default. All ebuilds are expected to set this variable. |
40 |
|
41 |
# @ECLASS-VARIABLE: RUBY_PATCHES |
42 |
# @DESCRIPTION: |
43 |
# A String or Array of filenames of patches to apply to all implementations. |
44 |
|
45 |
# @ECLASS-VARIABLE: RUBY_OPTIONAL |
46 |
# @DESCRIPTION: |
47 |
# Set the value to "yes" to make the dependency on a Ruby interpreter optional. |
48 |
|
49 |
inherit eutils toolchain-funcs |
50 |
|
51 |
EXPORT_FUNCTIONS src_unpack src_prepare src_configure src_compile src_test src_install pkg_setup |
52 |
|
53 |
case ${EAPI} in |
54 |
0|1) |
55 |
die "Unsupported EAPI=${EAPI} (too old) for ruby-ng.eclass" ;; |
56 |
2) ;; |
57 |
*) |
58 |
die "Unknown EAPI=${EAPI} for ruby-ng.eclass" |
59 |
esac |
60 |
|
61 |
# @FUNCTION: ruby_implementation_depend |
62 |
# @USAGE: target [comparator [version]] |
63 |
# @RETURN: Package atom of a Ruby implementation to be used in dependencies. |
64 |
# @DESCRIPTION: |
65 |
# This function returns the formal package atom for a Ruby implementation. |
66 |
# |
67 |
# `target' has to be one of the valid values for USE_RUBY (see above) |
68 |
# |
69 |
# Set `comparator' and `version' to include a comparator (=, >=, etc.) and a |
70 |
# version string to the returned string |
71 |
ruby_implementation_depend() { |
72 |
local rubypn= |
73 |
local rubyslot= |
74 |
|
75 |
case $1 in |
76 |
ruby18) |
77 |
rubypn="dev-lang/ruby" |
78 |
rubyslot=":1.8" |
79 |
;; |
80 |
ruby19) |
81 |
rubypn="dev-lang/ruby" |
82 |
rubyslot=":1.9" |
83 |
;; |
84 |
ree18) |
85 |
rubypn="dev-lang/ruby-enterprise" |
86 |
rubyslot=":1.8" |
87 |
;; |
88 |
jruby) |
89 |
rubypn="dev-java/jruby" |
90 |
rubyslot="" |
91 |
;; |
92 |
*) die "$1: unknown Ruby implementation" |
93 |
esac |
94 |
|
95 |
echo "$2${rubypn}$3${rubyslot}" |
96 |
} |
97 |
|
98 |
# @FUNCTION: ruby_samelib |
99 |
# @RETURN: use flag string with current ruby implementations |
100 |
# @DESCRIPTION: |
101 |
# Convenience function to output the use dependency part of a |
102 |
# dependency. Used as a building block for ruby_add_rdepend() and |
103 |
# ruby_add_bdepend(), but may also be useful in an ebuild to specify |
104 |
# more complex dependencies. |
105 |
ruby_samelib() { |
106 |
local res= |
107 |
for _ruby_implementation in $USE_RUBY; do |
108 |
has -${_ruby_implementation} $@ || \ |
109 |
res="${res}ruby_targets_${_ruby_implementation}?," |
110 |
done |
111 |
|
112 |
echo "[${res%,}]" |
113 |
} |
114 |
|
115 |
_ruby_implementation_depend() { |
116 |
echo "ruby_targets_${1}? ( ${2}[ruby_targets_${1}] )" |
117 |
} |
118 |
|
119 |
_ruby_add_bdepend() { |
120 |
local atom=$1 |
121 |
local conditions=$2 |
122 |
|
123 |
for condition in $conditions; do |
124 |
hasq $condition "$IUSE" || IUSE="${IUSE} $condition" |
125 |
atom="${condition}? ( ${atom} )" |
126 |
done |
127 |
|
128 |
DEPEND="${DEPEND} ${atom}" |
129 |
RDEPEND="${RDEPEND}" |
130 |
} |
131 |
|
132 |
_ruby_add_rdepend() { |
133 |
local atom=$1 |
134 |
local conditions=$2 |
135 |
|
136 |
for condition in $conditions; do |
137 |
hasq $condition "$IUSE" || IUSE="${IUSE} $condition" |
138 |
atom="${condition}? ( ${atom} )" |
139 |
done |
140 |
|
141 |
RDEPEND="${RDEPEND} ${atom}" |
142 |
_ruby_add_bdepend "$atom" test |
143 |
} |
144 |
|
145 |
# @FUNCTION: ruby_add_rdepend |
146 |
# @USAGE: [conditions] atom |
147 |
# @DESCRIPTION: |
148 |
# Adds the specified atom(s) with optional use condition(s) to |
149 |
# RDEPEND, taking the current set of ruby targets into account. This |
150 |
# makes sure that all ruby dependencies of the package are installed |
151 |
# for the same ruby targets. Use this function for all ruby |
152 |
# dependencies instead of setting RDEPEND yourself. Both atom and |
153 |
# conditions can be a space-separated list of atoms or conditions. |
154 |
ruby_add_rdepend() { |
155 |
local atoms= |
156 |
local conditions= |
157 |
case $# in |
158 |
1) |
159 |
atoms=$1 |
160 |
;; |
161 |
2) |
162 |
conditions=$1 |
163 |
atoms=$2 |
164 |
;; |
165 |
*) |
166 |
die "bad number of arguments to $0" |
167 |
;; |
168 |
esac |
169 |
|
170 |
for atom in $atoms; do |
171 |
_ruby_add_rdepend "${atom}$(ruby_samelib)" "$conditions" |
172 |
done |
173 |
} |
174 |
|
175 |
# @FUNCTION: ruby_add_bdepend |
176 |
# @USAGE: [conditions] atom |
177 |
# @DESCRIPTION: |
178 |
# Adds the specified atom(s) with optional use condition(s) to both |
179 |
# DEPEND and RDEPEND, taking the current set of ruby targets into |
180 |
# account. This makes sure that all ruby dependencies of the package |
181 |
# are installed for the same ruby targets. Use this function for all |
182 |
# ruby dependencies instead of setting DEPEND and RDEPEND |
183 |
# yourself. Both atom and conditions can be a space-separated list of |
184 |
# atoms or conditions. |
185 |
ruby_add_bdepend() { |
186 |
local atoms= |
187 |
local conditions= |
188 |
case $# in |
189 |
1) |
190 |
atoms=$1 |
191 |
;; |
192 |
2) |
193 |
conditions=$1 |
194 |
atoms=$2 |
195 |
;; |
196 |
*) |
197 |
die "bad number of arguments to $0" |
198 |
;; |
199 |
esac |
200 |
|
201 |
for atom in $atoms; do |
202 |
_ruby_add_bdepend "${atom}$(ruby_samelib)" "$conditions" |
203 |
done |
204 |
} |
205 |
|
206 |
for _ruby_implementation in $USE_RUBY; do |
207 |
IUSE="${IUSE} ruby_targets_${_ruby_implementation}" |
208 |
|
209 |
# If you specify RUBY_OPTIONAL you also need to take care of |
210 |
# ruby useflag and dependency. |
211 |
if [[ ${RUBY_OPTIONAL} != "yes" ]]; then |
212 |
DEPEND="${DEPEND} ruby_targets_${_ruby_implementation}? ( $(ruby_implementation_depend $_ruby_implementation) )" |
213 |
RDEPEND="${RDEPEND} ruby_targets_${_ruby_implementation}? ( $(ruby_implementation_depend $_ruby_implementation) )" |
214 |
fi |
215 |
done |
216 |
|
217 |
_ruby_invoke_environment() { |
218 |
old_S=${S} |
219 |
sub_S=${S#${WORKDIR}} |
220 |
|
221 |
environment=$1; shift |
222 |
|
223 |
my_WORKDIR="${WORKDIR}"/${environment} |
224 |
S="${my_WORKDIR}"/"${sub_S}" |
225 |
|
226 |
if [[ -d "${S}" ]]; then |
227 |
pushd "$S" &>/dev/null |
228 |
elif [[ -d "${my_WORKDIR}" ]]; then |
229 |
pushd "${my_WORKDIR}" &>/dev/null |
230 |
else |
231 |
pushd "${WORKDIR}" &>/dev/null |
232 |
fi |
233 |
|
234 |
ebegin "Running ${_PHASE:-${EBUILD_PHASE}} phase for $environment" |
235 |
"$@" |
236 |
popd &>/dev/null |
237 |
|
238 |
S=${old_S} |
239 |
} |
240 |
|
241 |
_ruby_each_implementation() { |
242 |
local invoked=no |
243 |
for _ruby_implementation in ${USE_RUBY}; do |
244 |
# only proceed if it's requested |
245 |
use ruby_targets_${_ruby_implementation} || continue |
246 |
|
247 |
local _ruby_name=$_ruby_implementation |
248 |
|
249 |
# Add all USE_RUBY values where the flag name diverts from the binary here |
250 |
case $_ruby_implementation in |
251 |
ree18) |
252 |
_ruby_name=rubyee18 |
253 |
;; |
254 |
esac |
255 |
|
256 |
RUBY=$(type -p $_ruby_name 2>/dev/null) |
257 |
invoked=yes |
258 |
|
259 |
if [[ -n "$1" ]]; then |
260 |
_ruby_invoke_environment $_ruby_implementation "$@" |
261 |
fi |
262 |
|
263 |
unset RUBY |
264 |
done |
265 |
|
266 |
[[ ${invoked} == "no" ]] && die "You need to select at least one Ruby implementation by setting RUBY_TARGETS in /etc/make.conf." |
267 |
} |
268 |
|
269 |
# @FUNCTION: ruby-ng_pkg_setup |
270 |
# @DESCRIPTION: |
271 |
# Check whether at least one ruby target implementation is present. |
272 |
ruby-ng_pkg_setup() { |
273 |
# This only checks that at least one implementation is present |
274 |
# before doing anything; by leaving the parameters empty we know |
275 |
# it's a special case. |
276 |
_ruby_each_implementation |
277 |
} |
278 |
|
279 |
# @FUNCTION: ruby-ng_src_unpack |
280 |
# @DESCRIPTION: |
281 |
# Unpack the source archive. |
282 |
ruby-ng_src_unpack() { |
283 |
mkdir "${WORKDIR}"/all |
284 |
pushd "${WORKDIR}"/all &>/dev/null |
285 |
|
286 |
# We don't support an each-unpack, it's either all or nothing! |
287 |
if type all_ruby_unpack &>/dev/null; then |
288 |
_ruby_invoke_environment all all_ruby_unpack |
289 |
else |
290 |
[[ -n ${A} ]] && unpack ${A} |
291 |
fi |
292 |
|
293 |
popd &>/dev/null |
294 |
} |
295 |
|
296 |
_ruby_apply_patches() { |
297 |
for patch in "${RUBY_PATCHES[@]}"; do |
298 |
if [ -f "${patch}" ]; then |
299 |
epatch "${patch}" |
300 |
elif [ -f "${FILESDIR}/${patch}" ]; then |
301 |
epatch "${FILESDIR}/${patch}" |
302 |
else |
303 |
die "Cannot find patch ${patch}" |
304 |
fi |
305 |
done |
306 |
|
307 |
# This is a special case: instead of executing just in the special |
308 |
# "all" environment, this will actually copy the effects on _all_ |
309 |
# the other environments, and is thus executed before the copy |
310 |
type all_ruby_prepare &>/dev/null && all_ruby_prepare |
311 |
} |
312 |
|
313 |
_ruby_source_copy() { |
314 |
# Until we actually find a reason not to, we use hardlinks, this |
315 |
# should reduce the amount of disk space that is wasted by this. |
316 |
cp -prl all ${_ruby_implementation} \ |
317 |
|| die "Unable to copy ${_ruby_implementation} environment" |
318 |
} |
319 |
|
320 |
# @FUNCTION: ruby-ng_src_prepare |
321 |
# @DESCRIPTION: |
322 |
# Apply patches and prepare versions for each ruby target |
323 |
# implementation. Also carry out common clean up tasks. |
324 |
ruby-ng_src_prepare() { |
325 |
# Way too many Ruby packages are prepared on OSX without removing |
326 |
# the extra data forks, we do it here to avoid repeating it for |
327 |
# almost every other ebuild. |
328 |
find . -name '._*' -delete |
329 |
|
330 |
_ruby_invoke_environment all _ruby_apply_patches |
331 |
|
332 |
_PHASE="source copy" \ |
333 |
_ruby_each_implementation _ruby_source_copy |
334 |
|
335 |
if type each_ruby_prepare &>/dev/null; then |
336 |
_ruby_each_implementation each_ruby_prepare |
337 |
fi |
338 |
} |
339 |
|
340 |
# @FUNCTION: ruby-ng_src_configure |
341 |
# @DESCRIPTION: |
342 |
# Configure the package. |
343 |
ruby-ng_src_configure() { |
344 |
if type each_ruby_configure &>/dev/null; then |
345 |
_ruby_each_implementation each_ruby_configure |
346 |
fi |
347 |
|
348 |
type all_ruby_configure &>/dev/null && \ |
349 |
_ruby_invoke_environment all all_ruby_configure |
350 |
} |
351 |
|
352 |
# @FUNCTION: ruby-ng_src_compile |
353 |
# @DESCRIPTION: |
354 |
# Compile the package. |
355 |
ruby-ng_src_compile() { |
356 |
if type each_ruby_compile &>/dev/null; then |
357 |
_ruby_each_implementation each_ruby_compile |
358 |
fi |
359 |
|
360 |
type all_ruby_compile &>/dev/null && \ |
361 |
_ruby_invoke_environment all all_ruby_compile |
362 |
} |
363 |
|
364 |
# @FUNCTION: ruby-ng_src_test |
365 |
# @DESCRIPTION: |
366 |
# Run tests for the package. |
367 |
ruby-ng_src_test() { |
368 |
if type each_ruby_test &>/dev/null; then |
369 |
_ruby_each_implementation each_ruby_test |
370 |
fi |
371 |
|
372 |
type all_ruby_test &>/dev/null && \ |
373 |
_ruby_invoke_environment all all_ruby_test |
374 |
} |
375 |
|
376 |
_each_ruby_check_install() { |
377 |
local libruby_basename=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["LIBRUBY_SO"]') |
378 |
local libruby_soname=$(scanelf -qS "/usr/$(get_libdir)/${libruby_basename}" | awk '{ print $1 }') |
379 |
local sitedir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["sitedir"]') |
380 |
local sitelibdir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["sitelibdir"]') |
381 |
|
382 |
# Look for wrong files in sitedir |
383 |
if [[ -d "${D}${sitedir}" ]]; then |
384 |
local f=$(find "${D}${sitedir}" -mindepth 1 -maxdepth 1 -not -wholename "${D}${sitelibdir}") |
385 |
if [[ -n ${f} ]]; then |
386 |
eerror "Found files in sitedir, outsite sitelibdir:" |
387 |
eerror "${f}" |
388 |
die "Misplaced files in sitedir" |
389 |
fi |
390 |
fi |
391 |
|
392 |
# The current implementation lacks libruby (i.e.: jruby) |
393 |
[[ -z ${libruby_soname} ]] && return 0 |
394 |
|
395 |
scanelf -qnR "${D}${sitedir}" \ |
396 |
| fgrep -v "${libruby_soname}" \ |
397 |
> "${T}"/ruby-ng-${_ruby_implementation}-mislink.log |
398 |
|
399 |
if [[ -s "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ]]; then |
400 |
ewarn "Extensions installed for ${_ruby_implementation} with missing links to ${libruby}" |
401 |
ewarn $(< "${T}"/ruby-ng-${_ruby_implementation}-mislink.log ) |
402 |
die "Missing links to ${libruby}" |
403 |
fi |
404 |
} |
405 |
|
406 |
# @FUNCTION: ruby-ng_src_install |
407 |
# @DESCRIPTION: |
408 |
# Install the package for each ruby target implementation. |
409 |
ruby-ng_src_install() { |
410 |
if type each_ruby_install &>/dev/null; then |
411 |
_ruby_each_implementation each_ruby_install |
412 |
fi |
413 |
|
414 |
type all_ruby_install &>/dev/null && \ |
415 |
_ruby_invoke_environment all all_ruby_install |
416 |
|
417 |
_PHASE="check install" \ |
418 |
_ruby_each_implementation _each_ruby_check_install |
419 |
} |
420 |
|
421 |
# @FUNCTION: doruby |
422 |
# @USAGE: file [file...] |
423 |
# @DESCRIPTION: |
424 |
# Installs the specified file(s) into the sitelibdir of the Ruby interpreter in ${RUBY}. |
425 |
doruby() { |
426 |
[[ -z ${RUBY} ]] && die "\$RUBY is not set" |
427 |
( # don't want to pollute calling env |
428 |
insinto $(${RUBY} -rrbconfig -e 'print Config::CONFIG["sitelibdir"]') |
429 |
insopts -m 0644 |
430 |
doins "$@" |
431 |
) || die "failed to install $@" |
432 |
} |
433 |
|
434 |
# @FUNCTION: ruby_get_libruby |
435 |
# @RETURN: The location of libruby*.so belonging to the Ruby interpreter in ${RUBY}. |
436 |
ruby_get_libruby() { |
437 |
${RUBY} -rrbconfig -e 'puts File.join(Config::CONFIG["libdir"], Config::CONFIG["LIBRUBY"])' |
438 |
} |
439 |
|
440 |
# @FUNCTION: ruby_get_hdrdir |
441 |
# @RETURN: The location of the header files belonging to the Ruby interpreter in ${RUBY}. |
442 |
ruby_get_hdrdir() { |
443 |
local rubyhdrdir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["rubyhdrdir"]') |
444 |
|
445 |
if [[ "${rubyhdrdir}" = "nil" ]] ; then |
446 |
rubyhdrdir=$(${RUBY} -rrbconfig -e 'puts Config::CONFIG["archdir"]') |
447 |
fi |
448 |
|
449 |
echo "${rubyhdrdir}" |
450 |
} |
451 |
|
452 |
# @FUNCTION: ruby_get_version |
453 |
# @RETURN: The version of the Ruby interpreter in ${RUBY}, or what 'ruby' points to. |
454 |
ruby_get_version() { |
455 |
local ruby=${RUBY:-$(type -p ruby 2>/dev/null)} |
456 |
|
457 |
echo $(${ruby} -e 'puts RUBY_VERSION') |
458 |
} |
459 |
|
460 |
# @FUNCTION: ruby_get_implementation |
461 |
# @RETURN: The implementation of the Ruby interpreter in ${RUBY}, or what 'ruby' points to. |
462 |
ruby_get_implementation() { |
463 |
local ruby=${RUBY:-$(type -p ruby 2>/dev/null)} |
464 |
|
465 |
case $(${ruby} --version) in |
466 |
*Enterprise*) |
467 |
echo "ree" |
468 |
;; |
469 |
*jruby*) |
470 |
echo "jruby" |
471 |
;; |
472 |
*) |
473 |
echo "mri" |
474 |
;; |
475 |
esac |
476 |
} |