4.3. Extending the rh-ruby23 Software Collection

In Red Hat Software Collections 3.7, it is possible to extend the rh-ruby23 Software Collection by adding dependent packages. The Ruby on Rails 4.2 (rh-ror42) Software Collection, which is built on top of Ruby 2.3 provided by the rh-ruby23 Software Collection, is one example of such an extension.
This section provides detailed information about the rh-ror42 metapackage and the rh-ror42-rubygem-bcrypt package, which are both part of the rh-ror42 Software Collection.

4.3.1. The rh-ror42 Software Collection

This section contains a commented example of the Ruby on Rails 4.2 metapackage for the rh-ror42 Software Collection. The rh-ror42 Software Collection depends on the rh-ruby23 Software Collection.
Note the following in the rh-ror42 Software Collection metapackage example:
  • The rh-ror42 Software Collection spec file has the following build dependencies set:
    BuildRequires: %{scl_prefix_ruby}scldevel
    BuildRequires: %{scl_prefix_ruby}rubygems-devel
    This expands to, for example, rh-ruby23-scldevel and rh-ruby23-rubygems-devel.
    The rh-ruby23-scldevel subpackage contains two important macros, %scl_ruby and %scl_prefix_ruby. The rh-ruby23-scldevel subpackage should be available in the build root. In case there are multiple Ruby Software Collections available, rh-ruby23-scldevel determines which of the available Software Collections should be used.
    Note that the %scl_ruby and %scl_prefix_ruby macros are also defined at the top of the spec file. Although the definitions are not required, they provide a visual hint that the rh-ror42 Software Collection has been designed to be built on top of the rh-ruby23 Software Collection. They also serve as a fallback value.
  • The rh-ror42-runtime subpackage must depend on the runtime subpackage of the Software Collection it depends on. This dependency is specified as follows:
    %package runtime
    Requires: %{scl_prefix_ruby}runtime
    When the package is built against the rh-ruby23 Software Collection, this expands to rh-ruby23-runtime.
  • The rh-ror42-build subpackage must depend on the scldevel subpackage of the Software Collection it depends on. This is to ensure that all other packages of this Software Collection will have the same macros defined, thus it is built against the same Ruby version.
    %package build
    Requires: %{scl_prefix_ruby}scldevel
    In the case of the rh-ruby23 Software Collection, this expands to rh-ruby23-scldevel.
  • The enable scriptlet for the rh-ror42 Software Collection contains the following line:
    . scl_source enable %{scl_ruby}
    Note the dot at the beginning of the line. This line makes the Ruby Software Collection start implicitly when the rh-ror42 Software Collection is started so that the user can only type scl enable rh-ror42 command instead of scl enable rh-ruby23 rh-ror42 command to run command in the Software Collection environment.
  • The rh-ror42-scldevel subpackage is provided so that it is available in case you need it to build a Software Collection which extends the rh-ror42 Software Collection. The package provides the %{scl_ror} and %{scl_prefix_ror} macros, which can be used to extend the rh-ror42 Software Collection.
  • Because the rh-ror42 Software Collection's gems are installed in a separate root directory structure, you need to ensure that the correct ownership for the rubygems directories is set. This is done by using a snippet to generate a file list rubygems_filesystem.list.
    You are advised to set the runtime package to own all directories which would, if located in the root file system, be owned by another package. One example of such directories in the case of the rh-ror42 Software Collection is the Rubygem directory structure.
%global scl_name_prefix rh-
%global scl_name_base ror
%global scl_name_version 41

%global scl %{scl_name_prefix}%{scl_name_base}%{scl_name_version}

# Fallback to rh-ruby23. rh-ruby23-scldevel is unlikely to be available in
# the build root.
%{!?scl_ruby:%global scl_ruby rh-ruby23}
%{!?scl_prefix_ruby:%global scl_prefix_ruby %{scl_ruby}-}

# Do not produce empty debuginfo package.
%global debug_package %{nil}

# Support SCL over NFS.
%global nfsmountable 1

%{!?install_scl: %global install_scl 1}

%scl_package %scl

Summary: Package that installs %scl
Name: %scl_name
Version: 2.0
Release: 5%{?dist}
License: GPLv2+

