From d22511fd7595ef1819baa42851d598d95b8f4d00 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Wed, 19 Jan 2022 13:28:23 +0900 Subject: Merge rubygems/rubygems HEAD. Picked at 12aeef6ba9a3be0022be9934c1a3e4c46a03ed3a --- lib/bundler/cli.rb | 13 +- lib/bundler/cli/update.rb | 8 +- lib/bundler/compact_index_client.rb | 6 - lib/bundler/compact_index_client/cache.rb | 9 -- lib/bundler/definition.rb | 8 -- lib/bundler/endpoint_specification.rb | 24 +++- lib/bundler/fetcher.rb | 13 +- lib/bundler/fetcher/compact_index.rb | 10 -- lib/bundler/fetcher/index.rb | 26 ---- lib/bundler/lazy_specification.rb | 4 +- lib/bundler/lockfile_generator.rb | 2 +- lib/bundler/resolver.rb | 10 +- lib/bundler/resolver/spec_group.rb | 2 +- lib/bundler/self_manager.rb | 132 ++++++++++++++++----- .../thor/lib/thor/actions/inject_into_file.rb | 5 +- lib/bundler/vendor/thor/lib/thor/version.rb | 2 +- 16 files changed, 145 insertions(+), 129 deletions(-) (limited to 'lib/bundler') 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 -- cgit v1.2.3