bundler-multilock 1.0.10 → 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 +150 -75
- data/plugins.rb +0 -23
- metadata +7 -5
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,36 +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
|
-
lockfile.
|
|
255
|
+
lockfile.instance_variable_set(:@ruby_version, parent_lockfile.ruby_version)
|
|
256
|
+
unless lockfile.bundler_version == parent_lockfile.bundler_version
|
|
257
|
+
unlocking_bundler = true
|
|
258
|
+
lockfile.instance_variable_set(:@bundler_version, parent_lockfile.bundler_version)
|
|
259
|
+
end
|
|
247
260
|
|
|
248
261
|
new_contents = LockfileGenerator.generate(lockfile)
|
|
249
262
|
else
|
|
250
|
-
# no lockfile? just start out with the
|
|
263
|
+
# no lockfile? just start out with the parent lockfile's contents to inherit its
|
|
251
264
|
# locked gems
|
|
252
|
-
new_contents =
|
|
265
|
+
new_contents = adjusted_parent_lockfile_contents
|
|
253
266
|
end
|
|
254
267
|
|
|
255
268
|
had_changes = false
|
|
@@ -261,7 +274,8 @@ module Bundler
|
|
|
261
274
|
had_changes = write_lockfile(lockfile_definition,
|
|
262
275
|
temp_lockfile.path,
|
|
263
276
|
install: install,
|
|
264
|
-
dependency_changes: dependency_changes
|
|
277
|
+
dependency_changes: dependency_changes,
|
|
278
|
+
unlocking_bundler: unlocking_bundler)
|
|
265
279
|
end
|
|
266
280
|
|
|
267
281
|
# if we had changes, bundler may have updated some common
|
|
@@ -269,8 +283,9 @@ module Bundler
|
|
|
269
283
|
# once to reset them back to the default lockfile's version.
|
|
270
284
|
# if it's already good, the `check` check at the beginning of
|
|
271
285
|
# the loop will skip the second sync anyway.
|
|
272
|
-
if had_changes && attempts <
|
|
286
|
+
if had_changes && attempts < 2
|
|
273
287
|
attempts += 1
|
|
288
|
+
Bundler.ui.debug("Re-running sync to #{relative_lockfile} to reset common dependencies")
|
|
274
289
|
redo
|
|
275
290
|
else
|
|
276
291
|
attempts = 1
|
|
@@ -293,9 +308,9 @@ module Bundler
|
|
|
293
308
|
@loaded = true
|
|
294
309
|
return if lockfile_definitions.empty?
|
|
295
310
|
|
|
296
|
-
return unless lockfile_definitions.none? { |definition| definition[:
|
|
311
|
+
return unless lockfile_definitions.none? { |definition| definition[:active] }
|
|
297
312
|
|
|
298
|
-
# Gemfile.lock isn't explicitly specified, otherwise it would be
|
|
313
|
+
# Gemfile.lock isn't explicitly specified, otherwise it would be active
|
|
299
314
|
default_lockfile_definition = lockfile_definitions.find do |definition|
|
|
300
315
|
definition[:lockfile] == Bundler.default_lockfile(force_original: true)
|
|
301
316
|
end
|
|
@@ -305,7 +320,7 @@ module Bundler
|
|
|
305
320
|
|
|
306
321
|
raise GemfileNotFound, "Could not locate lockfile #{ENV["BUNDLE_LOCKFILE"].inspect}" if ENV["BUNDLE_LOCKFILE"]
|
|
307
322
|
|
|
308
|
-
return unless default_lockfile_definition && default_lockfile_definition[:
|
|
323
|
+
return unless default_lockfile_definition && default_lockfile_definition[:active] == false
|
|
309
324
|
|
|
310
325
|
raise GemfileEvalError, "No lockfiles marked as default"
|
|
311
326
|
end
|
|
@@ -317,8 +332,10 @@ module Bundler
|
|
|
317
332
|
|
|
318
333
|
# @!visibility private
|
|
319
334
|
def inject_preamble
|
|
335
|
+
Bundler.ui.debug("Injecting multilock preamble")
|
|
336
|
+
|
|
320
337
|
minor_version = Gem::Version.new(::Bundler::Multilock::VERSION).segments[0..1].join(".")
|
|
321
|
-
bundle_preamble1_match =
|
|
338
|
+
bundle_preamble1_match = /plugin ["']bundler-multilock["']/
|
|
322
339
|
bundle_preamble1 = <<~RUBY
|
|
323
340
|
plugin "bundler-multilock", "~> #{minor_version}"
|
|
324
341
|
RUBY
|
|
@@ -342,7 +359,16 @@ module Bundler
|
|
|
342
359
|
end
|
|
343
360
|
|
|
344
361
|
builder = Bundler::Plugin::DSL.new
|
|
345
|
-
|
|
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
|
|
346
372
|
gemfiles = builder.instance_variable_get(:@gemfiles).map(&:read)
|
|
347
373
|
|
|
348
374
|
modified = inject_specific_preamble(gemfile, gemfiles, injection_point, bundle_preamble2, add_newline: true)
|
|
@@ -364,8 +390,20 @@ module Bundler
|
|
|
364
390
|
|
|
365
391
|
private
|
|
366
392
|
|
|
367
|
-
def
|
|
368
|
-
|
|
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) }
|
|
369
407
|
|
|
370
408
|
add_newline = false unless gemfile[injection_point - 1] == "\n"
|
|
371
409
|
|
|
@@ -375,7 +413,7 @@ module Bundler
|
|
|
375
413
|
true
|
|
376
414
|
end
|
|
377
415
|
|
|
378
|
-
def write_lockfile(lockfile_definition, lockfile, install:, dependency_changes: false)
|
|
416
|
+
def write_lockfile(lockfile_definition, lockfile, install:, dependency_changes: false, unlocking_bundler: false)
|
|
379
417
|
prepare_block = lockfile_definition[:prepare]
|
|
380
418
|
|
|
381
419
|
gemfile = lockfile_definition[:gemfile]
|
|
@@ -385,33 +423,45 @@ module Bundler
|
|
|
385
423
|
builder.eval_gemfile(gemfile, &prepare_block) if prepare_block
|
|
386
424
|
builder.eval_gemfile(gemfile)
|
|
387
425
|
|
|
388
|
-
definition = builder.to_definition(lockfile, {})
|
|
426
|
+
definition = builder.to_definition(lockfile, { bundler: unlocking_bundler })
|
|
389
427
|
definition.instance_variable_set(:@dependency_changes, dependency_changes) if dependency_changes
|
|
390
|
-
orig_definition = definition.dup # we might need it twice
|
|
391
428
|
|
|
392
429
|
current_lockfile = lockfile_definition[:lockfile]
|
|
393
|
-
if current_lockfile.exist?
|
|
394
|
-
|
|
395
|
-
|
|
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
|
|
396
436
|
current_definition = builder.to_definition(current_lockfile, {})
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
Installer.install(gemfile.dirname, current_definition, {})
|
|
402
|
-
end
|
|
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, {})
|
|
403
441
|
end
|
|
404
|
-
rescue RubyVersionMismatch, GemNotFound, SolveFailure
|
|
405
|
-
# ignore
|
|
406
442
|
end
|
|
443
|
+
rescue RubyVersionMismatch, GemNotFound, SolveFailure
|
|
444
|
+
# ignore
|
|
407
445
|
end
|
|
408
446
|
end
|
|
409
447
|
|
|
410
448
|
resolved_remotely = false
|
|
411
|
-
begin
|
|
449
|
+
accesses = begin
|
|
412
450
|
previous_ui_level = Bundler.ui.level
|
|
413
451
|
Bundler.ui.level = "warn"
|
|
414
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
|
|
415
465
|
definition.resolve_with_cache!
|
|
416
466
|
rescue GemNotFound, SolveFailure
|
|
417
467
|
definition = orig_definition
|
|
@@ -419,7 +469,9 @@ module Bundler
|
|
|
419
469
|
definition.resolve_remotely!
|
|
420
470
|
resolved_remotely = true
|
|
421
471
|
end
|
|
422
|
-
|
|
472
|
+
SharedHelpers.capture_filesystem_access do
|
|
473
|
+
definition.lock(lockfile_definition[:lockfile], true)
|
|
474
|
+
end
|
|
423
475
|
ensure
|
|
424
476
|
Bundler.ui.level = previous_ui_level
|
|
425
477
|
end
|
|
@@ -432,7 +484,7 @@ module Bundler
|
|
|
432
484
|
end
|
|
433
485
|
end
|
|
434
486
|
|
|
435
|
-
!
|
|
487
|
+
accesses && !accesses.empty?
|
|
436
488
|
end
|
|
437
489
|
end
|
|
438
490
|
|
|
@@ -444,3 +496,26 @@ module Bundler
|
|
|
444
496
|
end
|
|
445
497
|
|
|
446
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
|
|
@@ -25,19 +25,19 @@ dependencies:
|
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: 2.4.19
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: debug
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - "~>"
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '1.8'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
38
|
- - "~>"
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '1.8'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: rake
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -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
|