bundler-multilock 1.0.11 → 1.1.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 +4 -4
- data/lib/bundler/multilock/check.rb +39 -25
- data/lib/bundler/multilock/ext/shared_helpers.rb +28 -0
- data/lib/bundler/multilock/ext/source.rb +17 -0
- data/lib/bundler/multilock/version.rb +1 -1
- data/lib/bundler/multilock.rb +145 -74
- data/plugins.rb +0 -23
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 12e431ea7783f9bc36d1efae8aaeda88434936f587c954c34ad4163b3338dc44
|
4
|
+
data.tar.gz: 8eda2e0bc8f785b0ceefb312d4d34c6fd754dab58c835ec7b818c551af903bdf
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3fea018e198880d1c2a7dcaa635faa1ccff9b65d46bbb72c15cb153dd20acf34dfb833189bd1c4f3dd04f3053b23e2220ca769b101806e2b99a3ddc92097675c
|
7
|
+
data.tar.gz: 80095ec510ebefa11c457ef13c45bc0af40b6961b1ffff54c0724f5010cd72b6fa512f3de11155a6883db71dd6dc87322c6fbef314d5b7c61e99572e4fe77b43
|
@@ -5,6 +5,8 @@ require "set"
|
|
5
5
|
module Bundler
|
6
6
|
module Multilock
|
7
7
|
class Check
|
8
|
+
attr_reader :lockfiles, :lockfile_contents, :lockfile_specs
|
9
|
+
|
8
10
|
class << self
|
9
11
|
def run
|
10
12
|
new.run
|
@@ -12,23 +14,32 @@ module Bundler
|
|
12
14
|
end
|
13
15
|
|
14
16
|
def initialize
|
15
|
-
|
16
|
-
@
|
17
|
-
@
|
17
|
+
@lockfiles = {}
|
18
|
+
@lockfile_contents = {}
|
19
|
+
@lockfile_specs = {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def load_lockfile(lockfile)
|
23
|
+
return if lockfile_contents.key?(lockfile)
|
24
|
+
|
25
|
+
contents = lockfile_contents[lockfile] = lockfile.read.freeze
|
26
|
+
parser = lockfiles[lockfile] = LockfileParser.new(contents)
|
27
|
+
lockfile_specs[lockfile] = parser.specs.to_h do |spec|
|
18
28
|
[[spec.name, spec.platform], spec]
|
19
29
|
end
|
20
30
|
end
|
21
31
|
|
22
32
|
def run(skip_base_checks: false)
|
23
|
-
return true unless Bundler.default_lockfile.exist?
|
33
|
+
return true unless Bundler.default_lockfile(force_original: true).exist?
|
24
34
|
|
25
35
|
success = true
|
26
36
|
unless skip_base_checks
|
27
|
-
missing_specs = base_check({ gemfile: Bundler.default_gemfile,
|
37
|
+
missing_specs = base_check({ gemfile: Bundler.default_gemfile,
|
38
|
+
lockfile: Bundler.default_lockfile(force_original: true) },
|
28
39
|
return_missing: true).to_set
|
29
40
|
end
|
30
41
|
Multilock.lockfile_definitions.each do |lockfile_definition|
|
31
|
-
next if lockfile_definition[:lockfile] == Bundler.default_lockfile
|
42
|
+
next if lockfile_definition[:lockfile] == Bundler.default_lockfile(force_original: true)
|
32
43
|
|
33
44
|
unless lockfile_definition[:lockfile].exist?
|
34
45
|
Bundler.ui.error("Lockfile #{lockfile_definition[:lockfile]} does not exist.")
|
@@ -77,7 +88,7 @@ module Bundler
|
|
77
88
|
Multilock.prepare_block = nil
|
78
89
|
end
|
79
90
|
|
80
|
-
# this checks for mismatches between the
|
91
|
+
# this checks for mismatches between the parent lockfile and the given lockfile,
|
81
92
|
# and for pinned dependencies in lockfiles requiring them
|
82
93
|
def check(lockfile_definition, allow_mismatched_dependencies: true)
|
83
94
|
success = true
|
@@ -85,13 +96,16 @@ module Bundler
|
|
85
96
|
needs_pin_check = []
|
86
97
|
lockfile = LockfileParser.new(lockfile_definition[:lockfile].read)
|
87
98
|
lockfile_path = lockfile_definition[:lockfile].relative_path_from(Dir.pwd)
|
88
|
-
|
89
|
-
|
99
|
+
parent = lockfile_definition[:parent]
|
100
|
+
load_lockfile(parent)
|
101
|
+
parent_lockfile = lockfiles[parent]
|
102
|
+
unless lockfile.platforms == parent_lockfile.platforms
|
103
|
+
Bundler.ui.error("The platforms in #{lockfile_path} do not match the parent lockfile.")
|
90
104
|
success = false
|
91
105
|
end
|
92
|
-
unless lockfile.bundler_version ==
|
106
|
+
unless lockfile.bundler_version == parent_lockfile.bundler_version
|
93
107
|
Bundler.ui.error("bundler (#{lockfile.bundler_version}) in #{lockfile_path} " \
|
94
|
-
"does not match the
|
108
|
+
"does not match the parent lockfile's version (@#{parent_lockfile.bundler_version}).")
|
95
109
|
success = false
|
96
110
|
end
|
97
111
|
|
@@ -100,13 +114,13 @@ module Bundler
|
|
100
114
|
allow_mismatched_dependencies = lockfile_definition[:allow_mismatched_dependencies]
|
101
115
|
end
|
102
116
|
|
103
|
-
# build list of top-level dependencies that differ from the
|
117
|
+
# build list of top-level dependencies that differ from the parent lockfile,
|
104
118
|
# and all _their_ transitive dependencies
|
105
119
|
if allow_mismatched_dependencies
|
106
120
|
transitive_dependencies = Set.new
|
107
|
-
# only dependencies that differ from the
|
121
|
+
# only dependencies that differ from the parent lockfile
|
108
122
|
pending_transitive_dependencies = lockfile.dependencies.reject do |name, dep|
|
109
|
-
|
123
|
+
parent_lockfile.dependencies[name] == dep
|
110
124
|
end.map(&:first)
|
111
125
|
|
112
126
|
until pending_transitive_dependencies.empty?
|
@@ -133,40 +147,40 @@ module Bundler
|
|
133
147
|
|
134
148
|
# check for conflicting requirements (and build list of pins, in the same loop)
|
135
149
|
specs.values.flatten.each do |spec|
|
136
|
-
|
150
|
+
parent_spec = lockfile_specs[parent][[spec.name, spec.platform]]
|
137
151
|
|
138
152
|
if lockfile_definition[:enforce_pinned_additional_dependencies]
|
139
153
|
# look through what this spec depends on, and keep track of all pinned requirements
|
140
154
|
find_pinned_dependencies(proven_pinned, spec.dependencies)
|
141
155
|
|
142
|
-
needs_pin_check << spec unless
|
156
|
+
needs_pin_check << spec unless parent_spec
|
143
157
|
end
|
144
158
|
|
145
|
-
next unless
|
159
|
+
next unless parent_spec
|
146
160
|
|
147
161
|
# have to ensure Path sources are relative to their lockfile before comparing
|
148
|
-
same_source = if [
|
162
|
+
same_source = if [parent_spec.source, spec.source].grep(Source::Path).length == 2
|
149
163
|
lockfile_definition[:lockfile]
|
150
164
|
.dirname
|
151
165
|
.join(spec.source.path)
|
152
166
|
.ascend
|
153
|
-
.any?(
|
167
|
+
.any?(parent.dirname.join(parent_spec.source.path))
|
154
168
|
else
|
155
|
-
|
169
|
+
parent_spec.source == spec.source
|
156
170
|
end
|
157
171
|
|
158
|
-
next if
|
172
|
+
next if parent_spec.version == spec.version && same_source
|
159
173
|
next if allow_mismatched_dependencies && transitive_dependencies.include?(spec.name)
|
160
174
|
|
161
175
|
Bundler.ui.error("#{spec}#{spec.git_version} in #{lockfile_path} " \
|
162
|
-
"does not match the
|
163
|
-
"(@#{
|
176
|
+
"does not match the parent lockfile's version " \
|
177
|
+
"(@#{parent_spec.version}#{parent_spec.git_version}); " \
|
164
178
|
"this may be due to a conflicting requirement, which would require manual resolution.")
|
165
179
|
success = false
|
166
180
|
end
|
167
181
|
|
168
182
|
# now that we have built a list of every gem that is pinned, go through
|
169
|
-
# the gems that were in this lockfile, but not the
|
183
|
+
# the gems that were in this lockfile, but not the parent lockfile, and
|
170
184
|
# ensure it's pinned _somehow_
|
171
185
|
needs_pin_check.each do |spec|
|
172
186
|
pinned = case spec.source
|
@@ -183,7 +197,7 @@ module Bundler
|
|
183
197
|
next if pinned
|
184
198
|
|
185
199
|
Bundler.ui.error("#{spec} in #{lockfile_path} has not been pinned to a specific version, " \
|
186
|
-
"which is required since it is not part of the
|
200
|
+
"which is required since it is not part of the parent lockfile.")
|
187
201
|
success = false
|
188
202
|
end
|
189
203
|
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
module Multilock
|
5
|
+
module Ext
|
6
|
+
module SharedHeleprs
|
7
|
+
module ClassMethods
|
8
|
+
::Bundler::SharedHelpers.singleton_class.prepend(self)
|
9
|
+
::Bundler::SharedHelpers.instance_variable_set(:@filesystem_accesses, nil)
|
10
|
+
|
11
|
+
def capture_filesystem_access
|
12
|
+
@filesystem_accesses = []
|
13
|
+
yield
|
14
|
+
@filesystem_accesses
|
15
|
+
ensure
|
16
|
+
@filesystem_accesses = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def filesystem_access(path, action = :write)
|
20
|
+
@filesystem_accesses << [path, action] if @filesystem_accesses
|
21
|
+
|
22
|
+
super
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Bundler
|
4
|
+
module Multilock
|
5
|
+
module Ext
|
6
|
+
module Source
|
7
|
+
::Bundler::Source.prepend(self)
|
8
|
+
|
9
|
+
def print_using_message(...)
|
10
|
+
return if Bundler.settings[:suppress_install_using_messages]
|
11
|
+
|
12
|
+
super
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
data/lib/bundler/multilock.rb
CHANGED
@@ -5,6 +5,8 @@ require_relative "multilock/ext/definition"
|
|
5
5
|
require_relative "multilock/ext/dsl"
|
6
6
|
require_relative "multilock/ext/plugin"
|
7
7
|
require_relative "multilock/ext/plugin/dsl"
|
8
|
+
require_relative "multilock/ext/shared_helpers"
|
9
|
+
require_relative "multilock/ext/source"
|
8
10
|
require_relative "multilock/ext/source_list"
|
9
11
|
require_relative "multilock/version"
|
10
12
|
|
@@ -20,8 +22,11 @@ module Bundler
|
|
20
22
|
# @param builder [Dsl] The Bundler DSL
|
21
23
|
# @param gemfile [String, nil]
|
22
24
|
# The Gemfile for this lockfile (defaults to Gemfile)
|
23
|
-
# @param
|
25
|
+
# @param active [Boolean]
|
24
26
|
# If this lockfile should be the default (instead of Gemfile.lock)
|
27
|
+
# BUNDLE_LOCKFILE will still override a lockfile tagged as active
|
28
|
+
# @param parent [String] The parent lockfile to sync dependencies from.
|
29
|
+
# Also used for comparing enforce_pinned_additional_dependencies against.
|
25
30
|
# @param allow_mismatched_dependencies [true, false]
|
26
31
|
# Allows version differences in dependencies between this lockfile and
|
27
32
|
# the default lockfile. Note that even with this option, only top-level
|
@@ -32,34 +37,30 @@ module Bundler
|
|
32
37
|
# default lockfile, enforce that they are pinned.
|
33
38
|
# @yield
|
34
39
|
# Block executed only when this lockfile is active.
|
35
|
-
# @return [true, false] if the lockfile is the
|
40
|
+
# @return [true, false] if the lockfile is the active lockfile
|
36
41
|
def add_lockfile(lockfile = nil,
|
37
42
|
builder:,
|
38
43
|
gemfile: nil,
|
44
|
+
active: nil,
|
39
45
|
default: nil,
|
46
|
+
parent: nil,
|
40
47
|
allow_mismatched_dependencies: true,
|
41
48
|
enforce_pinned_additional_dependencies: false,
|
42
49
|
&block)
|
43
|
-
#
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
current = true if current.nil? && lockfile_definitions.empty? && lockfile.nil? && gemfile.nil?
|
50
|
+
# backcompat
|
51
|
+
active = default if active.nil?
|
52
|
+
Bundler.ui.warn("lockfile(default:) is deprecated. Use lockfile(active:) instead.") if default
|
53
|
+
|
54
|
+
active = true if active.nil? && lockfile_definitions.empty? && lockfile.nil? && gemfile.nil?
|
49
55
|
|
50
|
-
# allow short-form lockfile names
|
51
|
-
if lockfile.is_a?(String) && !(lockfile.include?("/") || lockfile.end_with?(".lock"))
|
52
|
-
lockfile = "Gemfile.#{lockfile}.lock"
|
53
|
-
end
|
54
56
|
# if a gemfile was provided, but not a lockfile, infer the default lockfile for that gemfile
|
55
57
|
lockfile ||= "#{gemfile}.lock" if gemfile
|
56
|
-
#
|
57
|
-
lockfile =
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
end
|
58
|
+
# allow short-form lockfile names
|
59
|
+
lockfile = expand_lockfile(lockfile)
|
60
|
+
|
61
|
+
if lockfile_definitions.find { |definition| definition[:lockfile] == lockfile }
|
62
|
+
raise ArgumentError, "Lockfile #{lockfile} is already defined"
|
63
|
+
end
|
63
64
|
|
64
65
|
env_lockfile = ENV["BUNDLE_LOCKFILE"]
|
65
66
|
if env_lockfile
|
@@ -67,18 +68,25 @@ module Bundler
|
|
67
68
|
env_lockfile = "Gemfile.#{env_lockfile}.lock"
|
68
69
|
end
|
69
70
|
env_lockfile = Bundler.root.join(env_lockfile).expand_path
|
70
|
-
|
71
|
+
active = env_lockfile == lockfile
|
72
|
+
end
|
73
|
+
|
74
|
+
if active && (old_active = lockfile_definitions.find { |definition| definition[:active] })
|
75
|
+
raise ArgumentError, "Only one lockfile (#{old_active[:lockfile]}) can be flagged as the default"
|
71
76
|
end
|
72
77
|
|
73
|
-
|
74
|
-
|
78
|
+
parent = expand_lockfile(parent)
|
79
|
+
if parent != Bundler.default_lockfile(force_original: true) &&
|
80
|
+
!lockfile_definitions.find { |definition| definition[:lockfile] == parent }
|
81
|
+
raise ArgumentError, "Parent lockfile #{parent} is not defined"
|
75
82
|
end
|
76
83
|
|
77
84
|
lockfile_definitions << (lockfile_def = {
|
78
85
|
gemfile: (gemfile && Bundler.root.join(gemfile).expand_path) || Bundler.default_gemfile,
|
79
86
|
lockfile: lockfile,
|
80
|
-
|
87
|
+
active: active,
|
81
88
|
prepare: block,
|
89
|
+
parent: parent,
|
82
90
|
allow_mismatched_dependencies: allow_mismatched_dependencies,
|
83
91
|
enforce_pinned_additional_dependencies: enforce_pinned_additional_dependencies
|
84
92
|
})
|
@@ -94,10 +102,10 @@ module Bundler
|
|
94
102
|
# If they're using BUNDLE_LOCKFILE, then they really do want to
|
95
103
|
# use a particular lockfile, and it overrides whatever they
|
96
104
|
# dynamically set in their gemfile
|
97
|
-
|
105
|
+
active = lockfile == Bundler.default_lockfile(force_original: true)
|
98
106
|
end
|
99
107
|
|
100
|
-
if
|
108
|
+
if active
|
101
109
|
block&.call
|
102
110
|
Bundler.default_lockfile = lockfile
|
103
111
|
|
@@ -146,16 +154,13 @@ module Bundler
|
|
146
154
|
require "tempfile"
|
147
155
|
require_relative "multilock/lockfile_generator"
|
148
156
|
|
157
|
+
Bundler.ui.debug("Syncing to alternate lockfiles")
|
149
158
|
Bundler.ui.info ""
|
150
159
|
|
151
|
-
default_lockfile_contents = Bundler.default_lockfile.read.freeze
|
152
|
-
default_specs = LockfileParser.new(default_lockfile_contents).specs.to_h do |spec|
|
153
|
-
[[spec.name, spec.platform], spec]
|
154
|
-
end
|
155
|
-
default_root = Bundler.root
|
156
|
-
|
157
160
|
attempts = 1
|
158
161
|
|
162
|
+
default_root = Bundler.root
|
163
|
+
|
159
164
|
checker = Check.new
|
160
165
|
synced_any = false
|
161
166
|
Bundler.settings.temporary(cache_all_platforms: true, suppress_install_using_messages: true) do
|
@@ -196,21 +201,26 @@ module Bundler
|
|
196
201
|
Bundler.ui.info("Syncing to #{relative_lockfile}...") if attempts == 1
|
197
202
|
synced_any = true
|
198
203
|
|
199
|
-
|
200
|
-
|
201
|
-
|
204
|
+
parent = lockfile_definition[:parent]
|
205
|
+
parent_root = parent.dirname
|
206
|
+
checker.load_lockfile(parent)
|
207
|
+
parent_specs = checker.lockfile_specs[parent]
|
208
|
+
|
209
|
+
# adjust locked paths from the parent lockfile to be relative to _this_ gemfile
|
210
|
+
adjusted_parent_lockfile_contents =
|
211
|
+
checker.lockfile_contents[parent].gsub(/PATH\n remote: ([^\n]+)\n/) do |remote|
|
202
212
|
remote_path = Pathname.new($1)
|
203
213
|
next remote if remote_path.absolute?
|
204
214
|
|
205
|
-
relative_remote_path = remote_path.expand_path(
|
215
|
+
relative_remote_path = remote_path.expand_path(parent_root).relative_path_from(Bundler.root).to_s
|
206
216
|
remote.sub($1, relative_remote_path)
|
207
217
|
end
|
208
218
|
|
209
219
|
# add a source for the current gem
|
210
|
-
gem_spec =
|
220
|
+
gem_spec = parent_specs[[File.basename(Bundler.root), "ruby"]]
|
211
221
|
|
212
222
|
if gem_spec
|
213
|
-
|
223
|
+
adjusted_parent_lockfile_contents += <<~TEXT
|
214
224
|
PATH
|
215
225
|
remote: .
|
216
226
|
specs:
|
@@ -220,39 +230,39 @@ module Bundler
|
|
220
230
|
|
221
231
|
if lockfile_definition[:lockfile].exist?
|
222
232
|
# if the lockfile already exists, "merge" it together
|
223
|
-
|
233
|
+
parent_lockfile = LockfileParser.new(adjusted_parent_lockfile_contents)
|
224
234
|
lockfile = LockfileParser.new(lockfile_definition[:lockfile].read)
|
225
235
|
|
226
236
|
dependency_changes = false
|
227
237
|
# replace any duplicate specs with what's in the default lockfile
|
228
238
|
lockfile.specs.map! do |spec|
|
229
|
-
|
230
|
-
next spec unless
|
239
|
+
parent_spec = parent_specs[[spec.name, spec.platform]]
|
240
|
+
next spec unless parent_spec
|
231
241
|
|
232
|
-
dependency_changes ||= spec !=
|
233
|
-
|
242
|
+
dependency_changes ||= spec != parent_spec
|
243
|
+
parent_spec
|
234
244
|
end
|
235
245
|
|
236
|
-
lockfile.specs.replace(
|
237
|
-
lockfile.sources.replace(
|
238
|
-
lockfile.platforms.replace(
|
246
|
+
lockfile.specs.replace(parent_lockfile.specs + lockfile.specs).uniq!
|
247
|
+
lockfile.sources.replace(parent_lockfile.sources + lockfile.sources).uniq!
|
248
|
+
lockfile.platforms.replace(parent_lockfile.platforms).uniq!
|
239
249
|
# prune more specific platforms
|
240
250
|
lockfile.platforms.delete_if do |p1|
|
241
251
|
lockfile.platforms.any? do |p2|
|
242
252
|
p2 != "ruby" && p1 != p2 && MatchPlatform.platforms_match?(p2, p1)
|
243
253
|
end
|
244
254
|
end
|
245
|
-
lockfile.instance_variable_set(:@ruby_version,
|
246
|
-
unless lockfile.bundler_version ==
|
255
|
+
lockfile.instance_variable_set(:@ruby_version, parent_lockfile.ruby_version)
|
256
|
+
unless lockfile.bundler_version == parent_lockfile.bundler_version
|
247
257
|
unlocking_bundler = true
|
248
|
-
lockfile.instance_variable_set(:@bundler_version,
|
258
|
+
lockfile.instance_variable_set(:@bundler_version, parent_lockfile.bundler_version)
|
249
259
|
end
|
250
260
|
|
251
261
|
new_contents = LockfileGenerator.generate(lockfile)
|
252
262
|
else
|
253
|
-
# no lockfile? just start out with the
|
263
|
+
# no lockfile? just start out with the parent lockfile's contents to inherit its
|
254
264
|
# locked gems
|
255
|
-
new_contents =
|
265
|
+
new_contents = adjusted_parent_lockfile_contents
|
256
266
|
end
|
257
267
|
|
258
268
|
had_changes = false
|
@@ -273,8 +283,9 @@ module Bundler
|
|
273
283
|
# once to reset them back to the default lockfile's version.
|
274
284
|
# if it's already good, the `check` check at the beginning of
|
275
285
|
# the loop will skip the second sync anyway.
|
276
|
-
if had_changes && attempts <
|
286
|
+
if had_changes && attempts < 2
|
277
287
|
attempts += 1
|
288
|
+
Bundler.ui.debug("Re-running sync to #{relative_lockfile} to reset common dependencies")
|
278
289
|
redo
|
279
290
|
else
|
280
291
|
attempts = 1
|
@@ -297,9 +308,9 @@ module Bundler
|
|
297
308
|
@loaded = true
|
298
309
|
return if lockfile_definitions.empty?
|
299
310
|
|
300
|
-
return unless lockfile_definitions.none? { |definition| definition[:
|
311
|
+
return unless lockfile_definitions.none? { |definition| definition[:active] }
|
301
312
|
|
302
|
-
# Gemfile.lock isn't explicitly specified, otherwise it would be
|
313
|
+
# Gemfile.lock isn't explicitly specified, otherwise it would be active
|
303
314
|
default_lockfile_definition = lockfile_definitions.find do |definition|
|
304
315
|
definition[:lockfile] == Bundler.default_lockfile(force_original: true)
|
305
316
|
end
|
@@ -309,7 +320,7 @@ module Bundler
|
|
309
320
|
|
310
321
|
raise GemfileNotFound, "Could not locate lockfile #{ENV["BUNDLE_LOCKFILE"].inspect}" if ENV["BUNDLE_LOCKFILE"]
|
311
322
|
|
312
|
-
return unless default_lockfile_definition && default_lockfile_definition[:
|
323
|
+
return unless default_lockfile_definition && default_lockfile_definition[:active] == false
|
313
324
|
|
314
325
|
raise GemfileEvalError, "No lockfiles marked as default"
|
315
326
|
end
|
@@ -321,8 +332,10 @@ module Bundler
|
|
321
332
|
|
322
333
|
# @!visibility private
|
323
334
|
def inject_preamble
|
335
|
+
Bundler.ui.debug("Injecting multilock preamble")
|
336
|
+
|
324
337
|
minor_version = Gem::Version.new(::Bundler::Multilock::VERSION).segments[0..1].join(".")
|
325
|
-
bundle_preamble1_match =
|
338
|
+
bundle_preamble1_match = /plugin ["']bundler-multilock["']/
|
326
339
|
bundle_preamble1 = <<~RUBY
|
327
340
|
plugin "bundler-multilock", "~> #{minor_version}"
|
328
341
|
RUBY
|
@@ -346,7 +359,16 @@ module Bundler
|
|
346
359
|
end
|
347
360
|
|
348
361
|
builder = Bundler::Plugin::DSL.new
|
349
|
-
|
362
|
+
# this method is called as part of the plugin loading, but @loaded_plugin_names
|
363
|
+
# hasn't been set yet, so avoid re-entrancy issues
|
364
|
+
plugins = Bundler::Plugin.instance_variable_get(:@loaded_plugin_names)
|
365
|
+
original_plugins = plugins.dup
|
366
|
+
plugins << "bundler-multilock"
|
367
|
+
begin
|
368
|
+
builder.eval_gemfile(Bundler.default_gemfile)
|
369
|
+
ensure
|
370
|
+
plugins.replace(original_plugins)
|
371
|
+
end
|
350
372
|
gemfiles = builder.instance_variable_get(:@gemfiles).map(&:read)
|
351
373
|
|
352
374
|
modified = inject_specific_preamble(gemfile, gemfiles, injection_point, bundle_preamble2, add_newline: true)
|
@@ -368,8 +390,20 @@ module Bundler
|
|
368
390
|
|
369
391
|
private
|
370
392
|
|
371
|
-
def
|
372
|
-
|
393
|
+
def expand_lockfile(lockfile)
|
394
|
+
if lockfile.is_a?(String) && !(lockfile.include?("/") || lockfile.end_with?(".lock"))
|
395
|
+
lockfile = "Gemfile.#{lockfile}.lock"
|
396
|
+
end
|
397
|
+
# use absolute paths
|
398
|
+
lockfile = Bundler.root.join(lockfile).expand_path if lockfile
|
399
|
+
# use the default lockfile (Gemfile.lock) if none was given
|
400
|
+
lockfile || Bundler.default_lockfile(force_original: true)
|
401
|
+
end
|
402
|
+
|
403
|
+
def inject_specific_preamble(gemfile, gemfiles, injection_point, preamble, add_newline:, match: nil)
|
404
|
+
# allow either type of quotes
|
405
|
+
match ||= Regexp.new(Regexp.escape(preamble).gsub('"', %(["'])))
|
406
|
+
return false if gemfiles.any? { |g| match.match?(g) }
|
373
407
|
|
374
408
|
add_newline = false unless gemfile[injection_point - 1] == "\n"
|
375
409
|
|
@@ -391,31 +425,43 @@ module Bundler
|
|
391
425
|
|
392
426
|
definition = builder.to_definition(lockfile, { bundler: unlocking_bundler })
|
393
427
|
definition.instance_variable_set(:@dependency_changes, dependency_changes) if dependency_changes
|
394
|
-
orig_definition = definition.dup # we might need it twice
|
395
428
|
|
396
429
|
current_lockfile = lockfile_definition[:lockfile]
|
397
|
-
if current_lockfile.exist?
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
430
|
+
definition.instance_variable_set(:@lockfile_contents, current_lockfile.read) if current_lockfile.exist?
|
431
|
+
|
432
|
+
orig_definition = definition.dup # we might need it twice
|
433
|
+
|
434
|
+
if current_lockfile.exist? && install
|
435
|
+
Bundler.settings.temporary(frozen: true) do
|
436
|
+
current_definition = builder.to_definition(current_lockfile, {})
|
437
|
+
current_definition.resolve_with_cache!
|
438
|
+
if current_definition.missing_specs.any?
|
439
|
+
Bundler.with_default_lockfile(current_lockfile) do
|
440
|
+
Installer.install(gemfile.dirname, current_definition, {})
|
407
441
|
end
|
408
|
-
rescue RubyVersionMismatch, GemNotFound, SolveFailure
|
409
|
-
# ignore
|
410
442
|
end
|
443
|
+
rescue RubyVersionMismatch, GemNotFound, SolveFailure
|
444
|
+
# ignore
|
411
445
|
end
|
412
446
|
end
|
413
447
|
|
414
448
|
resolved_remotely = false
|
415
|
-
begin
|
449
|
+
accesses = begin
|
416
450
|
previous_ui_level = Bundler.ui.level
|
417
451
|
Bundler.ui.level = "warn"
|
418
452
|
begin
|
453
|
+
# this is a horrible hack, to fix what I consider to be a Bundler bug.
|
454
|
+
# basically, if you have multiple platform specific gems in your
|
455
|
+
# lockfile, and that gem gets unlocked, Bundler will only search
|
456
|
+
# locally to find them. But non-platform-local gems are _never_
|
457
|
+
# installed locally. So just find the non-platform-local gems
|
458
|
+
# in the lockfile (that we know are there from a prior remote
|
459
|
+
# resolution), and add them to the locally installed spec list.
|
460
|
+
definition.send(:source_map).locked_specs.each do |spec|
|
461
|
+
next if spec.match_platform(Bundler.local_platform)
|
462
|
+
|
463
|
+
spec.source.specs.add(spec)
|
464
|
+
end
|
419
465
|
definition.resolve_with_cache!
|
420
466
|
rescue GemNotFound, SolveFailure
|
421
467
|
definition = orig_definition
|
@@ -423,7 +469,9 @@ module Bundler
|
|
423
469
|
definition.resolve_remotely!
|
424
470
|
resolved_remotely = true
|
425
471
|
end
|
426
|
-
|
472
|
+
SharedHelpers.capture_filesystem_access do
|
473
|
+
definition.lock(lockfile_definition[:lockfile], true)
|
474
|
+
end
|
427
475
|
ensure
|
428
476
|
Bundler.ui.level = previous_ui_level
|
429
477
|
end
|
@@ -436,7 +484,7 @@ module Bundler
|
|
436
484
|
end
|
437
485
|
end
|
438
486
|
|
439
|
-
!
|
487
|
+
accesses && !accesses.empty?
|
440
488
|
end
|
441
489
|
end
|
442
490
|
|
@@ -448,3 +496,26 @@ module Bundler
|
|
448
496
|
end
|
449
497
|
|
450
498
|
Bundler::Multilock.inject_preamble unless Bundler::Multilock.loaded?
|
499
|
+
|
500
|
+
# this is terrible, but we can't prepend into these modules because we only load
|
501
|
+
# _inside_ of the CLI commands already running
|
502
|
+
if defined?(Bundler::CLI::Check)
|
503
|
+
require_relative "multilock/check"
|
504
|
+
at_exit do
|
505
|
+
next unless $!.nil?
|
506
|
+
next if $!.is_a?(SystemExit) && !$!.success?
|
507
|
+
|
508
|
+
next if Bundler::Multilock::Check.run
|
509
|
+
|
510
|
+
Bundler.ui.warn("You can attempt to fix by running `bundle install`")
|
511
|
+
exit 1
|
512
|
+
end
|
513
|
+
end
|
514
|
+
if defined?(Bundler::CLI::Lock)
|
515
|
+
at_exit do
|
516
|
+
next unless $!.nil?
|
517
|
+
next if $!.is_a?(SystemExit) && !$!.success?
|
518
|
+
|
519
|
+
Bundler::Multilock.after_install_all(install: false)
|
520
|
+
end
|
521
|
+
end
|
data/plugins.rb
CHANGED
@@ -20,29 +20,6 @@
|
|
20
20
|
|
21
21
|
require_relative "lib/bundler/multilock"
|
22
22
|
|
23
|
-
# this is terrible, but we can't prepend into these modules because we only load
|
24
|
-
# _inside_ of the CLI commands already running
|
25
|
-
if defined?(Bundler::CLI::Check)
|
26
|
-
require_relative "lib/bundler/multilock/check"
|
27
|
-
at_exit do
|
28
|
-
next unless $!.nil?
|
29
|
-
next if $!.is_a?(SystemExit) && !$!.success?
|
30
|
-
|
31
|
-
next if Bundler::Multilock::Check.run
|
32
|
-
|
33
|
-
Bundler.ui.warn("You can attempt to fix by running `bundle install`")
|
34
|
-
exit 1
|
35
|
-
end
|
36
|
-
end
|
37
|
-
if defined?(Bundler::CLI::Lock)
|
38
|
-
at_exit do
|
39
|
-
next unless $!.nil?
|
40
|
-
next if $!.is_a?(SystemExit) && !$!.success?
|
41
|
-
|
42
|
-
Bundler::Multilock.after_install_all(install: false)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
23
|
Bundler::Plugin.add_hook(Bundler::Plugin::Events::GEM_AFTER_INSTALL_ALL) do |_|
|
47
24
|
Bundler::Multilock.after_install_all
|
48
25
|
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.0
|
4
|
+
version: 1.1.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-
|
11
|
+
date: 2023-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -121,6 +121,8 @@ files:
|
|
121
121
|
- lib/bundler/multilock/ext/dsl.rb
|
122
122
|
- lib/bundler/multilock/ext/plugin.rb
|
123
123
|
- lib/bundler/multilock/ext/plugin/dsl.rb
|
124
|
+
- lib/bundler/multilock/ext/shared_helpers.rb
|
125
|
+
- lib/bundler/multilock/ext/source.rb
|
124
126
|
- lib/bundler/multilock/ext/source_list.rb
|
125
127
|
- lib/bundler/multilock/lockfile_generator.rb
|
126
128
|
- lib/bundler/multilock/version.rb
|