diff options
author | Hiroshi SHIBATA <hsbt@ruby-lang.org> | 2022-07-13 14:37:17 +0900 |
---|---|---|
committer | nagachika <nagachika@ruby-lang.org> | 2022-09-03 15:54:07 +0900 |
commit | b9f6a09bd2127ea51612bd27bef5830831b48d4f (patch) | |
tree | 2ea33c0d2c14e86b1b0ad7449d85ec068d954aea | |
parent | d7862a5de43f7412ab41cdae6709c8a30b988621 (diff) |
Merge RubyGems-3.3.15 and Bundler-2.3.15
40 files changed, 385 insertions, 100 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index 0be01d1808..c99114ae64 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -97,6 +97,17 @@ module Bundler @bundle_path ||= Pathname.new(configured_bundle_path.path).expand_path(root) end + def create_bundle_path + SharedHelpers.filesystem_access(bundle_path.to_s) do |p| + mkdir_p(p) + end unless bundle_path.exist? + + @bundle_path = bundle_path.realpath + rescue Errno::EEXIST + raise PathError, "Could not install to path `#{bundle_path}` " \ + "because a file already exists at that path. Either remove or rename the file so the directory can be created." + end + def configured_bundle_path @configured_bundle_path ||= settings.path.tap(&:validate!) end diff --git a/lib/bundler/dsl.rb b/lib/bundler/dsl.rb index 8983ef3e2b..1ae19a46e9 100644 --- a/lib/bundler/dsl.rb +++ b/lib/bundler/dsl.rb @@ -124,19 +124,17 @@ module Bundler raise GemfileError, "You cannot specify the same gem twice with different version requirements.\n" \ "You specified: #{current.name} (#{current.requirement}) and #{dep.name} (#{dep.requirement})" \ "#{update_prompt}" + elsif current.source != dep.source + return if dep.type == :development + raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ + "You specified that #{dep.name} (#{dep.requirement}) should come from " \ + "#{current.source || "an unspecified source"} and #{dep.source}\n" else Bundler.ui.warn "Your Gemfile lists the gem #{current.name} (#{current.requirement}) more than once.\n" \ "You should probably keep only one of them.\n" \ "Remove any duplicate entries and specify the gem only once.\n" \ "While it's not a problem now, it could cause errors if you change the version of one of them later." end - - if current.source != dep.source - return if dep.type == :development - raise GemfileError, "You cannot specify the same gem twice coming from different sources.\n" \ - "You specified that #{dep.name} (#{dep.requirement}) should come from " \ - "#{current.source || "an unspecified source"} and #{dep.source}\n" - end end end diff --git a/lib/bundler/errors.rb b/lib/bundler/errors.rb index 9ad7460e58..0bc1a860df 100644 --- a/lib/bundler/errors.rb +++ b/lib/bundler/errors.rb @@ -79,10 +79,6 @@ module Bundler case @permission_type when :create "executable permissions for all parent directories and write permissions for `#{parent_folder}`" - when :delete - permissions = "executable permissions for all parent directories and write permissions for `#{parent_folder}`" - permissions += ", and the same thing for all subdirectories inside #{@path}" if File.directory?(@path) - permissions else "#{@permission_type} permissions for that path" end @@ -172,4 +168,16 @@ module Bundler status_code(32) end + + class DirectoryRemovalError < BundlerError + def initialize(orig_exception, msg) + full_message = "#{msg}.\n" \ + "The underlying error was #{orig_exception.class}: #{orig_exception.message}, with backtrace:\n" \ + " #{orig_exception.backtrace.join("\n ")}\n\n" \ + "Bundler Error Backtrace:" + super(full_message) + end + + status_code(36) + end end diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb index cc615db60c..ff6cdc4123 100644 --- a/lib/bundler/friendly_errors.rb +++ b/lib/bundler/friendly_errors.rb @@ -65,8 +65,7 @@ module Bundler --- ERROR REPORT TEMPLATE ------------------------------------------------------- ``` - #{e.class}: #{e.message} - #{e.backtrace && e.backtrace.join("\n ").chomp} + #{exception_message(e)} ``` #{Bundler::Env.report} @@ -85,6 +84,21 @@ module Bundler EOS end + def exception_message(error) + message = serialized_exception_for(error) + cause = error.cause + return message unless cause + + message + serialized_exception_for(cause) + end + + def serialized_exception_for(e) + <<-EOS.gsub(/^ {8}/, "") + #{e.class}: #{e.message} + #{e.backtrace && e.backtrace.join("\n ").chomp} + EOS + end + def issues_url(exception) message = exception.message.lines.first.tr(":", " ").chomp message = message.split("-").first if exception.is_a?(Errno) diff --git a/lib/bundler/injector.rb b/lib/bundler/injector.rb index 42f837a919..f6550abe88 100644 --- a/lib/bundler/injector.rb +++ b/lib/bundler/injector.rb @@ -72,6 +72,10 @@ module Bundler deps.each {|dep| Bundler.ui.confirm "#{SharedHelpers.pretty_dependency(dep, false)} was removed." } end + + # Invalidate the cached Bundler.definition. + # This prevents e.g. `bundle remove ...` from using outdated information. + Bundler.reset_paths! end private diff --git a/lib/bundler/inline.rb b/lib/bundler/inline.rb index a718418fce..8ef580f1f0 100644 --- a/lib/bundler/inline.rb +++ b/lib/bundler/inline.rb @@ -38,12 +38,7 @@ def gemfile(install = false, options = {}, &gemfile) raise ArgumentError, "Unknown options: #{opts.keys.join(", ")}" unless opts.empty? begin - old_root = Bundler.method(:root) - bundler_module = class << Bundler; self; end - bundler_module.send(:remove_method, :root) - def Bundler.root - Bundler::SharedHelpers.pwd.expand_path - end + Bundler.instance_variable_set(:@bundle_path, Pathname.new(Gem.dir)) old_gemfile = ENV["BUNDLE_GEMFILE"] Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", "Gemfile" @@ -71,11 +66,6 @@ def gemfile(install = false, options = {}, &gemfile) runtime.setup.require end ensure - if bundler_module - bundler_module.send(:remove_method, :root) - bundler_module.send(:define_method, :root, old_root) - end - if old_gemfile ENV["BUNDLE_GEMFILE"] = old_gemfile else diff --git a/lib/bundler/installer.rb b/lib/bundler/installer.rb index 915a04c0dc..f195d36600 100644 --- a/lib/bundler/installer.rb +++ b/lib/bundler/installer.rb @@ -66,7 +66,7 @@ module Bundler # require paths and save them in a `setup.rb` file. See `bundle standalone --help` for more # information. def run(options) - create_bundle_path + Bundler.create_bundle_path ProcessLock.lock do if Bundler.frozen_bundle? @@ -262,15 +262,6 @@ module Bundler end end - def create_bundle_path - SharedHelpers.filesystem_access(Bundler.bundle_path.to_s) do |p| - Bundler.mkdir_p(p) - end unless Bundler.bundle_path.exist? - rescue Errno::EEXIST - raise PathError, "Could not install to path `#{Bundler.bundle_path}` " \ - "because a file already exists at that path. Either remove or rename the file so the directory can be created." - end - # returns whether or not a re-resolve was needed def resolve_if_needed(options) if !@definition.unlocking? && !options["force"] && !Bundler.settings[:inline] && Bundler.default_lockfile.file? diff --git a/lib/bundler/process_lock.rb b/lib/bundler/process_lock.rb index a5cc614e20..0297f80e2c 100644 --- a/lib/bundler/process_lock.rb +++ b/lib/bundler/process_lock.rb @@ -12,7 +12,7 @@ module Bundler yield f.flock(File::LOCK_UN) end - rescue Errno::EACCES, Errno::ENOLCK, Errno::ENOTSUP + rescue Errno::EACCES, Errno::ENOLCK, Errno::ENOTSUP, Errno::EPERM, Errno::EROFS # In the case the user does not have access to # create the lock file or is using NFS where # locks are not available we skip locking. diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 2285114c57..d749694952 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -19,13 +19,15 @@ module Bundler # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) base = SpecSet.new(base) unless base.is_a?(SpecSet) - resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) + metadata_requirements, regular_requirements = requirements.partition {|dep| dep.name.end_with?("\0") } + resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) result = resolver.start(requirements) - SpecSet.new(SpecSet.new(result).for(requirements.reject {|dep| dep.name.end_with?("\0") })) + SpecSet.new(SpecSet.new(result).for(regular_requirements)) end - def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) + def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms, metadata_requirements) @source_requirements = source_requirements + @metadata_requirements = metadata_requirements @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @@ -344,8 +346,6 @@ module Bundler trees.sort_by! {|t| t.reverse.map(&:name) } end - metadata_requirements = {} - o << trees.map do |tree| t = "".dup depth = 2 @@ -354,7 +354,6 @@ module Bundler base_tree_name = base_tree.name if base_tree_name.end_with?("\0") - metadata_requirements[base_tree_name] = base_tree t = nil else tree.each do |req| @@ -393,10 +392,10 @@ module Bundler end end elsif name.end_with?("\0") - o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(metadata_requirements[name])}\n\n) + o << %(\n Current #{name} version:\n #{SharedHelpers.pretty_dependency(@metadata_requirements.find {|req| req.name == name })}\n\n) elsif conflict.locked_requirement o << "\n" - o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n) + o << %(Deleting your #{name_for_locking_dependency_source} file and running `bundle install` will rebuild your snapshot from scratch, using only\n) o << %(the gems in your Gemfile, which may resolve the conflict.\n) elsif !conflict.existing o << "\n" diff --git a/lib/bundler/rubygems_gem_installer.rb b/lib/bundler/rubygems_gem_installer.rb index 452583617b..87b9772c27 100644 --- a/lib/bundler/rubygems_gem_installer.rb +++ b/lib/bundler/rubygems_gem_installer.rb @@ -93,14 +93,9 @@ module Bundler private def strict_rm_rf(dir) - # FileUtils.rm_rf should probably rise in case of permission issues like - # `rm -rf` does. However, it fails to delete the folder silently due to - # https://github.com/ruby/fileutils/issues/57. It should probably be fixed - # inside `fileutils` but for now I`m checking whether the folder was - # removed after it completes, and raising otherwise. - FileUtils.rm_rf dir - - raise PermissionError.new(dir, :delete) if File.directory?(dir) + Bundler.rm_rf dir + rescue Errno::ENOTEMPTY => e + raise DirectoryRemovalError.new(e.cause, "Could not delete previous installation of `#{dir}`") end def validate_bundler_checksum(checksum) diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 8f263cd012..398c66055a 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -487,7 +487,7 @@ module Bundler /ix.freeze def self.key_for(key) - key = normalize_uri(key).to_s if key.is_a?(String) && /https?:/ =~ key + key = normalize_uri(key).to_s if key.is_a?(String) && key.start_with?("http", "mirror.http") key = key.to_s.gsub(".", "__").gsub("-", "___").upcase "BUNDLE_#{key}" end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index b37bfbccb9..5dceacbae4 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -499,7 +499,7 @@ module Bundler end def rubygems_dir - Bundler.rubygems.gem_dir + Bundler.bundle_path end def default_cache_path_for(dir) diff --git a/lib/bundler/stub_specification.rb b/lib/bundler/stub_specification.rb index fa071901e5..88a4257fa4 100644 --- a/lib/bundler/stub_specification.rb +++ b/lib/bundler/stub_specification.rb @@ -64,9 +64,11 @@ module Bundler end def full_gem_path - # deleted gems can have their stubs return nil, so in that case grab the - # expired path from the full spec - stub.full_gem_path || method_missing(:full_gem_path) + stub.full_gem_path + end + + def full_gem_path=(path) + stub.full_gem_path = path end def full_require_paths diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 492cd1d751..9e8fa48a1d 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.3.14".freeze + VERSION = "2.3.15".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 0b83b1f0ed..8c2c465ad4 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.3.14".freeze + VERSION = "3.3.15".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/command_manager.rb b/lib/rubygems/command_manager.rb index 03cdd6a4bb..e421f89884 100644 --- a/lib/rubygems/command_manager.rb +++ b/lib/rubygems/command_manager.rb @@ -148,7 +148,12 @@ class Gem::CommandManager def run(args, build_args=nil) process_args(args, build_args) rescue StandardError, Timeout::Error => ex - alert_error clean_text("While executing gem ... (#{ex.class})\n #{ex}") + if ex.respond_to?(:detailed_message) + msg = ex.detailed_message(highlight: false).sub(/\A(.*?)(?: \(.+?\))/) { $1 } + else + msg = ex.message + end + alert_error clean_text("While executing gem ... (#{ex.class})\n #{msg}") ui.backtrace ex terminate_interaction(1) diff --git a/lib/rubygems/commands/update_command.rb b/lib/rubygems/commands/update_command.rb index 42d6f6046b..54b1251010 100644 --- a/lib/rubygems/commands/update_command.rb +++ b/lib/rubygems/commands/update_command.rb @@ -173,10 +173,11 @@ command to remove old versions. highest_remote_gem.first end - def install_rubygems(version) # :nodoc: + def install_rubygems(spec) # :nodoc: args = update_rubygems_arguments + version = spec.version - update_dir = File.join Gem.dir, 'gems', "rubygems-update-#{version}" + update_dir = File.join spec.base_dir, 'gems', "rubygems-update-#{version}" Dir.chdir update_dir do say "Installing RubyGems #{version}" unless options[:silent] @@ -290,9 +291,7 @@ command to remove old versions. installed_gems = update_gem('rubygems-update', version) if installed_gems.empty? || installed_gems.first.version != version return if installed_gems.empty? - version = installed_gems.first.version - - install_rubygems version + install_rubygems installed_gems.first end def update_rubygems_arguments # :nodoc: diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 9b533caf54..33eb0a2bff 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -1270,7 +1270,14 @@ class Gem::Specification < Gem::BasicSpecification def self._load(str) Gem.load_yaml - array = Marshal.load str + array = begin + Marshal.load str + rescue ArgumentError => e + raise unless e.message.include?("YAML") + + Object.const_set "YAML", Psych + Marshal.load str + end spec = Gem::Specification.new spec.instance_variable_set :@specification_version, array[1] @@ -1289,11 +1296,6 @@ class Gem::Specification < Gem::BasicSpecification raise TypeError, "invalid Gem::Specification format #{array.inspect}" end - # Cleanup any Psych::PrivateType. They only show up for an old bug - # where nil => null, so just convert them to nil based on the type. - - array.map! {|e| e.kind_of?(Psych::PrivateType) ? nil : e } - spec.instance_variable_set :@rubygems_version, array[0] # spec version spec.instance_variable_set :@name, array[2] diff --git a/spec/bundler/commands/clean_spec.rb b/spec/bundler/commands/clean_spec.rb index 576872b0f6..db81c10e9d 100644 --- a/spec/bundler/commands/clean_spec.rb +++ b/spec/bundler/commands/clean_spec.rb @@ -208,7 +208,7 @@ RSpec.describe "bundle clean" do G FileUtils.mkdir_p(bundled_app("real-path")) - FileUtils.ln_sf(bundled_app("real-path"), bundled_app("symlink-path")) + File.symlink(bundled_app("real-path"), bundled_app("symlink-path")) bundle "config set path #{bundled_app("symlink-path")}" bundle "install" diff --git a/spec/bundler/commands/config_spec.rb b/spec/bundler/commands/config_spec.rb index fb7aa3cc67..6148b1c7ce 100644 --- a/spec/bundler/commands/config_spec.rb +++ b/spec/bundler/commands/config_spec.rb @@ -435,6 +435,34 @@ E end end + describe "commented out settings with urls" do + before do + bundle "config set #mirror.https://rails-assets.org http://localhost:9292" + end + + it "does not make bundler crash and ignores the configuration" do + bundle "config list --parseable" + + expect(out).to eq("#mirror.https://rails-assets.org/=http://localhost:9292") + expect(err).to be_empty + + ruby(<<~RUBY) + require "#{entrypoint}" + print Bundler.settings.mirror_for("https://rails-assets.org") + RUBY + expect(out).to eq("https://rails-assets.org/") + expect(err).to be_empty + + bundle "config set mirror.all http://localhost:9293" + ruby(<<~RUBY) + require "#{entrypoint}" + print Bundler.settings.mirror_for("https://rails-assets.org") + RUBY + expect(out).to eq("http://localhost:9293/") + expect(err).to be_empty + end + end + describe "subcommands" do it "list" do bundle "config list", :env => { "BUNDLE_FOO" => "bar" } diff --git a/spec/bundler/commands/install_spec.rb b/spec/bundler/commands/install_spec.rb index f189a70b10..4a48187db0 100644 --- a/spec/bundler/commands/install_spec.rb +++ b/spec/bundler/commands/install_spec.rb @@ -755,12 +755,8 @@ RSpec.describe "bundle install with gem sources" do end expect(err).not_to include("ERROR REPORT TEMPLATE") - - expect(err).to include( - "There was an error while trying to delete `#{foo_path}`. " \ - "It is likely that you need to grant executable permissions for all parent directories " \ - "and write permissions for `#{gems_path}`, and the same thing for all subdirectories inside #{foo_path}." - ) + expect(err).to include("Could not delete previous installation of `#{foo_path}`.") + expect(err).to include("The underlying error was Errno::EACCES") end end @@ -973,4 +969,37 @@ RSpec.describe "bundle install with gem sources" do expect(last_command).to be_success end end + + context "with a symlinked configured as bundle path and a gem with symlinks" do + before do + symlinked_bundled_app = tmp("bundled_app-symlink") + File.symlink(bundled_app, symlinked_bundled_app) + bundle "config path #{File.join(symlinked_bundled_app, ".vendor")}" + + binman_path = tmp("binman") + FileUtils.mkdir_p binman_path + + readme_path = File.join(binman_path, "README.markdown") + FileUtils.touch(readme_path) + + man_path = File.join(binman_path, "man", "man0") + FileUtils.mkdir_p man_path + + File.symlink("../../README.markdown", File.join(man_path, "README.markdown")) + + build_repo4 do + build_gem "binman", :path => gem_repo4("gems"), :lib_path => binman_path, :no_default => true do |s| + s.files = ["README.markdown", "man/man0/README.markdown"] + end + end + end + + it "installs fine" do + install_gemfile <<~G + source "#{file_uri_for(gem_repo4)}" + + gem "binman" + G + end + end end diff --git a/spec/bundler/commands/remove_spec.rb b/spec/bundler/commands/remove_spec.rb index 95d6e75e9f..ceba6c5ede 100644 --- a/spec/bundler/commands/remove_spec.rb +++ b/spec/bundler/commands/remove_spec.rb @@ -13,6 +13,36 @@ RSpec.describe "bundle remove" do end end + context "after 'bundle install' is run" do + describe "running 'bundle remove GEM_NAME'" do + it "removes it from the lockfile" do + rack_dep = <<~L + + DEPENDENCIES + rack + + L + + gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + + gem "rack" + G + + bundle "install" + + expect(lockfile).to include(rack_dep) + + bundle "remove rack" + + expect(gemfile).to eq <<~G + source "#{file_uri_for(gem_repo1)}" + G + expect(lockfile).to_not include(rack_dep) + end + end + end + context "when --install flag is specified", :bundler => "< 3" do it "removes gems from .bundle" do gemfile <<-G diff --git a/spec/bundler/install/gemfile/sources_spec.rb b/spec/bundler/install/gemfile/sources_spec.rb index 62cad6800f..89c812e5d5 100644 --- a/spec/bundler/install/gemfile/sources_spec.rb +++ b/spec/bundler/install/gemfile/sources_spec.rb @@ -1255,6 +1255,32 @@ RSpec.describe "bundle install with gems on multiple sources" do end end + context "when Gemfile overrides a gemspec development dependency to change the default source" do + before do + build_repo4 do + build_gem "bar" + end + + build_lib("gemspec_test", :path => tmp.join("gemspec_test")) do |s| + s.add_development_dependency "bar" + end + + install_gemfile <<-G, :artifice => "compact_index" + source "https://gem.repo1" + + source "https://gem.repo4" do + gem "bar" + end + + gemspec :path => "#{tmp.join("gemspec_test")}" + G + end + + it "does not print warnings" do + expect(err).to be_empty + end + end + it "doesn't update version when a gem uses a source block but a higher version from another source is already installed locally" do build_repo2 do build_gem "example", "0.1.0" diff --git a/spec/bundler/install/gems/flex_spec.rb b/spec/bundler/install/gems/flex_spec.rb index f9b374cf01..28ffaff3d5 100644 --- a/spec/bundler/install/gems/flex_spec.rb +++ b/spec/bundler/install/gems/flex_spec.rb @@ -156,7 +156,7 @@ RSpec.describe "bundle flex_install" do end end - describe "when Gemfile conflicts with lockfile" do + describe "when running bundle install and Gemfile conflicts with lockfile" do before(:each) do build_repo2 install_gemfile <<-G @@ -190,7 +190,7 @@ RSpec.describe "bundle flex_install" do expect(err).to match(/could not find gem 'rack-obama/i) end - it "suggests bundle update when the Gemfile requires different versions than the lock" do + it "suggests deleting the Gemfile.lock file when the Gemfile requires different versions than the lock" do bundle "config set force_ruby_platform true" nice_error = <<-E.strip.gsub(/^ {8}/, "") @@ -205,7 +205,7 @@ RSpec.describe "bundle flex_install" do rack_middleware was resolved to 1.0, which depends on rack (= 0.9.1) - Running `bundle update` will rebuild your snapshot from scratch, using only + Deleting your Gemfile.lock file and running `bundle install` will rebuild your snapshot from scratch, using only the gems in your Gemfile, which may resolve the conflict. E @@ -214,6 +214,67 @@ RSpec.describe "bundle flex_install" do end end + describe "when running bundle update and Gemfile conflicts with lockfile" do + before(:each) do + build_repo4 do + build_gem "jekyll-feed", "0.16.0" + build_gem "jekyll-feed", "0.15.1" + + build_gem "github-pages", "226" do |s| + s.add_dependency "jekyll-feed", "0.15.1" + end + end + + install_gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "jekyll-feed", "~> 0.12" + G + + puts lockfile + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo4)}/ + specs: + jekyll-feed (0.16.0) + + PLATFORMS + #{lockfile_platforms} + + DEPENDENCIES + jekyll-feed + + BUNDLED WITH + #{Bundler::VERSION} + L + + gemfile <<-G + source "#{file_uri_for(gem_repo4)}" + gem "github-pages", "~> 226" + gem "jekyll-feed", "~> 0.12" + G + end + + it "suggests deleting the Gemfile.lock file when the Gemfile requires different versions than the lock" do + nice_error = <<-E.strip.gsub(/^ {8}/, "") + Bundler could not find compatible versions for gem "jekyll-feed": + In snapshot (Gemfile.lock): + jekyll-feed (>= 0.16.0) + + In Gemfile: + jekyll-feed (~> 0.12) + + github-pages (~> 226) was resolved to 226, which depends on + jekyll-feed (= 0.15.1) + + Deleting your Gemfile.lock file and running `bundle install` will rebuild your snapshot from scratch, using only + the gems in your Gemfile, which may resolve the conflict. + E + + bundle :update, :raise_on_error => false + expect(err).to end_with(nice_error) + end + end + describe "subtler cases" do before :each do install_gemfile <<-G diff --git a/spec/bundler/install/gems/resolving_spec.rb b/spec/bundler/install/gems/resolving_spec.rb index 469ecd412f..f23d137bc1 100644 --- a/spec/bundler/install/gems/resolving_spec.rb +++ b/spec/bundler/install/gems/resolving_spec.rb @@ -282,6 +282,27 @@ RSpec.describe "bundle install with install-time dependencies" do expect(err).not_to include("That means the author of parallel_tests (3.8.0) has removed it.") end + it "gives a meaningful error on ruby version mismatches between dependencies" do + build_repo4 do + build_gem "requires-old-ruby" do |s| + s.required_ruby_version = "< #{RUBY_VERSION}" + end + end + + build_lib("foo", :path => bundled_app) do |s| + s.required_ruby_version = ">= #{RUBY_VERSION}" + + s.add_dependency "requires-old-ruby" + end + + install_gemfile <<-G, :raise_on_error => false + source "#{file_uri_for(gem_repo4)}" + gemspec + G + + expect(err).to include("Bundler found conflicting requirements for the Ruby\0 version:") + end + it "installs the older version under rate limiting conditions" do build_repo4 do build_gem "rack", "9001.0.0" do |s| diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb index 5cbb484c68..0bbd829148 100644 --- a/spec/bundler/install/gems/standalone_spec.rb +++ b/spec/bundler/install/gems/standalone_spec.rb @@ -147,9 +147,16 @@ RSpec.shared_examples "bundle install --standalone" do bundle "lock", :dir => cwd, :artifice => "compact_index" end - it "works" do + it "works and points to the vendored copies, not to the default copies" do bundle "config set --local path #{bundled_app("bundle")}" bundle :install, :standalone => true, :dir => cwd, :artifice => "compact_index", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } + + load_path_lines = bundled_app("bundle/bundler/setup.rb").read.split("\n").select {|line| line.start_with?("$:.unshift") } + + expect(load_path_lines).to eq [ + '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{RbConfig::CONFIG["ruby_version"]}/gems/bar-1.0.0/lib")', + '$:.unshift File.expand_path("#{__dir__}/../#{RUBY_ENGINE}/#{RbConfig::CONFIG["ruby_version"]}/gems/foo-1.0.0/lib")', + ] end end diff --git a/spec/bundler/install/process_lock_spec.rb b/spec/bundler/install/process_lock_spec.rb index dac0d34bc4..1f8c62f26e 100644 --- a/spec/bundler/install/process_lock_spec.rb +++ b/spec/bundler/install/process_lock_spec.rb @@ -31,5 +31,27 @@ RSpec.describe "process lock spec" do expect(processed).to eq true end end + + context "when creating a lock raises Errno::EPERM" do + before { allow(File).to receive(:open).and_raise(Errno::EPERM) } + + it "skips creating the lock file and yields" do + processed = false + Bundler::ProcessLock.lock(default_bundle_path) { processed = true } + + expect(processed).to eq true + end + end + + context "when creating a lock raises Errno::EROFS" do + before { allow(File).to receive(:open).and_raise(Errno::EROFS) } + + it "skips creating the lock file and yields" do + processed = false + Bundler::ProcessLock.lock(default_bundle_path) { processed = true } + + expect(processed).to eq true + end + end end end diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index 35873dcaa9..91f8aaf78a 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "tmpdir" -require "tempfile" RSpec.describe "Bundler.setup" do describe "with no arguments" do @@ -800,7 +799,7 @@ end run <<~RUBY puts ENV['MANPATH'] require "open3" - puts Open3.capture2e("man", "ls")[0] + puts Open3.capture2e({ "LC_ALL" => "C" }, "man", "ls")[0] RUBY lines = out.split("\n") @@ -861,19 +860,17 @@ end context "with bundler is located in symlinked GEM_HOME" do let(:gem_home) { Dir.mktmpdir } - let(:symlinked_gem_home) { Tempfile.new("gem_home").path } + let(:symlinked_gem_home) { tmp("gem_home-symlink").to_s } let(:full_name) { "bundler-#{Bundler::VERSION}" } before do - skip "symlink destination exists" if Gem.win_platform? - - FileUtils.ln_sf(gem_home, symlinked_gem_home) + File.symlink(gem_home, symlinked_gem_home) gems_dir = File.join(gem_home, "gems") specifications_dir = File.join(gem_home, "specifications") Dir.mkdir(gems_dir) Dir.mkdir(specifications_dir) - FileUtils.ln_s(source_root, File.join(gems_dir, full_name)) + File.symlink(source_root, File.join(gems_dir, full_name)) gemspec_content = File.binread(gemspec). sub("Bundler::VERSION", %("#{Bundler::VERSION}")). diff --git a/spec/bundler/spec_helper.rb b/spec/bundler/spec_helper.rb index dce2939e83..23db133b67 100644 --- a/spec/bundler/spec_helper.rb +++ b/spec/bundler/spec_helper.rb @@ -113,6 +113,10 @@ RSpec.configure do |config| end end + config.before :each, :sudo => true do + Spec::Sudo.write_safe_config + end + config.after :suite do FileUtils.rm_r Spec::Path.pristine_system_gem_path end diff --git a/spec/bundler/support/builders.rb b/spec/bundler/support/builders.rb index aca31638ac..91f0106d7d 100644 --- a/spec/bundler/support/builders.rb +++ b/spec/bundler/support/builders.rb @@ -484,7 +484,7 @@ module Spec end @spec.authors = ["no one"] - @spec.files = @files.keys + @spec.files += @files.keys case options[:gemspec] when false @@ -589,7 +589,8 @@ module Spec class GemBuilder < LibBuilder def _build(opts) - lib_path = super(opts.merge(:path => @context.tmp(".tmp/#{@spec.full_name}"), :no_default => opts[:no_default])) + lib_path = opts[:lib_path] || @context.tmp(".tmp/#{@spec.full_name}") + lib_path = super(opts.merge(:path => lib_path, :no_default => opts[:no_default])) destination = opts[:path] || _default_path FileUtils.mkdir_p(lib_path.join(destination)) diff --git a/spec/bundler/support/path.rb b/spec/bundler/support/path.rb index 41b36997b2..a39e46c78a 100644 --- a/spec/bundler/support/path.rb +++ b/spec/bundler/support/path.rb @@ -258,6 +258,10 @@ module Spec end end + def git_root + ruby_core? ? source_root : source_root.parent + end + private def git_ls_files(glob) @@ -278,10 +282,6 @@ module Spec ruby_core? ? "man/bundle* man/gemfile*" : "lib/bundler/man/bundle*.1 lib/bundler/man/gemfile*.5" end - def git_root - ruby_core? ? source_root : source_root.parent - end - def ruby_core_tarball? !git_root.join(".git").directory? end diff --git a/spec/bundler/support/sudo.rb b/spec/bundler/support/sudo.rb index 04e9443945..7b9b392754 100644 --- a/spec/bundler/support/sudo.rb +++ b/spec/bundler/support/sudo.rb @@ -6,6 +6,10 @@ module Spec @which_sudo ||= Bundler.which("sudo") end + def self.write_safe_config + File.write(Spec::Path.tmp("gitconfig"), "[safe]\n\tdirectory = #{Spec::Path.git_root}") + end + def sudo(cmd) raise "sudo not present" unless Sudo.present? sys_exec("sudo #{cmd}") diff --git a/test/rubygems/data/null-type.gemspec.rz b/test/rubygems/data/null-type.gemspec.rz Binary files differindex 2134fcde29..58fc1ed8a0 100644 --- a/test/rubygems/data/null-type.gemspec.rz +++ b/test/rubygems/data/null-type.gemspec.rz diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb index bee635d67e..00197d10f7 100644 --- a/test/rubygems/test_gem_command_manager.rb +++ b/test/rubygems/test_gem_command_manager.rb @@ -80,7 +80,13 @@ class TestGemCommandManager < Gem::TestCase message << "\nDid you mean? \"push\"" end - assert_equal message, e.message + if e.respond_to?(:detailed_message) + actual_message = e.detailed_message(highlight: false).sub(/\A(.*?)(?: \(.+?\))/) { $1 } + else + actual_message = e.message + end + + assert_equal message, actual_message end def test_run_interrupt diff --git a/test/rubygems/test_gem_commands_update_command.rb b/test/rubygems/test_gem_commands_update_command.rb index c765e9a8df..b5e9f004d1 100644 --- a/test/rubygems/test_gem_commands_update_command.rb +++ b/test/rubygems/test_gem_commands_update_command.rb @@ -191,6 +191,37 @@ class TestGemCommandsUpdateCommand < Gem::TestCase assert_empty out end + def test_execute_system_update_installed_in_non_default_gem_path + rubygems_update_spec = quick_gem "rubygems-update", 9 do |s| + write_file File.join(@tempdir, 'setup.rb') + + s.files += %w[setup.rb] + end + + util_setup_spec_fetcher rubygems_update_spec + + rubygems_update_package = Gem::Package.build rubygems_update_spec + + gemhome2 = "#{@gemhome}2" + + Gem::Installer.at(rubygems_update_package, :install_dir => gemhome2).install + + Gem.use_paths @gemhome, [gemhome2, @gemhome] + + @cmd.options[:args] = [] + @cmd.options[:system] = true + + use_ui @ui do + @cmd.execute + end + + out = @ui.output.split "\n" + assert_equal "Installing RubyGems 9", out.shift + assert_equal "RubyGems system software updated", out.shift + + assert_empty out + end + def test_execute_system_specific spec_fetcher do |fetcher| fetcher.download 'rubygems-update', 8 do |s| diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 8b0477c4dd..ccb81caf37 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1072,7 +1072,7 @@ dependencies: [] data = Marshal.load Gem::Util.inflate(Gem.read_binary(path)) - assert_nil data.signing_key + assert_instance_of Gem::Specification, data end def test_initialize diff --git a/tool/bundler/dev_gems.rb.lock b/tool/bundler/dev_gems.rb.lock index c467b988f6..fc48d3e05f 100644 --- a/tool/bundler/dev_gems.rb.lock +++ b/tool/bundler/dev_gems.rb.lock @@ -72,4 +72,4 @@ DEPENDENCIES webrick (~> 1.6) BUNDLED WITH - 2.3.14 + 2.3.15 diff --git a/tool/bundler/rubocop_gems.rb.lock b/tool/bundler/rubocop_gems.rb.lock index 0e2e34793f..4027570ebb 100644 --- a/tool/bundler/rubocop_gems.rb.lock +++ b/tool/bundler/rubocop_gems.rb.lock @@ -60,4 +60,4 @@ DEPENDENCIES test-unit BUNDLED WITH - 2.3.14 + 2.3.15 diff --git a/tool/bundler/standard_gems.rb.lock b/tool/bundler/standard_gems.rb.lock index fa8daf69de..b939fa05d6 100644 --- a/tool/bundler/standard_gems.rb.lock +++ b/tool/bundler/standard_gems.rb.lock @@ -66,4 +66,4 @@ DEPENDENCIES test-unit BUNDLED WITH - 2.3.14 + 2.3.15 diff --git a/tool/bundler/test_gems.rb.lock b/tool/bundler/test_gems.rb.lock index 05f88ccd98..dab017efc8 100644 --- a/tool/bundler/test_gems.rb.lock +++ b/tool/bundler/test_gems.rb.lock @@ -41,4 +41,4 @@ DEPENDENCIES webrick (= 1.7.0) BUNDLED WITH - 2.3.14 + 2.3.15 |