From 1ccf2859af0643aa7f7992976a43016cd28b7858 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Rodr=C3=ADguez?= Date: Wed, 26 Aug 2020 14:10:37 +0200 Subject: [PATCH] Make `bundle clean --force` leave default gem executables untouched --- bundler/lib/bundler/rubygems_integration.rb | 17 +++++++++++----- bundler/lib/bundler/runtime.rb | 2 +- bundler/spec/commands/clean_spec.rb | 22 +++++++++++++++++++++ bundler/spec/support/builders.rb | 2 +- bundler/spec/support/hax.rb | 2 ++ bundler/spec/support/helpers.rb | 14 ++++++++----- 6 files changed, 47 insertions(+), 12 deletions(-) diff --git a/bundler/lib/bundler/rubygems_integration.rb b/bundler/lib/bundler/rubygems_integration.rb index a728e1e27daa..17402f16f203 100644 --- a/bundler/lib/bundler/rubygems_integration.rb +++ b/bundler/lib/bundler/rubygems_integration.rb @@ -411,6 +411,17 @@ def replace_bin_path(specs_by_name) # Replace or hook into RubyGems to provide a bundlerized view # of the world. def replace_entrypoints(specs) + specs_by_name = add_default_gems_to(specs) + + replace_gem(specs, specs_by_name) + stub_rubygems(specs) + replace_bin_path(specs_by_name) + + Gem.clear_paths + end + + # Add default gems not already present in specs, and return them as a hash. + def add_default_gems_to(specs) specs_by_name = specs.reduce({}) do |h, s| h[s.name] = s h @@ -425,11 +436,7 @@ def replace_entrypoints(specs) specs_by_name[default_spec_name] = default_spec end - replace_gem(specs, specs_by_name) - stub_rubygems(specs) - replace_bin_path(specs_by_name) - - Gem.clear_paths + specs_by_name end def undo_replacements diff --git a/bundler/lib/bundler/runtime.rb b/bundler/lib/bundler/runtime.rb index 52fabfa60a84..e259b590bfc7 100644 --- a/bundler/lib/bundler/runtime.rb +++ b/bundler/lib/bundler/runtime.rb @@ -155,7 +155,7 @@ def clean(dry_run = false) spec_cache_paths = [] spec_gemspec_paths = [] spec_extension_paths = [] - specs.each do |spec| + Bundler.rubygems.add_default_gems_to(specs).values.each do |spec| spec_gem_paths << spec.full_gem_path # need to check here in case gems are nested like for the rails git repo md = %r{(.+bundler/gems/.+-[a-f0-9]{7,12})}.match(spec.full_gem_path) diff --git a/bundler/spec/commands/clean_spec.rb b/bundler/spec/commands/clean_spec.rb index 0ecdf230f9f8..61cfcf11965a 100644 --- a/bundler/spec/commands/clean_spec.rb +++ b/bundler/spec/commands/clean_spec.rb @@ -625,6 +625,28 @@ def should_not_have_gems(*gems) expect(out).to eq("1.0") end + it "when using --force, it doesn't remove default gem binaries", :rubygems => ">= 3.2.0.rc.1" do + skip "does not work on Windows because it changes the path to look for default gems, and Windows uses the default fiddle gem" if Gem.win_platform? + + default_irb_version = ruby "gem 'irb', '< 999999'; require 'irb'; puts IRB::VERSION", :raise_on_error => false + skip "irb isn't a default gem" if default_irb_version.empty? + + build_repo2 do + # simulate executable for default gem + build_gem "irb", default_irb_version, :to_system => true, :default => true do |s| + s.executables = "irb" + end + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo2)}" + G + + bundle "clean --force", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + + expect(out).not_to include("Removing irb") + end + it "doesn't blow up on path gems without a .gemspec" do relative_path = "vendor/private_gems/bar-1.0" absolute_path = bundled_app(relative_path) diff --git a/bundler/spec/support/builders.rb b/bundler/spec/support/builders.rb index 24dc552b11bc..e8481f98a377 100644 --- a/bundler/spec/support/builders.rb +++ b/bundler/spec/support/builders.rb @@ -758,7 +758,7 @@ def _build(opts) gem_path = File.expand_path("#{@spec.full_name}.gem", lib_path) if opts[:to_system] - @context.system_gems gem_path + @context.system_gems gem_path, :default => opts[:default] elsif opts[:to_bundle] @context.system_gems gem_path, :path => @context.default_bundle_path else diff --git a/bundler/spec/support/hax.rb b/bundler/spec/support/hax.rb index 7529dc460a8a..fc8e0ad55dce 100644 --- a/bundler/spec/support/hax.rb +++ b/bundler/spec/support/hax.rb @@ -9,6 +9,8 @@ def self.ruby=(ruby) Gem.ruby = ENV["RUBY"] end + @default_dir = ENV["BUNDLER_GEM_DEFAULT_DIR"] if ENV["BUNDLER_GEM_DEFAULT_DIR"] + if ENV["BUNDLER_SPEC_PLATFORM"] class Platform @local = new(ENV["BUNDLER_SPEC_PLATFORM"]) diff --git a/bundler/spec/support/helpers.rb b/bundler/spec/support/helpers.rb index 03bec8ecba30..c4018eb818cf 100644 --- a/bundler/spec/support/helpers.rb +++ b/bundler/spec/support/helpers.rb @@ -290,26 +290,30 @@ def system_gems(*gems) gems = gems.flatten options = gems.last.is_a?(Hash) ? gems.pop : {} path = options.fetch(:path, system_gem_path) + default = options.fetch(:default, false) with_gem_path_as(path) do gem_repo = options.fetch(:gem_repo, gem_repo1) gems.each do |g| gem_name = g.to_s if gem_name.start_with?("bundler") version = gem_name.match(/\Abundler-(?.*)\z/)[:version] if gem_name != "bundler" - with_built_bundler(version) {|gem_path| install_gem(gem_path) } + with_built_bundler(version) {|gem_path| install_gem(gem_path, default) } elsif gem_name =~ %r{\A(?:[a-zA-Z]:)?/.*\.gem\z} - install_gem(gem_name) + install_gem(gem_name, default) else - install_gem("#{gem_repo}/gems/#{gem_name}.gem") + install_gem("#{gem_repo}/gems/#{gem_name}.gem", default) end end end end - def install_gem(path) + def install_gem(path, default = false) raise "OMG `#{path}` does not exist!" unless File.exist?(path) - gem_command "install --no-document --ignore-dependencies '#{path}'" + args = "--no-document --ignore-dependencies" + args += " --default --install-dir #{system_gem_path}" if default + + gem_command "install #{args} '#{path}'" end def with_built_bundler(version = nil)