Skip to content

Instantly share code, notes, and snippets.

@sborsje
Created November 12, 2008 08:45
Show Gist options
  • Save sborsje/24113 to your computer and use it in GitHub Desktop.
Save sborsje/24113 to your computer and use it in GitHub Desktop.
#!/usr/bin/env ruby
require 'rubygems'
require 'rubygems/command'
require 'rubygems/commands/query_command'
CONFIG_FILE = 'config/gem_installer.yml'
def run
commands = parse_input_file
@gem_install_count = 0
@required_gems = 0
@source_installed = 0
@removed_gems = 0
error_count = 0
commands.each do |command|
if command[:command] == "source"
error_count += 1 unless do_source(command)
elsif command[:command] == "gem"
error_count += 1 unless do_gem(command)
end
end
puts "*** Finished installing #{@gem_install_count} out of #{@required_gems} gems"
puts "*** Removed #{@removed_gems} gems." if @removed_gems > 0
if error_count > 0
puts "*** ERROR: #{error_count} errors occured!"
exit 1
end
end
def parse_input_file
raise("Gem installer config file (#{CONFIG_FILE}) missing!") unless (File.exists?(CONFIG_FILE))
Gem.source_index # update gem sources
commands = []
config = YAML::load_file(CONFIG_FILE)
config["sources"].each do |source|
commands << { :command => 'source', :source => source }
end
config["gems"].each do |rubygem|
x = parse_gem_line(rubygem)
commands << x if x
end
return commands
end
def parse_gem_line(line)
split_line = line.split(" ")
name, version, command = split_line[0], split_line[1], nil
if split_line[2] == "--"
# custom command specified
command = split_line[3..split_line.size-1].join(" ")
end
unless name.empty?# or version.empty?
allow_siblings = version.nil? ? nil : (version.match(/\*$/) ? false : true)
version.gsub!(/\*$/, "") unless version.nil?
{ :command => 'gem', :name => name, :version => version, :allow_siblings => allow_siblings, :custom_command => command }
end
end
def do_source(command)
add_source(command[:source])
end
def do_gem(command)
@required_gems +=1
# uninstall unwanted siblings if required
unless command[:allow_siblings]
siblings = get_siblings_of(command[:name], command[:version])
(siblings || []).each do |sibling|
puts "==> Removing #{sibling[:name]} #{sibling[:version]}..."
unless remove_gem(sibling[:name], sibling[:version])
puts "==> Could not uninstall #{sibling[:name]} #{sibling[:version]}. An error was returned."
return false
else
@removed_gems +=1
end
end
end
# install the gem if it's not already installed
unless gem_installed?(command[:name], command[:version])
puts "==> Installing #{command[:name]} #{command[:version]}..."
@gem_install_count +=1
if command[:custom_command].nil?
version_string = ""
unless command[:version].nil? or command[:version].empty?
version_string = "-v #{command[:version]}"
end
output, exit_code = exec("gem install #{command[:name]} #{version_string} --no-rdoc --no-ri")
else
puts "==> Running custom command '#{command[:custom_command]}'..."
output, exit_code = exec("#{command[:custom_command]}")
end
return (exit_code == 0)
else
puts "==> #{command[:name]} #{command[:version]} is already installed."
return true
end
end
def remove_gem(name, version)
output, exit_code = exec("gem uninstall #{name} -v '#{version}' -I -x -a")
return (exit_code == 0)
end
def gem_installed?(gem_name, gem_version)
Gem::Commands::QueryCommand.new.installed?(gem_name, gem_version)
end
def source_installed?(source_uri)
Gem.sources.include?(source_uri)
end
def add_source(source_uri)
unless source_installed?(source_uri)
puts "==> Adding source #{source_uri}..."
output, exit_code = exec("gem sources -a #{source_uri} && gem sources --update")
return (exit_code == 0)
else
puts "==> Source #{source_uri} already installed."
return true
end
end
def get_siblings_of(gem_name, version)
# TODO: get the versions directly from a Rubygems method instead of parsing.
gem, exit_code = exec("gem list #{gem_name} | grep #{gem_name}")
versions = []
gem.each_line do |line|
if line.starts_with?(gem_name + " (")
versions = line.sub(gem_name + " (", "").sub(")","").sub(" ", "").split(',')
end
end
out = []
versions.each do |v|
v.chomp!
out << {:name => gem_name, :version => v} unless v == version
end
out
end
def exec(command)
output = `#{command}`
exit_code = $?
return [output, exit_code]
end
class Gem::Commands::QueryCommand
public :installed?
end
class String
def starts_with?(str)
str = str.to_str
head = self[0, str.length]
head == str
end
end
# run the script!
run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment