summaryrefslogtreecommitdiff
path: root/lib/bundler
diff options
context:
space:
mode:
authorHiroshi SHIBATA <hsbt@ruby-lang.org>2022-01-19 13:28:23 +0900
committerHiroshi SHIBATA <hsbt@ruby-lang.org>2022-01-19 15:01:44 +0900
commitd22511fd7595ef1819baa42851d598d95b8f4d00 (patch)
tree83e823c033f5c39c314cf4379f0bac5c43adf3d4 /lib/bundler
parent5646f4b67b75e7e558c994ff8cbd374e4b4bd3b5 (diff)
Merge rubygems/rubygems HEAD.
Picked at 12aeef6ba9a3be0022be9934c1a3e4c46a03ed3a
Notes
Notes: Merged: https://github.com/ruby/ruby/pull/5462
Diffstat (limited to 'lib/bundler')
-rw-r--r--lib/bundler/cli.rb13
-rw-r--r--lib/bundler/cli/update.rb8
-rw-r--r--lib/bundler/compact_index_client.rb6
-rw-r--r--lib/bundler/compact_index_client/cache.rb9
-rw-r--r--lib/bundler/definition.rb8
-rw-r--r--lib/bundler/endpoint_specification.rb24
-rw-r--r--lib/bundler/fetcher.rb13
-rw-r--r--lib/bundler/fetcher/compact_index.rb10
-rw-r--r--lib/bundler/fetcher/index.rb26
-rw-r--r--lib/bundler/lazy_specification.rb4
-rw-r--r--lib/bundler/lockfile_generator.rb2
-rw-r--r--lib/bundler/resolver.rb10
-rw-r--r--lib/bundler/resolver/spec_group.rb2
-rw-r--r--lib/bundler/self_manager.rb132
-rw-r--r--lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb5
-rw-r--r--lib/bundler/vendor/thor/lib/thor/version.rb2
16 files changed, 145 insertions, 129 deletions
diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb
index f6e20e7c67..16651dfad9 100644
--- a/lib/bundler/cli.rb
+++ b/lib/bundler/cli.rb
@@ -809,17 +809,10 @@ module Bundler
current = Gem::Version.new(VERSION)
return if current >= latest
- latest_installed = Bundler.rubygems.find_name("bundler").map(&:version).max
- installation = "To install the latest version, run `gem install bundler#{" --pre" if latest.prerelease?}`"
- if latest_installed && latest_installed > current
- suggestion = "To update to the most recent installed version (#{latest_installed}), run `bundle update --bundler`"
- suggestion = "#{installation}\n#{suggestion}" if latest_installed < latest
- else
- suggestion = installation
- end
-
- Bundler.ui.warn "The latest bundler is #{latest}, but you are currently running #{current}.\n#{suggestion}"
+ Bundler.ui.warn \
+ "The latest bundler is #{latest}, but you are currently running #{current}.\n" \
+ "To update to the most recent version, run `bundle update --bundler`"
rescue RuntimeError
nil
end
diff --git a/lib/bundler/cli/update.rb b/lib/bundler/cli/update.rb
index 95a8886ea5..b49182655b 100644
--- a/lib/bundler/cli/update.rb
+++ b/lib/bundler/cli/update.rb
@@ -11,12 +11,16 @@ module Bundler
def run
Bundler.ui.level = "warn" if options[:quiet]
+ update_bundler = options[:bundler]
+
+ Bundler.self_manager.update_bundler_and_restart_with_it_if_needed(update_bundler) if update_bundler
+
Plugin.gemfile_install(Bundler.default_gemfile) if Bundler.feature_flag.plugins?
sources = Array(options[:source])
groups = Array(options[:group]).map(&:to_sym)
- full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !options[:bundler]
+ full_update = gems.empty? && sources.empty? && groups.empty? && !options[:ruby] && !update_bundler
if full_update && !options[:all]
if Bundler.feature_flag.update_requires_all_flag?
@@ -49,7 +53,7 @@ module Bundler
Bundler.definition(:gems => gems, :sources => sources, :ruby => options[:ruby],
:conservative => conservative,
- :bundler => options[:bundler])
+ :bundler => update_bundler)
end
Bundler::CLI::Common.configure_gem_version_promoter(Bundler.definition, options)
diff --git a/lib/bundler/compact_index_client.rb b/lib/bundler/compact_index_client.rb
index d5dbeb3b10..127a50e810 100644
--- a/lib/bundler/compact_index_client.rb
+++ b/lib/bundler/compact_index_client.rb
@@ -73,12 +73,6 @@ module Bundler
end.flatten(1)
end
- def spec(name, version, platform = nil)
- Bundler::CompactIndexClient.debug { "spec(name = #{name}, version = #{version}, platform = #{platform})" }
- update_info(name)
- @cache.specific_dependency(name, version, platform)
- end
-
def update_and_parse_checksums!
Bundler::CompactIndexClient.debug { "update_and_parse_checksums!" }
return @info_checksums_by_name if @parsed_checksums
diff --git a/lib/bundler/compact_index_client/cache.rb b/lib/bundler/compact_index_client/cache.rb
index c2cd069ec1..2d83777139 100644
--- a/lib/bundler/compact_index_client/cache.rb
+++ b/lib/bundler/compact_index_client/cache.rb
@@ -76,15 +76,6 @@ module Bundler
end
end
- def specific_dependency(name, version, platform)
- pattern = [version, platform].compact.join("-")
- return nil if pattern.empty?
-
- gem_lines = info_path(name).read
- gem_line = gem_lines[/^#{Regexp.escape(pattern)}\b.*/, 0]
- gem_line ? parse_gem(gem_line) : nil
- end
-
private
def lines(path)
diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb
index f985e6a374..c31c41f76d 100644
--- a/lib/bundler/definition.rb
+++ b/lib/bundler/definition.rb
@@ -310,14 +310,6 @@ module Bundler
end
end
- def locked_bundler_version
- if @locked_bundler_version && @locked_bundler_version < Gem::Version.new(Bundler::VERSION)
- new_version = Bundler::VERSION
- end
-
- new_version || @locked_bundler_version || Bundler::VERSION
- end
-
def locked_ruby_version
return unless ruby_version
if @unlock[:ruby] || !@locked_ruby_version
diff --git a/lib/bundler/endpoint_specification.rb b/lib/bundler/endpoint_specification.rb
index 6cf597b943..f3260a38e6 100644
--- a/lib/bundler/endpoint_specification.rb
+++ b/lib/bundler/endpoint_specification.rb
@@ -5,14 +5,15 @@ module Bundler
class EndpointSpecification < Gem::Specification
include MatchPlatform
- attr_reader :name, :version, :platform, :required_rubygems_version, :required_ruby_version, :checksum
+ attr_reader :name, :version, :platform, :checksum
attr_accessor :source, :remote, :dependencies
- def initialize(name, version, platform, dependencies, metadata = nil)
+ def initialize(name, version, platform, spec_fetcher, dependencies, metadata = nil)
super()
@name = name
@version = Gem::Version.create version
@platform = platform
+ @spec_fetcher = spec_fetcher
@dependencies = dependencies.map {|dep, reqs| build_dependency(dep, reqs) }
@loaded_from = nil
@@ -21,6 +22,14 @@ module Bundler
parse_metadata(metadata)
end
+ def required_ruby_version
+ @required_ruby_version ||= _remote_specification.required_ruby_version
+ end
+
+ def required_rubygems_version
+ @required_rubygems_version ||= _remote_specification.required_rubygems_version
+ end
+
def fetch_platform
@platform
end
@@ -105,12 +114,21 @@ module Bundler
private
+ def _remote_specification
+ @_remote_specification ||= @spec_fetcher.fetch_spec([@name, @version, @platform])
+ end
+
def local_specification_path
"#{base_dir}/specifications/#{full_name}.gemspec"
end
def parse_metadata(data)
- return unless data
+ unless data
+ @required_ruby_version = nil
+ @required_rubygems_version = nil
+ return
+ end
+
data.each do |k, v|
next unless v
case k.to_s
diff --git a/lib/bundler/fetcher.rb b/lib/bundler/fetcher.rb
index a453157e68..89103fe1ec 100644
--- a/lib/bundler/fetcher.rb
+++ b/lib/bundler/fetcher.rb
@@ -129,17 +129,15 @@ module Bundler
specs = fetchers.last.specs(gem_names)
else
specs = []
- fetchers.shift until fetchers.first.available? || fetchers.empty?
- fetchers.dup.each do |f|
- break unless f.api_fetcher? && !gem_names || !specs = f.specs(gem_names)
- fetchers.delete(f)
+ @fetchers = fetchers.drop_while do |f|
+ !f.available? || (f.api_fetcher? && !gem_names) || !specs = f.specs(gem_names)
end
@use_api = false if fetchers.none?(&:api_fetcher?)
end
specs.each do |name, version, platform, dependencies, metadata|
spec = if dependencies
- EndpointSpecification.new(name, version, platform, dependencies, metadata)
+ EndpointSpecification.new(name, version, platform, self, dependencies, metadata)
else
RemoteSpecification.new(name, version, platform, self)
end
@@ -272,8 +270,7 @@ module Bundler
# cached gem specification path, if one exists
def gemspec_cached_path(spec_file_name)
paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) }
- paths = paths.select {|path| File.file? path }
- paths.first
+ paths.find {|path| File.file? path }
end
HTTP_ERRORS = [
@@ -301,8 +298,6 @@ module Bundler
store
end
- private
-
def remote_uri
@remote.uri
end
diff --git a/lib/bundler/fetcher/compact_index.rb b/lib/bundler/fetcher/compact_index.rb
index aa828af6b1..b23176588f 100644
--- a/lib/bundler/fetcher/compact_index.rb
+++ b/lib/bundler/fetcher/compact_index.rb
@@ -57,16 +57,6 @@ module Bundler
gem_info
end
- def fetch_spec(spec)
- spec -= [nil, "ruby", ""]
- contents = compact_index_client.spec(*spec)
- return nil if contents.nil?
- contents.unshift(spec.first)
- contents[3].map! {|d| Gem::Dependency.new(*d) }
- EndpointSpecification.new(*contents)
- end
- compact_index_request :fetch_spec
-
def available?
unless SharedHelpers.md5_available?
Bundler.ui.debug("FIPS mode is enabled, bundler can't use the CompactIndex API")
diff --git a/lib/bundler/fetcher/index.rb b/lib/bundler/fetcher/index.rb
index 0d14c47aa7..6bb9fcc193 100644
--- a/lib/bundler/fetcher/index.rb
+++ b/lib/bundler/fetcher/index.rb
@@ -21,32 +21,6 @@ module Bundler
raise HTTPError, "Could not fetch specs from #{display_uri} due to underlying error <#{e.message}>"
end
end
-
- def fetch_spec(spec)
- spec -= [nil, "ruby", ""]
- spec_file_name = "#{spec.join "-"}.gemspec"
-
- uri = Bundler::URI.parse("#{remote_uri}#{Gem::MARSHAL_SPEC_DIR}#{spec_file_name}.rz")
- if uri.scheme == "file"
- path = Bundler.rubygems.correct_for_windows_path(uri.path)
- Bundler.load_marshal Bundler.rubygems.inflate(Gem.read_binary(path))
- elsif cached_spec_path = gemspec_cached_path(spec_file_name)
- Bundler.load_gemspec(cached_spec_path)
- else
- Bundler.load_marshal Bundler.rubygems.inflate(downloader.fetch(uri).body)
- end
- rescue MarshalError
- raise HTTPError, "Gemspec #{spec} contained invalid data.\n" \
- "Your network or your gem server is probably having issues right now."
- end
-
- private
-
- # cached gem specification path, if one exists
- def gemspec_cached_path(spec_file_name)
- paths = Bundler.rubygems.spec_cache_dirs.map {|dir| File.join(dir, spec_file_name) }
- paths.find {|path| File.file? path }
- end
end
end
end
diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb
index 4eb228f314..fd7c8defdc 100644
--- a/lib/bundler/lazy_specification.rb
+++ b/lib/bundler/lazy_specification.rb
@@ -90,11 +90,11 @@ module Bundler
MatchPlatform.platforms_match?(spec.platform, platform_object)
end
installable_candidates = same_platform_candidates.select do |spec|
- !spec.is_a?(EndpointSpecification) ||
+ spec.is_a?(StubSpecification) ||
(spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version))
end
- search = installable_candidates.last || same_platform_candidates.last
+ search = installable_candidates.last
search.dependencies = dependencies if search && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification))
search
end
diff --git a/lib/bundler/lockfile_generator.rb b/lib/bundler/lockfile_generator.rb
index 3bc6bd7339..0578a93fdc 100644
--- a/lib/bundler/lockfile_generator.rb
+++ b/lib/bundler/lockfile_generator.rb
@@ -71,7 +71,7 @@ module Bundler
end
def add_bundled_with
- add_section("BUNDLED WITH", definition.locked_bundler_version.to_s)
+ add_section("BUNDLED WITH", Bundler::VERSION)
end
def add_section(name, value)
diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb
index 22d61fba36..bd579a5f0c 100644
--- a/lib/bundler/resolver.rb
+++ b/lib/bundler/resolver.rb
@@ -358,24 +358,18 @@ module Bundler
o << "\n"
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
o << %(the gems in your Gemfile, which may resolve the conflict.\n)
- elsif !conflict.existing
+ elsif !conflict.existing && !name.end_with?("\0")
o << "\n"
relevant_source = conflict.requirement.source || source_for(name)
- metadata_requirement = name.end_with?("\0")
-
extra_message = if conflict.requirement_trees.first.size > 1
", which is required by gem '#{SharedHelpers.pretty_dependency(conflict.requirement_trees.first[-2])}',"
else
""
end
- if metadata_requirement
- o << "#{SharedHelpers.pretty_dependency(conflict.requirement)}#{extra_message} is not available in #{relevant_source}"
- else
- o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
- end
+ o << gem_not_found_message(name, conflict.requirement, relevant_source, extra_message)
end
end,
:version_for_spec => lambda {|spec| spec.version },
diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb
index 8f4fd18c46..232520de77 100644
--- a/lib/bundler/resolver/spec_group.rb
+++ b/lib/bundler/resolver/spec_group.rb
@@ -95,7 +95,7 @@ module Bundler
def metadata_dependencies(platform)
spec = @specs[platform].first
- return [] unless spec.is_a?(Gem::Specification)
+ return [] if spec.is_a?(LazySpecification)
dependencies = []
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb
index 024b2bfbf2..827f3f9222 100644
--- a/lib/bundler/self_manager.rb
+++ b/lib/bundler/self_manager.rb
@@ -9,46 +9,58 @@ module Bundler
def restart_with_locked_bundler_if_needed
return unless needs_switching? && installed?
- restart_with_locked_bundler
+ restart_with(lockfile_version)
end
def install_locked_bundler_and_restart_with_it_if_needed
return unless needs_switching?
- install_and_restart_with_locked_bundler
+ 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."
+
+ install_and_restart_with(lockfile_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_locked_bundler
- bundler_dep = Gem::Dependency.new("bundler", lockfile_version)
- spec = fetch_spec_for(bundler_dep)
- return if spec.nil?
+ def install_and_restart_with(version)
+ requirement = Gem::Requirement.new(version)
+ spec = find_latest_matching_spec(requirement)
- 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."
+ 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
- spec.source.install(spec)
+ 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_locked_bundler
+ restart_with(version)
end
- def fetch_spec_for(bundler_dep)
- source = Bundler::Source::Rubygems.new("remotes" => "https://rubygems.org")
- source.remote!
- source.add_dependency_names("bundler")
- spec = source.specs.search(bundler_dep).first
- 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}"
- end
- spec
+ def install(spec)
+ spec.source.install(spec)
end
- def restart_with_locked_bundler
+ def restart_with(version)
configured_gem_home = ENV["GEM_HOME"]
configured_gem_path = ENV["GEM_PATH"]
@@ -57,20 +69,79 @@ module Bundler
Bundler.with_original_env do
Kernel.exec(
- { "GEM_HOME" => configured_gem_home, "GEM_PATH" => configured_gem_path, "BUNDLER_VERSION" => lockfile_version },
+ { "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?
+ end
+
+ def autoswitching_applies?
ENV["BUNDLER_VERSION"].nil? &&
Bundler.rubygems.supports_bundler_trampolining? &&
SharedHelpers.in_bundle? &&
- lockfile_version &&
- !lockfile_version.end_with?(".dev") &&
- lockfile_version != current_version &&
- !updating?
+ 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
+ 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?
@@ -80,15 +151,18 @@ module Bundler
def installed?
Bundler.configure
- Bundler.rubygems.find_bundler(lockfile_version)
+ Bundler.rubygems.find_bundler(lockfile_version.to_s)
end
def current_version
- @current_version ||= Bundler::VERSION
+ @current_version ||= Gem::Version.new(Bundler::VERSION)
end
def lockfile_version
- @lockfile_version ||= Bundler::LockfileParser.bundled_with
+ return @lockfile_version if defined?(@lockfile_version)
+
+ parsed_version = Bundler::LockfileParser.bundled_with
+ @lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil
end
end
end
diff --git a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
index f52ced2bcd..bf013307f1 100644
--- a/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
+++ b/lib/bundler/vendor/thor/lib/thor/actions/inject_into_file.rb
@@ -107,10 +107,7 @@ class Bundler::Thor
#
def replace!(regexp, string, force)
content = File.read(destination)
- before, after = content.split(regexp, 2)
- snippet = (behavior == :after ? after : before).to_s
-
- if force || !snippet.include?(replacement)
+ if force || !content.include?(replacement)
success = content.gsub!(regexp, string)
File.open(destination, "wb") { |file| file.write(content) } unless pretend?
diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb
index a3efa9f762..48a4788b3b 100644
--- a/lib/bundler/vendor/thor/lib/thor/version.rb
+++ b/lib/bundler/vendor/thor/lib/thor/version.rb
@@ -1,3 +1,3 @@
class Bundler::Thor
- VERSION = "1.1.0"
+ VERSION = "1.2.1"
end