Skip to content

Instantly share code, notes, and snippets.

@luislavena
Forked from jonforums/dk.rb
Created July 20, 2010 15:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save luislavena/483144 to your computer and use it in GitHub Desktop.
Save luislavena/483144 to your computer and use it in GitHub Desktop.
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|
unless ENV['PATH'].include?('#{d}\\\\mingw\\\\bin') then
puts 'Temporarily enhancing PATH to include DevKit...'
ENV['PATH'] = '#{d}\\\\bin;#{d}\\\\mingw\\\\bin;' + ENV['PATH']
end
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)
content = File.read(target)
unless content.include?('DevKit')
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] RubyGems override already in place, skipping.'
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