%if 0%{?install_scl}
Requires: %{scl_prefix}rubygem-therubyracer
Requires: %{scl_prefix}rubygem-sqlite3
Requires: %{scl_prefix}rubygem-rails
Requires: %{scl_prefix}rubygem-sass-rails
Requires: %{scl_prefix}rubygem-coffee-rails
Requires: %{scl_prefix}rubygem-jquery-rails
Requires: %{scl_prefix}rubygem-sdoc
Requires: %{scl_prefix}rubygem-turbolinks
Requires: %{scl_prefix}rubygem-bcrypt
Requires: %{scl_prefix}rubygem-uglifier
Requires: %{scl_prefix}rubygem-jbuilder
Requires: %{scl_prefix}rubygem-spring
%endif
BuildRequires: help2man
BuildRequires: scl-utils-build
BuildRequires: %{scl_prefix_ruby}scldevel
BuildRequires: %{scl_prefix_ruby}rubygems-devel

%description
This is the main package for %scl Software Collection.

%package runtime
Summary: Package that handles %scl Software Collection.
Requires: scl-utils
# The enable scriptlet depends on the ruby executable.
Requires: %{scl_prefix_ruby}ruby

%description runtime
Package shipping essential scripts to work with %scl Software Collection.

%package build
Summary: Package shipping basic build configuration
Requires: scl-utils-build
Requires: %{scl_runtime}
Requires: %{scl_prefix_ruby}scldevel

%description build
Package shipping essential configuration macros to build %scl Software Collection.

%package scldevel
Summary: Package shipping development files for %scl
Provides: scldevel(%{scl_name_base})

%description scldevel
Package shipping development files, especially usefull for development of
packages depending on %scl Software Collection.

%prep
%setup -c -T

%install
%scl_install

cat >> %{buildroot}%{_scl_scripts}/enable << EOF
export PATH="%{_bindir}:%{_sbindir}\${PATH:+:\${PATH}}"
export LD_LIBRARY_PATH="%{_libdir}\${LD_LIBRARY_PATH:+:\${LD_LIBRARY_PATH}}"
export MANPATH="%{_mandir}:\${MANPATH:-}"
export PKG_CONFIG_PATH="%{_libdir}/pkgconfig\${PKG_CONFIG_PATH:+:\${PKG_CONFIG_PATH}}"
export GEM_PATH="\${GEM_PATH:=%{gem_dir}:\`scl enable %{scl_ruby} -- ruby -e "print Gem.path.join(':')"\`}"

. scl_source enable %{scl_ruby}
EOF

cat >> %{buildroot}%{_root_sysconfdir}/rpm/macros.%{scl_name_base}-scldevel << EOF
%%scl_%{scl_name_base} %{scl}
%%scl_prefix_%{scl_name_base} %{scl_prefix}
EOF


scl enable %{scl_ruby} - << \EOF
set -e

# Fake rh-ror42 Software Collection environment.
GEM_PATH=%{gem_dir}:`ruby -e "print Gem.path.join(':')"` \
X_SCLS=%{scl} \
ruby -rfileutils > rubygems_filesystem.list << \EOR
  # Create the RubyGems file system.
  Gem.ensure_gem_subdirectories '%{buildroot}%{gem_dir}'
  FileUtils.mkdir_p File.join '%{buildroot}', Gem.default_ext_dir_for('%{gem_dir}')

  # Output the relevant directories.
  Gem.default_dirs['%{scl}_system'.to_sym].each { |k, p| puts p }
EOR
EOF

%files

%files runtime -f rubygems_filesystem.list
%scl_files

%files build
%{_root_sysconfdir}/rpm/macros.%{scl}-config

%files scldevel
%{_root_sysconfdir}/rpm/macros.%{scl_name_base}-scldevel


%changelog
* Thu Jan 16 2015 John Doe <jdoe@example.com> - 1-1
- Initial package.

4.3.2. The rh-ror42-rubygem-bcrypt Package

Below is a commented example of the rh-ror42-rubygem-bcrypt package spec file. This package provides the bcrypt Ruby gem. For more information on bcrypt, see the following website:
Note that the only significant difference between the rh-ror42-rubygem-bcrypt package spec file and a normal Software Collection package spec file is the following:
  • The BuildRequires tags are prefixed with %{?scl_prefix_ruby} instead of %{scl_prefix}.
