bundler 2.4.7 → 2.4.9

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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +48 -0
  3. data/README.md +1 -4
  4. data/lib/bundler/build_metadata.rb +2 -2
  5. data/lib/bundler/endpoint_specification.rb +0 -4
  6. data/lib/bundler/environment_preserver.rb +2 -2
  7. data/lib/bundler/fetcher/dependency.rb +1 -5
  8. data/lib/bundler/fetcher.rb +2 -2
  9. data/lib/bundler/incomplete_specification.rb +24 -0
  10. data/lib/bundler/index.rb +2 -2
  11. data/lib/bundler/injector.rb +1 -1
  12. data/lib/bundler/installer/parallel_installer.rb +1 -14
  13. data/lib/bundler/lazy_specification.rb +4 -8
  14. data/lib/bundler/lockfile_generator.rb +1 -1
  15. data/lib/bundler/lockfile_parser.rb +11 -11
  16. data/lib/bundler/plugin.rb +1 -1
  17. data/lib/bundler/remote_specification.rb +2 -6
  18. data/lib/bundler/resolver/base.rb +5 -3
  19. data/lib/bundler/resolver.rb +6 -9
  20. data/lib/bundler/rubygems_integration.rb +1 -1
  21. data/lib/bundler/settings.rb +1 -1
  22. data/lib/bundler/setup.rb +4 -1
  23. data/lib/bundler/shared_helpers.rb +1 -1
  24. data/lib/bundler/source/git/git_proxy.rb +21 -4
  25. data/lib/bundler/source/git.rb +2 -1
  26. data/lib/bundler/source/path.rb +1 -1
  27. data/lib/bundler/source/rubygems.rb +1 -2
  28. data/lib/bundler/spec_set.rb +19 -12
  29. data/lib/bundler/templates/Executable.bundler +1 -1
  30. data/lib/bundler/templates/newgem/Gemfile.tt +1 -1
  31. data/lib/bundler/templates/newgem/Rakefile.tt +10 -0
  32. data/lib/bundler/templates/newgem/github/workflows/main.yml.tt +1 -1
  33. data/lib/bundler/templates/newgem/newgem.gemspec.tt +1 -1
  34. data/lib/bundler/uri_normalizer.rb +23 -0
  35. data/lib/bundler/vendor/pub_grub/lib/pub_grub/incompatibility.rb +0 -5
  36. data/lib/bundler/version.rb +1 -1
  37. data/lib/bundler.rb +11 -9
  38. metadata +5 -3
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a65f84ced002f9c1ab71db372d85d37f9578c02a5dc1e454ca62c895e7a4d247
4
- data.tar.gz: f5e1e1f51f2eaa82029c2129a4c703c75a6e8950370be93cc7bd802d89155bda
3
+ metadata.gz: bea219e989f6693457e01025c959a3ece35ee46c5c07df07cd06e56f475c06dd
4
+ data.tar.gz: 389b2a53b46bb41a4c95d1ed70e6d4cc3f422de3e8f73ef70067c1e6477da277
5
5
  SHA512:
