bundler 2.4.18 → 2.4.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +45 -0
  3. data/lib/bundler/build_metadata.rb +2 -2
  4. data/lib/bundler/cli/binstubs.rb +1 -1
  5. data/lib/bundler/cli/info.rb +1 -1
  6. data/lib/bundler/cli/install.rb +1 -1
  7. data/lib/bundler/cli/outdated.rb +1 -1
  8. data/lib/bundler/cli/platform.rb +7 -5
  9. data/lib/bundler/cli/update.rb +1 -0
  10. data/lib/bundler/definition.rb +25 -20
  11. data/lib/bundler/dsl.rb +1 -1
  12. data/lib/bundler/env.rb +1 -1
  13. data/lib/bundler/fetcher/base.rb +2 -2
  14. data/lib/bundler/fetcher/compact_index.rb +4 -8
  15. data/lib/bundler/fetcher/dependency.rb +1 -1
  16. data/lib/bundler/fetcher/downloader.rb +2 -0
  17. data/lib/bundler/fetcher/index.rb +1 -2
  18. data/lib/bundler/fetcher.rb +42 -31
  19. data/lib/bundler/friendly_errors.rb +1 -1
  20. data/lib/bundler/gem_helper.rb +3 -4
  21. data/lib/bundler/index.rb +62 -31
  22. data/lib/bundler/installer/parallel_installer.rb +1 -1
  23. data/lib/bundler/installer/standalone.rb +8 -1
  24. data/lib/bundler/lockfile_parser.rb +3 -15
  25. data/lib/bundler/man/bundle-add.1 +1 -1
  26. data/lib/bundler/man/bundle-binstubs.1 +1 -1
  27. data/lib/bundler/man/bundle-cache.1 +1 -1
  28. data/lib/bundler/man/bundle-check.1 +1 -1
  29. data/lib/bundler/man/bundle-clean.1 +1 -1
  30. data/lib/bundler/man/bundle-config.1 +1 -1
  31. data/lib/bundler/man/bundle-console.1 +1 -1
  32. data/lib/bundler/man/bundle-doctor.1 +1 -1
  33. data/lib/bundler/man/bundle-exec.1 +1 -1
  34. data/lib/bundler/man/bundle-gem.1 +1 -1
  35. data/lib/bundler/man/bundle-help.1 +1 -1
  36. data/lib/bundler/man/bundle-info.1 +3 -3
  37. data/lib/bundler/man/bundle-info.1.ronn +3 -3
  38. data/lib/bundler/man/bundle-init.1 +1 -1
  39. data/lib/bundler/man/bundle-inject.1 +1 -1
  40. data/lib/bundler/man/bundle-install.1 +1 -1
  41. data/lib/bundler/man/bundle-list.1 +1 -1
  42. data/lib/bundler/man/bundle-lock.1 +1 -1
  43. data/lib/bundler/man/bundle-open.1 +1 -1
  44. data/lib/bundler/man/bundle-outdated.1 +1 -1
  45. data/lib/bundler/man/bundle-platform.1 +1 -1
  46. data/lib/bundler/man/bundle-plugin.1 +1 -1
  47. data/lib/bundler/man/bundle-pristine.1 +1 -1
  48. data/lib/bundler/man/bundle-remove.1 +1 -1
  49. data/lib/bundler/man/bundle-show.1 +1 -1
  50. data/lib/bundler/man/bundle-update.1 +1 -1
  51. data/lib/bundler/man/bundle-version.1 +1 -1
  52. data/lib/bundler/man/bundle-viz.1 +1 -1
  53. data/lib/bundler/man/bundle.1 +1 -1
  54. data/lib/bundler/man/gemfile.5 +25 -1
  55. data/lib/bundler/man/gemfile.5.ronn +10 -0
  56. data/lib/bundler/plugin/index.rb +1 -1
  57. data/lib/bundler/plugin.rb +1 -1
  58. data/lib/bundler/resolver.rb +18 -3
  59. data/lib/bundler/retry.rb +1 -1
  60. data/lib/bundler/ruby_dsl.rb +27 -0
  61. data/lib/bundler/ruby_version.rb +2 -2
  62. data/lib/bundler/rubygems_integration.rb +1 -1
  63. data/lib/bundler/self_manager.rb +2 -0
  64. data/lib/bundler/settings.rb +37 -13
  65. data/lib/bundler/source/git/git_proxy.rb +14 -2
  66. data/lib/bundler/source/git.rb +7 -0
  67. data/lib/bundler/source/rubygems.rb +22 -25
  68. data/lib/bundler/source_list.rb +0 -4
  69. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +1 -1
  70. data/lib/bundler/ui/rg_proxy.rb +1 -1
  71. data/lib/bundler/version.rb +1 -1
  72. data/lib/bundler.rb +1 -1
  73. metadata +3 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 534916a6124778247986f23f06f157b5f39564180b51361d3939265579a3ddd1