%{?scl:%scl_package rubygem-%{gem_name}}
%{!?scl:%global pkg_name %{name}}

%global gem_name bcrypt

Summary: Wrapper around bcrypt() password hashing algorithm
Name: %{?scl_prefix}rubygem-%{gem_name}
Version: 3.1.9
Release: 2%{?dist}
Group: Development/Languages
# ext/* - Public Domain
# spec/TestBCrypt.java - ISC
License: MIT and Public Domain and ISC
URL: https://github.com/codahale/bcrypt-ruby
Source0: http://rubygems.org/downloads/%{gem_name}-%{version}.gem
Requires: %{?scl_prefix_ruby}ruby(release)
Requires: %{?scl_prefix_ruby}ruby(rubygems) 
BuildRequires: %{?scl_prefix_ruby}rubygems-devel
BuildRequires: %{?scl_prefix_ruby}ruby-devel
BuildRequires: %{?scl_prefix}rubygem(rspec)
Provides: %{?scl_prefix}rubygem(bcrypt) = %{version}

%description
bcrypt() is a sophisticated and secure hash algorithm designed by The
OpenBSD project for hashing passwords. bcrypt provides a simple,
humane wrapper for safely handling passwords.

%package doc
Summary: Documentation for %{pkg_name}
Group: Documentation
Requires: %{?scl_prefix}%{pkg_name} = %{version}-%{release}

%description doc
Documentation for %{pkg_name}.

%prep
%setup -n %{pkg_name}-%{version} -q -c -T
%{?scl:scl enable %{scl} - << \EOF}
%gem_install -n %{SOURCE0}
%{?scl:EOF}

%build

%install
mkdir -p %{buildroot}%{gem_dir}
cp -pa .%{gem_dir}/* \
        %{buildroot}%{gem_dir}/

mkdir -p %{buildroot}%{gem_extdir_mri}
cp -pa .%{gem_extdir_mri}/* %{buildroot}%{gem_extdir_mri}/

# Prevent a symlink with an invalid target in -debuginfo (BZ#878863).
rm -rf %{buildroot}%{gem_instdir}/ext/

%check
%{?scl:scl enable %{scl} - << \EOF}
pushd .%{gem_instdir}
# 2 failutes due to old RSpec
# https://github.com/rspec/rspec-expectations/pull/284
rspec -I$(dirs +1)%{gem_extdir_mri} spec |grep '34 examples, 2 failures' || exit 1
popd
%{?scl:EOF}

%files
%dir %{gem_instdir}
%exclude %{gem_instdir}/.*
%{gem_libdir}
%{gem_extdir_mri}
%exclude %{gem_cache}
%{gem_spec}
%doc %{gem_instdir}/COPYING

%files doc
%doc %{gem_docdir}
%doc %{gem_instdir}/README.md
%doc %{gem_instdir}/CHANGELOG
%{gem_instdir}/Rakefile
%{gem_instdir}/Gemfile*
%{gem_instdir}/%{gem_name}.gemspec
%{gem_instdir}/spec


%changelog
* Fri Mar 21 2015 John Doe <jdoe@example.com> - 3.1.2-4
- Initial package.

4.3.3. Building the rh-ror42 Software Collection

To build the rh-ror42 Software Collection:
  1. Install the rh-ruby23-scldevel subpackage which is a part of the rh-ruby23 Software Collection.
  2. Build rh-ror42.spec and install the ror42-runtime and ror42-build packages.
  3. Build rubygem-bcrypt.spec.

4.3.4. Testing the rh-ror42 Software Collection

To test the rh-ror42 Software Collection:
  1. Install the rh-ror42-rubygem-bcrypt package.
  2. Run the following command:
    $ scl enable rh-ror42 -- ruby -r bcrypt -e "puts BCrypt::Password.create('my password')"
  3. Verify that the output contains the following line:
    $2a$10$s./ReniLY.wXPHVBQ9npoeyZf5KzywfpvI5lhjG6Ams3u0hKqwVbW