# 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 # RVM version used to install rubies RVM_VERSION = '1.10.2' # RVM releases URL RVM_RELEASES_URL = 'https://rvm.beginrescueend.com/releases' include Configurator register :ruby description "Installs ruby interpreter and rubygems.\n" + 'Installs and uses rvm on supported (i.e. non-Windows) platforms' settings :version => 'Ruby version using rvm notation (see "rvm list known")', :rubygems => 'Rubygems version, e.g. "1.3.7"', :gemset => 'Gemset to be used for platforms supporting rvm' validate_has_settings :version # 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 rvm and install it if needed # # === Return # true:: Always return true def run_linux check_rvm(RVM_VERSION) return true if aborting Command.set_ruby(version, gemset) report_check("Checking whether #{version} is the active ruby") out = Command.execute('rvm', 'current').output if out =~ /^#{version.gsub('.', '\\.')}/ report_success check_rvmrc else report_failure report_check("Switching to #{version}") out = Command.execute('rvm', 'use', version, :env => { 'rvm_is_not_a_shell_function' => '0' }).output case out when /is not installed\./ report_failure report_fatal "Failed to install #{ruby}" if @tried Platform.dispatch(version) { :install_ruby } @tried = true Command.execute_in_ruby('gem', 'install', 'rconf') unless gemset run return true when /^Using / report_success check_rvmrc else report_fatal("Failed to use #{version}:\n#{out}") end end if gemset report_check("Checking whether gemset #{gemset} exists") res = Command.execute('rvm', version, 'exec', 'rvm', 'gemset', 'list') if res.output =~ /^(\s+|=> )#{gemset}$/ report_success else report_failure report_check("Creating gemset #{gemset} for #{version}") Command.execute('rvm', version, 'exec', 'rvm', 'gemset', 'create', gemset, :abort_on_failure => "Failed to create gemset '#{gemset}'") end report_check("Checking whether rconf is installed") res = Command.execute('rconf', '--version') if res.output =~ /VERSION/ report_success else report_failure report_check("Installing rconf") Command.execute_in_ruby('gem', 'install', 'rconf', :abort_on_failure => "Failed to install rconf") report_success end report_check("Switching to gemset #{gemset}") Command.execute('rvm', version, 'exec', 'rvm', 'gemset', 'use', gemset, :abort_on_failure => "Failed to switch to gemset '#{gemset}'", :env => { 'rvm_is_not_a_shell_function' => '0' }) report_success end if rubygems report_check("Checking whether rubygems #{rubygems} is installed") res = Command.execute_in_ruby('gem', '--version') if res.success? && res.output =~ /^#{rubygems}$/ report_success else report_failure report_check("Installing rubygems #{rubygems}") Command.execute_in_ruby('rubygems', rubygems, :abort_on_failure => 'Failed to install rubygems') report_success end end true end alias :run_darwin :run_linux # Switch to ruby version defined in settings # TBD # # === Return # true:: Always return true def run_windows end # Set command prefix when already configured # Re-create .rvmrc if needed # # === Return # true:: Always return true def post_process Command.set_ruby(version, gemset) check_rvmrc true end protected # Check whether the right version of RVM is installed and install it if not # # === Parameters # version(String):: Version of RVM to be checked, e.g. '1.2.6' # # === Return # true:: Always return true def check_rvm(version) report_check("Checking that rvm #{version} is installed") out = Command.execute('rvm', '--version').output if out =~ /rvm #{RVM_VERSION.gsub('.', '\\.')}/ report_success else report_failure if out =~ /rvm ([^\s]+)/ report_error "WARNING!: You have rvm #{Regexp.last_match[1]} installed which may not be compatible with rconf.\n" + "rconf will proceed and try to install rvm #{version}." end report_check("Installing rvm #{version}") rvm_src = File.join(ENV['HOME'] || '/root', '.rvm/src') FileUtils.mkdir_p(rvm_src) Dir.chdir(rvm_src) do Command.execute('curl', '-O', '-f', "#{RVM_RELEASES_URL}/rvm-#{version}.tar.gz", :abort_on_failure => "Failed to download rvm #{version}") Command.execute('tar', 'zxf', "rvm-#{version}.tar.gz", :abort_on_failure => "Failed to extract rvm tgz from #{File.join(Dir.getwd, 'rvm-' + version + '.tar.gz')}") end Dir.chdir(File.join(rvm_src, "rvm-#{version}")) do Command.execute('./install', :abort_on_failure => "Failed to install rvm #{version}") end post_note "Configuration required installing RVM, please start a new shell to activate it and re-run rconf to finish configuration".green aborting(true) report_success end setup_bashrc true end # Install given ruby version using rvm # # === Parameters # ruby(String):: Ruby version compatible with rvm # # === Return # true:: Always return true def install_ruby(ruby) Platform.dispatch(ruby) { :install_ruby_prerequisites } report_check("Installing #{ruby} (this will take a while, please be patient)") Command.execute('rvm', 'install', ruby, :abort_on_failure => 'Failed to install ruby') report_success true end # Install given ruby version using rvm # On Lion, need to setup CC env var before running rvm install # # === Parameters # ruby(String):: Ruby version compatible with rvm # # === Return # true:: Always return true def install_ruby_darwin(ruby) report_check("Installing #{ruby} (this will take a while, please be patient)") 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 = {} if version =~ /^4\.2\.[0-9]+/ if !File.executable?('/usr/bin/gcc-4.2') report_fatal("The C compiler included with Xcode #{version} produces buggy ruby interpreters, please install the C compilers from https://github.com/downloads/kennethreitz/osx-gcc-installer/GCC-10.7-v2.pkg and re-run rconf") else env['CC'] = '/usr/bin/gcc-4.2' end end Command.execute('rvm', '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 # 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) true end # Check .rvmrc and its content # # === Return # true:: Always return true def check_rvmrc if !File.exist?('.rvmrc') || IO.read('.rvmrc') !~ /#{version}@#{gemset}/ report_check('Setting up .rvmrc') begin File.open('.rvmrc', 'w') do |f| f.puts "environment_id=\"#{version}@#{gemset}\"" f.puts RVM_HOOK f.puts "type -P rconf &>/dev/null && { rconf; }" f.puts "type -P rconf &>/dev/null || { echo 'rconf not installed, skipping (see .rvmrc)'; }" end report_success post_note "Configuration required switching the active ruby\nPlease run " + 'cd ..;cd -'.blue + ' to activate it and finish configuration'.green aborting(true) rescue Exception => e report_failure report_error(e.message) end end true end # rvm mojo for creating and enabling 'environments' RVM_HOOK = <<-EOF if [[ -d "${rvm_path:-$HOME/.rvm}/environments" \ && -s "${rvm_path:-$HOME/.rvm}/environments/$environment_id" ]] then \. "${rvm_path:-$HOME/.rvm}/environments/$environment_id" if [[ -s "${rvm_path:-$HOME/.rvm}/hooks/after_use" ]] then . "${rvm_path:-$HOME/.rvm}/hooks/after_use" fi else # If the environment file has not yet been created, use the RVM CLI to select. if ! rvm --create "$environment_id" then echo "Failed to create RVM environment '${environment_id}'." return 1 fi fi if [[ $- == *i* ]] # check for interactive shells then echo "Using: $(tput setaf 2)$GEM_HOME$(tput sgr0)" # show the user the ruby and gemset they are using in green else echo "Using: $GEM_HOME" # don't use colors in interactive shells fi EOF # Setup .bashrc for rvm support # # === Return # true:: Always return true def setup_bashrc if EnvironmentUpdater.update(rvm_bash_activation, ['PATH']) post_note '.rvmrc was updated, please reload your shell to activate it and re-run rconf' aborting(true) end end # rvm bash activation code # # === Return # code(String):: Code that needs to be added to bashrc to activate rvm def rvm_bash_activation code = <