#!/usr/bin/env ruby
#
# See manpage text on the bottom of this file for copyright information

ALTERNATIVES = `update-alternatives --list ruby`.split.inject({}) do |alternatives,ruby|
  alternatives[File.basename(ruby)] = {
    'ruby' => ruby,
    'gem' => ruby.gsub('ruby', 'gem') # FIXME a very strong assumption!
  }
  alternatives
end

$program_name = File.basename($PROGRAM_NAME)
def usage(exitstatus)
  puts "Usage:"
  puts
  puts "  #{$program_name} --list"
  puts "    Lists available Ruby interpreters"
  puts
  puts "  #{$program_name} --check"
  puts "    Checks the current Ruby alternatives configuration"
  puts
  puts "  #{$program_name} --set RUBYINTERPRETER"
  puts "    Changes the current Ruby interpreter"
  puts
  puts "  #{$program_name} --auto"
  puts "    Uses the default Ruby interpreter"
  puts
  exit(exitstatus)
end

def list(arg = nil)
  puts ALTERNATIVES.keys.sort
end

def current_alternative_settings
  @current_alternative_settings ||=
    begin
      ALTERNATIVES.values.map(&:keys).flatten.uniq.inject({}) do |result,p|
        result[p] = `readlink -f /usr/bin/#{p}`.strip
        result
      end
    end
end

def current_alternative
  @current_alternative ||= ALTERNATIVES.keys.find do |alt|
    ALTERNATIVES[alt] == current_alternative_settings
  end
end

$error = false
def write_msg(str = nil)
  puts ($error && $stdout.isatty && $stderr.isatty && $stdin.isatty) ? ("\033[31;40m%s\033[m" % str) : str
end

def header(msg)
  write_msg(msg)
  write_msg('-' * msg.size)
  puts
end

def print_settings(settings)
  settings.each do |program,implementation|
    write_msg "#{program}\t-> #{implementation}"
  end
end

def check(arg = nil)
  if current_alternative
    header("Currently using: #{current_alternative}")
  else
    $error = true
    header("WARNING: your Ruby alternatives settings are inconsistent")
  end
  print_settings(current_alternative_settings)
end

def set(interpreter)
  unless ALTERNATIVES.keys.include?(interpreter)
    puts "Invalid interpreter: #{interpreter}"
    exit 2
  end

  new_interpreter = ALTERNATIVES[interpreter]
  new_interpreter.each do |name,path|
    system('update-alternatives --set %s %s' % [name, path])
  end
end

def auto(arg = nil)
  system('update-alternatives --auto ruby')
  system('update-alternatives --auto gem')
end

def check_permissions
  unless File.writable?('/etc/alternatives')
    $error = true
    write_msg("You don't have the necessary permissions to perform this action.")
    write_msg("Try running #{$program_name} as root (or with sudo).")
    exit(1)
  end
end

require 'getoptlong'
opts = GetoptLong.new(
  [ '--list', '-l', GetoptLong::NO_ARGUMENT ],
  [ '--check', '-c', GetoptLong::NO_ARGUMENT ],
  [ '--set', '-s', GetoptLong::REQUIRED_ARGUMENT ],
  [ '--auto', '-a', GetoptLong::NO_ARGUMENT ],
  [ '--help', '-h', GetoptLong::NO_ARGUMENT ]
)

command = nil
chosen_interpreter = nil
begin
  opts.each do |opt,arg|
    case opt
    when '--help'
      usage(0)
    when '--list'
      usage(1) if command
      command = :list
    when '--check'
      usage(1) if command
      command = :check
    when '--set'
      command = :set
      chosen_interpreter = arg
    when '--auto'
      usage(1) if command
      command = :auto
    else
      usage(1)
    end
  end
rescue GetoptLong::InvalidOption => e
  usage(1)
end
if ARGV.size != 0 || command.nil?
  usage(1)
end
if [:set, :auto].include?(command)
  check_permissions
end

send(command, chosen_interpreter)

__END__
=head1 NAME

ruby-switch - switch between different Ruby interpreters

=head1 USAGE

ruby-switch --list

ruby-switch --check

ruby-switch --set RUBYVERSION

ruby-switch --auto

=head1 DESCRIPTION

B<ruby-switch> can be used to easily switch to different Ruby
interpreters as the default system-wide interpreter for your Debian system.

When run with I<--list>, all supported Ruby interpreters are listed.

When I<--check> is passed, ruby-switch will check which Ruby
interpreter is currently being used. If the settings are inconsistent -- e.g.
  `ruby` is Ruby 1.8 and `gem` is using Ruby 1.9.1, ruby-switch
will issue a big warning.

When I<--set RUBYINTERPRETER> is used B<ruby-switch> will switch
your system to the corresponding Ruby interpreter. This includes, for example,
the default implementations for the following programs:
I<ruby>,
I<gem>,
I<irb>,
I<erb>,
I<testrb>,
I<rdoc>,
I<ri>.

B<ruby-switch --set auto> will make your system use the default
Ruby interpreter currently suggested by Debian.

=head1 OPTIONS

=over

=item B<-h>, B<--help>

Displays the help and exits.

=back

=head1 A NOTE ON RUBY 1.9.x

Ruby uses two parallel versioning schemes: the `Ruby library compatibility
version' (1.9.1 at the time of writing this), which is similar to a library
SONAME, and the `Ruby version' (1.9.3 is about to be released at the time of
writing).

Ruby packages in Debian are named using the Ruby library compatibility version,
which is sometimes confusing for users who do not follow Ruby development
closely.

B<ruby-switch> also uses the Ruby library compatibility
version, so specifying `ruby1.9.1' might give you Ruby with version 1.9.2, or
with version 1.9.3, depending on the current Ruby version of the `ruby1.9.1'
package.

=head1 COPYRIGHT AND AUTHORS

Copyright (c) 2011, Antonio Terceiro <terceiro@debian.org>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

