#!/usr/bin/env ruby # # One-liner # curl -fsS https://gist.github.com/raw/542746/install_rvm.rb | ruby -e '$script=STDIN.read;eval $script' # # This script installs to /usr/local only. It assumes theres an # admin group on your system - either "wheel", "admin", or "staff" # # Sudo is used a few times during the initial install. But anyone # in admin group can manage rvm (regardless of sudo privelidges) # # In other words - no sudo'ing is needed thereafter. # All rvm stuff remains writable by the admin group # # Based enitrely on: https://gist.github.com/323731 # For the philosophy, see: https://github.com/mxcl/homebrew, "Quick Install to /usr/local" # # install_rvm.rb - Changelog # # 16th November 2010: # Cross-platform support - tested on mac osx and ubuntu # Fix permissions on /etc/rvmrc # Check for pre-requisite cmds (namely chgrp and curl) # Numerous minor Bug fixes # Accept git commit refs for the version to install # Break into a new shell for interactive installs # Assume wheel group for linuxes with no 'admin' group # Enable tarball installs if git is missing # # 21st August 2010: # New version to install Rvm allongside brew in /usr/local. # # # 14th March 2010: # Adapted CodeButler's fork: https://gist.github.com/331512 (now deleted) # # # Usage: ruby install_rvm.rb # <--- stable # ruby install_rvm.rb $version # ruby install_rvm.rb master # <--- head # ruby install_rvm.rb 606b9ebca # ruby install_rvm.rb stable # ruby install_rvm.rb 1.0.19 # require "etc" ####################################################################### helper methods module Tty extend self def blue; bold 34; end def white; bold 39; end def red; underline 31; end def reset; escape 0; end def bold n; escape "1;#{n}" end def underline n; escape "4;#{n}" end def escape n; "\033[#{n}m" if STDOUT.tty? end end class Array def shell_s cp = dup first = cp.shift cp.map{ |arg| arg.gsub " ", "\\ " }.unshift(first) * " " end end def ohai *args puts "#{Tty.blue}==>#{Tty.white} #{args.shell_s}#{Tty.reset}" end def warn warning puts "#{Tty.red}Warning#{Tty.reset}: #{warning.chomp}" end def system *args result = Kernel.system *args unless result puts Process.euid puts $?.inspect abort "Failed during: #{args.shell_s}" end result end def sudo *args args = if args.length > 1 args.unshift "sudo" else "sudo #{args}" end ohai *args system *args end def getc # NOTE was tested on OS X and Ubuntu system "stty raw -echo" if RUBY_VERSION >= '1.8.7' STDIN.getbyte else STDIN.getc end ensure system "stty -raw echo" end def executable binary Kernel.system "which #{binary} 2>&1 > /dev/null" end class String def undent gsub /^\s{#{slice(/^\s+/).length}}/, '' end def indent num=2 gsub /^/, ' '*num end end def is_mac? RUBY_PLATFORM.downcase.include?("darwin") end def admin_group groups = [] Etc.group {|g| groups << g.name } if is_mac? return "staff" if groups.include?("staff") end %w[ admin wheel ].each do |g| return g if groups.include?(g) end return nil end def spawning_shell parent = `ps c -o command= #{Process.ppid}`.delete("\n") [:bash,:tcsh,:csh,:dash,:ash,:ksh,:zsh,:sh].each do |shell| return shell.to_s if parent =~ Regexp.new("^-?#{shell.to_s}") end return nil end def user_shell user = ENV['SUDO_USER'] || Etc.getpwuid(Process::UID.eid).name user_shell = File.basename(Etc.getpwnam(user).shell) end def shell_best_guess spawning_shell || user_shell end def save_last_shell ENV["install_rvm_last_shell"] = shell_best_guess end def last_shell ENV["install_rvm_last_shell"] end def version if @version.nil? @version = ARGV[0] || %x[/usr/bin/curl -sSfL http://rvm.beginrescueend.com/releases/stable-version.txt].chomp case @version.downcase when "master", "head", "latest" @version = "master" when "stable", "release", "" @version = %x[/usr/bin/curl -sSfL http://rvm.beginrescueend.com/releases/stable-version.txt].chomp end else @version end end ####################################################################### prerequisites install_cmds = %w[groups sudo stty which mkdir chmod chgrp curl tar cp sh cat] install_cmds.each do |cmd| abort "Missing a vital shell command: #{cmd}" unless executable cmd end unless executable("git") if version =~ /^(master|[[:xdigit:]]+)$/ if is_mac? abort "Please `brew install git' first." elsif executable("aptitude") abort "Please `aptitude install -y git-core' first." else abort "Please install git first." end end end unless admin_group abort <<-EOABORT This installer requires that the system has an administrator group or "superuser group". The one which has sudo privelidges. Common admin group names are: # Mac OS-X only "staff" # Ubuntu, Debian "admin" # Others "wheel" No admin group was detected on your system, so its a requirement to create one. The name of this group must be "admin" or "wheel". Then please re-run the installer to continue. EOABORT end if STDIN.tty? && !last_shell save_last_shell end ohai "Checking for an existing installation..." if File.directory? "/usr/local/rvm" abort " /usr/local/rvm already exists - Exiting." end ohai "This script will create the following files and directories" puts "/usr/local/bin/rvm Symlink" puts "/usr/local/rvm Directory" dirs = %w[/usr/local /usr/local/rvm /usr/local/rvm/src /usr/local/rvm/src/rvm] chmods = dirs.select { |d| File.directory? d and not File.writable? d } chgrps = chmods.reject { |d| File.stat(d).grpowned? } unless chmods.empty? ohai "The following directories will be made group writable:" puts *chmods end unless chgrps.empty? ohai "The following directories will have their group set to #{Tty.underline 39}#{admin_group}#{Tty.reset}:" puts *chgrps end warn "/usr/local/bin is not in your PATH." unless ENV['PATH'].split(':').include? '/usr/local/bin' if STDIN.tty? puts puts "Press enter to continue" abort unless getc == 13 end def can_sudo if @can_sudo.nil? ohai "Testing for sudo" puts " Sudo is required only during installation" `sudo sleep 0` @can_sudo = true if $?.exitstatus == 0 @can_sudo ||= false else @can_sudo end end def sudo_this_script quoted_args = "'" << $*.join("' '") << "'" unless $*.empty? if $0 && $0 != "-e" # Local script so direct invocation is possible %Q{cd #{ENV["PWD"]} && sudo '#{$0}' #{quoted_args}} elsif $script # The new (gist-independant) curl one-liner invocation <<-EOS.undent cd #{ENV["PWD"]} && sudo 'ruby' '-e' '$script=STDIN.read;eval $script' #{quoted_args} <<-END_OF_SCRIPT #{$script.indent(4)} END_OF_SCRIPT EOS else # ruby -e "$(curl -fsS https://gist.github.com/raw/542746/install_rvm.rb)" $version # OLD curl one-liner invocation... its deprecated b/c does not vv update this gist number @! %Q{cd #{ENV["PWD"]} && curl -fsS https://gist.github.com/raw/542746/install_rvm.rb | sudo 'ruby' '-e' '$script=STDIN.read;eval $script' #{quoted_args}} end end # Here we escalate privelidges... unless Process.uid == 0 if can_sudo ohai "Executing with sudo" exec sudo_this_script else abort <<-EOABORT This script installs under shared 'admin' group ownership and permissions. Therefore sudo is a requirement for correct installation. Usually (for most operating systems) the relevant administrator group is already configured with sudo (ALL) rights. Otherwise `man sudo`, `sudo -e`. To add a user to the relevant admininistrator group: # Mac OS-X dscl /Local/Default -append /Groups/staff GroupMembership $USER # Ubuntu, Debian usermod -a -G admin $USER # Other flavors of Linux (arch-linux, redhat, slackware) usermod -a -G wheel $USER EOABORT end end # Drop straight back down into the correct Effective UID, Effective GID # before running the rvm installer. (we can only do this if we are root) unless Process.uid == 0 abort "Somethings wrong. We require UID=0 after this point." end admin_gid = Etc.getgrnam(admin_group).gid Process::Sys.setgid admin_gid unless Process.egid == admin_gid Process::Sys.setuid(ENV["SUDO_UID"].to_i) if ENV["SUDO_UID"] ####################################################################### start unless executable("git") if version =~ /^(master|[[:xdigit:]]+)$/ if is_mac? abort "Please `brew install git' first." elsif executable("aptitude") abort "Please `aptitude install -y git-core' first." else abort "Please install git first." end end end ####################################################################### mkdirs sudo "mkdir -p /usr/local" sudo "chgrp #{admin_group} /usr/local" sudo "chmod g+w /usr/local" [dirs, chmods, chgrps].each do |a| a.delete("/usr/local") end dirs.each do |dir| ohai "mkdir -p #{dir}" system "mkdir -p #{dir}" system "chmod g+s #{dir}" end sudo "chmod", "g+w", *chmods unless chmods.empty? sudo "chgrp", admin_group, *chgrps unless chgrps.empty? ####################################################################### download Dir.chdir "/usr/local/rvm" do ohai "Downloading and Installing Rvm #{version}..." # -m stops tar erroring out if it can't modify the mtime for root owned directories if version =~ /^(master|[[:xdigit:]]+)$/ system "curl -sSfL http://github.com/wayneeseguin/rvm/tarball/master | tar xz -m --strip 1" else system "curl -sSfL http://rvm.beginrescueend.com/releases/rvm-#{version}.tar.gz | tar xz -m --strip 1" end end ####################################################################### setup require 'tempfile' def rvmrc <<-EOS.undent # Default system-wide configuration for rvm # If an rvm install exists in the home directory, don't load this.' if [[ ! -s "\$HOME/.rvm/scripts/rvm" ]]; then # This is where rvm installs and manages everything in by default. rvm_prefix=/usr/local/ rvm_selfcontained=0 # Have rvm compile rubies and libraries as x86_64 on *Mac OS X*. rvm_archflags="-arch i386" # or for 64-bit use x86_64 fi EOS end t = Tempfile.new "rvmrc" t.puts rvmrc t.close ENV["rvmrc"] = t.path sudo "cp $rvmrc /etc/rvmrc" sudo "chgrp #{admin_group} /etc/rvmrc" sudo "chmod g+w,a+r /etc/rvmrc" def rvm_source_line <<-EOS.undent if [ -s "/usr/local/rvm/scripts/rvm" ]; then source "/usr/local/rvm/scripts/rvm" fi EOS end unless File.exist?("/etc/profile") && File.read("/etc/profile").include?(rvm_source_line) # Source rvm in /etc/profile. Gets loaded by all users # Individual users can optionally re-source ~/.rvm t = Tempfile.new "rvm_source_line" t.puts rvm_source_line t.close ENV["rvm_source_line"] = t.path sudo "sh -c \"cat $rvm_source_line >> /etc/profile\"" end ####################################################################### install # ENV["rvm_selfcontained"] = "1" # this can affet $rvm_bin_path if executable "git" Dir.chdir "/usr/local/rvm/src" do system "rm -rf rvm" if File.exists?("rvm") system "git clone git://github.com/wayneeseguin/rvm.git" Dir.chdir "/usr/local/rvm/src/rvm" do system "git checkout #{version}" unless version == "master" end end Dir.chdir "/usr/local/rvm/src/rvm" do system "/usr/local/rvm/src/rvm/scripts/install --prefix /usr/local/" end else system "/usr/local/rvm/scripts/install --prefix /usr/local/" end sudo "rm /usr/local/bin/rvm" if File.exists?("/usr/local/bin/rvm") sudo "ln -s /usr/local/rvm/bin/rvm /usr/local/bin/rvm" ohai "Installation successful!" if executable "gcc" puts "Now run `rvm reload` or open a new shell." else if is_mac? warn "Now install Xcode: http://developer.apple.com/technologies/xcode.html" elsif executable("aptitude") warn "Now install gcc: $ aptitude install -y build-essential" else warn "Now install gcc (you need gcc to build ruby!!)" end puts "Then run `rvm reload` or open a new shell." end if STDIN.tty? if ENV["SUDO_USER"] %w[ USER USERNAME LOGNAME].each do |var| ENV[var] = ENV["SUDO_USER"] if ENV[var] end end puts ohai "Sourcing rvm in a new shell..." ohai "/usr/bin/env #{last_shell} -l" puts "You can escape back to your old shell with `exit`" exec %Q{/usr/bin/env #{last_shell} -l} end