4
- data.tar.gz: f54fbf6640be1d86c63ca174873133a163a58cb3a48d4f382695bbf36ff1c959
3
+ metadata.gz: 6276990d50143a594e7e8625034add1d1168df511587dd82c74f7b93a7e66bdc
4
+ data.tar.gz: cca71ac6a7840814e8a7178ca795ed379684658b25c320e8bb67f2c022d3f2e8
5
5
  SHA512:
6
- metadata.gz: 0fee4fe07803ddf54fae1e1a0ff9cc04478ddc0180b1ace6ff43cac7183965e7478b7c580e36c34abc42cf2dc7dc581560900e3b4430cc5fd31b5faf986b2ccc
7
- data.tar.gz: 1245868925e6075dd7f1f93c66774fbefd4b25b47c5102cf101b5db561cc802723308c7064bc186f7e89beb6ab7c1aa59a234e81de113dbda529e99f515a05d4
6
+ metadata.gz: 5162fc140937170d6c3a58e7f9097cbffbcda5fa8edc96a22a14fa5c1ed548cebb8d45fc9ae9901078f4dd1ff99e6f9892f832c2b6a1f598cd34f5163e80b282
7
+ data.tar.gz: 0aea59def565fa9dc8172659891fe2e6ce7b20a033f5197e1679536c91d1102a170a3784d7a05da0255662d6d342b2d1972a437fcad919756f50321b0a6801df
data/CHANGELOG.md CHANGED
@@ -1,3 +1,48 @@
1
+ # 2.4.20 (September 27, 2023)
2
+
3
+ ## Enhancements:
4
+
5
+ - Bump actions/checkout to v4 in bundler gem template [#6966](https://github.com/rubygems/rubygems/pull/6966)
6
+ - Add support for the `ruby-3.2.2` format in the `ruby file:` Gemfile directive, and explicitly test the `3.2.2@gemset` format as rejected [#6954](https://github.com/rubygems/rubygems/pull/6954)
7
+ - Support `ruby file: ".tool-versions"` in Gemfile [#6898](https://github.com/rubygems/rubygems/pull/6898)
8
+ - Unify LockfileParser loading of SPECS section [#6933](https://github.com/rubygems/rubygems/pull/6933)
9
+ - Only check circular deps when dependency api is available, not on full index sources [#6919](https://github.com/rubygems/rubygems/pull/6919)
10
+
11
+ ## Bug fixes:
12
+
13
+ - Allow standalone mode to work on a Windows edge case [#6989](https://github.com/rubygems/rubygems/pull/6989)
14
+ - Fix `bundle outdated` crashing when both `ref` and `branch` specified for a git gem in Gemfile [#6959](https://github.com/rubygems/rubygems/pull/6959)
15
+ - Fix `bundle update --redownload` [#6924](https://github.com/rubygems/rubygems/pull/6924)
16
+ - Fixed malformed bundler version in lockfile making Bundler crash [#6920](https://github.com/rubygems/rubygems/pull/6920)
17
+ - Fix standalone install crashing when using legacy gemfiles with multiple global sources [#6918](https://github.com/rubygems/rubygems/pull/6918)
18
+ - Resolve ruby version file relative to bundle root [#6892](https://github.com/rubygems/rubygems/pull/6892)
19
+
20
+ ## Performance:
21
+
22
+ - Lazily construct fetcher debug messages [#6973](https://github.com/rubygems/rubygems/pull/6973)
23
+ - Avoid allocating empty hashes in Index [#6962](https://github.com/rubygems/rubygems/pull/6962)
24
+ - Stop allocating the same settings keys repeatedly [#6963](https://github.com/rubygems/rubygems/pull/6963)
25
+ - Improve `Bundler::Index` efficiency by removing unnecessary creation and dups [#6931](https://github.com/rubygems/rubygems/pull/6931)
26
+ - (Further) Improve Bundler::Settings#[] performance and memory usage [#6923](https://github.com/rubygems/rubygems/pull/6923)
27
+ - Don't use full indexes unnecessarily on legacy Gemfiles [#6916](https://github.com/rubygems/rubygems/pull/6916)
28
+ - Improve memory usage in Bundler::Settings, and thus improve boot time [#6884](https://github.com/rubygems/rubygems/pull/6884)
29
+
30
+ # 2.4.19 (August 17, 2023)
31
+
32
+ ## Enhancements:
33
+
34
+ - Add `file` option to `ruby` method in Gemfile [#6876](https://github.com/rubygems/rubygems/pull/6876)
35
+ - Show better error when PAT can't authenticate to a private server [#6871](https://github.com/rubygems/rubygems/pull/6871)
36
+ - Don't fallback to old dependency API when bad credentials are configured [#6869](https://github.com/rubygems/rubygems/pull/6869)
37
+
38
+ ## Bug fixes:
39
+
40
+ - Fix git source conservativeness [#6850](https://github.com/rubygems/rubygems/pull/6850)
41
+
42
+ ## Documentation:
43
+
44
+ - Clarify that `bundle info` takes a gem name [#6875](https://github.com/rubygems/rubygems/pull/6875)
45
+
1
46
  # 2.4.18 (August 2, 2023)
2
47
 
3
48
  ## Security:
@@ -4,8 +4,8 @@ module Bundler
4
4
  # Represents metadata from when the Bundler gem was built.
5
5
  module BuildMetadata
6
6
  # begin ivars
7
- @built_at = "2023-08-02".freeze
8
- @git_commit_sha = "d2e3d8e3f4".freeze
7
+ @built_at = "2023-09-27".freeze
8
+ @git_commit_sha = "de20c7e7b".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -11,7 +11,7 @@ module Bundler
11
11
  def run
12
12
  Bundler.definition.validate_runtime!
13
13
  path_option = options["path"]
14
- path_option = nil if path_option && path_option.empty?
14
+ path_option = nil if path_option&.empty?
15
15
  Bundler.settings.set_command_option :bin, path_option if options["path"]
16
16
  Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
17
17
  installer = Installer.new(Bundler.root, Bundler.definition)
@@ -33,7 +33,7 @@ module Bundler
33
33
  def default_gem_spec(gem_name)
34
34
  return unless Gem::Specification.respond_to?(:find_all_by_name)
35
35
  gem_spec = Gem::Specification.find_all_by_name(gem_name).last
36
- return gem_spec if gem_spec && gem_spec.respond_to?(:default_gem?) && gem_spec.default_gem?
36
+ gem_spec if gem_spec&.default_gem?
37
37
  end
38
38
 
39
39
  def spec_not_found(gem_name)
@@ -154,7 +154,7 @@ module Bundler
154
154
  end
155
155
 
156
156
  bin_option = options["binstubs"]
157
- bin_option = nil if bin_option && bin_option.empty?
157
+ bin_option = nil if bin_option&.empty?
158
158
  Bundler.settings.set_command_option :bin, bin_option if options["binstubs"]
159
159
 
160
160
  Bundler.settings.set_command_option_if_given :shebang, options["shebang"]
@@ -194,7 +194,7 @@ module Bundler
194
194
  end
195
195
  current_version = "#{current_spec.version}#{current_spec.git_version}"
196
196
 
197
- if dependency && dependency.specific?
197
+ if dependency&.specific?
198
198
  dependency_version = %(, requested #{dependency.requirement})
199
199
  end
200
200
 
@@ -8,12 +8,12 @@ module Bundler
8
8
  end
9
9
 
10
10
  def run
11
- platforms, ruby_version = Bundler.ui.silence do
12
- locked_ruby_version = Bundler.locked_gems && Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "")
13
- gemfile_ruby_version = Bundler.definition.ruby_version && Bundler.definition.ruby_version.single_version_string
14
- [Bundler.definition.platforms.map {|p| "* #{p}" },
15
- locked_ruby_version || gemfile_ruby_version]
11
+ ruby_version = if Bundler.locked_gems
12
+ Bundler.locked_gems.ruby_version&.gsub(/p\d+\Z/, "")
13
+ else
14
+ Bundler.definition.ruby_version&.single_version_string
16
15
  end
16
+
17
17
  output = []
18
18
 
19
19
  if options[:ruby]
@@ -23,6 +23,8 @@ module Bundler
23
23
  output << "No ruby version specified"
24
24
  end
25
25
  else
26
+ platforms = Bundler.definition.platforms.map {|p| "* #{p}" }
27
+
26
28
  output << "Your platform is: #{Gem::Platform.local}"
27
29
  output << "Your app has gems that work on these platforms:\n#{platforms.join("\n")}"
28
30
 
@@ -63,6 +63,7 @@ module Bundler
63
63
  opts = options.dup
64
64
  opts["update"] = true
65
65
  opts["local"] = options[:local]
66
+ opts["force"] = options[:redownload]
66
67
 
67
68
  Bundler.settings.set_command_option_if_given :jobs, opts["jobs"]
68
69
 
@@ -390,8 +390,8 @@ module Bundler
390
390
  both_sources.each do |name, (dep, lock_dep)|
391
391
  next if dep.nil? || lock_dep.nil?
392
392
 
393
- gemfile_source = dep.source || sources.default_source
394
- lock_source = lock_dep.source || sources.default_source
393
+ gemfile_source = dep.source || default_source
394
+ lock_source = lock_dep.source || default_source
395
395
  next if lock_source.include?(gemfile_source)
396
396
 
397
397
  gemfile_source_name = dep.source ? gemfile_source.to_gemfile : "no specified source"
@@ -671,8 +671,8 @@ module Bundler
671
671
 
672
672
  Bundler.settings.local_overrides.map do |k, v|
673
673
  spec = @dependencies.find {|s| s.name == k }
674
- source = spec && spec.source
675
- if source && source.respond_to?(:local_override!)
674
+ source = spec&.source
675
+ if source&.respond_to?(:local_override!)
676
676
  source.unlock! if @unlock[:gems].include?(spec.name)
677
677
  locals << [source, source.local_override!(v)]
678
678
  end
@@ -805,26 +805,27 @@ module Bundler
805
805
 
806
806
  def converge_specs(specs)
807
807
  converged = []
808
-
809
- deps = @dependencies.select do |dep|
810
- specs[dep].any? {|s| s.satisfies?(dep) && (!dep.source || s.source.include?(dep.source)) }
811
- end
808
+ deps = []
812
809
 
813
810
  @specs_that_changed_sources = []
814
811
 
815
812
  specs.each do |s|
813
+ name = s.name
816
814
  dep = @dependencies.find {|d| s.satisfies?(d) }
815
+ lockfile_source = s.source
817
816
 
818
- # Replace the locked dependency's source with the equivalent source from the Gemfile
819
- s.source = if dep && dep.source
820
- gemfile_source = dep.source
821
- lockfile_source = s.source
817
+ if dep
818
+ gemfile_source = dep.source || default_source
822
819
 
823
820
  @specs_that_changed_sources << s if gemfile_source != lockfile_source
821
+ deps << dep if !dep.source || lockfile_source.include?(dep.source)
822
+ @unlock[:gems] << name if lockfile_source.include?(dep.source) && lockfile_source != gemfile_source
824
823
 
825
- gemfile_source
824
+ # Replace the locked dependency's source with the equivalent source from the Gemfile
825
+ s.source = gemfile_source
826
826
  else
827
- sources.get_with_fallback(s.source)
827
+ # Replace the locked dependency's source with the default source, if the locked source is no longer in the Gemfile
828
+ s.source = default_source unless sources.get(lockfile_source)
828
829
  end
829
830
 
830
831
  next if @unlock[:sources].include?(s.source.name)
@@ -833,9 +834,9 @@ module Bundler
833
834
  if s.source.instance_of?(Source::Path) || s.source.instance_of?(Source::Gemspec)
834
835
  new_specs = begin
835
836
  s.source.specs
836
- rescue PathError, GitError
837
+ rescue PathError
837
838
  # if we won't need the source (according to the lockfile),
838
- # don't error if the path/git source isn't available
839
+ # don't error if the path source isn't available
839
840
  next if specs.
840
841
  for(requested_dependencies, false).
841
842
  none? {|locked_spec| locked_spec.source == s.source }
@@ -849,11 +850,11 @@ module Bundler
849
850
  else
850
851
  # If the spec is no longer in the path source, unlock it. This
851
852
  # commonly happens if the version changed in the gemspec
852
- @unlock[:gems] << s.name
853
+ @unlock[:gems] << name
853
854
  end
854
855
  end
855
856
 
856
- if dep.nil? && requested_dependencies.find {|d| s.name == d.name }
857
+ if dep.nil? && requested_dependencies.find {|d| name == d.name }
857
858
  @unlock[:gems] << s.name
858
859
  else
859
860
  converged << s
@@ -877,7 +878,7 @@ module Bundler
877
878
  source_requirements = if precompute_source_requirements_for_indirect_dependencies?
878
879
  all_requirements = source_map.all_requirements
879
880
  all_requirements = pin_locally_available_names(all_requirements) if @prefer_local
880
- { :default => sources.default_source }.merge(all_requirements)
881
+ { :default => default_source }.merge(all_requirements)
881
882
  else
882
883
  { :default => Source::RubygemsAggregate.new(sources, source_map) }.merge(source_map.direct_requirements)
883
884
  end
@@ -886,7 +887,7 @@ module Bundler
886
887
  source_requirements[dep.name] = sources.metadata_source
887
888
  end
888
889
 
889
- default_bundler_source = source_requirements["bundler"] || sources.default_source
890
+ default_bundler_source = source_requirements["bundler"] || default_source
890
891
 
891
892
  if @unlocking_bundler
892
893
  default_bundler_source.add_dependency_names("bundler")
@@ -899,6 +900,10 @@ module Bundler
899
900
  source_requirements
900
901
  end
901
902
 
903
+ def default_source
904
+ sources.default_source
905
+ end
906
+
902
907
  def verify_changed_sources!
903
908
  @specs_that_changed_sources.each do |s|
904
909
  if s.source.specs.search(s.name).empty?
data/lib/bundler/dsl.rb CHANGED
@@ -41,7 +41,7 @@ module Bundler
41
41
  end
42
42
 
43
43
  def eval_gemfile(gemfile, contents = nil)
44
- expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile && @gemfile.parent)
44
+ expanded_gemfile_path = Pathname.new(gemfile).expand_path(@gemfile&.parent)
45
45
  original_gemfile = @gemfile
46
46
  @gemfile = expanded_gemfile_path
47
47
  @gemfiles << expanded_gemfile_path
data/lib/bundler/env.rb CHANGED
@@ -122,7 +122,7 @@ module Bundler
122
122
  specs = Bundler.rubygems.find_name(name)
123
123
  out << [" #{name}", "(#{specs.map(&:version).join(",")})"] unless specs.empty?
124
124
  end
125
- if (exe = caller.last.split(":").first) && exe =~ %r{(exe|bin)/bundler?\z}
125
+ if (exe = caller.last.split(":").first)&.match? %r{(exe|bin)/bundler?\z}
126
126
  shebang = File.read(exe).lines.first
127
127
  shebang.sub!(/^#!\s*/, "")
128
128
  unless shebang.start_with?(Gem.ruby, "/usr/bin/env ruby")
@@ -38,9 +38,9 @@ module Bundler
38
38
 
39
39
  private
40
40
 
41
- def log_specs(debug_msg)
41
+ def log_specs(&block)
42
42
  if Bundler.ui.debug?
43
- Bundler.ui.debug debug_msg
43
+ Bundler.ui.debug yield
44
44
  else
45
45
  Bundler.ui.info ".", false
46
46
  end
@@ -15,7 +15,7 @@ module Bundler
15
15
  method.bind(self).call(*args, &blk)
16
16
  rescue NetworkDownError, CompactIndexClient::Updater::MisMatchedChecksumError => e
17
17
  raise HTTPError, e.message
18
- rescue AuthenticationRequiredError
18
+ rescue AuthenticationRequiredError, BadAuthenticationError
19
19
  # Fail since we got a 401 from the server.
20
20
  raise
21
21
  rescue HTTPError => e
@@ -35,12 +35,12 @@ module Bundler
35
35
  remaining_gems = gem_names.dup
36
36
 
37
37
  until remaining_gems.empty?
38
- log_specs "Looking up gems #{remaining_gems.inspect}"
38
+ log_specs { "Looking up gems #{remaining_gems.inspect}" }
39
39
 
40
40
  deps = begin
41
41
  parallel_compact_index_client.dependencies(remaining_gems)
42
42
  rescue TooManyRequestsError
43
- @bundle_worker.stop if @bundle_worker
43
+ @bundle_worker&.stop
44
44
  @bundle_worker = nil # reset it. Not sure if necessary
45
45
  serial_compact_index_client.dependencies(remaining_gems)
46
46
  end
@@ -49,7 +49,7 @@ module Bundler
49
49
  complete_gems.concat(deps.map(&:first)).uniq!
50
50
  remaining_gems = next_gems - complete_gems
51
51
  end
52
- @bundle_worker.stop if @bundle_worker
52
+ @bundle_worker&.stop
53
53
  @bundle_worker = nil # reset it. Not sure if necessary
54
54
 
55
55
  gem_info
@@ -60,10 +60,6 @@ module Bundler
60
60
  Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
61
61
  return nil
62
62
  end
63
- if fetch_uri.scheme == "file"
64
- Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
65
- return false
66
- end
67
63
  # Read info file checksums out of /versions, so we can know if gems are up to date
68
64
  compact_index_client.update_and_parse_checksums!
69
65
  rescue CompactIndexClient::Updater::MisMatchedChecksumError => e
@@ -24,7 +24,7 @@ module Bundler
24
24
  def specs(gem_names, full_dependency_list = [], last_spec_list = [])
25
25
  query_list = gem_names.uniq - full_dependency_list
26
26
 
27
- log_specs "Query List: #{query_list.inspect}"
27
+ log_specs { "Query List: #{query_list.inspect}" }
28
28
 
29
29
  return last_spec_list if query_list.empty?
30
30
 
@@ -41,6 +41,8 @@ module Bundler
41
41
  when Net::HTTPUnauthorized
42
42
  raise BadAuthenticationError, uri.host if uri.userinfo
43
43
  raise AuthenticationRequiredError, uri.host
44
+ when Net::HTTPForbidden
45
+ raise AuthenticationForbiddenError, uri.host
44
46
  when Net::HTTPNotFound
45
47
  raise FallbackError, "Net::HTTPNotFound: #{filtered_uri}"
46
48
  else
@@ -15,8 +15,7 @@ module Bundler
15
15
  raise BadAuthenticationError, remote_uri if remote_uri.userinfo
16
16
  raise AuthenticationRequiredError, remote_uri
17
17
  when /403/
18
- raise BadAuthenticationError, remote_uri if remote_uri.userinfo
19
- raise AuthenticationRequiredError, remote_uri
18
+ raise AuthenticationForbiddenError, remote_uri
20
19
  else
21
20
  raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>"
22
21
  end
@@ -9,6 +9,7 @@ require "rubygems/request"
9
9
  module Bundler
10
10
  # Handles all the fetching with the rubygems server
11
11
  class Fetcher
12
+ autoload :Base, File.expand_path("fetcher/base", __dir__)
12
13
  autoload :CompactIndex, File.expand_path("fetcher/compact_index", __dir__)
13
14
  autoload :Downloader, File.expand_path("fetcher/downloader", __dir__)
14
15
  autoload :Dependency, File.expand_path("fetcher/dependency", __dir__)
@@ -61,6 +62,16 @@ module Bundler
61
62
  end
62
63
  end
63
64
 
65
+ # This error is raised if HTTP authentication is correct, but lacks
66
+ # necessary permissions.
67
+ class AuthenticationForbiddenError < HTTPError
68
+ def initialize(remote_uri)
69
+ remote_uri = filter_uri(remote_uri)
70
+ super "Access token could not be authenticated for #{remote_uri}.\n" \
71
+ "Make sure it's valid and has the necessary scopes configured."
72
+ end
73
+ end
74
+
64
75
  # Exceptions classes that should bypass retry attempts. If your password didn't work the
65
76
  # first time, it's not going to the third time.
66
77
  NET_ERRORS = [:HTTPBadGateway, :HTTPBadRequest, :HTTPFailedDependency,
@@ -70,7 +81,7 @@ module Bundler
70
81
  :HTTPRequestURITooLong, :HTTPUnauthorized, :HTTPUnprocessableEntity,
71
82
  :HTTPUnsupportedMediaType, :HTTPVersionNotSupported].freeze
72
83
  FAIL_ERRORS = begin
73
- fail_errors = [AuthenticationRequiredError, BadAuthenticationError, FallbackError]
84
+ fail_errors = [AuthenticationRequiredError, BadAuthenticationError, AuthenticationForbiddenError, FallbackError]
74
85
  fail_errors << Gem::Requirement::BadRequirementError
75
86
  fail_errors.concat(NET_ERRORS.map {|e| Net.const_get(e) })
76
87
  end.freeze
@@ -124,18 +135,7 @@ module Bundler
124
135
  def specs(gem_names, source)
125
136
  index = Bundler::Index.new
126
137
 
127
- if Bundler::Fetcher.disable_endpoint
128
- @use_api = false
129
- specs = fetchers.last.specs(gem_names)
130
- else
131
- specs = []
132
- @fetchers = fetchers.drop_while do |f|
133
- !f.available? || (f.api_fetcher? && !gem_names) || !specs = f.specs(gem_names)
134
- end
135
- @use_api = false if fetchers.none?(&:api_fetcher?)
136
- end
137
-
138
- specs.each do |name, version, platform, dependencies, metadata|
138
+ fetch_specs(gem_names).each do |name, version, platform, dependencies, metadata|
139
139
  spec = if dependencies
140
140
  EndpointSpecification.new(name, version, platform, self, dependencies, metadata)
141
141
  else
@@ -148,22 +148,10 @@ module Bundler
148
148
 
149
149
  index
150
150
  rescue CertificateFailureError
151
- Bundler.ui.info "" if gem_names && use_api # newline after dots
151
+ Bundler.ui.info "" if gem_names && api_fetcher? # newline after dots
152
152
  raise
153
153
  end
154
154
 
155
- def use_api
156
- return @use_api if defined?(@use_api)
157
-
158
- fetchers.shift until fetchers.first.available?
159
-
160
- @use_api = if remote_uri.scheme == "file" || Bundler::Fetcher.disable_endpoint
161
- false
162
- else
163
- fetchers.first.api_fetcher?
164
- end
165
- end
166
-
167
155
  def user_agent
168
156
  @user_agent ||= begin
169
157
  ruby = Bundler::RubyVersion.system
@@ -199,10 +187,6 @@ module Bundler
199
187
  end
200
188
  end
201
189
 
202
- def fetchers
203
- @fetchers ||= FETCHERS.map {|f| f.new(downloader, @remote, uri) }
204
- end
205
-
206
190
  def http_proxy
207
191
  return unless uri = connection.proxy_uri
208
192
  uri.to_s
@@ -212,9 +196,36 @@ module Bundler
212
196
  "#<#{self.class}:0x#{object_id} uri=#{uri}>"
213
197
  end
214
198
 
199
+ def api_fetcher?
200
+ fetchers.first.api_fetcher?
201
+ end
202
+
215
203
  private
216
204
 
217
- FETCHERS = [CompactIndex, Dependency, Index].freeze
205
+ def available_fetchers
206
+ if Bundler::Fetcher.disable_endpoint
207
+ [Index]
208
+ elsif remote_uri.scheme == "file"
209
+ Bundler.ui.debug("Using a local server, bundler won't use the CompactIndex API")
210
+ [Index]
211
+ else
212
+ [CompactIndex, Dependency, Index]
213
+ end
214
+ end
215
+
216
+ def fetchers
217
+ @fetchers ||= available_fetchers.map {|f| f.new(downloader, @remote, uri) }.drop_while {|f| !f.available? }
218
+ end
219
+
220
+ def fetch_specs(gem_names)
221
+ fetchers.reject!(&:api_fetcher?) unless gem_names
222
+ fetchers.reject! do |f|
223
+ specs = f.specs(gem_names)
224
+ return specs if specs
225
+ true
226
+ end
227
+ []
228
+ end
218
229
 
219
230
  def cis
220
231
  env_cis = {
@@ -95,7 +95,7 @@ module Bundler
95
95
  def serialized_exception_for(e)
96
96
  <<-EOS.gsub(/^ {8}/, "")
97
97
  #{e.class}: #{e.message}
98
- #{e.backtrace && e.backtrace.join("\n ").chomp}
98
+ #{e.backtrace&.join("\n ")&.chomp}
99
99
  EOS
100
100
  end
101
101
 
@@ -21,7 +21,7 @@ module Bundler
21
21
 
22
22
  def gemspec(&block)
23
23
  gemspec = instance.gemspec
24
- block.call(gemspec) if block
24
+ block&.call(gemspec)
25
25
  gemspec
26
26
  end
27
27
  end
@@ -152,8 +152,7 @@ module Bundler
152
152
 
153
153
  def gem_push_host
154
154
  env_rubygems_host = ENV["RUBYGEMS_HOST"]
155
- env_rubygems_host = nil if
156
- env_rubygems_host && env_rubygems_host.empty?
155
+ env_rubygems_host = nil if env_rubygems_host&.empty?
157
156
 
158
157
  allowed_push_host || env_rubygems_host || "rubygems.org"
159
158
  end
@@ -218,7 +217,7 @@ module Bundler
218
217
  SharedHelpers.chdir(base) do
219
218
  outbuf = IO.popen(cmd, :err => [:child, :out], &:read)
220
219
  status = $?
221
- block.call(outbuf) if status.success? && block
220
+ block&.call(outbuf) if status.success?
222
221
  [outbuf, status]
223
222
  end
224
223
  end