class SyncWrap::CRubyVM

Provision 'C' Ruby (ruby-lang.org - Matz Ruby Interpreter, MRI) from source code, compiled on the target host. This is currently the most reliable way for staying up-to-date on stable Ruby releases across the bulk of Linux server distros (which have conservative update policies).

A reasonable alternative is to use distro provided packages. Since this varies so much based on distro particulars, but it is otherwise relatively easy to achieve (setup alt repos, dist_install, set alternatives) you are currently left to do this in your own component. Include RubySupport in that component for some common utility methods.

Alternatives like RVM, rbenv, etc. are disfavored by this author for server provisioning because of their intrusive shell and environment modifications and obscure interations with non-/login or non-/interactive sessions. These are fine tools if needed for development however. Again you are currently on your own (beyond RubySupport) if you wish to go this route.

Constants

DEFAULT_VERSION

Default ruby_version to install

KNOWN_HASHES

A set of known (sha256) cryptographic hashes, keyed by version string, for the source ruby-(version).tar.gz package.

Attributes

do_uninstall_distro_ruby[RW]

If true, attempt to uninstall any pre-existing distro packaged ruby, which might otherwise lead to errors and confusion. (Default: true)

hash[W]

A cryptographic hash value (hexadecimal, some standard length) to use for verifying the 'source.tar.gz' package. (Default: KNOWN_HASHES[ #ruby_version ])

ruby_version[RW]

The ruby version to install, as it appears in source packages from ruby-lang.org. Note that starting with 2.1.0, the patch release (p#) no longer appears in package names. (Default: DEFAULT_VERSION)

Example values: '2.0.0-p481', '2.2.8', '2.3.5', '2.4.2'

Public Class Methods

new( opts = {} ) click to toggle source
Calls superclass method SyncWrap::RubySupport.new
# File lib/syncwrap/components/cruby_vm.rb, line 94
def initialize( opts = {} )
  @ruby_version = DEFAULT_VERSION
  @do_uninstall_distro_ruby = true
  @hash = nil
  super
end

Public Instance Methods

hash() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 101
def hash
  @hash || KNOWN_HASHES[ ruby_version ]
end
install() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 105
def install
  install_ruby
  install_gemrc # from RubySupport
end
install_ruby() click to toggle source

If the current #ruby_command is not at the desired #ruby_version, download source, configure, make and install.

# File lib/syncwrap/components/cruby_vm.rb, line 116
def install_ruby
  cond = <<-SH
    rvr=`[ -x #{ruby_command} ] &&
         #{ruby_command} -v | grep -o -E '#{version_pattern}' \
         || true`
    if [ "$rvr" != "#{compact_version}" ]; then
  SH
  sudo( cond, close: "fi" ) do
    install_build_deps
    make_and_install

    # only after a successful source install:
    uninstall_distro_ruby if do_uninstall_distro_ruby
  end
end
ruby_command() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 110
def ruby_command
  "#{local_root}/bin/ruby"
end
uninstall_distro_ruby() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 132
def uninstall_distro_ruby
  if distro.is_a?( RHEL )
    dist_uninstall( %w[ ruby ruby18 ruby19
                        ruby20 ruby21 ruby22 ruby23 ruby24] )
  else
    dist_uninstall( %w[ ruby ruby1.8 ruby1.9 ruby1.9.1 ruby1.9.3
                        ruby2.0 ruby2.1 ruby2.2 ruby2.3 ruby2.4] )
  end
end

Protected Instance Methods

compact_version() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 146
def compact_version
  ruby_version.sub( '-', '' )
end
install_build_deps() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 161
def install_build_deps
  if distro.is_a?( RHEL )
    dist_install( %w[ curl gcc make autoconf zlib-devel
                      openssl-devel readline-devel libyaml-devel libffi-devel ] )
  else
    dist_install( %w[ curl gcc make autoconf ] )
    if distro.is_a?( Debian )
       dist_install( %w[ zlib1g-dev libssl-dev libreadline-dev
                         libyaml-dev libffi-dev ] )
       if version_lt?(ruby_version, [2,4]) && version_gte?(debian_version, [10])
         dist_install( %w[ libssl1.0-dev ] )
       end
    end
  end
end
make_and_install() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 177
def make_and_install
  # Arguably all but the final install should be run by an
  # unprivileged user. But its more likely merged this way, and if
  # "configure" or "make" can be exploited, so can "make install".
  sfile = File.basename( src_url )
  sudo <<-SH
    [ -e /tmp/src ] && rm -rf /tmp/src || true
    mkdir -p /tmp/src/ruby
    cd /tmp/src/ruby
    curl -sSL -o #{sfile} #{src_url}
  SH

  hash_verify( hash, sfile, user: :root ) if hash

  sudo <<-SH
    tar -zxf #{sfile}
    rm -f #{sfile}
    cd ruby-#{ruby_version}
    ./configure --prefix=#{local_root} #{redirect?}
    make #{redirect?}
    make install #{redirect?}
    cd / && rm -rf /tmp/src
  SH
end
redirect?() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 208
def redirect?
  verbose? ? "" : ">/dev/null"
end
src_url() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 202
def src_url
  [ 'http://cache.ruby-lang.org/pub/ruby',
    ruby_version =~ /^(\d+\.\d+)/ && $1,
    "ruby-#{ruby_version}.tar.gz" ].join( '/' )
end
version_pattern() click to toggle source
# File lib/syncwrap/components/cruby_vm.rb, line 150
def version_pattern
  if version_gte?( ruby_version, [2,1] )
    # Starting with 2.1.x, the p# (patch number) is no longer used
    # for download, won't be in ruby_version, and shouldn't be
    # used for version comparison.
    '[0-9]+(\.[0-9]+)+'
  else
    '[0-9]+(\.[0-9]+)+(p[0-9]+)?'
  end
end