bundler-multilock 1.1.1 → 1.2.0

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: cac57db5334b1e1eca3b690b889b28fbb0fa0ffed4a2961ddc8208f3fc7620f1
4
- data.tar.gz: 0f80468fd6caab34bc0139aaf078cfc6b8e635237570fdcc803a46d658872515
3
+ metadata.gz: c84016021b1c7595a4e796a80de94d7df2160f016c4bdc286f1616c61bb09170
4
+ data.tar.gz: 8b8ed6c345db6beb1fdf681e603ffee395d39459fc5a81982f1457876bea4037
5
5
  SHA512:
6
- metadata.gz: aa446fe3eb1cbf6896083dee2b5063c1fd5569043b3f2d4df7572f91d1054409bb83c0a29061390d367906f1649bf3a3c646440fa7f664454be0863dedc95885
7
- data.tar.gz: 11bbaa79a07b0854150a053a83f9f3d32afe8e4ab7ffeda8936d878b1842b98f50d956941a33ecc90710cd2ca916f569e4328097c259153979addb2beac6cf75
6
+ metadata.gz: 4eb1334a6a9860cea9fbb7ece25741bc35f9dd3e44ab6a17bbf041998116445acf53173a7372f6c1f19dedf1538f1bccc0db859123493b5addae86d134f81146
7
+ data.tar.gz: 6bc840a4f41344443609f00447e87c95a89eab942446b5dd2598e55bcd15a79a7fcdb3952a4e417ce7664e50316073defdb627bba2da1b886323c0d92292d345
@@ -58,7 +58,7 @@ module Bundler
58
58
 
59
59
  # this is mostly equivalent to the built in checks in `bundle check`, but even
60
60
  # more conservative, and returns false instead of exiting on failure
61
- def base_check(lockfile_definition, log_missing: false, return_missing: false)
61
+ def base_check(lockfile_definition, log_missing: false, return_missing: false, check_missing_deps: false)
62
62
  return return_missing ? [] : false unless lockfile_definition[:lockfile].file?
63
63
 
64
64
  Multilock.prepare_block = lockfile_definition[:prepare]
@@ -83,14 +83,17 @@ module Bundler
83
83
 
84
84
  return not_installed if return_missing
85
85
 
86
- not_installed.empty? && definition.no_resolve_needed?
86
+ return false unless not_installed.empty? && definition.no_resolve_needed?
87
+ return true unless check_missing_deps
88
+
89
+ (definition.locked_gems.dependencies.values - definition.dependencies).empty?
87
90
  ensure
88
91
  Multilock.prepare_block = nil
89
92
  end
90
93
 
91
94
  # this checks for mismatches between the parent lockfile and the given lockfile,
92
95
  # and for pinned dependencies in lockfiles requiring them
93
- def check(lockfile_definition, allow_mismatched_dependencies: true)
96
+ def check(lockfile_definition)
94
97
  success = true
95
98
  proven_pinned = Set.new
96
99
  needs_pin_check = []
@@ -109,36 +112,8 @@ module Bundler
109
112
  success = false
110
113
  end
111
114
 
112
- specs = lockfile.specs.group_by(&:name)
113
- if allow_mismatched_dependencies
114
- allow_mismatched_dependencies = lockfile_definition[:allow_mismatched_dependencies]
115
- end
116
-
117
- # build list of top-level dependencies that differ from the parent lockfile,
118
- # and all _their_ transitive dependencies
119
- if allow_mismatched_dependencies
120
- transitive_dependencies = Set.new
121
- # only dependencies that differ from the parent lockfile
122
- pending_transitive_dependencies = lockfile.dependencies.reject do |name, dep|
123
- parent_lockfile.dependencies[name] == dep
124
- end.map(&:first)
125
-
126
- until pending_transitive_dependencies.empty?
127
- dep = pending_transitive_dependencies.shift
128
- next if transitive_dependencies.include?(dep)
129
-
130
- transitive_dependencies << dep
131
- platform_specs = specs[dep]
132
- unless platform_specs
133
- # should only be bundler that's missing a spec
134
- raise "Could not find spec for dependency #{dep}" unless dep == "bundler"
135
-
136
- next
137
- end
138
-
139
- pending_transitive_dependencies.concat(platform_specs.flat_map(&:dependencies).map(&:name).uniq)
140
- end
141
- end
115
+ reverse_dependencies = cache_reverse_dependencies(lockfile)
116
+ parent_reverse_dependencies = cache_reverse_dependencies(parent_lockfile)
142
117
 
