Skip to content
This repository has been archived by the owner on Apr 14, 2021. It is now read-only.

Commit

Permalink
Handle rubygems executable wrappers better
Browse files Browse the repository at this point in the history
  • Loading branch information
Carl Lerche committed Feb 6, 2010
1 parent d19c577 commit 2d05242
Show file tree
Hide file tree
Showing 4 changed files with 119 additions and 44 deletions.
126 changes: 84 additions & 42 deletions lib/bundler/runtime.rb
Expand Up @@ -3,8 +3,11 @@
module Bundler
class Runtime < Environment
def setup(*groups)
specs = specs_for(*groups)
# Has to happen first
clean_load_path

specs = specs_for(*groups)

cripple_rubygems(specs)

# Activate the specs
Expand Down Expand Up @@ -119,7 +122,56 @@ def load_paths
specs.map { |s| s.load_paths }.flatten
end

def cripple_rubygems(specs)
def write_rb_lock
template = File.read(File.expand_path("../templates/environment.erb", __FILE__))
erb = ERB.new(template, nil, '-')
File.open("#{root}/.bundle/environment.rb", 'w') do |f|
f.puts erb.result(binding)
end
end

def write_yml_lock
yml = details.to_yaml
File.open("#{root}/Gemfile.lock", 'w') do |f|
f.puts yml
end
end

def details
details = {}
details["hash"] = gemfile_fingerprint
details["sources"] = sources.map { |s| { s.class.name.split("::").last => s.options} }

details["specs"] = specs.map do |s|
options = {"version" => s.version.to_s}
options["source"] = sources.index(s.source) if sources.include?(s.source)
{ s.name => options }
end

details["dependencies"] = @definition.dependencies.map { |d| {d.name => d.version_requirements.to_s} }
details
end

def gemfile_fingerprint
Digest::SHA1.hexdigest(File.read("#{root}/Gemfile"))
end

def autorequires_for_groups(*groups)
autorequires = Hash.new { |h,k| h[k] = [] }
@definition.dependencies.each do |dep|
dep.groups.each do |group|
autorequires[group].concat dep.autorequire
end
end

if groups.empty?
autorequires
else
groups.inject({}) { |h,g| h[g] = autorequires[g]; h }
end
end

def clean_load_path
# handle 1.9 where system gems are always on the load path
if defined?(::Gem)
me = File.expand_path("../../", __FILE__)
Expand All @@ -130,7 +182,9 @@ def cripple_rubygems(specs)
$LOAD_PATH.unshift me
$LOAD_PATH.uniq!
end
end

def reverse_rubygems_kernel_mixin
# Disable rubygems' gem activation system
::Kernel.class_eval do
if private_method_defined?(:gem_original_require)
Expand All @@ -140,8 +194,17 @@ def cripple_rubygems(specs)

undef gem
end
end

def cripple_rubygems(specs)
reverse_rubygems_kernel_mixin

executables = specs.map { |s| s.executables }.flatten

::Kernel.send(:define_method, :gem) do |dep, *reqs|
if executables.include? File.basename(caller.first.split(':').first)
return
end
opts = reqs.last.is_a?(Hash) ? reqs.pop : {}

unless dep.respond_to?(:name) && dep.respond_to?(:version_requirements)
Expand All @@ -165,54 +228,33 @@ def cripple_rubygems(specs)

true
end
end

def write_rb_lock
template = File.read(File.expand_path("../templates/environment.erb", __FILE__))
erb = ERB.new(template, nil, '-')
File.open("#{root}/.bundle/environment.rb", 'w') do |f|
f.puts erb.result(binding)
end
end

def write_yml_lock
yml = details.to_yaml
File.open("#{root}/Gemfile.lock", 'w') do |f|
f.puts yml
end
end

def details
details = {}
details["hash"] = gemfile_fingerprint
details["sources"] = sources.map { |s| { s.class.name.split("::").last => s.options} }
# === Following hacks are to improve on the generated bin wrappers ===

details["specs"] = specs.map do |s|
options = {"version" => s.version.to_s}
options["source"] = sources.index(s.source) if sources.include?(s.source)
{ s.name => options }
# Yeah, talk about a hack
source_index_class = (class << Gem::SourceIndex ; self ; end)
source_index_class.send(:define_method, :from_gems_in) do |*args|
source_index = Gem::SourceIndex.new
source_index.add_specs *specs
source_index
end

details["dependencies"] = @definition.dependencies.map { |d| {d.name => d.version_requirements.to_s} }
details
end
# OMG more hacks
gem_class = (class << Gem ; self ; end)
gem_class.send(:define_method, :bin_path) do |name, *args|
exec_name, *reqs = args

def gemfile_fingerprint
Digest::SHA1.hexdigest(File.read("#{root}/Gemfile"))
end
spec = nil

def autorequires_for_groups(*groups)
autorequires = Hash.new { |h,k| h[k] = [] }
@definition.dependencies.each do |dep|
dep.groups.each do |group|
autorequires[group].concat dep.autorequire
if exec_name
spec = specs.find { |s| s.executables.include?(exec_name) }
spec or raise Gem::Exception, "can't find executable #{exec_name}"
else
spec = specs.find { |s| s.name == name }
exec_name = spec.default_executable or raise Gem::Exception, "no default executable for #{spec.full_name}"
end
end

if groups.empty?
autorequires
else
groups.inject({}) { |h,g| h[g] = autorequires[g]; h }
File.join(spec.full_gem_path, spec.bindir, exec_name)
end
end
end
Expand Down
7 changes: 5 additions & 2 deletions lib/bundler/source.rb
Expand Up @@ -30,8 +30,11 @@ def install(spec)
gem_path = Gem::RemoteFetcher.fetcher.download(spec, uri, destination)
Bundler.ui.debug " * Installing"
installer = Gem::Installer.new gem_path,
:install_dir => Gem.dir,
:ignore_dependencies => true
:install_dir => Gem.dir,
:ignore_dependencies => true,
:wrappers => true,
:env_shebang => true,
:bin_dir => "#{Gem.dir}/bin"

installer.install
end
Expand Down
29 changes: 29 additions & 0 deletions spec/other/exec_spec.rb
Expand Up @@ -32,4 +32,33 @@

out.should == "1.0.0"
end

it "handles different versions in different bundles" do
build_repo2 do
build_gem "rack_two", "1.0.0" do |s|
s.executables = "rackup"
end
end

install_gemfile <<-G
source "file://#{gem_repo1}"
gem "rack", "0.9.1"
G

Dir.chdir bundled_app2 do
install_gemfile bundled_app2('Gemfile'), <<-G
source "file://#{gem_repo2}"
gem "rack_two", "1.0.0"
G
end

bundle "exec rackup"

out.should == "0.9.1"

Dir.chdir bundled_app2 do
bundle "exec rackup"
out.should == "1.0.0"
end
end
end
1 change: 1 addition & 0 deletions spec/support/builders.rb
Expand Up @@ -110,6 +110,7 @@ def update_repo2
build_gem "rack", "1.2" do |s|
s.executables = "rackup"
end
yield if block_given?
end
end

Expand Down

0 comments on commit 2d05242

Please sign in to comment.