diff options
-rw-r--r-- | Rakefile | 15 | ||||
-rw-r--r-- | lib/bundler/cli/pristine.rb | 8 | ||||
-rw-r--r-- | lib/bundler/rubygems_gem_installer.rb | 22 | ||||
-rw-r--r-- | lib/bundler/rubygems_integration.rb | 5 | ||||
-rw-r--r-- | lib/bundler/source.rb | 13 | ||||
-rw-r--r-- | lib/bundler/source/git.rb | 10 | ||||
-rw-r--r-- | lib/bundler/source/path.rb | 3 | ||||
-rw-r--r-- | lib/bundler/source/path/installer.rb | 1 | ||||
-rw-r--r-- | lib/bundler/source/rubygems.rb | 8 | ||||
-rw-r--r-- | spec/commands/pristine_spec.rb | 19 | ||||
-rw-r--r-- | spec/install/global_cache_spec.rb | 46 | ||||
-rw-r--r-- | spec/support/builders.rb | 17 |
12 files changed, 152 insertions, 15 deletions
@@ -48,10 +48,17 @@ namespace :spec do deps.delete("rdiscount") end - gem_install_command = "install --no-ri --no-rdoc --conservative " + deps.sort_by {|name, _| name }.map do |name, version| - "'#{name}:#{version}'" - end.join(" ") - sh %(#{Gem.ruby} -S gem #{gem_install_command}) + if Gem::VERSION < "2.0.0" + deps.sort_by {|name, _| name }.map do |name, version| + gem_install_command = "install --no-ri --no-rdoc --conservative #{name} -v '#{version}'" + sh %(#{Gem.ruby} -S gem #{gem_install_command}) + end + else + gem_install_command = "install --no-ri --no-rdoc --conservative " + deps.sort_by {|name, _| name }.map do |name, version| + "'#{name}:#{version}'" + end.join(" ") + sh %(#{Gem.ruby} -S gem #{gem_install_command}) + end # Download and install gems used inside tests $LOAD_PATH.unshift("./spec") diff --git a/lib/bundler/cli/pristine.rb b/lib/bundler/cli/pristine.rb index 48c5b13899..7dca77050f 100644 --- a/lib/bundler/cli/pristine.rb +++ b/lib/bundler/cli/pristine.rb @@ -10,6 +10,9 @@ module Bundler def run CLI::Common.ensure_all_gems_in_lockfile!(@gems) + definition = Bundler.definition + definition.validate_runtime! + installer = Bundler::Installer.new(Bundler.root, definition) Bundler.load.specs.each do |spec| next if spec.name == "bundler" # Source::Rubygems doesn't install bundler @@ -27,14 +30,15 @@ module Bundler end FileUtils.rm_rf spec.full_gem_path - source.install(spec, :force => true) when Source::Git source.remote! FileUtils.rm_rf spec.full_gem_path - source.install(spec, :force => true) else Bundler.ui.warn("Cannot pristine #{gem_name}. Gem is sourced from local path.") + next end + + Bundler::GemInstaller.new(spec, installer, false, 0, true).install_from_spec end end end diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 1d9da0e329..e7e1a7e940 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -18,6 +18,28 @@ module Bundler super && validate_bundler_checksum(options[:bundler_expected_checksum]) end + def build_extensions + extension_cache_path = options[:bundler_extension_cache_path] + return super unless extension_cache_path && extension_dir = Bundler.rubygems.spec_extension_dir(spec) + + extension_dir = Pathname.new(extension_dir) + build_complete = SharedHelpers.filesystem_access(extension_cache_path.join("gem.build_complete"), :read, &:file?) + if build_complete && !options[:force] + SharedHelpers.filesystem_access(extension_dir.parent, &:mkpath) + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_cache_path, spec.extension_dir + end + else + super + if extension_dir.directory? # not made for gems without extensions + SharedHelpers.filesystem_access(extension_cache_path.parent, &:mkpath) + SharedHelpers.filesystem_access(extension_cache_path) do + FileUtils.cp_r extension_dir, extension_cache_path + end + end + end + end + private def validate_bundler_checksum(checksum) diff --git a/lib/bundler/rubygems_integration.rb b/lib/bundler/rubygems_integration.rb index dc1c35b990..202903d981 100644 --- a/lib/bundler/rubygems_integration.rb +++ b/lib/bundler/rubygems_integration.rb @@ -93,6 +93,11 @@ module Bundler end.flatten(1) end + def spec_extension_dir(spec) + return unless spec.respond_to?(:extension_dir) + spec.extension_dir + end + def stub_set_spec(stub, spec) stub.instance_variable_set(:@spec, spec) end diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb index 38e001535c..956cf39d56 100644 --- a/lib/bundler/source.rb +++ b/lib/bundler/source.rb @@ -73,5 +73,18 @@ module Bundler Bundler.ui.info message end end + + def extension_cache_path(spec) + return unless Bundler.feature_flag.global_gem_cache? + return unless source_slug = extension_cache_slug(spec) + Bundler.user_cache.join( + "extensions", Gem::Platform.local.to_s, Bundler.ruby_scope, + source_slug, spec.full_name + ) + end + + def extension_cache_slug(_) + nil + end end end diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index fd8f6debea..c66cbb17fb 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -209,8 +209,6 @@ module Bundler # When using local git repos, this is set to the local repo. def cache_path @cache_path ||= begin - git_scope = "#{base_name}-#{uri_hash}" - if Bundler.requires_sudo? || Bundler.feature_flag.global_gem_cache? Bundler.user_cache else @@ -318,6 +316,14 @@ module Bundler StubSpecification.from_stub(stub) end end + + def git_scope + "#{base_name}-#{uri_hash}" + end + + def extension_cache_slug(_) + extension_dir_name + end end end end diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb index 806ba81935..afd8723168 100644 --- a/lib/bundler/source/path.rb +++ b/lib/bundler/source/path.rb @@ -227,7 +227,8 @@ module Bundler spec, :env_shebang => false, :disable_extensions => options[:disable_extensions], - :build_args => options[:build_args] + :build_args => options[:build_args], + :bundler_extension_cache_path => extension_cache_path(spec) ) installer.post_install rescue Gem::InvalidSpecificationException => e diff --git a/lib/bundler/source/path/installer.rb b/lib/bundler/source/path/installer.rb index 64e63766dd..a0357ffa39 100644 --- a/lib/bundler/source/path/installer.rb +++ b/lib/bundler/source/path/installer.rb @@ -7,6 +7,7 @@ module Bundler attr_reader :spec def initialize(spec, options = {}) + @options = options @spec = spec @gem_dir = Bundler.rubygems.path(spec.full_gem_path) @wrappers = true diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 70dc5ac038..fa60bb0c84 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -148,7 +148,8 @@ module Bundler :wrappers => true, :env_shebang => true, :build_args => opts[:build_args], - :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum + :bundler_expected_checksum => spec.respond_to?(:checksum) && spec.checksum, + :bundler_extension_cache_path => extension_cache_path(spec) ).install end spec.full_gem_path = installed_spec.full_gem_path @@ -498,6 +499,11 @@ module Bundler Bundler.user_cache.join("gems", cache_slug, spec.file_name) end + + def extension_cache_slug(spec) + return unless remote = spec.remote + remote.cache_slug + end end end end diff --git a/spec/commands/pristine_spec.rb b/spec/commands/pristine_spec.rb index 90f6cffeb6..108606e8aa 100644 --- a/spec/commands/pristine_spec.rb +++ b/spec/commands/pristine_spec.rb @@ -12,6 +12,7 @@ RSpec.describe "bundle pristine" do build_repo2 do build_gem "weakling" build_gem "baz-dev", "1.0.0" + build_gem "very_simple_binary", &:add_c_extension build_git "foo", :path => lib_path("foo") build_lib "bar", :path => lib_path("bar") end @@ -19,6 +20,7 @@ RSpec.describe "bundle pristine" do install_gemfile! <<-G source "file://#{gem_repo2}" gem "weakling" + gem "very_simple_binary" gem "foo", :git => "#{lib_path("foo")}" gem "bar", :path => "#{lib_path("bar")}" @@ -143,4 +145,21 @@ RSpec.describe "bundle pristine" do expect(out).to include("Could not find gem 'abcabcabc'.") end end + + context "when a build config exists for one of the gems" do + let(:very_simple_binary) { Bundler.definition.specs["very_simple_binary"].first } + let(:c_ext_dir) { Pathname.new(very_simple_binary.full_gem_path).join("ext") } + let(:build_opt) { "--with-ext-lib=#{c_ext_dir}" } + before { bundle "config build.very_simple_binary -- #{build_opt}" } + + # This just verifies that the generated Makefile from the c_ext gem makes + # use of the build_args from the bundle config + it "applies the config when installing the gem" do + bundle! "pristine" + + makefile_contents = File.read(c_ext_dir.join("Makefile").to_s) + expect(makefile_contents).to match(/libpath =.*#{c_ext_dir}/) + expect(makefile_contents).to match(/LIBPATH =.*-L#{c_ext_dir}/) + end + end end diff --git a/spec/install/global_cache_spec.rb b/spec/install/global_cache_spec.rb index c48bb1bd89..3664d3963a 100644 --- a/spec/install/global_cache_spec.rb +++ b/spec/install/global_cache_spec.rb @@ -186,4 +186,50 @@ RSpec.describe "global gem caching" do end end end + + describe "extension caching", :rubygems => "2.2" do + it "works" do + build_git "very_simple_git_binary", &:add_c_extension + build_lib "very_simple_path_binary", &:add_c_extension + revision = revision_for(lib_path("very_simple_git_binary-1.0"))[0, 12] + + install_gemfile! <<-G + source "file:#{gem_repo1}" + + gem "very_simple_binary" + gem "very_simple_git_binary", :git => "#{lib_path("very_simple_git_binary-1.0")}" + gem "very_simple_path_binary", :path => "#{lib_path("very_simple_path_binary-1.0")}" + G + + gem_binary_cache = home(".bundle", "cache", "extensions", specific_local_platform.to_s, Bundler.ruby_scope, + Digest(:MD5).hexdigest("#{gem_repo1}/"), "very_simple_binary-1.0") + git_binary_cache = home(".bundle", "cache", "extensions", specific_local_platform.to_s, Bundler.ruby_scope, + "very_simple_git_binary-1.0-#{revision}", "very_simple_git_binary-1.0") + + cached_extensions = Pathname.glob(home(".bundle", "cache", "extensions", "*", "*", "*", "*", "*")).sort + expect(cached_extensions).to eq [gem_binary_cache, git_binary_cache].sort + + run! <<-R + require 'very_simple_binary_c'; puts ::VERY_SIMPLE_BINARY_IN_C + require 'very_simple_git_binary_c'; puts ::VERY_SIMPLE_GIT_BINARY_IN_C + R + expect(out).to eq "VERY_SIMPLE_BINARY_IN_C\nVERY_SIMPLE_GIT_BINARY_IN_C" + + FileUtils.rm Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")] + + gem_binary_cache.join("very_simple_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" } + git_binary_cache.join("very_simple_git_binary_c.rb").open("w") {|f| f << "puts File.basename(__FILE__)" } + + bundle! "config --local path different_path" + bundle! :install + + expect(Dir[home(".bundle", "cache", "extensions", "**", "*binary_c*")]).to all(end_with(".rb")) + + run! <<-R + require 'very_simple_binary_c' + require 'very_simple_git_binary_c' + R + expect(out).to eq "very_simple_binary_c.rb\nvery_simple_git_binary_c.rb" + end + end end diff --git a/spec/support/builders.rb b/spec/support/builders.rb index af91c5e6a7..e8208eacd9 100644 --- a/spec/support/builders.rb +++ b/spec/support/builders.rb @@ -563,17 +563,24 @@ module Spec write "ext/extconf.rb", <<-RUBY require "mkmf" + # exit 1 unless with_config("simple") - extension_name = "very_simple_binary_c" - dir_config extension_name + extension_name = "#{name}_c" + if extra_lib_dir = with_config("ext-lib") + # add extra libpath if --with-ext-lib is + # passed in as a build_arg + dir_config extension_name, nil, extra_lib_dir + else + dir_config extension_name + end create_makefile extension_name RUBY - write "ext/very_simple_binary.c", <<-C + write "ext/#{name}.c", <<-C #include "ruby.h" - void Init_very_simple_binary_c() { - rb_define_module("VerySimpleBinaryInC"); + void Init_#{name}_c() { + rb_define_module("#{Builders.constantize(name)}_IN_C"); } C end |