143
118
  # look through top-level explicit dependencies for pinned requirements
144
119
  if lockfile_definition[:enforce_pinned_additional_dependencies]
@@ -146,7 +121,7 @@ module Bundler
146
121
  end
147
122
 
148
123
  # check for conflicting requirements (and build list of pins, in the same loop)
149
- specs.values.flatten.each do |spec|
124
+ lockfile.specs.each do |spec|
150
125
  parent_spec = lockfile_specs[parent][[spec.name, spec.platform]]
151
126
 
152
127
  if lockfile_definition[:enforce_pinned_additional_dependencies]
@@ -170,7 +145,15 @@ module Bundler
170
145
  end
171
146
 
172
147
  next if parent_spec.version == spec.version && same_source
173
- next if allow_mismatched_dependencies && transitive_dependencies.include?(spec.name)
148
+
149
+ # the version in the parent lockfile cannot possibly satisfy the requirements
150
+ # in this lockfile, and vice versa, so we assume it's intentional and allow it
151
+ unless reverse_dependencies[spec.name].satisfied_by?(parent_spec.version) ||
152
+ parent_reverse_dependencies[spec.name].satisfied_by?(spec.version)
153
+ # we're allowing it to differ from the parent, so pin check requirement comes into play
154
+ needs_pin_check << spec if lockfile_definition[:enforce_pinned_additional_dependencies]
155
+ next
156
+ end
174
157
 
175
158
  Bundler.ui.error("#{spec}#{spec.git_version} in #{lockfile_path} " \
176
159
  "does not match the parent lockfile's version " \
@@ -206,6 +189,21 @@ module Bundler
206
189
 
207
190
  private
208
191
 
192
+ def cache_reverse_dependencies(lockfile)
193
+ reverse_dependencies = Hash.new { |h, k| h[k] = Gem::Requirement.default_prerelease }
194
+
195
+ lockfile.dependencies.each_value do |spec|
196
+ reverse_dependencies[spec.name].requirements.concat(spec.requirement.requirements)
197
+ end
198
+ lockfile.specs.each do |spec|
199
+ spec.dependencies.each do |dependency|
200
+ reverse_dependencies[dependency.name].requirements.concat(dependency.requirement.requirements)
201
+ end
202
+ end
203
+
204
+ reverse_dependencies
205
+ end
206
+
209
207
  def find_pinned_dependencies(proven_pinned, dependencies)
210
208
  dependencies.each do |dependency|
211
209
  dependency.requirement.requirements.each do |requirement|
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Bundler
4
4
  module Multilock
5
- VERSION = "1.1.1"
5
+ VERSION = "1.2.0"
6
6
  end
7
7
  end
@@ -27,11 +27,6 @@ module Bundler
27
27
  # BUNDLE_LOCKFILE will still override a lockfile tagged as active
28
28
  # @param parent [String] The parent lockfile to sync dependencies from.
29
29
  # Also used for comparing enforce_pinned_additional_dependencies against.
30
- # @param allow_mismatched_dependencies [true, false]
31
- # Allows version differences in dependencies between this lockfile and
32
- # the default lockfile. Note that even with this option, only top-level
33
- # dependencies that differ from the default lockfile, and their transitive
34
- # depedencies, are allowed to mismatch.
35
30
  # @param enforce_pinned_additional_dependencies [true, false]
36
31
  # If dependencies are present in this lockfile that are not present in the
37
32
  # default lockfile, enforce that they are pinned.
@@ -44,12 +39,15 @@ module Bundler
44
39
  active: nil,
45
40
  default: nil,
46
41
  parent: nil,
47
- allow_mismatched_dependencies: true,
42
+ allow_mismatched_dependencies: nil,
48
43
  enforce_pinned_additional_dependencies: false,
49
44
  &block)
50
45
  # backcompat
51
46
  active = default if active.nil?
52
47
  Bundler.ui.warn("lockfile(default:) is deprecated. Use lockfile(active:) instead.") if default
48
+ unless allow_mismatched_dependencies.nil?
49
+ Bundler.ui.warn("lockfile(allow_mismatched_dependencies:) is deprecated.")
50
+ end
53
51
 
54
52
  active = true if active.nil? && lockfile_definitions.empty? && lockfile.nil? && gemfile.nil?
55
53
 
@@ -62,14 +60,8 @@ module Bundler
62
60
  raise ArgumentError, "Lockfile #{lockfile} is already defined"
