Skip to content

Instantly share code, notes, and snippets.

@dreamcat4
Created August 21, 2010 19:33
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save dreamcat4/542746 to your computer and use it in GitHub Desktop.
Save dreamcat4/542746 to your computer and use it in GitHub Desktop.
Install RVM to /usr/local - as admin group
#!/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
@dreamcat4
Copy link
Author

Thanks for noticing this. In response to your points there are new improvements to the script.

Please be aware that the curl one-liner has also changed.

curl -fsS https://gist.github.com/raw/542746/install_rvm.rb | ruby -e '$script=STDIN.read;eval $script'

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment