Created
July 16, 2010 21:21
-
-
Save jonforums/478933 to your computer and use it in GitHub Desktop.
DevKit install helper script
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'win32/registry' | |
require 'yaml' | |
require 'fileutils' | |
module DevKitInstaller | |
DEVKIT_ROOT = File.expand_path(File.dirname(__FILE__)) | |
REG_KEYS = [ | |
'Software\RubyInstaller\MRI', | |
'Software\RubyInstaller\Rubinius' | |
] | |
STUB_CMDS = [ | |
'gcc', | |
'g++', | |
'make', | |
'sh' | |
] | |
CONFIG_FILE = 'config.yml' | |
def self.usage | |
<<-EOT | |
Configures an MSYS/MinGW based Development Kit (DevKit) for | |
each of the Ruby installations on your Windows system. The | |
DevKit enables you to build many of the available native | |
C-based RubyGems that don't yet have a binary gem. | |
Usage: ruby dk.rb COMMAND | |
where COMMAND is one of: | |
init prepare DevKit for installation | |
review review DevKit install plan | |
install install required DevKit executables | |
EOT | |
end | |
def self.stub_for(cmd, dk_root=DEVKIT_ROOT) | |
<<-EOT | |
@ECHO OFF | |
SETLOCAL | |
SET DEVKIT=#{dk_root.gsub('/','\\')} | |
SET PATH=%DEVKIT%\\bin;%DEVKIT%\\mingw\\bin;%PATH% | |
#{cmd}.exe %* | |
EOT | |
end | |
private_class_method :stub_for | |
def self.gem_override(dk_root=DEVKIT_ROOT) | |
d = dk_root.gsub('/', '\\\\\\') | |
<<-EOT | |
Gem.pre_install do |i| | |
puts 'Temporarily enhancing PATH to include DevKit...' | |
ENV['PATH'] = '#{d}\\\\bin;#{d}\\\\mingw\\\\bin;' + ENV['PATH'] | |
end | |
EOT | |
end | |
private_class_method :gem_override | |
def self.scan_for(key) | |
ris = [] | |
[Win32::Registry::HKEY_LOCAL_MACHINE, Win32::Registry::HKEY_CURRENT_USER].each do |hive| | |
begin | |
hive.open(key) do |ri_key| | |
ri_key.each_key do |skey, wtime| | |
# read the install location if a version subkey | |
if skey =~ /\d\.\d\.\d/ | |
ri_key.open(skey) do |ver_key| | |
ris << ver_key['InstallLocation'].gsub('\\', '/') | |
end | |
end | |
end | |
end | |
rescue Win32::Registry::Error => ex | |
$stderr.puts '[INFO] unable to open %s\%s...' % [hive.keyname, key] | |
end | |
end | |
ris | |
end | |
private_class_method :scan_for | |
def self.installed_rubies | |
rubies = REG_KEYS.collect { |key| scan_for(key) } | |
rubies.flatten.uniq | |
end | |
private_class_method :installed_rubies | |
def self.init | |
# get all known installed Ruby bindirs and write | |
# them to 'config.yml', overwriting existing file | |
ir = installed_rubies | |
File.open(CONFIG_FILE, 'w') do |f| | |
f.write <<-EOT | |
# This configuration file is meant to contain the absolute path locations | |
# of all installed Rubies that should be enhanced to work with the DevKit. | |
# It is generated by the 'init' step and may be modified before running the | |
# 'install' step. For example, to include any installed Rubies that were | |
# not automagically discovered, simply add a line with the absolute path | |
# location to the desired Ruby's root directory. | |
EOT | |
f.write(ir.to_yaml) | |
end | |
end | |
private_class_method :init | |
def self.review | |
if File.exists?(File.expand_path(CONFIG_FILE)) | |
File.open(CONFIG_FILE, 'r') do |f| | |
puts <<-EOT | |
Based upon the results contained in your '#{CONFIG_FILE}' config | |
file resulting from running 'ruby dk.rb init' and any of your | |
customizations, DevKit functionality will be injected into the | |
following Rubies when you run 'ruby dk.rb install' | |
EOT | |
puts YAML.load(f.read) | |
end | |
else | |
puts <<-EOT | |
Unable to find '#{CONFIG_FILE}'. Have you run 'ruby dk.rb init' yet? | |
EOT | |
end | |
end | |
def self.install | |
rubies = YAML.load_file(CONFIG_FILE) | |
rubies.each do |path| | |
site_ruby = Dir.glob("#{path}/lib/ruby/site_ruby/**/rubygems") | |
# inject stubs if no RubyGems in site_ruby, making backups of | |
# any existing stubs | |
if site_ruby.empty? | |
puts <<-EOT | |
Unable to find RubyGems in site_ruby. Falling back to installing | |
gcc, g++, make, and sh into #{path} | |
EOT | |
STUB_CMDS.each do |command| | |
target = File.join(path, 'bin', "#{command}.cmd") | |
if File.exist?(target) | |
puts "Renaming #{command}.cmd to #{command}.cmd.orig..." | |
File.rename(target, "#{target}.orig") | |
end | |
File.open(target, 'w') do |f| | |
f.write(stub_for command) | |
end | |
end | |
else | |
# inject RubyGems override file into proper site_ruby location | |
# appending an existing override file | |
site_ruby.each do |folder| | |
target = File.join(folder, 'defaults', 'operating_system.rb') | |
FileUtils.mkdir_p File.dirname(target) | |
if File.exist?(target) | |
puts '[INFO] Updating existing RubyGems override...' | |
File.open(target, 'a') do |f| | |
f.write("\n# override 'gem install' to enable RubyInstaller DevKit usage\n") | |
f.write(gem_override) | |
end | |
else | |
puts "[INFO] Installing #{target}..." | |
File.open(target, 'w') do |f| | |
f.write(gem_override) | |
end | |
end | |
end | |
end | |
end | |
end | |
private_class_method :install | |
def self.usage_and_exit | |
$stderr.puts usage | |
exit -1 | |
end | |
def self.run(*args) | |
send(args.first) | |
end | |
end | |
if __FILE__ == $0 | |
DevKitInstaller.usage_and_exit if ARGV.empty? | |
cmd = ARGV.delete('init') || | |
ARGV.delete('review') || | |
ARGV.delete('install') | |
DevKitInstaller.usage_and_exit unless ARGV.empty? | |
DevKitInstaller.run(cmd) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment