bundler 2.4.18 → 2.4.20

Sign up to get free protection for your applications and to get access to all the features.
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