1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
|
# frozen_string_literal: true
require "pathname"
require "rbconfig"
require_relative "version"
require_relative "constants"
require_relative "rubygems_integration"
require_relative "current_ruby"
module Bundler
module SharedHelpers
def root
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path.parent
end
def default_gemfile
gemfile = find_gemfile
raise GemfileNotFound, "Could not locate Gemfile" unless gemfile
Pathname.new(gemfile).tap{|x| x.untaint if RUBY_VERSION < "2.7" }.expand_path
end
def default_lockfile
gemfile = default_gemfile
case gemfile.basename.to_s
when "gems.rb" then Pathname.new(gemfile.sub(/.rb$/, ".locked"))
else Pathname.new("#{gemfile}.lock")
end.tap{|x| x.untaint if RUBY_VERSION < "2.7" }
end
def default_bundle_dir
bundle_dir = find_directory(".bundle")
return nil unless bundle_dir
bundle_dir = Pathname.new(bundle_dir)
global_bundle_dir = Bundler.user_home.join(".bundle")
return nil if bundle_dir == global_bundle_dir
bundle_dir
end
def in_bundle?
find_gemfile
end
def chdir(dir, &blk)
Bundler.rubygems.ext_lock.synchronize do
Dir.chdir dir, &blk
end
end
def pwd
Bundler.rubygems.ext_lock.synchronize do
Pathname.pwd
end
end
def with_clean_git_env(&block)
keys = %w[GIT_DIR GIT_WORK_TREE]
old_env = keys.inject({}) do |h, k|
h.update(k => ENV[k])
end
keys.each {|key| ENV.delete(key) }
block.call
ensure
keys.each {|key| ENV[key] = old_env[key] }
end
def set_bundle_environment
set_bundle_variables
set_path
set_rubyopt
set_rubylib
end
# Rescues permissions errors raised by file system operations
# (ie. Errno:EACCESS, Errno::EAGAIN) and raises more friendly errors instead.
#
# @param path [String] the path that the action will be attempted to
# @param action [Symbol, #to_s] the type of operation that will be
# performed. For example: :write, :read, :exec
#
# @yield path
#
# @raise [Bundler::PermissionError] if Errno:EACCES is raised in the
# given block
# @raise [Bundler::TemporaryResourceError] if Errno:EAGAIN is raised in the
# given block
#
# @example
# filesystem_access("vendor/cache", :write) do
# FileUtils.mkdir_p("vendor/cache")
# end
#
# @see {Bundler::PermissionError}
def filesystem_access(path, action = :write, &block)
yield(path.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" })
rescue Errno::EACCES
raise PermissionError.new(path, action)
rescue Errno::EAGAIN
raise TemporaryResourceError.new(path, action)
rescue Errno::EPROTO
raise VirtualProtocolError.new
rescue Errno::ENOSPC
raise NoSpaceOnDeviceError.new(path, action)
rescue *[const_get_safely(:ENOTSUP, Errno)].compact
raise OperationNotSupportedError.new(path, action)
rescue Errno::EEXIST, Errno::ENOENT
raise
rescue SystemCallError => e
raise GenericSystemCallError.new(e, "There was an error accessing `#{path}`.")
end
def const_get_safely(constant_name, namespace)
const_in_namespace = namespace.constants.include?(constant_name.to_s) ||
namespace.constants.include?(constant_name.to_sym)
return nil unless const_in_namespace
namespace.const_get(constant_name)
end
def major_deprecation(major_version, message, print_caller_location: false)
if print_caller_location
caller_location = caller_locations(2, 2).first
message = "#{message} (called at #{caller_location.path}:#{caller_location.lineno})"
end
bundler_major_version = Bundler.bundler_major_version
if bundler_major_version > major_version
require_relative "errors"
raise DeprecatedError, "[REMOVED] #{message}"
end
return unless bundler_major_version >= major_version && prints_major_deprecations?
Bundler.ui.warn("[DEPRECATED] #{message}")
end
def print_major_deprecations!
multiple_gemfiles = search_up(".") do |dir|
gemfiles = gemfile_names.select {|gf| File.file? File.expand_path(gf, dir) }
next if gemfiles.empty?
break gemfiles.size != 1
end
return unless multiple_gemfiles
message = "Multiple gemfiles (gems.rb and Gemfile) detected. " \
"Make sure you remove Gemfile and Gemfile.lock since bundler is ignoring them in favor of gems.rb and gems.rb.locked."
Bundler.ui.warn message
end
def trap(signal, override = false, &block)
prior = Signal.trap(signal) do
block.call
prior.call unless override
end
end
def ensure_same_dependencies(spec, old_deps, new_deps)
new_deps = new_deps.reject {|d| d.type == :development }
old_deps = old_deps.reject {|d| d.type == :development }
without_type = proc {|d| Gem::Dependency.new(d.name, d.requirements_list.sort) }
new_deps.map!(&without_type)
old_deps.map!(&without_type)
extra_deps = new_deps - old_deps
return if extra_deps.empty?
Bundler.ui.debug "#{spec.full_name} from #{spec.remote} has either corrupted API or lockfile dependencies" \
" (was expecting #{old_deps.map(&:to_s)}, but the real spec has #{new_deps.map(&:to_s)})"
raise APIResponseMismatchError,
"Downloading #{spec.full_name} revealed dependencies not in the API or the lockfile (#{extra_deps.join(", ")})." \
"\nEither installing with `--full-index` or running `bundle update #{spec.name}` should fix the problem."
end
def pretty_dependency(dep, print_source = false)
msg = String.new(dep.name)
msg << " (#{dep.requirement})" unless dep.requirement == Gem::Requirement.default
if dep.is_a?(Bundler::Dependency)
platform_string = dep.platforms.join(", ")
msg << " " << platform_string if !platform_string.empty? && platform_string != Gem::Platform::RUBY
end
msg << " from the `#{dep.source}` source" if print_source && dep.source
msg
end
def md5_available?
return @md5_available if defined?(@md5_available)
@md5_available = begin
require "openssl"
OpenSSL::Digest::MD5.digest("")
true
rescue LoadError
true
rescue OpenSSL::Digest::DigestError
false
end
end
def digest(name)
require "digest"
Digest(name)
end
def write_to_gemfile(gemfile_path, contents)
filesystem_access(gemfile_path) {|g| File.open(g, "w") {|file| file.puts contents } }
end
private
def validate_bundle_path
path_separator = Bundler.rubygems.path_separator
return unless Bundler.bundle_path.to_s.split(path_separator).size > 1
message = "Your bundle path contains text matching #{path_separator.inspect}, " \
"which is the path separator for your system. Bundler cannot " \
"function correctly when the Bundle path contains the " \
"system's PATH separator. Please change your " \
"bundle path to not match #{path_separator.inspect}." \
"\nYour current bundle path is '#{Bundler.bundle_path}'."
raise Bundler::PathError, message
end
def find_gemfile
given = ENV["BUNDLE_GEMFILE"]
return given if given && !given.empty?
find_file(*gemfile_names)
end
def gemfile_names
["gems.rb", "Gemfile"]
end
def find_file(*names)
search_up(*names) do |filename|
return filename if File.file?(filename)
end
end
def find_directory(*names)
search_up(*names) do |dirname|
return dirname if File.directory?(dirname)
end
end
def search_up(*names)
previous = nil
current = File.expand_path(SharedHelpers.pwd).tap{|x| x.untaint if RUBY_VERSION < "2.7" }
until !File.directory?(current) || current == previous
if ENV["BUNDLE_SPEC_RUN"]
# avoid stepping above the tmp directory when testing
gemspec = if ENV["GEM_COMMAND"]
# for Ruby Core
"lib/bundler/bundler.gemspec"
else
"bundler.gemspec"
end
# avoid stepping above the tmp directory when testing
return nil if File.file?(File.join(current, gemspec))
end
names.each do |name|
filename = File.join(current, name)
yield filename
end
previous = current
current = File.expand_path("..", current)
end
end
def set_env(key, value)
raise ArgumentError, "new key #{key}" unless EnvironmentPreserver::BUNDLER_KEYS.include?(key)
orig_key = "#{EnvironmentPreserver::BUNDLER_PREFIX}#{key}"
orig = ENV[key]
orig ||= EnvironmentPreserver::INTENTIONALLY_NIL
ENV[orig_key] ||= orig
ENV[key] = value
end
public :set_env
def set_bundle_variables
# bundler exe & lib folders have same root folder, typical gem installation
exe_file = File.expand_path("../../../exe/bundle", __FILE__)
# for Ruby core repository testing
exe_file = File.expand_path("../../../libexec/bundle", __FILE__) unless File.exist?(exe_file)
# bundler is a default gem, exe path is separate
exe_file = Bundler.rubygems.bin_path("bundler", "bundle", VERSION) unless File.exist?(exe_file)
Bundler::SharedHelpers.set_env "BUNDLE_BIN_PATH", exe_file
Bundler::SharedHelpers.set_env "BUNDLE_GEMFILE", find_gemfile.to_s
Bundler::SharedHelpers.set_env "BUNDLER_VERSION", Bundler::VERSION
end
def set_path
validate_bundle_path
paths = (ENV["PATH"] || "").split(File::PATH_SEPARATOR)
paths.unshift "#{Bundler.bundle_path}/bin"
Bundler::SharedHelpers.set_env "PATH", paths.uniq.join(File::PATH_SEPARATOR)
end
def set_rubyopt
rubyopt = [ENV["RUBYOPT"]].compact
setup_require = "-r#{File.expand_path("setup", __dir__)}"
return if !rubyopt.empty? && rubyopt.first =~ /#{setup_require}/
rubyopt.unshift setup_require
Bundler::SharedHelpers.set_env "RUBYOPT", rubyopt.join(" ")
end
def set_rubylib
rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR)
rubylib.unshift bundler_ruby_lib unless RbConfig::CONFIG["rubylibdir"] == bundler_ruby_lib
Bundler::SharedHelpers.set_env "RUBYLIB", rubylib.uniq.join(File::PATH_SEPARATOR)
end
def bundler_ruby_lib
resolve_path File.expand_path("../..", __FILE__)
end
def clean_load_path
bundler_lib = bundler_ruby_lib
loaded_gem_paths = Bundler.rubygems.loaded_gem_paths
$LOAD_PATH.reject! do |p|
next if resolve_path(p).start_with?(bundler_lib)
loaded_gem_paths.delete(p)
end
$LOAD_PATH.uniq!
end
def resolve_path(path)
expanded = File.expand_path(path)
return expanded unless File.respond_to?(:realpath) && File.exist?(expanded)
File.realpath(expanded)
end
def prints_major_deprecations?
require_relative "../bundler"
return false if Bundler.settings[:silence_deprecations]
require_relative "deprecate"
return false if Bundler::Deprecate.skip
true
end
extend self
end
end
|