x11-misc/alock: Take ownership of package
[gentoo.git] / eclass / ruby-fakegem.eclass
1 # Copyright 1999-2015 Gentoo Foundation
2 # Distributed under the terms of the GNU General Public License v2
3 # $Id$
4
5 # @ECLASS: ruby-fakegem.eclass
6 # @MAINTAINER:
7 # Ruby herd <ruby@gentoo.org>
8 # @AUTHOR:
9 # Author: Diego E. Pettenò <flameeyes@gentoo.org>
10 # Author: Alex Legler <a3li@gentoo.org>
11 # @BLURB: An eclass for installing Ruby packages to behave like RubyGems.
12 # @DESCRIPTION:
13 # This eclass allows to install arbitrary Ruby libraries (including Gems),
14 # providing integration into the RubyGems system even for "regular" packages.
15
16 inherit ruby-ng
17
18 # @ECLASS-VARIABLE: RUBY_FAKEGEM_NAME
19 # @DESCRIPTION:
20 # Sets the Gem name for the generated fake gemspec.
21 # This variable MUST be set before inheriting the eclass.
22 # RUBY_FAKEGEM_NAME="${PN}"
23
24 # @ECLASS-VARIABLE: RUBY_FAKEGEM_VERSION
25 # @DESCRIPTION:
26 # Sets the Gem version for the generated fake gemspec.
27 # This variable MUST be set before inheriting the eclass.
28 # RUBY_FAKEGEM_VERSION="${PV}"
29
30 # @ECLASS-VARIABLE: RUBY_FAKEGEM_TASK_DOC
31 # @DESCRIPTION:
32 # Specify the rake(1) task to run to generate documentation.
33 # RUBY_FAKEGEM_TASK_DOC="rdoc"
34
35 # @ECLASS-VARIABLE: RUBY_FAKEGEM_RECIPE_TEST
36 # @DESCRIPTION:
37 # Specify one of the default testing function for ruby-fakegem:
38 #  - rake (default; see also RUBY_FAKEGEM_TASK_TEST)
39 #  - rspec (calls ruby-ng_rspec, adds dev-ruby/rspec:2 to the dependencies)
40 #  - rspec3 (calls ruby-ng_rspec, adds dev-ruby/rspec:3 to the dependencies)
41 #  - cucumber (calls ruby-ng_cucumber, adds dev-util/cucumber to the
42 #    dependencies; does not work on JRuby).
43 #  - none
44 # RUBY_FAKEGEM_RECIPE_TEST="rake"
45
46 # @ECLASS-VARIABLE: RUBY_FAKEGEM_TASK_TEST
47 # @DESCRIPTION:
48 # Specify the rake(1) task used for executing tests. Only valid
49 # if RUBY_FAKEGEM_RECIPE_TEST is set to "rake" (the default).
50 # RUBY_FAKEGEM_TASK_TEST="test"
51
52 # @ECLASS-VARIABLE: RUBY_FAKEGEM_RECIPE_DOC
53 # @DESCRIPTION:
54 # Specify one of the default API doc building function for ruby-fakegem:
55 #  - rake (default; see also RUBY_FAKEGEM_TASK_DOC)
56 #  - rdoc (calls `rdoc-2`, adds dev-ruby/rdoc to the dependencies);
57 #  - yard (calls `yard`, adds dev-ruby/yard to the dependencies);
58 #  - none
59 # RUBY_FAKEGEM_RECIPE_DOC="rake"
60
61 # @ECLASS-VARIABLE: RUBY_FAKEGEM_DOCDIR
62 # @DESCRIPTION:
63 # Specify the directory under which the documentation is built;
64 # if empty no documentation will be installed automatically.
65 # Note: if RUBY_FAKEGEM_RECIPE_DOC is set to `rdoc`, this variable is
66 # hardwired to `doc`.
67 # RUBY_FAKEGEM_DOCDIR=""
68
69 # @ECLASS-VARIABLE: RUBY_FAKEGEM_EXTRADOC
70 # @DESCRIPTION:
71 # Extra documentation to install (readme, changelogs, …).
72 # RUBY_FAKEGEM_EXTRADOC=""
73
74 # @ECLASS-VARIABLE: RUBY_FAKEGEM_DOC_SOURCES
75 # @DESCRIPTION:
76 # Allow settings defined sources to scan for documentation.
77 # This only applies if RUBY_FAKEGEM_DOC_TASK is set to `rdoc`.
78 # RUBY_FAKEGEM_DOC_SOURCES="lib"
79
80 # @ECLASS-VARIABLE: RUBY_FAKEGEM_BINWRAP
81 # @DESCRIPTION:
82 # Binaries to wrap around (relative to the bin/ directory)
83 # RUBY_FAKEGEM_BINWRAP="*"
84
85 # @ECLASS-VARIABLE: RUBY_FAKEGEM_BINDIR
86 # @DESCRIPTION:
87 # Path that contains binaries to be binwrapped. Equivalent to the
88 # gemspec bindir option.
89 # RUBY_FAKEGEM_BINDIR="bin"
90
91 # @ECLASS-VARIABLE: RUBY_FAKEGEM_REQUIRE_PATHS
92 # @DESCRIPTION:
93 # Extra require paths (beside lib) to add to the specification
94 # RUBY_FAKEGEM_REQUIRE_PATHS=""
95
96 # @ECLASS-VARIABLE: RUBY_FAKEGEM_GEMSPEC
97 # @DESCRIPTION:
98 # Filename of .gemspec file to install instead of generating a generic one.
99 # RUBY_FAKEGEM_GEMSPEC=""
100
101 # @ECLASS-VARIABLE: RUBY_FAKEGEM_EXTRAINSTALL
102 # @DESCRIPTION:
103 # List of files and directories relative to the top directory that also
104 # get installed. Some gems provide extra files such as version information,
105 # Rails generators, or data that needs to be installed as well.
106 # RUBY_FAKEGEM_EXTRAINSTALL=""
107
108 RUBY_FAKEGEM_NAME="${RUBY_FAKEGEM_NAME:-${PN}}"
109 RUBY_FAKEGEM_VERSION="${RUBY_FAKEGEM_VERSION:-${PV/_pre/.pre}}"
110 RUBY_FAKEGEM_SUFFIX="${RUBY_FAKEGEM_SUFFIX:-}"
111
112 RUBY_FAKEGEM_RECIPE_DOC="${RUBY_FAKEGEM_RECIPE_DOC-rake}"
113 RUBY_FAKEGEM_TASK_DOC="${RUBY_FAKEGEM_TASK_DOC-rdoc}"
114 RUBY_FAKEGEM_DOC_SOURCES="${RUBY_FAKEGEM_DOC_SOURCES-lib}"
115
116 RUBY_FAKEGEM_RECIPE_TEST="${RUBY_FAKEGEM_RECIPE_TEST-rake}"
117 RUBY_FAKEGEM_TASK_TEST="${RUBY_FAKEGEM_TASK_TEST-test}"
118
119 RUBY_FAKEGEM_BINWRAP="${RUBY_FAKEGEM_BINWRAP-*}"
120 RUBY_FAKEGEM_BINDIR="${RUBY_FAKEGEM_BINDIR-bin}"
121
122 [[ ${RUBY_FAKEGEM_TASK_DOC} == "" ]] && RUBY_FAKEGEM_RECIPE_DOC="none"
123
124 case ${RUBY_FAKEGEM_RECIPE_DOC} in
125         rake)
126                 IUSE+=" doc"
127                 ruby_add_bdepend "doc? ( dev-ruby/rake )"
128                 RUBY_FAKEGEM_DOCDIR="doc"
129                 ;;
130         rdoc)
131                 IUSE+=" doc"
132                 ruby_add_bdepend "doc? ( dev-ruby/rdoc )"
133                 RUBY_FAKEGEM_DOCDIR="doc"
134                 ;;
135         yard)
136                 IUSE+="doc"
137                 ruby_add_bdepend "doc? ( dev-ruby/yard )"
138                 RUBY_FAKEGEM_DOCDIR="doc"
139                 ;;
140         none)
141                 [[ -n ${RUBY_FAKEGEM_DOCDIR} ]] && IUSE+=" doc"
142                 ;;
143 esac
144
145 [[ ${RUBY_FAKEGEM_TASK_TEST} == "" ]] && RUBY_FAKEGEM_RECIPE_TEST="none"
146
147 case ${RUBY_FAKEGEM_RECIPE_TEST} in
148         rake)
149                 IUSE+=" test"
150                 ruby_add_bdepend "test? ( dev-ruby/rake )"
151                 ;;
152         rspec)
153                 IUSE+=" test"
154                 # Also require a new enough rspec-core version that installs the
155                 # rspec-2 wrapper.
156                 ruby_add_bdepend "test? ( dev-ruby/rspec:2 >=dev-ruby/rspec-core-2.14.8-r2 )"
157                 ;;
158         rspec3)
159                 IUSE+=" test"
160                 ruby_add_bdepend "test? ( dev-ruby/rspec:3 )"
161                 ;;
162         cucumber)
163                 IUSE+=" test"
164                 # Unfortunately as of August 2012, cucumber is not supported on
165                 # JRuby.  We work it around here to avoid repeating the same
166                 # code over and over again.
167                 USE_RUBY="${USE_RUBY/jruby/}" ruby_add_bdepend "test? ( dev-util/cucumber )"
168                 ;;
169         *)
170                 RUBY_FAKEGEM_RECIPE_TEST="none"
171                 ;;
172 esac
173
174 SRC_URI="mirror://rubygems/${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}${RUBY_FAKEGEM_SUFFIX:+-${RUBY_FAKEGEM_SUFFIX}}.gem"
175
176 ruby_add_bdepend virtual/rubygems
177 ruby_add_rdepend virtual/rubygems
178
179 # @FUNCTION: ruby_fakegem_gemsdir
180 # @RETURN: Returns the gem data directory
181 # @DESCRIPTION:
182 # This function returns the gems data directory for the ruby
183 # implementation in question.
184 ruby_fakegem_gemsdir() {
185         has "${EAPI}" 2 && ! use prefix && EPREFIX=
186
187         local _gemsitedir=$(ruby_rbconfig_value 'sitelibdir')
188         _gemsitedir=${_gemsitedir//site_ruby/gems}
189         _gemsitedir=${_gemsitedir#${EPREFIX}}
190
191         [[ -z ${_gemsitedir} ]] && {
192                 eerror "Unable to find the gems dir"
193                 die "Unable to find the gems dir"
194         }
195
196         echo "${_gemsitedir}"
197 }
198
199 # @FUNCTION: ruby_fakegem_doins
200 # @USAGE: file [file...]
201 # @DESCRIPTION:
202 # Installs the specified file(s) into the gems directory.
203 ruby_fakegem_doins() {
204         (
205                 insinto $(ruby_fakegem_gemsdir)/gems/${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}
206                 doins "$@"
207         ) || die "failed $0 $@"
208 }
209
210 # @FUNCTION: ruby_fakegem_newsins()
211 # @USAGE: file filename
212 # @DESCRIPTION:
213 # Installs the specified file into the gems directory using the provided filename.
214 ruby_fakegem_newins() {
215         (
216                 # Since newins does not accept full paths but just basenames
217                 # for the target file, we want to extend it here.
218                 local newdirname=/$(dirname "$2")
219                 [[ ${newdirname} == "/." ]] && newdirname=
220
221                 local newbasename=$(basename "$2")
222
223                 insinto $(ruby_fakegem_gemsdir)/gems/${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}${newdirname}
224                 newins "$1" ${newbasename}
225         ) || die "failed $0 $@"
226 }
227
228 # @FUNCTION: ruby_fakegem_install_gemspec
229 # @DESCRIPTION:
230 # Install a .gemspec file for this package. Either use the file indicated
231 # by the RUBY_FAKEGEM_GEMSPEC variable, or generate one using
232 # ruby_fakegem_genspec.
233 ruby_fakegem_install_gemspec() {
234         local gemspec="${T}"/${RUBY_FAKEGEM_NAME}-${_ruby_implementation}
235
236         (
237                 if [[ ${RUBY_FAKEGEM_GEMSPEC} != "" ]]; then
238                         ruby_fakegem_gemspec_gemspec ${RUBY_FAKEGEM_GEMSPEC} ${gemspec}
239                 else
240                         local metadata="${WORKDIR}"/${_ruby_implementation}/metadata
241
242                         if [[ -e ${metadata} ]]; then
243                                 ruby_fakegem_metadata_gemspec ${metadata} ${gemspec}
244                         else
245                                 ruby_fakegem_genspec ${gemspec}
246                         fi
247                 fi
248         ) || die "Unable to generate gemspec file."
249
250         insinto $(ruby_fakegem_gemsdir)/specifications
251         newins ${gemspec} ${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}.gemspec || die "Unable to install gemspec file."
252 }
253
254 # @FUNCTION: ruby_fakegem_gemspec_gemspec
255 # @USAGE: gemspec-input gemspec-output
256 # @DESCRIPTION:
257 # Generates an installable version of the specification indicated by
258 # RUBY_FAKEGEM_GEMSPEC. This file is eval'ed to produce a final specification
259 # in a way similar to packaging the gemspec file.
260 ruby_fakegem_gemspec_gemspec() {
261         ${RUBY} -e "puts eval(File::open('$1').read).to_ruby" > $2
262 }
263
264 # @FUNCTION: ruby_fakegem_metadata_gemspec
265 # @USAGE: gemspec-metadata gemspec-output
266 # @DESCRIPTION:
267 # Generates an installable version of the specification indicated by
268 # the metadata distributed by the gem itself. This is similar to how
269 # rubygems creates an installation from a .gem file.
270 ruby_fakegem_metadata_gemspec() {
271         case ${RUBY} in
272                 *jruby)
273                         ${RUBY} -r yaml -e "puts Gem::Specification.from_yaml(File::open('$1').read).to_ruby" > $2
274                                 ;;
275                 *)
276                         ${RUBY} -r yaml -e "puts Gem::Specification.from_yaml(File::open('$1', :encoding => 'UTF-8').read).to_ruby" > $2
277                                 ;;
278         esac
279 }
280
281 # @FUNCTION: ruby_fakegem_genspec
282 # @USAGE: output-gemspec
283 # @DESCRIPTION:
284 # Generates a gemspec for the package and places it into the "specifications"
285 # directory of RubyGems.
286 # If the metadata normally distributed with a gem is present then that is
287 # used to generate the gemspec file.
288 #
289 # As a fallback we can generate our own version.
290 # In the gemspec, the following values are set: name, version, summary,
291 # homepage, and require_paths=["lib"].
292 # See RUBY_FAKEGEM_NAME and RUBY_FAKEGEM_VERSION for setting name and version.
293 # See RUBY_FAKEGEM_REQUIRE_PATHS for setting extra require paths.
294 ruby_fakegem_genspec() {
295         local required_paths="'lib'"
296         for path in ${RUBY_FAKEGEM_REQUIRE_PATHS}; do
297                 required_paths="${required_paths}, '${path}'"
298         done
299
300         # We use the _ruby_implementation variable to avoid having stray
301         # copies with different implementations; while for now we're using
302         # the same exact content, we might have differences in the future,
303         # so better taking this into consideration.
304         local quoted_description=${DESCRIPTION//\"/\\\"}
305         cat - > $1 <<EOF
306 # generated by ruby-fakegem.eclass $Revision: 1.45 $
307 Gem::Specification.new do |s|
308   s.name = "${RUBY_FAKEGEM_NAME}"
309   s.version = "${RUBY_FAKEGEM_VERSION}"
310   s.summary = "${quoted_description}"
311   s.homepage = "${HOMEPAGE}"
312   s.require_paths = [${required_paths}]
313 end
314 EOF
315 }
316
317 # @FUNCTION: ruby_fakegem_binwrapper
318 # @USAGE: command [path] [content]
319 # @DESCRIPTION:
320 # Creates a new binary wrapper for a command installed by the RubyGem.
321 # path defaults to /usr/bin/$command content is optional and can be used
322 # to inject additional ruby code into the wrapper. This may be useful to
323 # e.g. force a specific version using the gem command.
324 ruby_fakegem_binwrapper() {
325         (
326                 local gembinary=$1
327                 local newbinary=${2:-/usr/bin/$gembinary}
328                 local content=$3
329                 local relativegembinary=${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}/${RUBY_FAKEGEM_BINDIR}/${gembinary}
330                 local binpath=$(dirname $newbinary)
331                 [[ ${binpath} = . ]] && binpath=/usr/bin
332
333                 # Try to find out whether the package is going to install for
334                 # one or multiple implementations; if we're installing for a
335                 # *single* implementation, no need to use “/usr/bin/env ruby”
336                 # in the shebang, and we can actually avoid errors when
337                 # calling the script by default (see for instance the
338                 # JRuby-specific commands).
339                 local rubycmd=
340                 for implementation in ${USE_RUBY}; do
341                         # ignore non-enabled implementations
342                         use ruby_targets_${implementation} || continue
343                         if [ -z $rubycmd ]; then
344                                 # if no other implementation was set before, set it.
345                                 rubycmd="$(ruby_implementation_command ${implementation})"
346                         else
347                                 # if another implementation already arrived, then make
348                                 # it generic and break out of the loop. This ensures
349                                 # that we do at most two iterations.
350                                 rubycmd="/usr/bin/env ruby"
351                                 break
352                         fi
353                 done
354
355                 cat - > "${T}"/gembin-wrapper-${gembinary} <<EOF
356 #!${rubycmd}
357 # This is a simplified version of the RubyGems wrapper
358 #
359 # Generated by ruby-fakegem.eclass $Revision: 1.45 $
360
361 require 'rubygems'
362
363 ${content}
364 load Gem::default_path[-1] + "/gems/${relativegembinary}"
365
366 EOF
367
368                 exeinto ${binpath:-/usr/bin}
369                 newexe "${T}"/gembin-wrapper-${gembinary} $(basename $newbinary)
370         ) || die "Unable to create fakegem wrapper"
371 }
372
373 # @FUNCTION: all_fakegem_compile
374 # @DESCRIPTION:
375 # Build documentation for the package if indicated by the doc USE flag
376 # and if there is a documetation task defined.
377 all_fakegem_compile() {
378         if [[ -n ${RUBY_FAKEGEM_DOCDIR} ]] && use doc; then
379                 case ${RUBY_FAKEGEM_RECIPE_DOC} in
380                         rake)
381                                 rake ${RUBY_FAKEGEM_TASK_DOC} || die "failed to (re)build documentation"
382                                 ;;
383                         rdoc)
384                                 rdoc ${RUBY_FAKEGEM_DOC_SOURCES} || die "failed to (re)build documentation"
385                                 ;;
386                         yard)
387                                 yard doc ${RUBY_FAKEGEM_DOC_SOURCES} || die "failed to (re)build documentation"
388                                 ;;
389                 esac
390         fi
391 }
392
393 # @FUNCTION: all_ruby_unpack
394 # @DESCRIPTION:
395 # Unpack the source archive, including support for unpacking gems.
396 all_ruby_unpack() {
397         # Special support for extracting .gem files; the file need to be
398         # extracted twice and the mtime from the archive _has_ to be
399         # ignored (it's always set to epoch 0).
400         for archive in ${A}; do
401                 case "${archive}" in
402                         *.gem)
403                                 # Make sure that we're not running unpack for more than
404                                 # one .gem file, since we won't support that at all.
405                                 [[ -d "${S}" ]] && die "Unable to unpack ${archive}, ${S} exists"
406
407                                 ebegin "Unpacking .gem file..."
408                                 tar -mxf "${DISTDIR}"/${archive} || die
409                                 eend $?
410
411                                 ebegin "Uncompressing metadata"
412                                 gunzip metadata.gz || die
413                                 eend $?
414
415                                 mkdir "${S}"
416                                 pushd "${S}" &>/dev/null || die
417
418                                 ebegin "Unpacking data.tar.gz"
419                                 tar -mxf "${my_WORKDIR}"/data.tar.gz || die
420                                 eend $?
421
422                                 popd &>/dev/null || die
423                                 ;;
424                         *.patch.bz2)
425                                 # We apply the patches with RUBY_PATCHES directly from DISTDIR,
426                                 # as the WORKDIR variable changes value between the global-scope
427                                 # and the time all_ruby_unpack/_prepare are called. Since we can
428                                 # simply decompress them when applying, this is much easier to
429                                 # deal with for us.
430                                 einfo "Keeping ${archive} as-is"
431                                 ;;
432                         *)
433                                 unpack ${archive}
434                                 ;;
435                 esac
436         done
437 }
438
439 # @FUNCTION: all_ruby_compile
440 # @DESCRIPTION:
441 # Compile the package.
442 all_ruby_compile() {
443         all_fakegem_compile
444 }
445
446 # @FUNCTION: each_fakegem_test
447 # @DESCRIPTION:
448 # Run tests for the package for each ruby target if the test task is defined.
449 each_fakegem_test() {
450         case ${RUBY_FAKEGEM_RECIPE_TEST} in
451                 rake)
452                         ${RUBY} -S rake ${RUBY_FAKEGEM_TASK_TEST} || die "tests failed"
453                         ;;
454                 rspec)
455                         RSPEC_VERSION=2 ruby-ng_rspec
456                         ;;
457                 rspec3)
458                         RSPEC_VERSION=3 ruby-ng_rspec
459                         ;;
460                 cucumber)
461                         ruby-ng_cucumber
462                         ;;
463                 none)
464                         ewarn "each_fakegem_test called, but \${RUBY_FAKEGEM_RECIPE_TEST} is 'none'"
465                         ;;
466         esac
467 }
468
469 if [[ ${RUBY_FAKEGEM_RECIPE_TEST} != none ]]; then
470                 # @FUNCTION: each_ruby_test
471                 # @DESCRIPTION:
472                 # Run the tests for this package.
473                 each_ruby_test() {
474                         each_fakegem_test
475                 }
476 fi
477
478 # @FUNCTION: each_fakegem_install
479 # @DESCRIPTION:
480 # Install the package for each ruby target.
481 each_fakegem_install() {
482         ruby_fakegem_install_gemspec
483
484         local _gemlibdirs="${RUBY_FAKEGEM_EXTRAINSTALL}"
485         for directory in "${RUBY_FAKEGEM_BINDIR}" lib; do
486                 [[ -d ${directory} ]] && _gemlibdirs="${_gemlibdirs} ${directory}"
487         done
488
489         [[ -n ${_gemlibdirs} ]] && \
490                 ruby_fakegem_doins -r ${_gemlibdirs}
491 }
492
493 # @FUNCTION: each_ruby_install
494 # @DESCRIPTION:
495 # Install the package for each target.
496 each_ruby_install() {
497         each_fakegem_install
498 }
499
500 # @FUNCTION: all_fakegem_install
501 # @DESCRIPTION:
502 # Install files common to all ruby targets.
503 all_fakegem_install() {
504         if [[ -n ${RUBY_FAKEGEM_DOCDIR} ]] && use doc; then
505                 for dir in ${RUBY_FAKEGEM_DOCDIR}; do
506                         [[ -d ${dir} ]] || continue
507
508                         pushd ${dir} &>/dev/null || die
509                         dohtml -r * || die "failed to install documentation"
510                         popd &>/dev/null || die
511                 done
512         fi
513
514         if [[ -n ${RUBY_FAKEGEM_EXTRADOC} ]]; then
515                 dodoc ${RUBY_FAKEGEM_EXTRADOC} || die "failed to install further documentation"
516         fi
517
518         # binary wrappers; we assume that all the implementations get the
519         # same binaries, or something is wrong anyway, so...
520         if [[ -n ${RUBY_FAKEGEM_BINWRAP} ]]; then
521                 local bindir=$(find "${D}" -type d -path "*/gems/${RUBY_FAKEGEM_NAME}-${RUBY_FAKEGEM_VERSION}/${RUBY_FAKEGEM_BINDIR}" -print -quit)
522
523                 if [[ -d "${bindir}" ]]; then
524                         pushd "${bindir}" &>/dev/null || die
525                         local binaries=$(eval ls ${RUBY_FAKEGEM_BINWRAP})
526                         for binary in $binaries; do
527                                 ruby_fakegem_binwrapper $binary
528                         done
529                         popd &>/dev/null || die
530                 fi
531         fi
532 }
533
534 # @FUNCTION: all_ruby_install
535 # @DESCRIPTION:
536 # Install files common to all ruby targets.
537 all_ruby_install() {
538         all_fakegem_install
539 }