bundler-multilock 1.3.1 → 1.3.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1a0cfa166a89e37eb6e7716c6be3f974d2c928c18c03fd2b45451f8bf1a005d6
4
- data.tar.gz: 7b9a270fa65c7d076db82aa4f3db317a74b8e888235902799661982be326dccb
3
+ metadata.gz: ba0cab59258e277e546634302417061f583bccb384c48d2573ac5565c23d436b
4
+ data.tar.gz: f0571eef5788f3299324cc39c8ca6bdeb742d7296b2a564d5511e5118e72e94c
5
5
  SHA512:
6
- metadata.gz: 1d68d41b6415bb46eff5b33d159985afdd0d65ea5492f4b753edad491116144d1f467a9e3441c9c3fa141a01db37fe1450158436113f27dc848c799396537ab1
7
- data.tar.gz: e024f799b4f52a2cce3be0025b1e0cc0165a0bedd4ce9adf157b292fe3cb6590739654ac8c2bdebf01d362f1bc0e97e62662b00b6d7e1c3be4d97621a506ee7a
6
+ metadata.gz: 92aa36d22778ef5073846af9eae61c1046be24ca103edd3b6ad4efc2ad2d99e0463e6b0750c74dc24174a16414aae64356465c957a1e85f4c214c4e42c49b3ad
7
+ data.tar.gz: 4b420871866b9be6de5e33671e63ad9741ddb17909a9899c8ed86ebe2c8b011e3e89366c99dc8c044323697636edbd9a048f8173572f5218100f3024300ff662
@@ -57,11 +57,27 @@ module Bundler
57
57
  end
58
58
 
59
59
  def specs(lockfile_name)
60
- @specs[lockfile_name] ||= parser(lockfile_name).specs.to_h do |spec|
61
- [[spec.name, spec.platform], spec]
60
+ @specs[lockfile_name] ||= begin
61
+ specs = {}
62
+ parser(lockfile_name).specs.each do |spec|
63
+ (specs[spec.name] ||= {})[spec.platform] = spec
64
+ end
65
+ specs
62
66
  end
63
67
  end
64
68
 
69
+ # sometimes a gem changes platforms with a new version, such as from aarch64-linux
70
+ # to aarch64-linux-gnu. we need to still sync it
71
+ def find_matching_spec(specs, spec)
72
+ specs = self.specs(specs) unless specs.is_a?(Hash)
73
+ platform_specs = specs[spec.name]
74
+ return unless platform_specs
75
+
76
+ parent_spec = platform_specs[spec.platform]
77
+ parent_spec ||= platform_specs.find { |platform, _| platform =~ spec.platform }&.last
78
+ parent_spec || platform_specs.find { |platform, _| platform == "ruby" }&.last
79
+ end
80
+
65
81
  # @param lockfile_name [Pathname]
66
82
  # @return [Hash<String, Set<String>>] hash of gem name to set of gem names that depend on it
67
83
  def reverse_dependencies(lockfile_name)
@@ -88,7 +88,7 @@ module Bundler
88
88
 
89
89
  # this checks for mismatches between the parent lockfile and the given lockfile,
90
90
  # and for pinned dependencies in lockfiles requiring them
91
- def deep_check(lockfile_definition)
91
+ def deep_check(lockfile_definition, conflicts: nil)
92
92
  lockfile_name = lockfile_definition[:lockfile]
93
93
  @cache.deep_check(lockfile_name) do
94
94
  success = true
@@ -120,7 +120,7 @@ module Bundler
120
120
 
121
121
  # check for conflicting requirements (and build list of pins, in the same loop)
122
122
  parser.specs.each do |spec|
123
- parent_spec = @cache.specs(parent_lockfile_name)[[spec.name, spec.platform]]
123
+ parent_spec = @cache.find_matching_spec(parent_lockfile_name, spec)
124
124
 
125
125
  if lockfile_definition[:enforce_pinned_additional_dependencies]
126
126
  # look through what this spec depends on, and keep track of all pinned requirements
@@ -156,6 +156,7 @@ module Bundler
156
156
  "does not match the parent lockfile's version " \
157
157
  "(@#{parent_spec.version}#{parent_spec.git_version}); " \
158
158
  "this may be due to a conflicting requirement, which would require manual resolution.")
159
+ conflicts&.add(spec.name)
159
160
  success = false
160
161
  end
161
162
 
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Bundler
4
+ module Multilock
5
+ module Ext
6
+ module CLI
7
+ module ClassMethods
8
+ def instance
9
+ return @instance if instance_variable_defined?(:@instance)
10
+
11
+ # this is a little icky, but there's no other way to determine which command was run
12
+ @instance = ObjectSpace.each_object(::Bundler::CLI).first
13
+ end
14
+ end
15
+
16
+ ::Bundler::CLI.extend(ClassMethods)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "delegate"
4
+
3
5
  require "bundler/lockfile_generator"