6
- metadata.gz: 458454313b85996243c7c77ba6ad6fba40ec2185bf657def24c8bce61595c2bd86f973f465dfcebec1ef01130c5c784dc820710437f62de9701bb6317236b3fb
7
- data.tar.gz: e35d6b4c930214928c4480df520ef5b342107d1d25da2dbc9596591eab94e115b53c2c4432ff5513630f3d60d18c8935b415bdb2b2bbd60e40d04228b8e2d292
6
+ metadata.gz: 7f9d947e46ea956603b8893d024e6833da24b8684416b9d25376cac3279a641d6bf18bf156b67af1fa2c490020064e09eac1ae04ff759bf0945bc189298a24cb
7
+ data.tar.gz: f78b90fb696e544268cb590af87b7e6ab4d22c9918222d7d494dde6bc28c91b555af93afa0b61f8ae863a1c48f5151e0370d3443285ae45c7418745e8225f592
data/CHANGELOG.md CHANGED
@@ -1,3 +1,51 @@
1
+ # 2.4.9 (March 20, 2023)
2
+
3
+ ## Security:
4
+
5
+ - Don't recommend `--full-index` on errors [#6493](https://github.com/rubygems/rubygems/pull/6493)
6
+
7
+ ## Enhancements:
8
+
9
+ - Fix duplicated specs in some error messages [#6475](https://github.com/rubygems/rubygems/pull/6475)
10
+ - When running `bundle lock --update <name>`, checkout locked revision of unrelated git sources directly [#6459](https://github.com/rubygems/rubygems/pull/6459)
11
+ - Avoid expiring git sources when unnecessary [#6458](https://github.com/rubygems/rubygems/pull/6458)
12
+ - Use `RbSys::ExtensionTask` when creating new rust gems [#6352](https://github.com/rubygems/rubygems/pull/6352)
13
+ - Don't ignore pre-releases when there's only one candidate [#6441](https://github.com/rubygems/rubygems/pull/6441)
14
+
15
+ ## Bug fixes:
16
+
17
+ - Fix incorrect removal of ruby platform when auto-healing corrupted lockfiles [#6495](https://github.com/rubygems/rubygems/pull/6495)
18
+ - Don't consider platform specific candidates when `force_ruby_platform` set [#6442](https://github.com/rubygems/rubygems/pull/6442)
19
+ - Better deal with circular dependencies [#6330](https://github.com/rubygems/rubygems/pull/6330)
20
+
21
+ ## Documentation:
22
+
23
+ - Add debugging docs [#6387](https://github.com/rubygems/rubygems/pull/6387)
24
+ - Document our current release policy [#6450](https://github.com/rubygems/rubygems/pull/6450)
25
+
26
+ # 2.4.8 (March 8, 2023)
27
+
28
+ ## Security:
29
+
30
+ - Safe load all marshaled data [#6384](https://github.com/rubygems/rubygems/pull/6384)
31
+
32
+ ## Enhancements:
33
+
34
+ - Better suggestion when `bundler/setup` fails due to missing gems and Gemfile is not the default [#6428](https://github.com/rubygems/rubygems/pull/6428)
35
+ - Simplify the gem package file filter in the gemspec template [#6344](https://github.com/rubygems/rubygems/pull/6344)
36
+ - Auto-heal corrupted `Gemfile.lock` with no specs [#6423](https://github.com/rubygems/rubygems/pull/6423)
37
+ - Auto-heal on corrupted lockfile with missing deps [#6400](https://github.com/rubygems/rubygems/pull/6400)
38
+ - Give a better message when Gemfile branch does not exist [#6383](https://github.com/rubygems/rubygems/pull/6383)
39
+
40
+ ## Bug fixes:
41
+
42
+ - Respect --no-install option for git: sources [#6088](https://github.com/rubygems/rubygems/pull/6088)
43
+ - Fix `gems.rb` lockfile for bundler version lookup in template [#6413](https://github.com/rubygems/rubygems/pull/6413)
44
+
45
+ ## Documentation:
46
+
47
+ - Switch supporting explanations to all Ruby Central [#6419](https://github.com/rubygems/rubygems/pull/6419)
48
+
1
49
  # 2.4.7 (February 15, 2023)
2
50
 
3
51
  ## Enhancements:
data/README.md CHANGED
@@ -46,12 +46,9 @@ If you'd like to contribute to Bundler, that's awesome, and we <3 you. We've put
46
46
 
47
47
  If you'd like to request a substantial change to Bundler or its documentation, refer to the [Bundler RFC process](https://github.com/rubygems/rfcs) for more information.
48
48
 
49
- While some Bundler contributors are compensated by Ruby Together, the project maintainers make decisions independent of Ruby Together. As a project, we welcome contributions regardless of the author's affiliation with Ruby Together.
50
-
51
49
  ### Supporting
52
50
 
53
- <a href="https://rubytogether.org/"><img src="https://rubytogether.org/images/rubies.svg" width="150"></a><br>
54
- <a href="https://rubytogether.org/">Ruby Together</a> pays some Bundler maintainers for their ongoing work. As a grassroots initiative committed to supporting the critical Ruby infrastructure you rely on, Ruby Together is funded entirely by the Ruby community. Contribute today <a href="https://rubytogether.org/developers">as an individual</a> or (better yet) <a href="https://rubytogether.org/companies">as a company</a> to ensure that Bundler, RubyGems, and other shared tooling is around for years to come.
51
+ RubyGems is managed by [Ruby Central](https://rubycentral.org), a non-profit organization that supports the Ruby community through projects like this one, as well as [RubyConf](https://rubyconf.org), [RailsConf](https://railsconf.org), and [RubyGems.org](https://rubygems.org). You can support Ruby Central by attending or [sponsoring](sponsors@rubycentral.org) a conference, or by [joining as a supporting member](https://rubycentral.org/#/portal/signup).
55
52
 
56
53
  ### Code of Conduct
57
54
 
@@ -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-02-15".freeze
8
- @git_commit_sha = "5d717a27e0".freeze
7
+ @built_at = "2023-03-20".freeze
8
+ @git_commit_sha = "6f8e92bcc6".freeze
9
9
  @release = true
10
10
  # end ivars
11
11
 
@@ -26,10 +26,6 @@ module Bundler
26
26
  @platform
27
27
  end
28
28
 
29
- def identifier
30
- @__identifier ||= [name, version, platform.to_s]
31
- end
32
-
33
29
  # needed for standalone, load required_paths from local gemspec
34
30
  # after the gem is installed
35
31
  def require_paths
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Bundler
4
4
  class EnvironmentPreserver
5
- INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze
5
+ INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL"
6
6
  BUNDLER_KEYS = %w[
7
7
  BUNDLE_BIN_PATH
8
8
  BUNDLE_GEMFILE
@@ -16,7 +16,7 @@ module Bundler
16
16
  RUBYLIB
17
17
  RUBYOPT
18
18
  ].map(&:freeze).freeze
19
- BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze
19
+ BUNDLER_PREFIX = "BUNDLER_ORIG_"
20
20
 
21
21
  def self.from_env
22
22
  new(env_to_hash(ENV), BUNDLER_KEYS)
@@ -34,14 +34,10 @@ module Bundler
34
34
 
35
35
  returned_gems = spec_list.map(&:first).uniq
36
36
  specs(deps_list, full_dependency_list + returned_gems, spec_list + last_spec_list)
37
- rescue MarshalError
37
+ rescue MarshalError, HTTPError, GemspecError
38
38
  Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
39
39
  Bundler.ui.debug "could not fetch from the dependency API, trying the full index"
40
40
  nil
41
- rescue HTTPError, GemspecError
42
- Bundler.ui.info "" unless Bundler.ui.debug? # new line now that the dots are over
43
- Bundler.ui.debug "could not fetch from the dependency API\nit's suggested to retry using the full index via `bundle install --full-index`"
44
- nil
45
41
  end
46
42
 
47
43
  def dependency_specs(gem_names)
@@ -102,11 +102,11 @@ module Bundler
102
102
  uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
103
103
  if uri.scheme == "file"
104
104
  path = Bundler.rubygems.correct_for_windows_path(uri.path)
105
- Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
105
+ Bundler.safe_load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
106
106
  elsif cached_spec_path = gemspec_cached_path(spec_file_name)
107
107
  Bundler.load_gemspec(cached_spec_path)
108
108
  else
109
- Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
109
+ Bundler.safe_load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
110
110
  end
111
111
  rescue MarshalError
112
112
  raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ #
5
+ # Represents a package name that was found to be incomplete when trying to
6
+ # materialize a fresh resolution or the lockfile.
7
+ #
8
+ # Holds the actual partially complete set of specifications for the name.
9
+ # These are used so that they can be unlocked in a future resolution, and fix
10
+ # the situation.
11
+ #
12
+ class IncompleteSpecification
13
+ attr_reader :name, :partially_complete_specs
14
+
15
+ def initialize(name, partially_complete_specs = [])
16
+ @name = name
17
+ @partially_complete_specs = partially_complete_specs
18
+ end
19
+
20
+ def ==(other)
21
+ partially_complete_specs == other.partially_complete_specs
22
+ end
23
+ end
24
+ end
data/lib/bundler/index.rb CHANGED
@@ -13,8 +13,8 @@ module Bundler
13
13
  attr_reader :specs, :all_specs, :sources
14
14
  protected :specs, :all_specs
15
15
 
16
- RUBY = "ruby".freeze
17
- NULL = "\0".freeze
16
+ RUBY = "ruby"
17
+ NULL = "\0"
18
18
 
19
19
  def initialize
20
20
  @sources = []
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Bundler
4
4
  class Injector
5
- INJECTED_GEMS = "injected gems".freeze
5
+ INJECTED_GEMS = "injected gems"
6
6
 
7
7
  def self.inject(new_deps, options = {})
8
8
  injector = new(new_deps, options)
@@ -47,13 +47,6 @@ module Bundler
47
47
  dependencies.all? {|d| installed_specs.include? d.name }
48
48
  end
49
49
 
50
- # Check whether spec's dependencies are missing, which can indicate a
51
- # corrupted lockfile
52
- def dependencies_missing?(all_specs)
53
- spec_names = all_specs.map(&:name)
54
- dependencies.any? {|d| !spec_names.include? d.name }
55
- end
56
-
57
50
  # Represents only the non-development dependencies, the ones that are
58
51
  # itself and are in the total list.
59
52
  def dependencies
@@ -123,11 +116,7 @@ module Bundler
123
116
  unmet_dependencies.each do |spec, unmet_spec_dependencies|
124
117
  unmet_spec_dependencies.each do |unmet_spec_dependency|
125
118
  found = @specs.find {|s| s.name == unmet_spec_dependency.name && !unmet_spec_dependency.matches_spec?(s.spec) }
126
- if found
127
- warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}"
128
- else
129
- warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name} but missing from lockfile"
130
- end
119
+ warning << "* #{unmet_spec_dependency}, dependency of #{spec.full_name}, unsatisfied by #{found.full_name}"
131
120
  end
132
121
  end
133
122
 
@@ -224,8 +213,6 @@ module Bundler
224
213
  if spec.dependencies_installed? @specs
225
214
  spec.state = :enqueued
226
215
  worker_pool.enq spec
227
- elsif spec.dependencies_missing? @specs
228
- spec.state = :failed
229
216
  end
230
217
  end
231
218
  end
@@ -20,7 +20,7 @@ module Bundler
20
20
  end
21
21
 
22
22
  def full_name
23
- if platform == Gem::Platform::RUBY
23
+ @full_name ||= if platform == Gem::Platform::RUBY
24
24
  "#{@name}-#{@version}"
25
25
  else
26
26
  "#{@name}-#{@version}-#{platform}"
@@ -28,15 +28,15 @@ module Bundler
28
28
  end
29
29
 
30
30
  def ==(other)
31
- identifier == other.identifier
31
+ full_name == other.full_name
32
32
  end
33
33
 
34
34
  def eql?(other)
35
- identifier.eql?(other.identifier)
35
+ full_name.eql?(other.full_name)
36
36
  end
37
37
 
38
38
  def hash
39
- identifier.hash
39
+ full_name.hash
40
40
  end
41
41
 
42
42
  ##
@@ -129,10 +129,6 @@ module Bundler
129
129
  end
130
130
  end
131
131
 
132
- def identifier
133
- @__identifier ||= [name, version, platform.to_s]
134
- end
135
-
136
132
  def git_version
137
133
  return unless source.is_a?(Bundler::Source::Git)
138
134
  " #{source.revision[0..6]}"
@@ -45,7 +45,7 @@ module Bundler
45
45
  # gems with the same name, but different platform
46
46
  # are ordered consistently
47
47
  specs.sort_by(&:full_name).each do |spec|
48
- next if spec.name == "bundler".freeze
48
+ next if spec.name == "bundler"
49
49
  out << spec.to_lock
50
50
  end
51
51
  end
@@ -4,15 +4,15 @@ module Bundler
4
4
  class LockfileParser
5
5
  attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version
6
6
 
7
- BUNDLED = "BUNDLED WITH".freeze
8
- DEPENDENCIES = "DEPENDENCIES".freeze
9
- PLATFORMS = "PLATFORMS".freeze
10
- RUBY = "RUBY VERSION".freeze
11
- GIT = "GIT".freeze
12
- GEM = "GEM".freeze
13
- PATH = "PATH".freeze
14
- PLUGIN = "PLUGIN SOURCE".freeze
15
- SPECS = " specs:".freeze
7
+ BUNDLED = "BUNDLED WITH"
8
+ DEPENDENCIES = "DEPENDENCIES"
9
+ PLATFORMS = "PLATFORMS"
10
+ RUBY = "RUBY VERSION"
11
+ GIT = "GIT"
12
+ GEM = "GEM"
13
+ PATH = "PATH"
14
+ PLUGIN = "PLUGIN SOURCE"
15
+ SPECS = " specs:"
16
16
  OPTIONS = /^ ([a-z]+): (.*)$/i.freeze
17
17
  SOURCE = [GIT, GEM, PATH, PLUGIN].freeze
18
18
 
@@ -86,7 +86,7 @@ module Bundler
86
86
  send("parse_#{@state}", line)
87
87
  end
88
88
  end
89
- @specs = @specs.values.sort_by(&:identifier)
89
+ @specs = @specs.values.sort_by(&:full_name)
90
90
  rescue ArgumentError => e
91
91
  Bundler.ui.debug(e)
92
92
  raise LockfileError, "Your lockfile is unreadable. Run `rm #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` " \
@@ -199,7 +199,7 @@ module Bundler
199
199
  @current_spec.source = @current_source
200
200
  @current_source.add_dependency_names(name)
201
201
 
202
- @specs[@current_spec.identifier] = @current_spec
202
+ @specs[@current_spec.full_name] = @current_spec
203
203
  elsif spaces.size == 6
204
204
  version = version.split(",").map(&:strip) if version
205
205
  dep = Gem::Dependency.new(name, version)
@@ -15,7 +15,7 @@ module Bundler
15
15
  class UnknownSourceError < PluginError; end
16
16
  class PluginInstallError < PluginError; end
17
17
 
18
- PLUGIN_FILE_NAME = "plugins.rb".freeze
18
+ PLUGIN_FILE_NAME = "plugins.rb"
19
19
 
20
20
  module_function
21
21
 
@@ -29,12 +29,8 @@ module Bundler
29
29
  @platform = _remote_specification.platform
30
30
  end
31
31
 
32
- def identifier
33
- @__identifier ||= [name, version, @platform.to_s]
34
- end
35
-
36
32
  def full_name
37
- if @platform == Gem::Platform::RUBY
33
+ @full_name ||= if @platform == Gem::Platform::RUBY
38
34
  "#{@name}-#{@version}"
39
35
  else
40
36
  "#{@name}-#{@version}-#{@platform}"
@@ -106,7 +102,7 @@ module Bundler
106
102
  def _remote_specification
107
103
  @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @original_platform])
108
104
  @_remote_specification || raise(GemspecError, "Gemspec data for #{full_name} was" \
109
- " missing from the server! Try installing with `--full-index` as a workaround.")
105
+ " missing from the server!")
110
106
  end
111
107
 
112
108
  def method_missing(method, *args, &blk)
@@ -34,9 +34,11 @@ module Bundler
34
34
  @base[name]
35
35
  end
36
36
 
37
- def delete(specs)
38
- specs.each do |spec|
39
- @base.delete(spec)
37
+ def delete(incomplete_specs)
38
+ incomplete_specs.each do |incomplete_spec|
39
+ incomplete_spec.partially_complete_specs.each do |spec|
40
+ @base.delete(spec)
41
+ end
40
42
  end
41
43
  end
42
44
 
@@ -37,7 +37,9 @@ module Bundler
37
37
  root_version = Resolver::Candidate.new(0)
38
38
 
39
39
  @all_specs = Hash.new do |specs, name|
40
- specs[name] = source_for(name).specs.search(name).sort_by {|s| [s.version, s.platform.to_s] }
40
+ specs[name] = source_for(name).specs.search(name).reject do |s|
41
+ s.dependencies.any? {|d| d.name == name && !d.requirement.satisfied_by?(s.version) } # ignore versions that depend on themselves incorrectly
42
+ end.sort_by {|s| [s.version, s.platform.to_s] }
41
43
  end
42
44
 
43
45
  @sorted_versions = Hash.new do |candidates, package|
@@ -55,7 +57,7 @@ module Bundler
55
57
  { root_version => root_dependencies }
56
58
  else
57
59
  Hash.new do |versions, version|
58
- versions[version] = to_dependency_hash(version.dependencies, @packages)
60
+ versions[version] = to_dependency_hash(version.dependencies.reject {|d| d.name == package.name }, @packages)
59
61
  end
60
62
  end
61
63
  end
@@ -186,11 +188,6 @@ module Bundler
186
188
  package_deps = @cached_dependencies[package]
187
189
  sorted_versions = @sorted_versions[package]
188
190
  package_deps[version].map do |dep_package, dep_constraint|
189
- if package == dep_package
190
- cause = PubGrub::Incompatibility::CircularDependency.new(dep_package, dep_constraint.constraint_string)
191
- return [PubGrub::Incompatibility.new([PubGrub::Term.new(dep_constraint, true)], :cause => cause)]
192
- end
193
-
194
191
  low = high = sorted_versions.index(version)
195
192
 
196
193
  # find version low such that all >= low share the same dep
@@ -243,7 +240,7 @@ module Bundler
243
240
  ruby_specs = select_best_platform_match(specs, Gem::Platform::RUBY)
244
241
  groups << Resolver::Candidate.new(version, :specs => ruby_specs) if ruby_specs.any?
245
242
 
246
- next groups if platform_specs == ruby_specs
243
+ next groups if platform_specs == ruby_specs || package.force_ruby_platform?
247
244
 
248
245
  groups << Resolver::Candidate.new(version, :specs => platform_specs)
249
246
 
@@ -302,7 +299,7 @@ module Bundler
302
299
  end
303
300
 
304
301
  def filter_prereleases(specs, package)
305
- return specs unless package.ignores_prereleases?
302
+ return specs unless package.ignores_prereleases? && specs.size > 1
306
303
 
307
304
  specs.reject {|s| s.version.prerelease? }
308
305
  end
@@ -453,7 +453,7 @@ module Bundler
453
453
  fetcher = gem_remote_fetcher
454
454
  fetcher.headers = { "X-Gemfile-Source" => remote.original_uri.to_s } if remote.original_uri
455
455
  string = fetcher.fetch_path(path)
456
- Bundler.load_marshal(string)
456
+ Bundler.safe_load_marshal(string)
457
457
  rescue Gem::RemoteFetcher::FetchError
458
458
  # it's okay for prerelease to fail
459
459
  raise unless name == "prerelease_specs"
@@ -495,7 +495,7 @@ module Bundler
495
495
  uri = $2
496
496
  suffix = $3
497
497
  end
498
- uri = "#{uri}/" unless uri.end_with?("/")
498
+ uri = URINormalizer.normalize_suffix(uri)
499
499
  require_relative "vendored_uri"
500
500
  uri = Bundler::URI(uri)
501
501
  unless uri.absolute?
data/lib/bundler/setup.rb CHANGED
@@ -12,7 +12,10 @@ if Bundler::SharedHelpers.in_bundle?
12
12
  Bundler.ui.error e.message
13
13
  Bundler.ui.warn e.backtrace.join("\n") if ENV["DEBUG"]
14
14
  if e.is_a?(Bundler::GemNotFound)
15
- Bundler.ui.warn "Run `bundle install` to install missing gems."
15
+ suggested_cmd = "bundle install"
16
+ original_gemfile = Bundler.original_env["BUNDLE_GEMFILE"]
17
+ suggested_cmd += " --gemfile #{original_gemfile}" if original_gemfile
18
+ Bundler.ui.warn "Run `#{suggested_cmd}` to install missing gems."
16
19
  end
17
20
  exit e.status_code
18
21
  end
@@ -160,7 +160,7 @@ module Bundler
160
160
  " (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})"
161
161
  raise APIResponseMismatchError,
162
162
  "Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \
163
- "\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem."
163
+ "\nRunning `bundle update #{spec.name}` should fix the problem."
164
164
  end
165
165
 
166
166
  def pretty_dependency(dep)
@@ -28,8 +28,9 @@ module Bundler
28
28
  def initialize(command, path, extra_info = nil)
29
29
  @command = command
30
30
 
31
- msg = String.new
32
- msg << "Git error: command `#{command}` in directory #{path} has failed."
31
+ msg = String.new("Git error: command `#{command}`")
32
+ msg << " in directory #{path}" if path
33
+ msg << " has failed."
33
34
  msg << "\n#{extra_info}" if extra_info
34
35
  super msg
35
36
  end
@@ -153,9 +154,20 @@ module Bundler
153
154
  SharedHelpers.filesystem_access(path.dirname) do |p|
154
155
  FileUtils.mkdir_p(p)
155
156
  end
156
- git_retry "clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s
157
157
 
158
- extra_ref
158
+ command = ["clone", "--bare", "--no-hardlinks", "--quiet", *extra_clone_args, "--", configured_uri, path.to_s]
159
+ command_with_no_credentials = check_allowed(command)
160
+
161
+ Bundler::Retry.new("`#{command_with_no_credentials}`", [MissingGitRevisionError]).attempts do
162
+ _, err, status = capture(command, nil)
163
+ return extra_ref if status.success?
164
+
165
+ if err.include?("Could not find remote branch")
166
+ raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
167
+ else
168
+ raise GitCommandError.new(command_with_no_credentials, path, err)
169
+ end
170
+ end
159
171
  end
160
172
 
161
173
  def clone_needs_unshallow?
@@ -354,6 +366,11 @@ module Bundler
354
366
  args += ["--single-branch"]
355
367
  args.unshift("--no-tags") if supports_cloning_with_no_tags?
356
368
 
369
+ # If there's a locked revision, no need to clone any specific branch
370
+ # or tag, since we will end up checking out that locked revision
371
+ # anyways.
372
+ return args if @revision
373
+
357
374
  args += ["--branch", branch || tag] if branch || tag
358
375
  args
359
376
  end
@@ -19,7 +19,7 @@ module Bundler
19
19
  # Stringify options that could be set as symbols
20
20
  %w[ref branch tag revision].each {|k| options[k] = options[k].to_s if options[k] }
21
21
 
22
- @uri = options["uri"] || ""
22
+ @uri = URINormalizer.normalize_suffix(options["uri"] || "", :trailing_slash => false)
23
23
  @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri)
24
24
  @branch = options["branch"]
25
25
  @ref = options["ref"] || options["branch"] || options["tag"]
@@ -173,6 +173,7 @@ module Bundler
173
173
  end
174
174
 
175
175
  def install(spec, options = {})
176
+ return if Bundler.settings[:no_install]
176
177
  force = options[:force]
177
178
 
178
179
  print_using_message "Using #{version_message(spec, options[:previous_spec])} from #{self}"
@@ -11,7 +11,7 @@ module Bundler
11
11
 
12
12
  protected :original_path
13
13
 
14
- DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze
14
+ DEFAULT_GLOB = "{,*,*/*}.gemspec"
15
15
 
16
16
  def initialize(options)
17
17
  @options = options.dup
@@ -337,8 +337,7 @@ module Bundler
337
337
  end
338
338
 
339
339
  def normalize_uri(uri)
340
- uri = uri.to_s
341
- uri = "#{uri}/" unless %r{/$}.match?(uri)
340
+ uri = URINormalizer.normalize_suffix(uri.to_s)
342
341
  require_relative "../vendored_uri"
343
342
  uri = Bundler::URI(uri)
344
343
  raise ArgumentError, "The source must be an absolute URI. For example:\n" \
@@ -7,11 +7,8 @@ module Bundler
7
7
  include Enumerable
8
8
  include TSort
9
9
 
10
- attr_reader :incomplete_specs
11
-
12
- def initialize(specs, incomplete_specs = [])
10
+ def initialize(specs)
13
11
  @specs = specs
14
- @incomplete_specs = incomplete_specs
15
12
  end
16
13
 
17
14
  def for(dependencies, check = false, platforms = [nil])
@@ -24,6 +21,7 @@ module Bundler
24
21
 
25
22
  name = dep[0].name
26
23
  platform = dep[1]
24
+ incomplete = false
27
25
 
28
26
  key = [name, platform]
29
27
  next if handled.key?(key)
@@ -36,14 +34,19 @@ module Bundler
36
34
 
37
35
  specs_for_dep.first.dependencies.each do |d|
38
36
  next if d.type == :development
37
+ incomplete = true if d.name != "bundler" && lookup[d.name].empty?
39
38
  deps << [d, dep[1]]
40
39
  end
41
- elsif check
42
- @incomplete_specs += lookup[name]
40
+ else
41
+ incomplete = true
42
+ end
43
+
44
+ if incomplete && check
45
+ specs << IncompleteSpecification.new(name, lookup[name])
43
46
  end
44
47
  end
45
48
 
46
- specs
49
+ specs.uniq
47
50
  end
48
51
 
49
52
  def [](key)
@@ -75,10 +78,10 @@ module Bundler
75
78
  lookup.dup
76
79
  end
77
80
 
78
- def materialize(deps)
79
- materialized = self.for(deps, true)
81
+ def materialize(deps, platforms = [nil])
82
+ materialized = self.for(deps, true, platforms)
80
83
 
81
- SpecSet.new(materialized, incomplete_specs)
84
+ SpecSet.new(materialized)
82
85
  end
83
86
 
84
87
  # Materialize for all the specs in the spec set, regardless of what platform they're for
@@ -95,15 +98,19 @@ module Bundler
95
98
  end
96
99
 
97
100
  def incomplete_ruby_specs?(deps)
98
- self.for(deps, true, [Gem::Platform::RUBY])
101
+ return false if @specs.empty?
99
102
 
100
- @incomplete_specs.any?
103
+ materialize(deps, [Gem::Platform::RUBY]).incomplete_specs.any?
101
104
  end
102
105
 
103
106
  def missing_specs
104
107
  @specs.select {|s| s.is_a?(LazySpecification) }
105
108
  end
106
109
 
110
+ def incomplete_specs
111
+ @specs.select {|s| s.is_a?(IncompleteSpecification) }
112
+ end
113
+
107
114
  def merge(set)
108
115
  arr = sorted.dup
109
116
  set.each do |set_spec|
@@ -47,7 +47,7 @@ m = Module.new do
47
47
  def lockfile
48
48
  lockfile =
49
49
  case File.basename(gemfile)
50
- when "gems.rb" then gemfile.sub(/\.rb$/, gemfile)
50
+ when "gems.rb" then gemfile.sub(/\.rb$/, ".locked")
51
51
  else "#{gemfile}.lock"
52
52
  end
53
53
  File.expand_path(lockfile)
@@ -10,7 +10,7 @@ gem "rake", "~> 13.0"
10
10
 
11
11
  gem "rake-compiler"
12
12
  <%- if config[:ext] == 'rust' -%>
13
- gem "rb_sys"
13
+ gem "rb_sys", "~> 0.9.63"
14
14
  <%- end -%>
15
15
  <%- end -%>
16
16
  <%- if config[:test] -%>
@@ -41,6 +41,15 @@ require "standard/rake"
41
41
  <% if config[:ext] -%>
42
42
  <% default_task_names.unshift(:compile) -%>
43
43
  <% default_task_names.unshift(:clobber) unless config[:ext] == 'rust' -%>
44
+ <% if config[:ext] == 'rust' -%>
45
+ require "rb_sys/extensiontask"
46
+
47
+ task build: :compile
48
+
49
+ RbSys::ExtensionTask.new(<%= config[:name].inspect %>) do |ext|
50
+ ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
51
+ end
52
+ <% else -%>
44
53
  require "rake/extensiontask"
45
54
 
46
55
  task build: :compile
@@ -48,6 +57,7 @@ task build: :compile
48
57
  Rake::ExtensionTask.new("<%= config[:underscored_name] %>") do |ext|
49
58
  ext.lib_dir = "lib/<%= config[:namespaced_path] %>"
50
59
  end
60
+ <% end -%>
51
61
 
52
62
  <% end -%>
53
63
  <% if default_task_names.size == 1 -%>
@@ -20,7 +20,7 @@ jobs:
20
20
  - uses: actions/checkout@v3
21
21
  <%- if config[:ext] == 'rust' -%>
22
22
  - name: Set up Ruby & Rust
23
- uses: oxidize-rb/actions/setup-ruby-and-rust@main
23
+ uses: oxidize-rb/actions/setup-ruby-and-rust@v1
24
24
  with:
25
25
  ruby-version: ${{ matrix.ruby }}
26
26
  bundler-cache: true
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
30
  spec.files = Dir.chdir(__dir__) do
31
31
  `git ls-files -z`.split("\x0").reject do |f|
32
- (File.expand_path(f) == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|circleci)|appveyor)})
32
+ (File.expand_path(f) == __FILE__) || f.start_with?(*%w[bin/ test/ spec/ features/ .git .circleci appveyor])
33
33
  end
34
34
  end
35
35
  spec.bindir = "exe"
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module URINormalizer
5
+ module_function
6
+
7
+ # Normalizes uri to a consistent version, either with or without trailing
8
+ # slash.
9
+ #
10
+ # TODO: Currently gem sources are locked with a trailing slash, while git
11
+ # sources are locked without a trailing slash. This should be normalized but
12
+ # the inconsistency is there for now to avoid changing all lockfiles
13
+ # including GIT sources. We could normalize this on the next major.
14
+ #
15
+ def normalize_suffix(uri, trailing_slash: true)
16
+ if trailing_slash
17
+ uri.end_with?("/") ? uri : "#{uri}/"
18
+ else
19
+ uri.end_with?("/") ? uri.delete_suffix("/") : uri
20
+ end
21
+ end
22
+ end
23
+ end
@@ -8,9 +8,6 @@ module Bundler::PubGrub
8
8
  InvalidDependency = Struct.new(:package, :constraint) do
9
9
  end
10
10
 
11
- CircularDependency = Struct.new(:package, :constraint) do
12
- end
13
-
14
11
  NoVersions = Struct.new(:constraint) do
15
12
  end
16
13
 
@@ -66,8 +63,6 @@ module Bundler::PubGrub
66
63
  "#{terms[0].to_s(allow_every: true)} depends on #{terms[1].invert}"
67
64
  when Bundler::PubGrub::Incompatibility::InvalidDependency
68
65
  "#{terms[0].to_s(allow_every: true)} depends on unknown package #{cause.package}"
69
- when Bundler::PubGrub::Incompatibility::CircularDependency
70
- "#{terms[0].to_s(allow_every: true)} depends on itself"
71
66
  when Bundler::PubGrub::Incompatibility::NoVersions
72
67
  "no versions satisfy #{cause.constraint}"
73
68
  when Bundler::PubGrub::Incompatibility::ConflictCause
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: false
2
2
 
3
3
  module Bundler
4
- VERSION = "2.4.7".freeze
4
+ VERSION = "2.4.9".freeze
5
5
 
6
6
  def self.bundler_major_version
7
7
  @bundler_major_version ||= VERSION.split(".").first.to_i
data/lib/bundler.rb CHANGED
@@ -39,8 +39,8 @@ module Bundler
39
39
  environment_preserver.replace_with_backup
40
40
  SUDO_MUTEX = Thread::Mutex.new
41
41
 
42
- SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash].freeze
43
- SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed.".freeze
42
+ SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash, Gem::Version, Gem::Specification].freeze
43
+ SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed."
44
44
  SAFE_MARSHAL_PROC = proc do |object|
45
45
  object.tap do
46
46
  unless SAFE_MARSHAL_CLASSES.include?(object.class)
@@ -62,6 +62,7 @@ module Bundler
62
62
  autoload :GemHelpers, File.expand_path("bundler/gem_helpers", __dir__)
63
63
  autoload :GemVersionPromoter, File.expand_path("bundler/gem_version_promoter", __dir__)
64
64
  autoload :Graph, File.expand_path("bundler/graph", __dir__)
65
+ autoload :IncompleteSpecification, File.expand_path("bundler/incomplete_specification", __dir__)
65
66
  autoload :Index, File.expand_path("bundler/index", __dir__)
66
67
  autoload :Injector, File.expand_path("bundler/injector", __dir__)
67
68
  autoload :Installer, File.expand_path("bundler/installer", __dir__)
@@ -85,6 +86,7 @@ module Bundler
85
86
  autoload :StubSpecification, File.expand_path("bundler/stub_specification", __dir__)
86
87
  autoload :UI, File.expand_path("bundler/ui", __dir__)
87
88
  autoload :URICredentialsFilter, File.expand_path("bundler/uri_credentials_filter", __dir__)
89
+ autoload :URINormalizer, File.expand_path("bundler/uri_normalizer", __dir__)
88
90
 
89
91
  class << self
90
92
  def configure
@@ -506,7 +508,7 @@ EOF
506
508
  if File.file?(executable) && File.executable?(executable)
507
509
  executable
508
510
  elsif paths = ENV["PATH"]
509
- quote = '"'.freeze
511
+ quote = '"'
510
512
  paths.split(File::PATH_SEPARATOR).find do |path|
511
513
  path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote)
512
514
  executable_path = File.expand_path(executable, path)
@@ -525,12 +527,6 @@ EOF
525
527
  load_marshal(data, :marshal_proc => SAFE_MARSHAL_PROC)
526
528
  end
527
529
 
528
- def load_marshal(data, marshal_proc: nil)
529
- Marshal.load(data, marshal_proc)
530
- rescue TypeError => e
531
- raise MarshalError, "#{e.class}: #{e.message}"
532
- end
533
-
534
530
  def load_gemspec(file, validate = false)
535
531
  @gemspec_cache ||= {}
536
532
  key = File.expand_path(file)
@@ -619,6 +615,12 @@ EOF
619
615
 
620
616
  private
621
617
 
618
+ def load_marshal(data, marshal_proc: nil)
619
+ Marshal.load(data, marshal_proc)
620
+ rescue TypeError => e
621
+ raise MarshalError, "#{e.class}: #{e.message}"
622
+ end
623
+
622
624
  def eval_yaml_gemspec(path, contents)
623
625
  Kernel.require "psych"
624
626
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.7
4
+ version: 2.4.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - André Arko
@@ -22,7 +22,7 @@ authors:
22
22
  autorequire:
23
23
  bindir: exe
24
24
  cert_chain: []
25
- date: 2023-02-15 00:00:00.000000000 Z
25
+ date: 2023-03-20 00:00:00.000000000 Z
26
26
  dependencies: []
27
27
  description: Bundler manages an application's dependencies through its entire life,
28
28
  across many machines, systematically and repeatably
@@ -103,6 +103,7 @@ files:
103
103
  - lib/bundler/gem_tasks.rb
104
104
  - lib/bundler/gem_version_promoter.rb
105
105
  - lib/bundler/graph.rb
106
+ - lib/bundler/incomplete_specification.rb
106
107
  - lib/bundler/index.rb
107
108
  - lib/bundler/injector.rb
108
109
  - lib/bundler/inline.rb
@@ -266,6 +267,7 @@ files:
266
267
  - lib/bundler/ui/shell.rb
267
268
  - lib/bundler/ui/silent.rb
268
269
  - lib/bundler/uri_credentials_filter.rb
270
+ - lib/bundler/uri_normalizer.rb
269
271
  - lib/bundler/vendor/.document
270
272
  - lib/bundler/vendor/connection_pool/LICENSE
271
273
  - lib/bundler/vendor/connection_pool/lib/connection_pool.rb
@@ -379,7 +381,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
379
381
  - !ruby/object:Gem::Version
380
382
  version: 3.0.1
381
383
  requirements: []
382
- rubygems_version: 3.4.7
384
+ rubygems_version: 3.4.9
383
385
  signing_key:
384
386
  specification_version: 4
385
387
  summary: The best way to manage your application's dependencies