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
|
# frozen_string_literal: true
module Bundler
#
# This class handles installing and switching to the version of bundler needed
# by an application.
#
class SelfManager
def restart_with_locked_bundler_if_needed
return unless needs_switching? && installed?
restart_with(restart_version)
end
def install_locked_bundler_and_restart_with_it_if_needed
return unless needs_switching?
if restart_version == lockfile_version
Bundler.ui.info \
"Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \
"Installing Bundler #{lockfile_version} and restarting using that version."
else
Bundler.ui.info \
"Bundler #{current_version} is running, but your configuration was #{restart_version}. " \
"Installing Bundler #{restart_version} and restarting using that version."
end
install_and_restart_with(restart_version)
end
def update_bundler_and_restart_with_it_if_needed(target)
return unless autoswitching_applies?
spec = resolve_update_version_from(target)
return unless spec
version = spec.version
Bundler.ui.info "Updating bundler to #{version}."
install(spec)
restart_with(version)
end
private
def install_and_restart_with(version)
requirement = Gem::Requirement.new(version)
spec = find_latest_matching_spec(requirement)
if spec.nil?
Bundler.ui.warn "Your lockfile is locked to a version of bundler (#{lockfile_version}) that doesn't exist at https://rubygems.org/. Going on using #{current_version}"
return
end
install(spec)
rescue StandardError => e
Bundler.ui.trace e
Bundler.ui.warn "There was an error installing the locked bundler version (#{lockfile_version}), rerun with the `--verbose` flag for more details. Going on using bundler #{current_version}."
else
restart_with(version)
end
def install(spec)
spec.source.install(spec)
end
def restart_with(version)
configured_gem_home = ENV["GEM_HOME"]
configured_gem_path = ENV["GEM_PATH"]
cmd = [$PROGRAM_NAME, *ARGV]
cmd.unshift(Gem.ruby) unless File.executable?($PROGRAM_NAME)
Bundler.with_original_env do
Kernel.exec(
{ "GEM_HOME" => configured_gem_home, "GEM_PATH" => configured_gem_path, "BUNDLER_VERSION" => version.to_s },
*cmd
)
end
end
def needs_switching?
autoswitching_applies? &&
released?(lockfile_version) &&
!running?(lockfile_version) &&
!updating? &&
Bundler.settings[:version] != "system"
end
def autoswitching_applies?
ENV["BUNDLER_VERSION"].nil? &&
Bundler.rubygems.supports_bundler_trampolining? &&
SharedHelpers.in_bundle? &&
lockfile_version
end
def resolve_update_version_from(target)
requirement = Gem::Requirement.new(target)
update_candidate = find_latest_matching_spec(requirement)
if update_candidate.nil?
raise InvalidOption, "The `bundle update --bundler` target version (#{target}) does not exist"
end
resolved_version = update_candidate.version
needs_update = requirement.specific? ? !running?(resolved_version) : running_older_than?(resolved_version)
return unless needs_update
update_candidate
end
def local_specs
@local_specs ||= Bundler::Source::Rubygems.new("allow_local" => true).specs.select {|spec| spec.name == "bundler" }
end
def remote_specs
@remote_specs ||= begin
source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org")
source.remote!
source.add_dependency_names("bundler")
source.specs.select(&:matches_current_metadata?)
end
end
def find_latest_matching_spec(requirement)
local_result = find_latest_matching_spec_from_collection(local_specs, requirement)
return local_result if local_result && requirement.specific?
remote_result = find_latest_matching_spec_from_collection(remote_specs, requirement)
return remote_result if local_result.nil?
[local_result, remote_result].max
end
def find_latest_matching_spec_from_collection(specs, requirement)
specs.sort.reverse_each.find {|spec| requirement.satisfied_by?(spec.version) }
end
def running?(version)
version == current_version
end
def running_older_than?(version)
current_version < version
end
def released?(version)
!version.to_s.end_with?(".dev")
end
def updating?
"update".start_with?(ARGV.first || " ") && ARGV[1..-1].any? {|a| a.start_with?("--bundler") }
end
def installed?
Bundler.configure
Bundler.rubygems.find_bundler(restart_version.to_s)
end
def current_version
@current_version ||= Gem::Version.new(Bundler::VERSION)
end
def lockfile_version
return @lockfile_version if defined?(@lockfile_version)
parsed_version = Bundler::LockfileParser.bundled_with
@lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil
rescue ArgumentError
@lockfile_version = nil
end
def restart_version
return @restart_version if defined?(@restart_version)
# BUNDLE_VERSION=x.y.z
@restart_version = Gem::Version.new(Bundler.settings[:version])
rescue ArgumentError
# BUNDLE_VERSION=lockfile
@restart_version = lockfile_version
end
end
end
|