4
6
 
5
7
  module Bundler
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module Multilock
5
- VERSION = "1.3.1"
5
+ VERSION = "1.3.3"
6
6
  end
7
7
  end
@@ -82,17 +82,13 @@ module Bundler
82
82
  enforce_pinned_additional_dependencies: enforce_pinned_additional_dependencies
83
83
  })
84
84
 
85
- if (defined?(CLI::Check) ||
86
- defined?(CLI::Install) ||
87
- defined?(CLI::Lock) ||
88
- defined?(CLI::Update)) &&
89
- !defined?(CLI::Cache) && !env_lockfile
85
+ # If they're using BUNDLE_LOCKFILE, then they really do want to
86
+ # use a particular lockfile, and it overrides whatever they
87
+ # dynamically set in their gemfile
88
+ if !env_lockfile && defined?(CLI) &&
89
+ %i[check install lock update].include?(CLI.instance&.current_command_chain&.first)
90
90
  # always use Gemfile.lock for `bundle check`, `bundle install`,
91
- # `bundle lock`, and `bundle update`. `bundle cache` delegates to
92
- # `bundle install`, but we want that to run as normal.
93
- # If they're using BUNDLE_LOCKFILE, then they really do want to
94
- # use a particular lockfile, and it overrides whatever they
95
- # dynamically set in their gemfile
91
+ # `bundle lock`, and `bundle update`.
96
92
  active = lockfile == Bundler.default_lockfile(force_original: true)
97
93
  end
98
94
 
@@ -179,10 +175,11 @@ module Bundler
179
175
 
180
176
  # already up to date?
181
177
  up_to_date = false
178
+ conflicts = Set.new
182
179
  Bundler.settings.temporary(frozen: true) do
183
180
  Bundler.ui.silence do
184
181
  up_to_date = checker.base_check(lockfile_definition, check_missing_deps: true) &&
185
- checker.deep_check(lockfile_definition)
182
+ checker.deep_check(lockfile_definition, conflicts: conflicts)
186
183
  end
187
184
  end
188
185
  if up_to_date
@@ -206,7 +203,6 @@ module Bundler
206
203
  Bundler.ui.info("Syncing to #{relative_lockfile}...") if attempts == 1
207
204
  synced_any = true
208
205
 
209
- specs = lockfile_name.exist? ? cache.specs(lockfile_name) : {}
210
206
  parent_lockfile_name = lockfile_definition[:parent]
211
207
  parent_root = parent_lockfile_name.dirname
212
208
  parent_specs = cache.specs(parent_lockfile_name)
@@ -222,7 +218,7 @@ module Bundler
222
218
  end
223
219
 
224
220
  # add a source for the current gem
225
- gem_spec = parent_specs[[File.basename(Bundler.root), "ruby"]]
221
+ gem_spec = parent_specs.dig(File.basename(Bundler.root), "ruby")
226
222
 
227
223
  if gem_spec
228
224
  adjusted_parent_lockfile_contents += <<~TEXT
@@ -252,39 +248,30 @@ module Bundler
252
248
  next :self if parent_spec.nil?
253
249
  next spec_precedences[spec.name] if spec_precedences.key?(spec.name)
254
250
 
255
- precedence = :self if cache.conflicting_requirements?(lockfile_name,
256
- parent_lockfile_name,
257
- spec,
258
- parent_spec)
259
-
260
- # look through all reverse dependencies; if any of them say it
261
- # has to come from self, due to conflicts, then this gem has
262
- # to come from self as well
263
- [cache.reverse_dependencies(lockfile_name),
264
- cache.reverse_dependencies(parent_lockfile_name)].each do |reverse_dependencies|
265
- break if precedence == :self
266
-
267
- reverse_dependencies[spec.name].each do |dep_name|
268
- precedence = check_precedence.call(specs[dep_name], parent_specs[dep_name])
269
- break if precedence == :self
270
- end
271
- end
251
+ precedence = if !(cache.reverse_dependencies(lockfile_name)[spec.name] & conflicts).empty?
252
+ :parent
253
+ elsif cache.conflicting_requirements?(lockfile_name,
254
+ parent_lockfile_name,
255
+ spec,
256
+ parent_spec)
257
+ :self
258
+ end
272
259
 
273
260
  spec_precedences[spec.name] = precedence || :parent
274
261
  end
275
262
 
263
+ lockfile.sources.map! do |source|
264
+ parent_lockfile.sources.find { |s| s == source } || source
265
+ end
276
266
  # replace any duplicate specs with what's in the parent lockfile
277
267
  lockfile.specs.map! do |spec|
278
- parent_spec = parent_specs[[spec.name, spec.platform]]
268
+ parent_spec = cache.find_matching_spec(parent_specs, spec)
279
269
  next spec unless parent_spec