63
61
  end
64
62
 
65
- env_lockfile = ENV["BUNDLE_LOCKFILE"]
66
- if env_lockfile
67
- unless env_lockfile.include?("/") || env_lockfile.end_with?(".lock")
68
- env_lockfile = "Gemfile.#{env_lockfile}.lock"
69
- end
70
- env_lockfile = Bundler.root.join(env_lockfile).expand_path
71
- active = env_lockfile == lockfile
72
- end
63
+ env_lockfile = ENV["BUNDLE_LOCKFILE"]&.then { |l| expand_lockfile(l) }
64
+ active = env_lockfile == lockfile if env_lockfile
73
65
 
74
66
  if active && (old_active = lockfile_definitions.find { |definition| definition[:active] })
75
67
  raise ArgumentError, "Only one lockfile (#{old_active[:lockfile]}) can be flagged as the default"
@@ -87,7 +79,6 @@ module Bundler
87
79
  active: active,
88
80
  prepare: block,
89
81
  parent: parent,
90
- allow_mismatched_dependencies: allow_mismatched_dependencies,
91
82
  enforce_pinned_additional_dependencies: enforce_pinned_additional_dependencies
92
83
  })
93
84
 
@@ -155,7 +146,6 @@ module Bundler
155
146
  require_relative "multilock/lockfile_generator"
156
147
 
157
148
  Bundler.ui.debug("Syncing to alternate lockfiles")
158
- Bundler.ui.info ""
159
149
 
160
150
  attempts = 1
161
151
 
@@ -177,8 +167,8 @@ module Bundler
177
167
  up_to_date = false
178
168
  Bundler.settings.temporary(frozen: true) do
179
169
  Bundler.ui.silence do
180
- up_to_date = checker.base_check(lockfile_definition) &&
181
- checker.check(lockfile_definition, allow_mismatched_dependencies: false)
170
+ up_to_date = checker.base_check(lockfile_definition, check_missing_deps: true) &&
171
+ checker.check(lockfile_definition)
182
172
  end
183
173
  end
184
174
  if up_to_date
@@ -310,16 +300,17 @@ module Bundler
310
300
 
311
301
  return unless lockfile_definitions.none? { |definition| definition[:active] }
312
302
 
313
- # Gemfile.lock isn't explicitly specified, otherwise it would be active
314
- default_lockfile_definition = lockfile_definitions.find do |definition|
315
- definition[:lockfile] == Bundler.default_lockfile(force_original: true)
316
- end
317
- if ENV["BUNDLE_LOCKFILE"] == Bundler.default_lockfile(force_original: true) && default_lockfile_definition
303
+ if ENV["BUNDLE_LOCKFILE"]&.then { |l| expand_lockfile(l) } ==
304
+ Bundler.default_lockfile(force_original: true)
318
305
  return
319
306
  end
320
307
 
321
308
  raise GemfileNotFound, "Could not locate lockfile #{ENV["BUNDLE_LOCKFILE"].inspect}" if ENV["BUNDLE_LOCKFILE"]
322
309
 
310
+ # Gemfile.lock isn't explicitly specified, otherwise it would be active
311
+ default_lockfile_definition = lockfile_definitions.find do |definition|
312
+ definition[:lockfile] == Bundler.default_lockfile(force_original: true)
313
+ end
323
314
  return unless default_lockfile_definition && default_lockfile_definition[:active] == false
324
315
 
325
316
  raise GemfileEvalError, "No lockfiles marked as default"
@@ -431,9 +422,16 @@ module Bundler
431
422
 
432
423
  orig_definition = definition.dup # we might need it twice
433
424
 
425
+ # install gems for the exact current version of the lockfile
426
+ # this ensures it doesn't re-resolve with only (different)
427
+ # local gems after you've pulled down an update to the lockfile
428
+ # from someone else
434
429
  if current_lockfile.exist? && install
435
430
  Bundler.settings.temporary(frozen: true) do
436
431
  current_definition = builder.to_definition(current_lockfile, {})
432
+ # if something has changed, we skip this step; it's unlocking anyway
433
+ next unless current_definition.no_resolve_needed?
434
+
437
435
  current_definition.resolve_with_cache!
438
436
  if current_definition.missing_specs.any?
439
437
  Bundler.with_default_lockfile(current_lockfile) do
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.1.1
4
+ version: 1.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Instructure
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-10-06 00:00:00.000000000 Z
11
+ date: 2023-10-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler