# Copyright (C) 2011-2012 RightScale, Inc, All Rights Reserved Worldwide. # # THIS PROGRAM IS CONFIDENTIAL AND PROPRIETARY TO RIGHTSCALE # AND CONSTITUTES A VALUABLE TRADE SECRET. Any unauthorized use, # reproduction, modification, or disclosure of this program is # strictly prohibited. Any use of this program by an authorized # licensee is strictly subject to the terms and conditions, # including confidentiality obligations, set forth in the applicable # License Agreement between RightScale.com, Inc. and # the licensee module RightConf class RubyConfigurator include Configurator register :ruby description "Installs ruby interpreter and rubygems.\n" + 'Installs and uses rbenv on supported (i.e. non-Windows) platforms' setting 'version', 'Ruby version using rbenv notation (see "rbenv versions")', :required => true # Let configurator run, it is idempotent # # === Return # false:: Always return false def check_linux false end alias :check_darwin :check_linux alias :check_windows :check_linux # Switch to ruby version defined in settings # Use rbenv and install it if needed # # === Return # true:: Always return true def run_linux if Command.execute('rvm').success? report_fatal "rconf detected an installation of RVM, rconf now uses rbenv to configure ruby versions.\n" + "Unfortunately rbenv and RVM cannot be installed together on the same machine (see https://github.com/sstephenson/rbenv/).\n" + "Please uninstall RVM and try again ('rvm implode' will delete RVM and all installed rubies and gems).\n" + "Once RVM is uninstalled please start a new shell (you may also need to remove references to RVM from your ~/.bash_profile)" return true end check_rbenv return true if aborting check_ruby Command.set_ruby(ruby_version) true end alias :run_darwin :run_linux # Switch to ruby version defined in settings # TBD # # === Return # true:: Always return true def run_windows end protected # Make version compatible with RVM def ruby_version @ruby_version ||= version.start_with?('ruby-') ? version[5..-1] : version end # Check whether rbenv and ruby-build are installed and installs it/them if not # # === Return # true:: Always return true def check_rbenv res = Command.execute('rbenv') rbenv_in_path = res.success? if rbenv_in_path res.output =~ /^rbenv ([0-9]+)\.([0-9]+)\.([0-9]+)$/ maj, min, build = [$1.to_i, $2.to_i, $3.to_i] if maj == 0 && min < 4 report_fatal("rconf requires rbenv version 0.4.0 or greater, you have #{maj}.#{min}.#{build} installed, please upgrade (e.g. via brew upgrade rbenv) and try again") end return true end rbenv_present = File.exist?(File.join(ENV['HOME'], '.rbenv', 'bin', 'rbenv')) update_msg = "You should add 'eval \"$(rbenv init -)\"' to your .bash_profile / .bashrc etc. " + "so rbenv is properly initialized in new shells, the following assumes ~/.bash_profile is used (Mac OS X):\n\n" + "echo 'eval \"$(rbenv init -)\"' >> ~/.bash_profile\n\n".blue + "You should also update your PATH environment variable with:\n\n" + "echo 'export PATH=\"$HOME/.rbenv/shims:$PATH\" >> ~/.bash_profile'\n".blue if rbenv_present post_note "rconf detected rbenv is installed in #{rbenv_path} but it is not in the PATH.\n" + update_msg aborting(true) return true else opts = { :report => true, :post_install => update_msg }.merge(abort_option('Failed to install rbenv')) PackageInstaller.install('rbenv', opts) opts = { :report => true }.merge(abort_option('Failed to install ruby-build')) PackageInstaller.install('ruby-build', opts) true end end # Check .ruby-version and its content # # === Return # true:: Always return true def check_ruby unless Command.execute('rbenv', 'local', ruby_version).success? report_check("Installing ruby #{ruby_version} (this will take a while, please be patient)") Platform.dispatch(ruby_version) { :install_ruby } Command.execute('rbenv', 'local', ruby_version) end true end # Install given ruby version using rbenv # Install any prerequesites first # # === Parameters # ruby(String):: Ruby version compatible with rbenv # # === Return # true:: Always return true def install_ruby(ruby) Platform.dispatch(ruby) { :install_ruby_prerequisites } # Can't abort on failure rbenv install seems to exist with a non zero error code even when successful :( Command.execute('rbenv', 'install', ruby) report_success true end # Install given ruby version using rbenv # On Lion, need to setup CC env var before running rbenv install # # === Parameters # ruby(String):: Ruby version compatible with rbenv # # === Return # true:: Always return true def install_ruby_darwin(ruby) Platform.dispatch(ruby) { :install_ruby_prerequisites } c_version = `system_profiler SPDeveloperToolsDataType -xml | xpath "//*[text()='_items']/following-sibling::array/dict/child::key[text()='spdevtools_version']/following-sibling::string/text()" 2> /dev/null` env = {} gcc42 = ['/usr/local/bin/gcc-4.2', '/usr/bin/gcc-4.2'].detect { |p| File.executable?(p) } if c_version =~ /^4\.2\.[0-9]+/ if !gcc42 report_fatal("The C compiler included with Xcode #{c_version} produces buggy ruby interpreters, please install the C compilers from https://github.com/downloads/kennethreitz/osx-gcc-installer/GCC-10.7-v2.pkg or update your version of Xcode and re-run rconf") else env['CC'] = gcc42 end end if ruby =~ /1\.8/ if File.directory?('/opt/X11/include') env['CC'] = gcc42 env['CPPFLAGS'] = '-I/opt/X11/include' else report_fatal("Installing ruby 1.8 (or ree 1.8) on Mac OS X requires that XQuartz be installed on the machine first, please go to http://xquartz.macosforge.org/landing/, install XQuartz and try again") end end Command.execute('rbenv', 'install', ruby, :abort_on_failure => 'Failed to install ruby', :env => env) report_success end # Make sure to install all required linux packages first # # === Return # true:: Always return true def install_ruby_prerequisites_linux_ubuntu(ruby) report_check("Installing required packages, this could take a while") packages = [] if ruby =~ /^ree-|^ruby-/ packages = %w(build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev) end # TBD Define packages needed for other rubies Command.sudo('apt-get', 'install', '-y', *packages) report_success end alias install_ruby_prerequisites_linux_debian install_ruby_prerequisites_linux_ubuntu # Make sure to install all required CentOS / RedHhat packages first # NOTE: For centos 5.4 final iconv-devel might not be available :( # # === Return # true:: Always return true def install_ruby_prerequisites_linux_centos(ruby) report_check("Installing required packages, this could take a while") packages = [] if ruby =~ /^ree-|^ruby-/ packages = %w(gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel iconv-devel) end # TBD Define packages needed for other rubies Command.sudo('yum', 'install', '-y', *packages) report_success end alias :install_ruby_prerequisites_linux_redhat :install_ruby_prerequisites_linux_centos # No pre-requesites to install ree or Matz ruby on Mac (TBD others) # # === Return # true:: Always return true def install_ruby_prerequisites_darwin(ruby) version_output = `sw_vers` if m = /ProductVersion:\s*([0-9.]+)/m.match(version_output) osx_version = m[1].split(".").map { |c| c.to_i } else raise RuntimeError, "Can't determine OS X version from sw_vers output (#{version_output})" end if (osx_version[0] > 10 || osx_version[1] > 6) report_check("installing non-LLVM GCC 4.2") PackageInstaller.install('https://raw.github.com/Homebrew/homebrew-dupes/master/apple-gcc42.rb', :abort_on_failure => "Could not install gcc 4.2") report_success end true end # Produce abort on failure option # # === Parameters # message(String):: Abort message to be used in case abort option should be set # # === Return # {}:: Empty hash if 'abort_on_failure' is notset # opts(Hash):: Abort option with give message otherwise def abort_option(message) opts = abort_on_failure && { :abort_on_failure => message } || {} end end end