280
-
281
270
  next spec if check_precedence.call(spec, parent_spec) == :self
282
271
 
283
272
  dependency_changes ||= spec != parent_spec
284
273
 
285
- new_spec = parent_spec.dup
286
- new_spec.source = spec.source
287
- new_spec
274
+ parent_spec
288
275
  end
289
276
 
290
277
  lockfile.platforms.replace(parent_lockfile.platforms).uniq!
@@ -497,6 +484,13 @@ module Bundler
497
484
  # from someone else
498
485
  if current_lockfile.exist? && install
499
486
  Bundler.settings.temporary(frozen: true) do
487
+ # it keeps the same sources as the builder, which now shares with
488
+ # `definition` above; give it its own copy to avoid stomping on it
489
+ builder.instance_variable_set(
490
+ :@sources,
491
+ builder.instance_variable_get(:@sources).dup
492
+ )
493
+
500
494
  current_definition = builder.to_definition(current_lockfile, {})
501
495
  # if something has changed, we skip this step; it's unlocking anyway
502
496
  next unless current_definition.no_resolve_needed?
@@ -518,6 +512,14 @@ module Bundler
518
512
  previous_ui_level = Bundler.ui.level
519
513
  Bundler.ui.level = "warn"
520
514
  begin
515
+ # force a remote resolution if intermediate gems are missing
516
+ if definition.instance_variable_get(:@locked_spec_with_missing_deps) ||
517
+ definition.instance_variable_get(:@locked_spec_with_invalid_deps) ||
518
+ definition.instance_variable_get(:@missing_lockfile_dep) ||
519
+ definition.instance_variable_get(:@invalid_lockfile_dep)
520
+ raise SolveFailure
521
+ end
522
+
521
523
  # this is a horrible hack, to fix what I consider to be a Bundler bug.
522
524
  # basically, if you have multiple platform specific gems in your
523
525
  # lockfile, and that gem gets unlocked, Bundler will only search
@@ -577,25 +579,29 @@ end
577
579
  Bundler::LazySpecification.include(Bundler::MatchMetadata) if defined?(Bundler::MatchMetadata)
578
580
  Bundler::Multilock.inject_preamble unless Bundler::Multilock.loaded?
579
581
 
580
- # this is terrible, but we can't prepend into these modules because we only load
581
- # _inside_ of the CLI commands already running
582
- if defined?(Bundler::CLI::Check)
583
- require_relative "multilock/check"
584
- at_exit do
585
- next unless $!.nil?
586
- next if $!.is_a?(SystemExit) && !$!.success?
582
+ if defined?(Bundler::CLI)
583
+ require_relative "multilock/ext/cli"
584
+
585
+ # this is terrible, but we can't prepend into these modules because we only load
586
+ # _inside_ of the CLI commands already running
587
+ if Bundler::CLI.instance&.current_command_chain&.first == :check
588
+ require_relative "multilock/check"
589
+ at_exit do
590
+ next unless $!.nil?
591
+ next if $!.is_a?(SystemExit) && !$!.success?
587
592
 
588
- next if Bundler::Multilock::Check.run
593
+ next if Bundler::Multilock::Check.run
589
594
 
590
- Bundler.ui.warn("You can attempt to fix by running `bundle install`")
591
- exit 1
595
+ Bundler.ui.warn("You can attempt to fix by running `bundle install`")
596
+ exit 1
597
+ end
592
598
  end
593
- end
594
- if defined?(Bundler::CLI::Lock)
595
- at_exit do
596
- next unless $!.nil?
597
- next if $!.is_a?(SystemExit) && !$!.success?
599
+ if Bundler::CLI.instance&.current_command_chain&.first == :lock
600
+ at_exit do
601
+ next unless $!.nil?
602
+ next if $!.is_a?(SystemExit) && !$!.success?
598
603
 
599
- Bundler::Multilock.after_install_all(install: false)
604
+ Bundler::Multilock.after_install_all(install: false)
605
+ end
600
606
  end
601
607
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bundler-multilock
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-04-25 00:00:00.000000000 Z
11
+ date: 2024-06-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -82,6 +82,7 @@ files:
82
82
  - lib/bundler/multilock/cache.rb
83
83
  - lib/bundler/multilock/check.rb
84
84
  - lib/bundler/multilock/ext/bundler.rb
85
+ - lib/bundler/multilock/ext/cli.rb
85
86
  - lib/bundler/multilock/ext/definition.rb
86
87
  - lib/bundler/multilock/ext/dsl.rb
87
88
  - lib/bundler/multilock/ext/plugin.rb
@@ -113,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
113
114
  - !ruby/object:Gem::Version
114
115
  version: '0'
115
116
  requirements: []
116
- rubygems_version: 3.5.9
117
+ rubygems_version: 3.5.14
117
118
  signing_key:
118
119
  specification_version: 4
119
120
  summary: Support Multiple Lockfiles