From d4b4281959d2a9846d766253b5e21e8158948aa7 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 14 Jun 2021 12:55:03 +0900 Subject: Merge RubyGems-3.2.18 and Bundler-2.2.18 --- lib/bundler.rb | 1 + lib/bundler/bundler.gemspec | 5 +- lib/bundler/cli.rb | 46 +++------- lib/bundler/cli/outdated.rb | 17 ++-- lib/bundler/definition.rb | 89 +++--------------- lib/bundler/feature_flag.rb | 1 - lib/bundler/friendly_errors.rb | 2 +- lib/bundler/index.rb | 3 +- lib/bundler/man/bundle-add.1 | 2 +- lib/bundler/man/bundle-binstubs.1 | 2 +- lib/bundler/man/bundle-cache.1 | 2 +- lib/bundler/man/bundle-check.1 | 2 +- lib/bundler/man/bundle-clean.1 | 2 +- lib/bundler/man/bundle-config.1 | 8 +- lib/bundler/man/bundle-config.1.ronn | 8 -- lib/bundler/man/bundle-doctor.1 | 2 +- lib/bundler/man/bundle-exec.1 | 2 +- lib/bundler/man/bundle-gem.1 | 2 +- lib/bundler/man/bundle-info.1 | 2 +- lib/bundler/man/bundle-init.1 | 2 +- lib/bundler/man/bundle-inject.1 | 2 +- lib/bundler/man/bundle-install.1 | 2 +- lib/bundler/man/bundle-list.1 | 2 +- lib/bundler/man/bundle-lock.1 | 2 +- lib/bundler/man/bundle-open.1 | 2 +- lib/bundler/man/bundle-outdated.1 | 2 +- lib/bundler/man/bundle-platform.1 | 2 +- lib/bundler/man/bundle-pristine.1 | 2 +- lib/bundler/man/bundle-remove.1 | 2 +- lib/bundler/man/bundle-show.1 | 2 +- lib/bundler/man/bundle-update.1 | 2 +- lib/bundler/man/bundle-viz.1 | 2 +- lib/bundler/man/bundle.1 | 2 +- lib/bundler/man/gemfile.5 | 2 +- lib/bundler/plugin/api/source.rb | 14 +++ lib/bundler/resolver.rb | 109 +++------------------- lib/bundler/resolver/spec_group.rb | 24 ----- lib/bundler/rubygems_ext.rb | 4 +- lib/bundler/settings.rb | 1 - lib/bundler/source.rb | 9 ++ lib/bundler/source/rubygems.rb | 19 +++- lib/bundler/source/rubygems_aggregate.rb | 64 +++++++++++++ lib/bundler/source_list.rb | 39 +++++--- lib/bundler/source_map.rb | 58 ++++++++++++ lib/bundler/templates/newgem/newgem.gemspec.tt | 2 +- lib/bundler/version.rb | 2 +- lib/rubygems.rb | 2 +- lib/rubygems/ext/ext_conf_builder.rb | 8 +- lib/rubygems/specification.rb | 2 - lib/rubygems/test_case.rb | 120 +++++++++++++++++++++---- 50 files changed, 377 insertions(+), 328 deletions(-) create mode 100644 lib/bundler/source/rubygems_aggregate.rb create mode 100644 lib/bundler/source_map.rb (limited to 'lib') diff --git a/lib/bundler.rb b/lib/bundler.rb index d370d8a53a..b2363a25f4 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -69,6 +69,7 @@ module Bundler autoload :SharedHelpers, File.expand_path("bundler/shared_helpers", __dir__) autoload :Source, File.expand_path("bundler/source", __dir__) autoload :SourceList, File.expand_path("bundler/source_list", __dir__) + autoload :SourceMap, File.expand_path("bundler/source_map", __dir__) autoload :SpecSet, File.expand_path("bundler/spec_set", __dir__) autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__) autoload :UI, File.expand_path("bundler/ui", __dir__) diff --git a/lib/bundler/bundler.gemspec b/lib/bundler/bundler.gemspec index f6cb02cea2..1a2ced54d3 100644 --- a/lib/bundler/bundler.gemspec +++ b/lib/bundler/bundler.gemspec @@ -34,13 +34,12 @@ Gem::Specification.new do |s| s.required_ruby_version = ">= 2.3.0" s.required_rubygems_version = ">= 2.5.2" - s.files = Dir.glob("{lib,exe}/**/*", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } + s.files = Dir.glob("lib/bundler{.rb,/**/*}", File::FNM_DOTMATCH).reject {|f| File.directory?(f) } - # Include the CHANGELOG.md, LICENSE.md, README.md manually - s.files += %w[CHANGELOG.md LICENSE.md README.md] # include the gemspec itself because warbler breaks w/o it s.files += %w[bundler.gemspec] + s.extra_rdoc_files = %w[CHANGELOG.md LICENSE.md README.md] s.bindir = "exe" s.executables = %w[bundle bundler] s.require_paths = ["lib"] diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index d6e69afddf..45d4e62481 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -308,39 +308,19 @@ module Bundler end end - unless Bundler.feature_flag.bundler_3_mode? - desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" - long_desc <<-D - Show lists the names and versions of all gems that are required by your Gemfile. - Calling show with [GEM] will list the exact location of that gem on your machine. - D - method_option "paths", :type => :boolean, - :banner => "List the paths of all gems that are required by your Gemfile." - method_option "outdated", :type => :boolean, - :banner => "Show verbose output including whether gems are outdated." - def show(gem_name = nil) - if ARGV[0] == "show" - rest = ARGV[1..-1] - - if flag = rest.find{|arg| ["--verbose", "--outdated"].include?(arg) } - Bundler::SharedHelpers.major_deprecation(2, "the `#{flag}` flag to `bundle show` was undocumented and will be removed without replacement") - else - new_command = rest.find {|arg| !arg.start_with?("--") } ? "info" : "list" - - new_arguments = rest.map do |arg| - next arg if arg != "--paths" - next "--path" if new_command == "info" - end - - old_argv = ARGV.join(" ") - new_argv = [new_command, *new_arguments.compact].join(" ") - - Bundler::SharedHelpers.major_deprecation(2, "use `bundle #{new_argv}` instead of `bundle #{old_argv}`") - end - end - require_relative "cli/show" - Show.new(options, gem_name).run - end + desc "show GEM [OPTIONS]", "Shows all gems that are part of the bundle, or the path to a given gem" + long_desc <<-D + Show lists the names and versions of all gems that are required by your Gemfile. + Calling show with [GEM] will list the exact location of that gem on your machine. + D + method_option "paths", :type => :boolean, + :banner => "List the paths of all gems that are required by your Gemfile." + method_option "outdated", :type => :boolean, + :banner => "Show verbose output including whether gems are outdated." + def show(gem_name = nil) + SharedHelpers.major_deprecation(2, "the `--outdated` flag to `bundle show` was undocumented and will be removed without replacement") if ARGV.include?("--outdated") + require_relative "cli/show" + Show.new(options, gem_name).run end desc "list", "List all gems in the bundle" diff --git a/lib/bundler/cli/outdated.rb b/lib/bundler/cli/outdated.rb index e5d9af477c..d86ed2d002 100644 --- a/lib/bundler/cli/outdated.rb +++ b/lib/bundler/cli/outdated.rb @@ -146,17 +146,14 @@ module Bundler end def retrieve_active_spec(definition, current_spec) - if strict - active_spec = definition.find_resolved_spec(current_spec) - else - active_specs = definition.find_indexed_specs(current_spec) - if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 - active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } - end - active_spec = active_specs.last - end + active_spec = definition.resolve.find_by_name_and_platform(current_spec.name, current_spec.platform) + return active_spec if strict - active_spec + active_specs = active_spec.source.specs.search(current_spec.name).select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) + if !current_spec.version.prerelease? && !options[:pre] && active_specs.size > 1 + active_specs.delete_if {|b| b.respond_to?(:version) && b.version.prerelease? } + end + active_specs.last end def print_gems(gems_list) diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index d4d3ce5a2d..bdf287b1e7 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -219,7 +219,6 @@ module Bundler Bundler.ui.debug "The definition is missing #{missing.map(&:full_name)}" true rescue BundlerError => e - @index = nil @resolve = nil @specs = nil @gem_version_promoter = nil @@ -282,50 +281,6 @@ module Bundler end end - def index - @index ||= Index.build do |idx| - dependency_names = @dependencies.map(&:name) - - sources.all_sources.each do |source| - source.dependency_names = dependency_names - pinned_spec_names(source) - idx.add_source source.specs - dependency_names.concat(source.unmet_deps).uniq! - end - - double_check_for_index(idx, dependency_names) - end - end - - # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both - # sources A and B. At this point, the API request will have found all the versions of Bar in source A, - # but will not have found any versions of Bar from source B, which is a problem if the requested version - # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for - # each spec we found, we add all possible versions from all sources to the index. - def double_check_for_index(idx, dependency_names) - pinned_names = pinned_spec_names - loop do - idxcount = idx.size - - names = :names # do this so we only have to traverse to get dependency_names from the index once - unmet_dependency_names = lambda do - return names unless names == :names - new_names = sources.all_sources.map(&:dependency_names_to_double_check) - return names = nil if new_names.compact! - names = new_names.flatten(1).concat(dependency_names) - names.uniq! - names -= pinned_names - names - end - - sources.all_sources.each do |source| - source.double_check_for(unmet_dependency_names) - end - - break if idxcount == idx.size - end - end - private :double_check_for_index - def has_rubygems_remotes? sources.rubygems_sources.any? {|s| s.remotes.any? } end @@ -532,14 +487,6 @@ module Bundler end end - def find_resolved_spec(current_spec) - specs.find_by_name_and_platform(current_spec.name, current_spec.platform) - end - - def find_indexed_specs(current_spec) - index[current_spec.name].select {|spec| spec.match_platform(current_spec.platform) }.sort_by(&:version) - end - attr_reader :sources private :sources @@ -556,6 +503,10 @@ module Bundler private + def precompute_source_requirements_for_indirect_dependencies? + sources.non_global_rubygems_sources.all?(&:dependency_api_available?) && sources.no_aggregate_global_source? + end + def current_ruby_platform_locked? return false unless generic_local_platform == Gem::Platform::RUBY @@ -681,9 +632,9 @@ module Bundler changes = false # If there is a RubyGems source in both - locked_gem_sources.each do |locked_gem| + locked_gem_sources.each do |locked_gem_source| # Merge the remotes from the Gemfile into the Gemfile.lock - changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) + changes |= locked_gem_source.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes]) end changes @@ -902,26 +853,22 @@ module Bundler end def source_requirements - # Load all specs from remote sources - index - # Record the specs available in each gem's source, so that those # specs will be available later when the resolver knows where to # look for that gemspec (or its dependencies) - source_requirements = { :default => sources.default_source }.merge(dependency_source_requirements) + source_requirements = if precompute_source_requirements_for_indirect_dependencies? + { :default => sources.default_source }.merge(source_map.all_requirements) + else + { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements) + end metadata_dependencies.each do |dep| source_requirements[dep.name] = sources.metadata_source end - source_requirements[:global] = index unless Bundler.feature_flag.disable_multisource? - source_requirements[:default_bundler] = source_requirements["bundler"] || source_requirements[:default] + source_requirements[:default_bundler] = source_requirements["bundler"] || sources.default_source source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements end - def pinned_spec_names(skip = nil) - dependency_source_requirements.reject {|_, source| source == skip }.keys - end - def requested_groups groups - Bundler.settings[:without] - @optional_groups + Bundler.settings[:with] end @@ -977,16 +924,8 @@ module Bundler Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) end - def dependency_source_requirements - @dependency_source_requirements ||= begin - source_requirements = {} - default = sources.default_source - dependencies.each do |dep| - dep_source = dep.source || default - source_requirements[dep.name] = dep_source - end - source_requirements - end + def source_map + @source_map ||= SourceMap.new(sources, dependencies) end end end diff --git a/lib/bundler/feature_flag.rb b/lib/bundler/feature_flag.rb index 3f9a502179..53d76b8ae8 100644 --- a/lib/bundler/feature_flag.rb +++ b/lib/bundler/feature_flag.rb @@ -32,7 +32,6 @@ module Bundler settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:default_install_uses_path) { bundler_3_mode? } settings_flag(:deployment_means_frozen) { bundler_3_mode? } - settings_flag(:disable_multisource) { bundler_3_mode? } settings_flag(:forget_cli_options) { bundler_3_mode? } settings_flag(:global_gem_cache) { bundler_3_mode? } settings_flag(:path_relative_to_cwd) { bundler_3_mode? } diff --git a/lib/bundler/friendly_errors.rb b/lib/bundler/friendly_errors.rb index 5d0bb905bc..c5a19d3eea 100644 --- a/lib/bundler/friendly_errors.rb +++ b/lib/bundler/friendly_errors.rb @@ -112,7 +112,7 @@ module Bundler #{issues_url(e)} If there aren't any reports for this error yet, please create copy and paste the report template above into a new issue. Don't forget to anonymize any private data! The new issue form is located at: - https://github.com/rubygems/rubygems/issues/new?labels=Bundler + https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md EOS end diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index f945176037..36520c0a43 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -122,10 +122,9 @@ module Bundler names end - # returns a list of the dependencies def unmet_dependency_names dependency_names.select do |name| - name != "bundler" && search(name).empty? + search(name).empty? end end diff --git a/lib/bundler/man/bundle-add.1 b/lib/bundler/man/bundle-add.1 index ffcd63bbcc..a8d3420d59 100644 --- a/lib/bundler/man/bundle-add.1 +++ b/lib/bundler/man/bundle-add.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-ADD" "1" "April 2021" "" "" +.TH "BUNDLE\-ADD" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install diff --git a/lib/bundler/man/bundle-binstubs.1 b/lib/bundler/man/bundle-binstubs.1 index 23c371b7de..3493770304 100644 --- a/lib/bundler/man/bundle-binstubs.1 +++ b/lib/bundler/man/bundle-binstubs.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-BINSTUBS" "1" "April 2021" "" "" +.TH "BUNDLE\-BINSTUBS" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems diff --git a/lib/bundler/man/bundle-cache.1 b/lib/bundler/man/bundle-cache.1 index 9bb8011a8a..7bfbaa6a4e 100644 --- a/lib/bundler/man/bundle-cache.1 +++ b/lib/bundler/man/bundle-cache.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CACHE" "1" "April 2021" "" "" +.TH "BUNDLE\-CACHE" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application diff --git a/lib/bundler/man/bundle-check.1 b/lib/bundler/man/bundle-check.1 index 6696479fef..bae888df27 100644 --- a/lib/bundler/man/bundle-check.1 +++ b/lib/bundler/man/bundle-check.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CHECK" "1" "April 2021" "" "" +.TH "BUNDLE\-CHECK" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems diff --git a/lib/bundler/man/bundle-clean.1 b/lib/bundler/man/bundle-clean.1 index 625d87c580..2e2bb615c4 100644 --- a/lib/bundler/man/bundle-clean.1 +++ b/lib/bundler/man/bundle-clean.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CLEAN" "1" "April 2021" "" "" +.TH "BUNDLE\-CLEAN" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 3a1cee9b81..26e9418c0c 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-CONFIG" "1" "April 2021" "" "" +.TH "BUNDLE\-CONFIG" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-config\fR \- Set bundler configuration options @@ -56,9 +56,6 @@ Executing \fBbundle config unset \-\-local \fR will delete the con .P Executing bundle with the \fBBUNDLE_IGNORE_CONFIG\fR environment variable set will cause it to ignore all configuration\. . -.P -Executing \fBbundle config set \-\-local disable_multisource true\fR upgrades the warning about the Gemfile containing multiple primary sources to an error\. Executing \fBbundle config unset disable_multisource\fR downgrades this error to a warning\. -. .SH "REMEMBERING OPTIONS" Flags passed to \fBbundle install\fR or the Bundler runtime, such as \fB\-\-path foo\fR or \fB\-\-without production\fR, are remembered between commands and saved to your local application\'s configuration (normally, \fB\./\.bundle/config\fR)\. . @@ -184,9 +181,6 @@ The following is a list of all configuration keys and their purpose\. You can le \fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\. . .IP "\(bu" 4 -\fBdisable_multisource\fR (\fBBUNDLE_DISABLE_MULTISOURCE\fR): When set, Gemfiles containing multiple sources will produce errors instead of warnings\. Use \fBbundle config unset disable_multisource\fR to unset\. -. -.IP "\(bu" 4 \fBdisable_shared_gems\fR (\fBBUNDLE_DISABLE_SHARED_GEMS\fR): Stop Bundler from accessing gems installed to RubyGems\' normal location\. . .IP "\(bu" 4 diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index 15bc5af778..cffd87a160 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -47,10 +47,6 @@ configuration only from the local application. Executing bundle with the `BUNDLE_IGNORE_CONFIG` environment variable set will cause it to ignore all configuration. -Executing `bundle config set --local disable_multisource true` upgrades the warning about -the Gemfile containing multiple primary sources to an error. Executing `bundle -config unset disable_multisource` downgrades this error to a warning. - ## REMEMBERING OPTIONS Flags passed to `bundle install` or the Bundler runtime, such as `--path foo` or @@ -178,10 +174,6 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). * `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository. -* `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`): - When set, Gemfiles containing multiple sources will produce errors - instead of warnings. - Use `bundle config unset disable_multisource` to unset. * `disable_shared_gems` (`BUNDLE_DISABLE_SHARED_GEMS`): Stop Bundler from accessing gems installed to RubyGems' normal location. * `disable_version_check` (`BUNDLE_DISABLE_VERSION_CHECK`): diff --git a/lib/bundler/man/bundle-doctor.1 b/lib/bundler/man/bundle-doctor.1 index 8e4c47c683..0c8ff27d3e 100644 --- a/lib/bundler/man/bundle-doctor.1 +++ b/lib/bundler/man/bundle-doctor.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-DOCTOR" "1" "April 2021" "" "" +.TH "BUNDLE\-DOCTOR" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-doctor\fR \- Checks the bundle for common problems diff --git a/lib/bundler/man/bundle-exec.1 b/lib/bundler/man/bundle-exec.1 index 863b76e4b7..c8d51cd4a2 100644 --- a/lib/bundler/man/bundle-exec.1 +++ b/lib/bundler/man/bundle-exec.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-EXEC" "1" "April 2021" "" "" +.TH "BUNDLE\-EXEC" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-exec\fR \- Execute a command in the context of the bundle diff --git a/lib/bundler/man/bundle-gem.1 b/lib/bundler/man/bundle-gem.1 index e71ccb4832..4b7e5a088c 100644 --- a/lib/bundler/man/bundle-gem.1 +++ b/lib/bundler/man/bundle-gem.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-GEM" "1" "April 2021" "" "" +.TH "BUNDLE\-GEM" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem diff --git a/lib/bundler/man/bundle-info.1 b/lib/bundler/man/bundle-info.1 index 168d021112..4039ec9c94 100644 --- a/lib/bundler/man/bundle-info.1 +++ b/lib/bundler/man/bundle-info.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INFO" "1" "April 2021" "" "" +.TH "BUNDLE\-INFO" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-info\fR \- Show information for the given gem in your bundle diff --git a/lib/bundler/man/bundle-init.1 b/lib/bundler/man/bundle-init.1 index 5d3e61d05b..f538b06bf6 100644 --- a/lib/bundler/man/bundle-init.1 +++ b/lib/bundler/man/bundle-init.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INIT" "1" "April 2021" "" "" +.TH "BUNDLE\-INIT" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-init\fR \- Generates a Gemfile into the current working directory diff --git a/lib/bundler/man/bundle-inject.1 b/lib/bundler/man/bundle-inject.1 index 37acabfa9a..85549b4585 100644 --- a/lib/bundler/man/bundle-inject.1 +++ b/lib/bundler/man/bundle-inject.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INJECT" "1" "April 2021" "" "" +.TH "BUNDLE\-INJECT" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile diff --git a/lib/bundler/man/bundle-install.1 b/lib/bundler/man/bundle-install.1 index 2dcb4d3ac6..867a41d70d 100644 --- a/lib/bundler/man/bundle-install.1 +++ b/lib/bundler/man/bundle-install.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-INSTALL" "1" "April 2021" "" "" +.TH "BUNDLE\-INSTALL" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile diff --git a/lib/bundler/man/bundle-list.1 b/lib/bundler/man/bundle-list.1 index 7c93b89dc3..0b67785a21 100644 --- a/lib/bundler/man/bundle-list.1 +++ b/lib/bundler/man/bundle-list.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LIST" "1" "April 2021" "" "" +.TH "BUNDLE\-LIST" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-list\fR \- List all the gems in the bundle diff --git a/lib/bundler/man/bundle-lock.1 b/lib/bundler/man/bundle-lock.1 index a4dfda9c86..860a2e07ef 100644 --- a/lib/bundler/man/bundle-lock.1 +++ b/lib/bundler/man/bundle-lock.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-LOCK" "1" "April 2021" "" "" +.TH "BUNDLE\-LOCK" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing diff --git a/lib/bundler/man/bundle-open.1 b/lib/bundler/man/bundle-open.1 index 0511bc655b..b907e2d544 100644 --- a/lib/bundler/man/bundle-open.1 +++ b/lib/bundler/man/bundle-open.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OPEN" "1" "April 2021" "" "" +.TH "BUNDLE\-OPEN" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle diff --git a/lib/bundler/man/bundle-outdated.1 b/lib/bundler/man/bundle-outdated.1 index 268b4b157c..5427a2ab77 100644 --- a/lib/bundler/man/bundle-outdated.1 +++ b/lib/bundler/man/bundle-outdated.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-OUTDATED" "1" "April 2021" "" "" +.TH "BUNDLE\-OUTDATED" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-outdated\fR \- List installed gems with newer versions available diff --git a/lib/bundler/man/bundle-platform.1 b/lib/bundler/man/bundle-platform.1 index 77638b2b4b..2a80abb8d6 100644 --- a/lib/bundler/man/bundle-platform.1 +++ b/lib/bundler/man/bundle-platform.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PLATFORM" "1" "April 2021" "" "" +.TH "BUNDLE\-PLATFORM" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-platform\fR \- Displays platform compatibility information diff --git a/lib/bundler/man/bundle-pristine.1 b/lib/bundler/man/bundle-pristine.1 index 0fcf9fdb39..7fff665de0 100644 --- a/lib/bundler/man/bundle-pristine.1 +++ b/lib/bundler/man/bundle-pristine.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-PRISTINE" "1" "April 2021" "" "" +.TH "BUNDLE\-PRISTINE" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition diff --git a/lib/bundler/man/bundle-remove.1 b/lib/bundler/man/bundle-remove.1 index ca366b81a9..17de5ed5a9 100644 --- a/lib/bundler/man/bundle-remove.1 +++ b/lib/bundler/man/bundle-remove.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-REMOVE" "1" "April 2021" "" "" +.TH "BUNDLE\-REMOVE" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-remove\fR \- Removes gems from the Gemfile diff --git a/lib/bundler/man/bundle-show.1 b/lib/bundler/man/bundle-show.1 index e403ae980f..fbbe18741f 100644 --- a/lib/bundler/man/bundle-show.1 +++ b/lib/bundler/man/bundle-show.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-SHOW" "1" "April 2021" "" "" +.TH "BUNDLE\-SHOW" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem diff --git a/lib/bundler/man/bundle-update.1 b/lib/bundler/man/bundle-update.1 index 5546b51792..3c9af3dcc1 100644 --- a/lib/bundler/man/bundle-update.1 +++ b/lib/bundler/man/bundle-update.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-UPDATE" "1" "April 2021" "" "" +.TH "BUNDLE\-UPDATE" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-update\fR \- Update your gems to the latest available versions diff --git a/lib/bundler/man/bundle-viz.1 b/lib/bundler/man/bundle-viz.1 index 645c45b607..fbc48aa902 100644 --- a/lib/bundler/man/bundle-viz.1 +++ b/lib/bundler/man/bundle-viz.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE\-VIZ" "1" "April 2021" "" "" +.TH "BUNDLE\-VIZ" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile diff --git a/lib/bundler/man/bundle.1 b/lib/bundler/man/bundle.1 index 5c1bc96572..5b6c9afe78 100644 --- a/lib/bundler/man/bundle.1 +++ b/lib/bundler/man/bundle.1 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "BUNDLE" "1" "April 2021" "" "" +.TH "BUNDLE" "1" "May 2021" "" "" . .SH "NAME" \fBbundle\fR \- Ruby Dependency Management diff --git a/lib/bundler/man/gemfile.5 b/lib/bundler/man/gemfile.5 index 480d38f39c..2497fad234 100644 --- a/lib/bundler/man/gemfile.5 +++ b/lib/bundler/man/gemfile.5 @@ -1,7 +1,7 @@ .\" generated with Ronn/v0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3 . -.TH "GEMFILE" "5" "April 2021" "" "" +.TH "GEMFILE" "5" "May 2021" "" "" . .SH "NAME" \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs diff --git a/lib/bundler/plugin/api/source.rb b/lib/bundler/plugin/api/source.rb index d70a16f4bc..f6f4ac4f0a 100644 --- a/lib/bundler/plugin/api/source.rb +++ b/lib/bundler/plugin/api/source.rb @@ -244,6 +244,20 @@ module Bundler specs.unmet_dependency_names end + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def spec_names + specs.spec_names + end + + # Used by definition. + # + # Note: Do not override if you don't know what you are doing. + def add_dependency_names(names) + @dependencies |= Array(names) + end + # Note: Do not override if you don't know what you are doing. def can_lock?(spec) spec.source == self diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 69899dc6c3..9a25e49d4b 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -21,17 +21,11 @@ module Bundler base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) - SpecSet.new(result) + SpecSet.new(result).for(requirements.reject{|dep| dep.name.end_with?("\0") }) end def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) @source_requirements = source_requirements - - @index_requirements = source_requirements.each_with_object({}) do |source_requirement, index_requirements| - name, source = source_requirement - index_requirements[name] = name == :global ? source : source.specs - end - @base = base @resolver = Molinillo::Resolver.new(self, self) @search_for = {} @@ -45,10 +39,6 @@ module Bundler @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? - @no_aggregate_global_source = @source_requirements[:global].nil? - - @variant_specific_names = [] - @generic_names = ["Ruby\0", "RubyGems\0"] end def start(requirements) @@ -58,7 +48,6 @@ module Bundler verify_gemfile_dependencies_are_found!(requirements) dg = @resolver.resolve(requirements, @base_dg) dg. - tap {|resolved| validate_resolved_specs!(resolved) }. map(&:payload). reject {|sg| sg.name.end_with?("\0") }. map(&:to_specs). @@ -112,24 +101,14 @@ module Bundler include Molinillo::SpecificationProvider def dependencies_for(specification) - all_dependencies = specification.dependencies_for_activated_platforms - - if @variant_specific_names.include?(specification.name) - @variant_specific_names |= all_dependencies.map(&:name) - @generic_names - else - generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms - @variant_specific_names |= variant_specific_names - @generic_names - @generic_names |= generic_names - end - - all_dependencies + specification.dependencies_for_activated_platforms end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep name = dependency.name - search_result = @search_for[dependency_proxy] ||= begin + @search_for[dependency_proxy] ||= begin results = results_for(dependency, @base[name]) if vertex = @base_dg.vertex_named(name) @@ -181,35 +160,14 @@ module Bundler @gem_version_promoter.sort_versions(dependency, spec_groups) end end - - unless search_result.empty? - specific_dependency = @variant_specific_names.include?(name) - return search_result unless specific_dependency - - search_result.each do |sg| - if @generic_names.include?(name) - @variant_specific_names -= [name] - sg.activate_all_platforms! - else - sg.activate_platform!(platform) - end - end - end - - search_result end def index_for(dependency) - source = @index_requirements[dependency.name] - if source - source - elsif @no_aggregate_global_source - Index.build do |idx| - dependency.all_sources.each {|s| idx.add_source(s.specs) } - end - else - @index_requirements[:global] - end + source_for(dependency.name).specs + end + + def source_for(name) + @source_requirements[name] || @source_requirements[:default] end def results_for(dependency, base) @@ -240,23 +198,10 @@ module Bundler dependencies.map(&:dep) == other_dependencies.map(&:dep) end - def relevant_sources_for_vertex(vertex) - if vertex.root? - [@source_requirements[vertex.name]] - elsif @no_aggregate_global_source - vertex.recursive_predecessors.map do |v| - @source_requirements[v.name] - end.compact << @source_requirements[:default] - else - [] - end - end - def sort_dependencies(dependencies, activated, conflicts) dependencies.sort_by do |dependency| name = name_for(dependency) vertex = activated.vertex_named(name) - dependency.all_sources = relevant_sources_for_vertex(vertex) [ @base_dg.vertex_named(name) ? 0 : 1, vertex.payload ? 0 : 1, @@ -398,7 +343,7 @@ module Bundler if other_bundler_required o << "\n\n" - candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency) + candidate_specs = source_for(:default_bundler).specs.search(conflict_dependency) if candidate_specs.any? target_version = candidate_specs.last.version new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") @@ -415,11 +360,7 @@ module Bundler elsif !conflict.existing o << "\n" - relevant_sources = if conflict.requirement.source - [conflict.requirement.source] - else - conflict.requirement.all_sources - end.compact.map(&:to_s).uniq.sort + relevant_source = conflict.requirement.source || source_for(name) metadata_requirement = name.end_with?("\0") @@ -432,12 +373,10 @@ module Bundler end o << " " - o << if relevant_sources.empty? - "in any of the sources.\n" - elsif metadata_requirement - "is not available in #{relevant_sources.join(" or ")}" + o << if metadata_requirement + "is not available in #{relevant_source}" else - "in any of the relevant sources:\n #{relevant_sources * "\n "}\n" + "in #{relevant_source}.\n" end end end, @@ -451,27 +390,5 @@ module Bundler end ) end - - def validate_resolved_specs!(resolved_specs) - resolved_specs.each do |v| - name = v.name - sources = relevant_sources_for_vertex(v) - next unless sources.any? - if default_index = sources.index(@source_requirements[:default]) - sources.delete_at(default_index) - end - sources.reject! {|s| s.specs.search(name).empty? } - sources.uniq! - next if sources.size <= 1 - - msg = ["The gem '#{name}' was found in multiple relevant sources."] - msg.concat sources.map {|s| " * #{s}" }.sort - msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from." - msg = msg.join("\n") - - raise SecurityError, msg if @no_aggregate_global_source - Bundler.ui.warn "Warning: #{msg}" - end - end end end diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb index 73ffec5838..8f4fd18c46 100644 --- a/lib/bundler/resolver/spec_group.rb +++ b/lib/bundler/resolver/spec_group.rb @@ -21,14 +21,10 @@ module Bundler @version = exemplary_spec.version @source = exemplary_spec.source - @all_platforms = relevant_platforms @activated_platforms = relevant_platforms @dependencies = Hash.new do |dependencies, platforms| dependencies[platforms] = dependencies_for(platforms) end - @partitioned_dependency_names = Hash.new do |partitioned_dependency_names, platforms| - partitioned_dependency_names[platforms] = partitioned_dependency_names_for(platforms) - end @specs = specs end @@ -45,14 +41,6 @@ module Bundler end.flatten.compact.uniq end - def activate_platform!(platform) - self.activated_platforms = [platform] - end - - def activate_all_platforms! - self.activated_platforms = @all_platforms - end - def to_s activated_platforms_string = sorted_activated_platforms.join(", ") "#{name} (#{version}) (#{activated_platforms_string})" @@ -62,10 +50,6 @@ module Bundler @dependencies[activated_platforms] end - def partitioned_dependency_names_for_activated_platforms - @partitioned_dependency_names[activated_platforms] - end - def ==(other) return unless other.is_a?(SpecGroup) name == other.name && @@ -100,14 +84,6 @@ module Bundler end.flatten end - def partitioned_dependency_names_for(platforms) - return @dependencies[platforms].map(&:name), [] if platforms.size == 1 - - @dependencies[platforms].partition do |dep_proxy| - @dependencies[platforms].count {|dp| dp.dep == dep_proxy.dep } == platforms.size - end.map {|deps| deps.map(&:name) } - end - def __dependencies(platform) dependencies = [] @specs[platform].first.dependencies.each do |dep| diff --git a/lib/bundler/rubygems_ext.rb b/lib/bundler/rubygems_ext.rb index 2bd2dcb451..c95664965c 100644 --- a/lib/bundler/rubygems_ext.rb +++ b/lib/bundler/rubygems_ext.rb @@ -105,7 +105,7 @@ module Gem end class Dependency - attr_accessor :source, :groups, :all_sources + attr_accessor :source, :groups alias_method :eql?, :== @@ -116,7 +116,7 @@ module Gem end def to_yaml_properties - instance_variables.reject {|p| ["@source", "@groups", "@all_sources"].include?(p.to_s) } + instance_variables.reject {|p| ["@source", "@groups"].include?(p.to_s) } end def to_lock diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index 612c56f041..0702a80440 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -21,7 +21,6 @@ module Bundler disable_exec_load disable_local_branch_check disable_local_revision_check - disable_multisource disable_shared_gems disable_version_check force_ruby_platform diff --git a/lib/bundler/source.rb b/lib/bundler/source.rb index a3f4b09cce..f39072791c 100644 --- a/lib/bundler/source.rb +++ b/lib/bundler/source.rb @@ -7,6 +7,7 @@ module Bundler autoload :Metadata, File.expand_path("source/metadata", __dir__) autoload :Path, File.expand_path("source/path", __dir__) autoload :Rubygems, File.expand_path("source/rubygems", __dir__) + autoload :RubygemsAggregate, File.expand_path("source/rubygems_aggregate", __dir__) attr_accessor :dependency_names @@ -39,6 +40,10 @@ module Bundler def remote!; end + def add_dependency_names(names) + @dependency_names = Array(dependency_names) | Array(names) + end + # it's possible that gems from one source depend on gems from some # other source, so now we download gemspecs and iterate over those # dependencies, looking for gems we don't have info on yet. @@ -48,6 +53,10 @@ module Bundler specs.dependency_names end + def spec_names + specs.spec_names + end + def include?(other) other == self end diff --git a/lib/bundler/source/rubygems.rb b/lib/bundler/source/rubygems.rb index 2b7cfd53b9..a11a89cf72 100644 --- a/lib/bundler/source/rubygems.rb +++ b/lib/bundler/source/rubygems.rb @@ -259,8 +259,16 @@ module Bundler !equivalent end + def spec_names + if @allow_remote && dependency_api_available? + remote_specs.spec_names + else + [] + end + end + def unmet_deps - if @allow_remote && api_fetchers.any? + if @allow_remote && dependency_api_available? remote_specs.unmet_dependency_names else [] @@ -276,7 +284,7 @@ module Bundler def double_check_for(unmet_dependency_names) return unless @allow_remote - return unless api_fetchers.any? + return unless dependency_api_available? unmet_dependency_names = unmet_dependency_names.call unless unmet_dependency_names.nil? @@ -298,17 +306,20 @@ module Bundler remote_specs.each do |spec| case spec when EndpointSpecification, Gem::Specification, StubSpecification, LazySpecification - names.concat(spec.runtime_dependencies) + names.concat(spec.runtime_dependencies.map(&:name)) when RemoteSpecification # from the full index return nil else raise "unhandled spec type (#{spec.inspect})" end end - names.map!(&:name) if names names end + def dependency_api_available? + api_fetchers.any? + end + protected def credless_remotes diff --git a/lib/bundler/source/rubygems_aggregate.rb b/lib/bundler/source/rubygems_aggregate.rb new file mode 100644 index 0000000000..685bf7e90a --- /dev/null +++ b/lib/bundler/source/rubygems_aggregate.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +module Bundler + class Source + class RubygemsAggregate + attr_reader :source_map, :sources + + def initialize(sources, source_map) + @sources = sources + @source_map = source_map + + @index = build_index + end + + def specs + @index + end + + def to_s + "any of the sources" + end + + private + + def build_index + Index.build do |idx| + dependency_names = source_map.pinned_spec_names + + sources.all_sources.each do |source| + source.dependency_names = dependency_names - source_map.pinned_spec_names(source) + idx.add_source source.specs + dependency_names.concat(source.unmet_deps).uniq! + end + + double_check_for_index(idx, dependency_names) + end + end + + # Suppose the gem Foo depends on the gem Bar. Foo exists in Source A. Bar has some versions that exist in both + # sources A and B. At this point, the API request will have found all the versions of Bar in source A, + # but will not have found any versions of Bar from source B, which is a problem if the requested version + # of Foo specifically depends on a version of Bar that is only found in source B. This ensures that for + # each spec we found, we add all possible versions from all sources to the index. + def double_check_for_index(idx, dependency_names) + pinned_names = source_map.pinned_spec_names + + names = :names # do this so we only have to traverse to get dependency_names from the index once + unmet_dependency_names = lambda do + return names unless names == :names + new_names = sources.all_sources.map(&:dependency_names_to_double_check) + return names = nil if new_names.compact! + names = new_names.flatten(1).concat(dependency_names) + names.uniq! + names -= pinned_names + names + end + + sources.all_sources.each do |source| + source.double_check_for(unmet_dependency_names) + end + end + end + end +end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 6f5636f41e..f7eb3a1c03 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -21,15 +21,19 @@ module Bundler @rubygems_sources = [] @metadata_source = Source::Metadata.new - @disable_multisource = true + @merged_gem_lockfile_sections = false end - def disable_multisource? - @disable_multisource + def merged_gem_lockfile_sections? + @merged_gem_lockfile_sections end def merged_gem_lockfile_sections! - @disable_multisource = false + @merged_gem_lockfile_sections = true + end + + def no_aggregate_global_source? + global_rubygems_source.remotes.size <= 1 end def add_path_source(options = {}) @@ -70,7 +74,11 @@ module Bundler end def rubygems_sources - @rubygems_sources + [global_rubygems_source] + non_global_rubygems_sources + [global_rubygems_source] + end + + def non_global_rubygems_sources + @rubygems_sources end def rubygems_remotes @@ -81,16 +89,27 @@ module Bundler path_sources + git_sources + plugin_sources + rubygems_sources + [metadata_source] end + def non_default_explicit_sources + all_sources - [default_source, metadata_source] + end + def get(source) source_list_for(source).find {|s| equal_source?(source, s) || equivalent_source?(source, s) } end def lock_sources - lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) - if disable_multisource? - lock_sources + rubygems_sources.sort_by(&:to_s).uniq + lock_other_sources + lock_rubygems_sources + end + + def lock_other_sources + (path_sources + git_sources + plugin_sources).sort_by(&:to_s) + end + + def lock_rubygems_sources + if merged_gem_lockfile_sections? + [combine_rubygems_sources] else - lock_sources << combine_rubygems_sources + rubygems_sources.sort_by(&:to_s).uniq end end @@ -104,7 +123,7 @@ module Bundler end end - replacement_rubygems = !disable_multisource? && + replacement_rubygems = merged_gem_lockfile_sections? && replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } @global_rubygems_source = replacement_rubygems if replacement_rubygems diff --git a/lib/bundler/source_map.rb b/lib/bundler/source_map.rb new file mode 100644 index 0000000000..a554f26f76 --- /dev/null +++ b/lib/bundler/source_map.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +module Bundler + class SourceMap + attr_reader :sources, :dependencies + + def initialize(sources, dependencies) + @sources = sources + @dependencies = dependencies + end + + def pinned_spec_names(skip = nil) + direct_requirements.reject {|_, source| source == skip }.keys + end + + def all_requirements + requirements = direct_requirements.dup + + unmet_deps = sources.non_default_explicit_sources.map do |source| + (source.spec_names - pinned_spec_names).each do |indirect_dependency_name| + previous_source = requirements[indirect_dependency_name] + if previous_source.nil? + requirements[indirect_dependency_name] = source + else + no_ambiguous_sources = Bundler.feature_flag.bundler_3_mode? + + msg = ["The gem '#{indirect_dependency_name}' was found in multiple relevant sources."] + msg.concat [previous_source, source].map {|s| " * #{s}" }.sort + msg << "You #{no_ambiguous_sources ? :must : :should} add this gem to the source block for the source you wish it to be installed from." + msg = msg.join("\n") + + raise SecurityError, msg if no_ambiguous_sources + Bundler.ui.warn "Warning: #{msg}" + end + end + + source.unmet_deps + end + + sources.default_source.add_dependency_names(unmet_deps.flatten - requirements.keys) + + requirements + end + + def direct_requirements + @direct_requirements ||= begin + requirements = {} + default = sources.default_source + dependencies.each do |dep| + dep_source = dep.source || default + dep_source.add_dependency_names(dep.name) + requirements[dep.name] = dep_source + end + requirements + end + end + end +end diff --git a/lib/bundler/templates/newgem/newgem.gemspec.tt b/lib/bundler/templates/newgem/newgem.gemspec.tt index 632b24dda9..7032004076 100644 --- a/lib/bundler/templates/newgem/newgem.gemspec.tt +++ b/lib/bundler/templates/newgem/newgem.gemspec.tt @@ -14,7 +14,7 @@ Gem::Specification.new do |spec| <%- if config[:mit] -%> spec.license = "MIT" <%- end -%> - spec.required_ruby_version = Gem::Requirement.new(">= <%= config[:required_ruby_version] %>") + spec.required_ruby_version = ">= <%= config[:required_ruby_version] %>" spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 735cb09c88..8e327e0951 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.17".freeze + VERSION = "2.2.18".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 48d0117efb..dec57f8309 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.17".freeze + VERSION = "3.2.18".freeze end # Must be first since it unloads the prelude from 1.9.2 diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index fede270417..1f73796351 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -23,11 +23,11 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder # spaces do not work. # # Details: https://github.com/rubygems/rubygems/issues/977#issuecomment-171544940 - tmp_dest = get_relative_path(tmp_dest, extension_dir) + tmp_dest_relative = get_relative_path(tmp_dest.clone, extension_dir) Tempfile.open %w[siteconf .rb], extension_dir do |siteconf| siteconf.puts "require 'rbconfig'" - siteconf.puts "dest_path = #{tmp_dest.dump}" + siteconf.puts "dest_path = #{tmp_dest_relative.dump}" %w[sitearchdir sitelibdir].each do |dir| siteconf.puts "RbConfig::MAKEFILE_CONFIG['#{dir}'] = dest_path" siteconf.puts "RbConfig::CONFIG['#{dir}'] = dest_path" @@ -63,8 +63,8 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder make dest_path, results, extension_dir - if tmp_dest - full_tmp_dest = File.join(extension_dir, tmp_dest) + if tmp_dest_relative + full_tmp_dest = File.join(extension_dir, tmp_dest_relative) # TODO remove in RubyGems 3 if Gem.install_extension_in_lib and lib_dir diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 6b569032ba..7206c3eaf0 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -1558,7 +1558,6 @@ class Gem::Specification < Gem::BasicSpecification def build_extensions # :nodoc: return if default_gem? return if extensions.empty? - return if installed_by_version < Gem::Version.new('2.2.0.preview.2') return if File.exist? gem_build_complete_path return if !File.writable?(base_dir) return if !File.exist?(File.join(base_dir, 'extensions')) @@ -2129,7 +2128,6 @@ class Gem::Specification < Gem::BasicSpecification def missing_extensions? return false if default_gem? return false if extensions.empty? - return false if installed_by_version < Gem::Version.new('2.2.0.preview.2') return false if File.exist? gem_build_complete_path true diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index e2763561c6..b3e23360ed 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -12,7 +12,7 @@ if File.exist?(bundler_gemspec) end begin - gem 'minitest', '~> 5.13' + gem 'test-unit', '~> 3.0' rescue Gem::LoadError end @@ -32,16 +32,7 @@ else require 'bundler' end -# Enable server plugin needed for bisection -if ENV["RG_BISECT_SERVER_PLUGIN"] - require ENV["RG_BISECT_SERVER_PLUGIN"] - - Minitest.extensions << "server" -end - -ENV["MT_NO_PLUGINS"] = "true" - -require 'minitest/autorun' +require 'test/unit' ENV["JARS_SKIP"] = "true" if Gem.java_platform? # avoid unnecessary and noisy `jar-dependencies` post install hook @@ -111,7 +102,7 @@ end # and uninstall gems, fetch remote gems through a stub fetcher and be assured # your normal set of gems is not affected. -class Gem::TestCase < Minitest::Test +class Gem::TestCase < Test::Unit::TestCase extend Gem::Deprecate attr_accessor :fetcher # :nodoc: @@ -140,11 +131,48 @@ class Gem::TestCase < Minitest::Test end def assert_directory_exists(path, msg = nil) - msg = message(msg) { "Expected path '#{path}' to be a directory" } - assert_path_exists path + msg = build_message(msg, "Expected path '#{path}' to be a directory") + assert_path_exist path assert File.directory?(path), msg end + # https://github.com/seattlerb/minitest/blob/21d9e804b63c619f602f3f4ece6c71b48974707a/lib/minitest/assertions.rb#L188 + def _synchronize + yield + end + + # https://github.com/seattlerb/minitest/blob/21d9e804b63c619f602f3f4ece6c71b48974707a/lib/minitest/assertions.rb#L546 + def capture_subprocess_io + _synchronize do + begin + require "tempfile" + + captured_stdout, captured_stderr = Tempfile.new("out"), Tempfile.new("err") + + orig_stdout, orig_stderr = $stdout.dup, $stderr.dup + $stdout.reopen captured_stdout + $stderr.reopen captured_stderr + + yield + + $stdout.rewind + $stderr.rewind + + return captured_stdout.read, captured_stderr.read + ensure + captured_stdout.unlink + captured_stderr.unlink + $stdout.reopen orig_stdout + $stderr.reopen orig_stderr + + orig_stdout.close + orig_stderr.close + captured_stdout.close + captured_stderr.close + end + end + end + ## # Sets the ENABLE_SHARED entry in RbConfig::CONFIG to +value+ and restores # the original value when the block ends @@ -262,19 +290,19 @@ class Gem::TestCase < Minitest::Test def assert_contains_make_command(target, output, msg = nil) if output.match(/\n/) - msg = message(msg) do + msg = build_message(msg, "Expected output containing make command \"%s\", but was \n\nBEGIN_OF_OUTPUT\n%sEND_OF_OUTPUT" % [ ('%s %s' % [make_command, target]).rstrip, output, ] - end + ) else - msg = message(msg) do + msg = build_message(msg, 'Expected make command "%s": %s' % [ ('%s %s' % [make_command, target]).rstrip, output, ] - end + ) end assert scan_make_command_lines(output).any? {|line| @@ -664,6 +692,28 @@ class Gem::TestCase < Minitest::Test path end + ## + # Load a YAML string, the psych 3 way + + def load_yaml(yaml) + if YAML.respond_to?(:unsafe_load) + YAML.unsafe_load(yaml) + else + YAML.load(yaml) + end + end + + ## + # Load a YAML file, the psych 3 way + + def load_yaml_file(file) + if YAML.respond_to?(:unsafe_load_file) + YAML.unsafe_load_file(file) + else + YAML.load_file(file) + end + end + def all_spec_names Gem::Specification.map(&:full_name) end @@ -1519,4 +1569,38 @@ Also, a list: end if Gem::HAVE_OPENSSL end +# https://github.com/seattlerb/minitest/blob/13c48a03d84a2a87855a4de0c959f96800100357/lib/minitest/mock.rb#L192 +class Object + def stub(name, val_or_callable, *block_args) + new_name = "__minitest_stub__#{name}" + + metaclass = class << self; self; end + + if respond_to? name and not methods.map(&:to_s).include? name.to_s + metaclass.send :define_method, name do |*args| + super(*args) + end + end + + metaclass.send :alias_method, new_name, name + + metaclass.send :define_method, name do |*args, &blk| + if val_or_callable.respond_to? :call + val_or_callable.call(*args, &blk) + else + blk.call(*block_args) if blk + val_or_callable + end + end + + metaclass.send(:ruby2_keywords, name) if metaclass.respond_to?(:ruby2_keywords, true) + + yield self + ensure + metaclass.send :undef_method, name + metaclass.send :alias_method, name, new_name + metaclass.send :undef_method, new_name + end +end + require 'rubygems/test_utilities' -- cgit v1.2.3