mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Merge RubyGems 3.2.3 and Bundler 2.2.3
This commit is contained in:
parent
733ed1e184
commit
339227363c
Notes:
git
2020-12-23 10:18:06 +09:00
38 changed files with 671 additions and 296 deletions
|
@ -212,13 +212,10 @@ module Bundler
|
|||
end
|
||||
end
|
||||
|
||||
def locked_bundler_version
|
||||
return nil unless defined?(@definition) && @definition
|
||||
def most_specific_locked_platform?(platform)
|
||||
return false unless defined?(@definition) && @definition
|
||||
|
||||
locked_gems = definition.locked_gems
|
||||
return nil unless locked_gems
|
||||
|
||||
locked_gems.bundler_version
|
||||
definition.most_specific_locked_platform == platform
|
||||
end
|
||||
|
||||
def ruby_scope
|
||||
|
|
|
@ -82,7 +82,7 @@ module Bundler
|
|||
locked_spec = locked_info[:spec]
|
||||
new_spec = Bundler.definition.specs[name].first
|
||||
unless new_spec
|
||||
if Bundler.rubygems.platforms.none? {|p| locked_spec.match_platform(p) }
|
||||
unless locked_spec.match_platform(Bundler.local_platform)
|
||||
Bundler.ui.warn "Bundler attempted to update #{name} but it was not considered because it is for a different platform from the current one"
|
||||
end
|
||||
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "gem_parser"
|
||||
|
||||
module Bundler
|
||||
class CompactIndexClient
|
||||
class Cache
|
||||
|
@ -92,19 +94,9 @@ module Bundler
|
|||
header ? lines[header + 1..-1] : lines
|
||||
end
|
||||
|
||||
def parse_gem(string)
|
||||
version_and_platform, rest = string.split(" ", 2)
|
||||
version, platform = version_and_platform.split("-", 2)
|
||||
dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
|
||||
dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
|
||||
requirements = requirements ? requirements.map {|r| parse_dependency(r) } : []
|
||||
[version, platform, dependencies, requirements]
|
||||
end
|
||||
|
||||
def parse_dependency(string)
|
||||
dependency = string.split(":")
|
||||
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
|
||||
dependency
|
||||
def parse_gem(line)
|
||||
@dependency_parser ||= GemParser.new
|
||||
@dependency_parser.parse(line)
|
||||
end
|
||||
|
||||
def info_roots
|
||||
|
|
28
lib/bundler/compact_index_client/gem_parser.rb
Normal file
28
lib/bundler/compact_index_client/gem_parser.rb
Normal file
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Bundler
|
||||
class CompactIndexClient
|
||||
if defined?(Gem::Resolver::APISet::GemParser)
|
||||
GemParser = Gem::Resolver::APISet::GemParser
|
||||
else
|
||||
class GemParser
|
||||
def parse(line)
|
||||
version_and_platform, rest = line.split(" ", 2)
|
||||
version, platform = version_and_platform.split("-", 2)
|
||||
dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
|
||||
dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
|
||||
requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
|
||||
[version, platform, dependencies, requirements]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_dependency(string)
|
||||
dependency = string.split(":")
|
||||
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
|
||||
dependency
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -118,7 +118,7 @@ module Bundler
|
|||
end
|
||||
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
|
||||
|
||||
add_current_platform unless Bundler.frozen_bundle?
|
||||
add_current_platform unless current_ruby_platform_locked? || Bundler.frozen_bundle?
|
||||
|
||||
converge_path_sources_to_gemspec_sources
|
||||
@path_changes = converge_paths
|
||||
|
@ -157,7 +157,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def resolve_remotely!
|
||||
raise "Specs already loaded" if @specs
|
||||
return if @specs
|
||||
@remote = true
|
||||
sources.remote!
|
||||
specs
|
||||
|
@ -269,9 +269,8 @@ module Bundler
|
|||
else
|
||||
# Run a resolve against the locally available gems
|
||||
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
|
||||
platforms_for_resolve = platforms.one? {|p| generic(p) == Gem::Platform::RUBY } ? platforms : platforms.reject{|p| p == Gem::Platform::RUBY }
|
||||
expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote, platforms_for_resolve.map {|p| generic(p) })
|
||||
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms_for_resolve)
|
||||
expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote)
|
||||
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
|
||||
end
|
||||
|
||||
# filter out gems that _can_ be installed on multiple platforms, but don't need
|
||||
|
@ -507,15 +506,11 @@ module Bundler
|
|||
end
|
||||
|
||||
def validate_platforms!
|
||||
return if @platforms.any? do |bundle_platform|
|
||||
Bundler.rubygems.platforms.any? do |local_platform|
|
||||
MatchPlatform.platforms_match?(bundle_platform, local_platform)
|
||||
end
|
||||
end
|
||||
return if current_platform_locked?
|
||||
|
||||
raise ProductionError, "Your bundle only supports platforms #{@platforms.map(&:to_s)} " \
|
||||
"but your local platforms are #{Bundler.rubygems.platforms.map(&:to_s)}, and " \
|
||||
"there's no compatible match between those two lists."
|
||||
"but your local platform is #{Bundler.local_platform}. " \
|
||||
"Add the current platform to the lockfile with `bundle lock --add-platform #{Bundler.local_platform}` and try again."
|
||||
end
|
||||
|
||||
def add_platform(platform)
|
||||
|
@ -528,6 +523,12 @@ module Bundler
|
|||
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
|
||||
end
|
||||
|
||||
def most_specific_locked_platform
|
||||
@platforms.min_by do |bundle_platform|
|
||||
platform_specificity_match(bundle_platform, local_platform)
|
||||
end
|
||||
end
|
||||
|
||||
def find_resolved_spec(current_spec)
|
||||
specs.find_by_name_and_platform(current_spec.name, current_spec.platform)
|
||||
end
|
||||
|
@ -549,6 +550,18 @@ module Bundler
|
|||
|
||||
private
|
||||
|
||||
def current_ruby_platform_locked?
|
||||
return false unless generic_local_platform == Gem::Platform::RUBY
|
||||
|
||||
current_platform_locked?
|
||||
end
|
||||
|
||||
def current_platform_locked?
|
||||
@platforms.any? do |bundle_platform|
|
||||
MatchPlatform.platforms_match?(bundle_platform, Bundler.local_platform)
|
||||
end
|
||||
end
|
||||
|
||||
def add_current_platform
|
||||
add_platform(local_platform)
|
||||
end
|
||||
|
@ -871,8 +884,7 @@ module Bundler
|
|||
end
|
||||
end
|
||||
|
||||
def expand_dependencies(dependencies, remote = false, platforms = nil)
|
||||
platforms ||= @platforms
|
||||
def expand_dependencies(dependencies, remote = false)
|
||||
deps = []
|
||||
dependencies.each do |dep|
|
||||
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
|
||||
|
|
|
@ -35,41 +35,33 @@ module Bundler
|
|||
|
||||
def platform_specificity_match(spec_platform, user_platform)
|
||||
spec_platform = Gem::Platform.new(spec_platform)
|
||||
return PlatformMatch::EXACT_MATCH if spec_platform == user_platform
|
||||
return PlatformMatch::WORST_MATCH if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
|
||||
|
||||
PlatformMatch.new(
|
||||
PlatformMatch.os_match(spec_platform, user_platform),
|
||||
PlatformMatch.cpu_match(spec_platform, user_platform),
|
||||
PlatformMatch.platform_version_match(spec_platform, user_platform)
|
||||
)
|
||||
PlatformMatch.specificity_score(spec_platform, user_platform)
|
||||
end
|
||||
module_function :platform_specificity_match
|
||||
|
||||
def select_best_platform_match(specs, platform)
|
||||
specs.select {|spec| spec.match_platform(platform) }.
|
||||
min_by {|spec| platform_specificity_match(spec.platform, platform) }
|
||||
matching = specs.select {|spec| spec.match_platform(platform) }
|
||||
exact = matching.select {|spec| spec.platform == platform }
|
||||
return exact if exact.any?
|
||||
|
||||
sorted_matching = matching.sort_by {|spec| platform_specificity_match(spec.platform, platform) }
|
||||
exemplary_spec = sorted_matching.first
|
||||
|
||||
sorted_matching.take_while{|spec| same_specificity(platform, spec, exemplary_spec) && same_deps(spec, exemplary_spec) }
|
||||
end
|
||||
module_function :select_best_platform_match
|
||||
|
||||
PlatformMatch = Struct.new(:os_match, :cpu_match, :platform_version_match)
|
||||
class PlatformMatch
|
||||
def <=>(other)
|
||||
return nil unless other.is_a?(PlatformMatch)
|
||||
def self.specificity_score(spec_platform, user_platform)
|
||||
return -1 if spec_platform == user_platform
|
||||
return 1_000_000 if spec_platform.nil? || spec_platform == Gem::Platform::RUBY || user_platform == Gem::Platform::RUBY
|
||||
|
||||
m = os_match <=> other.os_match
|
||||
return m unless m.zero?
|
||||
|
||||
m = cpu_match <=> other.cpu_match
|
||||
return m unless m.zero?
|
||||
|
||||
m = platform_version_match <=> other.platform_version_match
|
||||
m
|
||||
os_match(spec_platform, user_platform) +
|
||||
cpu_match(spec_platform, user_platform) * 10 +
|
||||
platform_version_match(spec_platform, user_platform) * 100
|
||||
end
|
||||
|
||||
EXACT_MATCH = new(-1, -1, -1).freeze
|
||||
WORST_MATCH = new(1_000_000, 1_000_000, 1_000_000).freeze
|
||||
|
||||
def self.os_match(spec_platform, user_platform)
|
||||
if spec_platform.os == user_platform.os
|
||||
0
|
||||
|
@ -100,5 +92,19 @@ module Bundler
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def same_specificity(platform, spec, exemplary_spec)
|
||||
platform_specificity_match(spec.platform, platform) == platform_specificity_match(exemplary_spec.platform, platform)
|
||||
end
|
||||
module_function :same_specificity
|
||||
|
||||
def same_deps(spec, exemplary_spec)
|
||||
same_runtime_deps = spec.dependencies.sort == exemplary_spec.dependencies.sort
|
||||
return same_runtime_deps unless spec.is_a?(Gem::Specification) && exemplary_spec.is_a?(Gem::Specification)
|
||||
|
||||
same_metadata_deps = spec.required_ruby_version == exemplary_spec.required_ruby_version && spec.required_rubygems_version == exemplary_spec.required_rubygems_version
|
||||
same_runtime_deps && same_metadata_deps
|
||||
end
|
||||
module_function :same_deps
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,7 +4,7 @@ require_relative "match_platform"
|
|||
|
||||
module Bundler
|
||||
class LazySpecification
|
||||
Identifier = Struct.new(:name, :version, :source, :platform, :dependencies)
|
||||
Identifier = Struct.new(:name, :version, :platform)
|
||||
class Identifier
|
||||
include Comparable
|
||||
def <=>(other)
|
||||
|
@ -108,7 +108,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def identifier
|
||||
@__identifier ||= Identifier.new(name, version, source, platform, dependencies)
|
||||
@__identifier ||= Identifier.new(name, version, platform)
|
||||
end
|
||||
|
||||
def git_version
|
||||
|
@ -131,17 +131,16 @@ module Bundler
|
|||
end
|
||||
|
||||
#
|
||||
# Bundler 2.2.0 was the first version that records the full resolution
|
||||
# including platform specific gems in the lockfile, which means that if a
|
||||
# gem with RUBY platform is recorded, the RUBY platform version of the gem
|
||||
# should be installed. Previously bundler would record only generic versions
|
||||
# in the lockfile and then install the most specific platform variant if
|
||||
# available.
|
||||
# For backwards compatibility with existing lockfiles, if the most specific
|
||||
# locked platform is RUBY, we keep the previous behaviour of resolving the
|
||||
# best platform variant at materiliazation time. For previous bundler
|
||||
# versions (before 2.2.0) this was always the case (except when the lockfile
|
||||
# only included non-ruby platforms), but we're also keeping this behaviour
|
||||
# on newer bundlers unless users generate the lockfile from scratch or
|
||||
# explicitly add a more specific platform.
|
||||
#
|
||||
def ruby_platform_materializes_to_ruby_platform?
|
||||
locked_bundler_version = Bundler.locked_bundler_version
|
||||
|
||||
locked_bundler_version.nil? || Gem::Version.new(locked_bundler_version) >= Gem::Version.new("2.2.0")
|
||||
!Bundler.most_specific_locked_platform?(Gem::Platform::RUBY)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -25,11 +25,15 @@ module Bundler
|
|||
|
||||
def to_specs
|
||||
@activated_platforms.map do |p|
|
||||
next unless s = @specs[p]
|
||||
specs = @specs[p]
|
||||
next unless specs.any?
|
||||
|
||||
specs.map do |s|
|
||||
lazy_spec = LazySpecification.new(name, version, s.platform, source)
|
||||
lazy_spec.dependencies.replace s.dependencies
|
||||
lazy_spec
|
||||
end.compact.uniq
|
||||
end
|
||||
end.flatten.compact.uniq
|
||||
end
|
||||
|
||||
def copy_for(platforms)
|
||||
|
@ -42,12 +46,8 @@ module Bundler
|
|||
copied_sg
|
||||
end
|
||||
|
||||
def spec_for(platform)
|
||||
@specs[platform]
|
||||
end
|
||||
|
||||
def for?(platform)
|
||||
!spec_for(platform).nil?
|
||||
@specs[platform].any?
|
||||
end
|
||||
|
||||
def to_s
|
||||
|
@ -58,7 +58,7 @@ module Bundler
|
|||
def dependencies_for_activated_platforms
|
||||
dependencies = @activated_platforms.map {|p| __dependencies[p] }
|
||||
metadata_dependencies = @activated_platforms.map do |platform|
|
||||
metadata_dependencies(@specs[platform], platform)
|
||||
metadata_dependencies(@specs[platform].first, platform)
|
||||
end
|
||||
dependencies.concat(metadata_dependencies).flatten
|
||||
end
|
||||
|
@ -94,7 +94,8 @@ module Bundler
|
|||
def __dependencies
|
||||
@dependencies = Hash.new do |dependencies, platform|
|
||||
dependencies[platform] = []
|
||||
if spec = @specs[platform]
|
||||
specs = @specs[platform]
|
||||
if spec = specs.first
|
||||
spec.dependencies.each do |dep|
|
||||
next if dep.type == :development
|
||||
next if @ignores_bundler_dependencies && dep.name == "bundler".freeze
|
||||
|
@ -106,10 +107,7 @@ module Bundler
|
|||
end
|
||||
|
||||
def metadata_dependencies(spec, platform)
|
||||
return [] unless spec
|
||||
# Only allow endpoint specifications since they won't hit the network to
|
||||
# fetch the full gemspec when calling required_ruby_version
|
||||
return [] if !spec.is_a?(EndpointSpecification) && !spec.is_a?(Gem::Specification)
|
||||
return [] unless spec && spec.is_a?(Gem::Specification)
|
||||
dependencies = []
|
||||
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
|
||||
dependencies << DepProxy.new(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
|
||||
|
|
|
@ -110,11 +110,6 @@ module Bundler
|
|||
obj.to_s
|
||||
end
|
||||
|
||||
def platforms
|
||||
return [Gem::Platform::RUBY] if Bundler.settings[:force_ruby_platform]
|
||||
Gem.platforms
|
||||
end
|
||||
|
||||
def configuration
|
||||
require_relative "psyched_yaml"
|
||||
Gem.configuration
|
||||
|
|
|
@ -22,10 +22,11 @@ module Bundler
|
|||
break unless dep = deps.shift
|
||||
next if !handled.add?(dep) || skip.include?(dep.name)
|
||||
|
||||
if spec = spec_for_dependency(dep, match_current_platform)
|
||||
specs << spec
|
||||
specs_for_dep = spec_for_dependency(dep, match_current_platform)
|
||||
if specs_for_dep.any?
|
||||
specs += specs_for_dep
|
||||
|
||||
spec.dependencies.each do |d|
|
||||
specs_for_dep.first.dependencies.each do |d|
|
||||
next if d.type == :development
|
||||
d = DepProxy.new(d, dep.__platform) unless match_current_platform
|
||||
deps << d
|
||||
|
@ -184,11 +185,7 @@ module Bundler
|
|||
def spec_for_dependency(dep, match_current_platform)
|
||||
specs_for_platforms = lookup[dep.name]
|
||||
if match_current_platform
|
||||
Bundler.rubygems.platforms.reverse_each do |pl|
|
||||
match = GemHelpers.select_best_platform_match(specs_for_platforms, pl)
|
||||
return match if match
|
||||
end
|
||||
nil
|
||||
GemHelpers.select_best_platform_match(specs_for_platforms, Bundler.local_platform)
|
||||
else
|
||||
GemHelpers.select_best_platform_match(specs_for_platforms, dep.__platform)
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: false
|
||||
|
||||
module Bundler
|
||||
VERSION = "2.2.2".freeze
|
||||
VERSION = "2.2.3".freeze
|
||||
|
||||
def self.bundler_major_version
|
||||
@bundler_major_version ||= VERSION.split(".").first.to_i
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
require 'rbconfig'
|
||||
|
||||
module Gem
|
||||
VERSION = "3.2.2".freeze
|
||||
VERSION = "3.2.3".freeze
|
||||
end
|
||||
|
||||
# Must be first since it unloads the prelude from 1.9.2
|
||||
|
|
|
@ -286,6 +286,7 @@ class Gem::DependencyInstaller
|
|||
|
||||
installer_set = Gem::Resolver::InstallerSet.new @domain
|
||||
installer_set.ignore_installed = (@minimal_deps == false) || @only_install_dir
|
||||
installer_set.force = @force
|
||||
|
||||
if consider_local?
|
||||
if dep_or_name =~ /\.gem$/ and File.file? dep_or_name
|
||||
|
|
|
@ -638,27 +638,6 @@ class Gem::Installer
|
|||
end
|
||||
end
|
||||
|
||||
def ensure_required_ruby_version_met # :nodoc:
|
||||
if rrv = spec.required_ruby_version
|
||||
ruby_version = Gem.ruby_version
|
||||
unless rrv.satisfied_by? ruby_version
|
||||
raise Gem::RuntimeRequirementNotMetError,
|
||||
"#{spec.name} requires Ruby version #{rrv}. The current ruby version is #{ruby_version}."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_required_rubygems_version_met # :nodoc:
|
||||
if rrgv = spec.required_rubygems_version
|
||||
unless rrgv.satisfied_by? Gem.rubygems_version
|
||||
rg_version = Gem::VERSION
|
||||
raise Gem::RuntimeRequirementNotMetError,
|
||||
"#{spec.name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
|
||||
"Try 'gem update --system' to update RubyGems itself."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_dependencies_met # :nodoc:
|
||||
deps = spec.runtime_dependencies
|
||||
deps |= spec.development_dependencies if @development
|
||||
|
@ -914,8 +893,6 @@ TEXT
|
|||
|
||||
return true if @force
|
||||
|
||||
ensure_required_ruby_version_met
|
||||
ensure_required_rubygems_version_met
|
||||
ensure_dependencies_met unless @ignore_dependencies
|
||||
|
||||
true
|
||||
|
|
|
@ -215,7 +215,7 @@ class Gem::RemoteFetcher
|
|||
|
||||
case response
|
||||
when Net::HTTPOK, Net::HTTPNotModified then
|
||||
response.uri = uri if response.respond_to? :uri
|
||||
response.uri = uri
|
||||
head ? response : response.body
|
||||
when Net::HTTPMovedPermanently, Net::HTTPFound, Net::HTTPSeeOther,
|
||||
Net::HTTPTemporaryRedirect then
|
||||
|
|
|
@ -195,19 +195,8 @@ class Gem::RequestSet
|
|||
yield req, installer if block_given?
|
||||
end
|
||||
rescue Gem::RuntimeRequirementNotMetError => e
|
||||
recent_match = req.spec.set.find_all(req.request).sort_by(&:version).reverse_each.find do |s|
|
||||
s = s.spec
|
||||
s.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
|
||||
s.required_rubygems_version.satisfied_by?(Gem.rubygems_version) &&
|
||||
Gem::Platform.installable?(s)
|
||||
end
|
||||
if recent_match
|
||||
suggestion = "The last version of #{req.request} to support your Ruby & RubyGems was #{recent_match.version}. Try installing it with `gem install #{recent_match.name} -v #{recent_match.version}`"
|
||||
suggestion += " and then running the current command again" unless @always_install.include?(req.spec.spec)
|
||||
else
|
||||
suggestion = "There are no versions of #{req.request} compatible with your Ruby & RubyGems"
|
||||
suggestion += ". Maybe try installing an older version of the gem you're looking for?" unless @always_install.include?(req.spec.spec)
|
||||
end
|
||||
e.suggestion = suggestion
|
||||
raise
|
||||
end
|
||||
|
|
|
@ -261,7 +261,12 @@ class Gem::Resolver
|
|||
end
|
||||
|
||||
def requirement_satisfied_by?(requirement, activated, spec)
|
||||
requirement.matches_spec? spec
|
||||
matches_spec = requirement.matches_spec? spec
|
||||
return matches_spec if @soft_missing
|
||||
|
||||
matches_spec &&
|
||||
spec.spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
|
||||
spec.spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
|
||||
end
|
||||
|
||||
def name_for(dependency)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
# Returns instances of APISpecification.
|
||||
|
||||
class Gem::Resolver::APISet < Gem::Resolver::Set
|
||||
autoload :GemParser, File.expand_path("api_set/gem_parser", __dir__)
|
||||
|
||||
##
|
||||
# The URI for the dependency API this APISet uses.
|
||||
|
||||
|
@ -24,13 +26,13 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
# API URL +dep_uri+ which is described at
|
||||
# https://guides.rubygems.org/rubygems-org-api
|
||||
|
||||
def initialize(dep_uri = 'https://rubygems.org/api/v1/dependencies')
|
||||
def initialize(dep_uri = 'https://index.rubygems.org/info/')
|
||||
super()
|
||||
|
||||
dep_uri = URI dep_uri unless URI === dep_uri
|
||||
|
||||
@dep_uri = dep_uri
|
||||
@uri = dep_uri + '../..'
|
||||
@uri = dep_uri + '..'
|
||||
|
||||
@data = Hash.new {|h,k| h[k] = [] }
|
||||
@source = Gem::Source.new @uri
|
||||
|
@ -75,20 +77,8 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
def prefetch_now # :nodoc:
|
||||
needed, @to_fetch = @to_fetch, []
|
||||
|
||||
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
|
||||
str = Gem::RemoteFetcher.fetcher.fetch_path uri
|
||||
|
||||
loaded = []
|
||||
|
||||
Marshal.load(str).each do |ver|
|
||||
name = ver[:name]
|
||||
|
||||
@data[name] << ver
|
||||
loaded << name
|
||||
end
|
||||
|
||||
(needed - loaded).each do |missing|
|
||||
@data[missing] = []
|
||||
needed.sort.each do |name|
|
||||
versions(name)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -111,13 +101,32 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
|
|||
return @data[name]
|
||||
end
|
||||
|
||||
uri = @dep_uri + "?gems=#{name}"
|
||||
uri = @dep_uri + name
|
||||
str = Gem::RemoteFetcher.fetcher.fetch_path uri
|
||||
|
||||
Marshal.load(str).each do |ver|
|
||||
@data[ver[:name]] << ver
|
||||
lines(str).each do |ver|
|
||||
number, platform, dependencies, requirements = parse_gem(ver)
|
||||
|
||||
platform ||= "ruby"
|
||||
dependencies = dependencies.map {|dep_name, reqs| [dep_name, reqs.join(", ")] }
|
||||
requirements = requirements.map {|req_name, reqs| [req_name.to_sym, reqs] }.to_h
|
||||
|
||||
@data[name] << { name: name, number: number, platform: platform, dependencies: dependencies, requirements: requirements }
|
||||
end
|
||||
|
||||
@data[name]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lines(str)
|
||||
lines = str.split("\n")
|
||||
header = lines.index("---")
|
||||
header ? lines[header + 1..-1] : lines
|
||||
end
|
||||
|
||||
def parse_gem(string)
|
||||
@gem_parser ||= GemParser.new
|
||||
@gem_parser.parse(string)
|
||||
end
|
||||
end
|
||||
|
|
20
lib/rubygems/resolver/api_set/gem_parser.rb
Normal file
20
lib/rubygems/resolver/api_set/gem_parser.rb
Normal file
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Gem::Resolver::APISet::GemParser
|
||||
def parse(line)
|
||||
version_and_platform, rest = line.split(" ", 2)
|
||||
version, platform = version_and_platform.split("-", 2)
|
||||
dependencies, requirements = rest.split("|", 2).map {|s| s.split(",") } if rest
|
||||
dependencies = dependencies ? dependencies.map {|d| parse_dependency(d) } : []
|
||||
requirements = requirements ? requirements.map {|d| parse_dependency(d) } : []
|
||||
[version, platform, dependencies, requirements]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_dependency(string)
|
||||
dependency = string.split(":")
|
||||
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
|
||||
dependency
|
||||
end
|
||||
end
|
|
@ -35,6 +35,8 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
|
|||
@dependencies = api_data[:dependencies].map do |name, ver|
|
||||
Gem::Dependency.new(name, ver.split(/\s*,\s*/)).freeze
|
||||
end.freeze
|
||||
@required_ruby_version = Gem::Requirement.new(api_data.dig(:requirements, :ruby)).freeze
|
||||
@required_rubygems_version = Gem::Requirement.new(api_data.dig(:requirements, :rubygems)).freeze
|
||||
end
|
||||
|
||||
def ==(other) # :nodoc:
|
||||
|
@ -42,12 +44,11 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
|
|||
@set == other.set and
|
||||
@name == other.name and
|
||||
@version == other.version and
|
||||
@platform == other.platform and
|
||||
@dependencies == other.dependencies
|
||||
@platform == other.platform
|
||||
end
|
||||
|
||||
def hash
|
||||
@set.hash ^ @name.hash ^ @version.hash ^ @platform.hash ^ @dependencies.hash
|
||||
@set.hash ^ @name.hash ^ @version.hash ^ @platform.hash
|
||||
end
|
||||
|
||||
def fetch_development_dependencies # :nodoc:
|
||||
|
|
|
@ -60,7 +60,7 @@ class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
|
|||
def replace_failed_api_set(error) # :nodoc:
|
||||
uri = error.uri
|
||||
uri = URI uri unless URI === uri
|
||||
uri.query = nil
|
||||
uri = uri + "."
|
||||
|
||||
raise error unless api_set = @sets.find do |set|
|
||||
Gem::Resolver::APISet === set and set.dep_uri == uri
|
||||
|
|
|
@ -33,6 +33,21 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
|
|||
spec.dependencies
|
||||
end
|
||||
|
||||
##
|
||||
# The required_ruby_version constraint for this specification
|
||||
|
||||
def required_ruby_version
|
||||
spec.required_ruby_version
|
||||
end
|
||||
|
||||
##
|
||||
# The required_rubygems_version constraint for this specification
|
||||
#
|
||||
|
||||
def required_rubygems_version
|
||||
spec.required_rubygems_version
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
self.class === other &&
|
||||
@name == other.name &&
|
||||
|
|
|
@ -25,6 +25,12 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
|
||||
attr_reader :remote_set # :nodoc:
|
||||
|
||||
##
|
||||
# Ignore ruby & rubygems specification constraints.
|
||||
#
|
||||
|
||||
attr_accessor :force # :nodoc:
|
||||
|
||||
##
|
||||
# Creates a new InstallerSet that will look for gems in +domain+.
|
||||
|
||||
|
@ -41,6 +47,7 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
@local = {}
|
||||
@local_source = Gem::Source::Local.new
|
||||
@remote_set = Gem::Resolver::BestSet.new
|
||||
@force = false
|
||||
@specs = {}
|
||||
end
|
||||
|
||||
|
@ -63,15 +70,30 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
Gem::Platform.local === s.platform
|
||||
end
|
||||
|
||||
if found.empty?
|
||||
found = found.sort_by do |s|
|
||||
[s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
|
||||
end
|
||||
|
||||
newest = found.last
|
||||
|
||||
unless @force
|
||||
found_matching_metadata = found.select do |spec|
|
||||
metadata_satisfied?(spec)
|
||||
end
|
||||
|
||||
if found_matching_metadata.empty?
|
||||
if newest
|
||||
ensure_required_ruby_version_met(newest.spec)
|
||||
ensure_required_rubygems_version_met(newest.spec)
|
||||
else
|
||||
exc = Gem::UnsatisfiableDependencyError.new request
|
||||
exc.errors = errors
|
||||
|
||||
raise exc
|
||||
end
|
||||
|
||||
newest = found.max_by do |s|
|
||||
[s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
|
||||
else
|
||||
newest = found_matching_metadata.last
|
||||
end
|
||||
end
|
||||
|
||||
@always_install << newest.spec
|
||||
|
@ -221,4 +243,32 @@ class Gem::Resolver::InstallerSet < Gem::Resolver::Set
|
|||
@domain = :local unless remote
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def metadata_satisfied?(spec)
|
||||
spec.required_ruby_version.satisfied_by?(Gem.ruby_version) &&
|
||||
spec.required_rubygems_version.satisfied_by?(Gem.rubygems_version)
|
||||
end
|
||||
|
||||
def ensure_required_ruby_version_met(spec) # :nodoc:
|
||||
if rrv = spec.required_ruby_version
|
||||
ruby_version = Gem.ruby_version
|
||||
unless rrv.satisfied_by? ruby_version
|
||||
raise Gem::RuntimeRequirementNotMetError,
|
||||
"#{spec.full_name} requires Ruby version #{rrv}. The current ruby version is #{ruby_version}."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def ensure_required_rubygems_version_met(spec) # :nodoc:
|
||||
if rrgv = spec.required_rubygems_version
|
||||
unless rrgv.satisfied_by? Gem.rubygems_version
|
||||
rg_version = Gem::VERSION
|
||||
raise Gem::RuntimeRequirementNotMetError,
|
||||
"#{spec.full_name} requires RubyGems version #{rrgv}. The current RubyGems version is #{rg_version}. " +
|
||||
"Try 'gem update --system' to update RubyGems itself."
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -22,6 +22,20 @@ class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
|
|||
spec.dependencies
|
||||
end
|
||||
|
||||
##
|
||||
# The required_ruby_version constraint for this specification
|
||||
|
||||
def required_ruby_version
|
||||
spec.required_ruby_version
|
||||
end
|
||||
|
||||
##
|
||||
# The required_rubygems_version constraint for this specification
|
||||
|
||||
def required_rubygems_version
|
||||
spec.required_rubygems_version
|
||||
end
|
||||
|
||||
##
|
||||
# The name and version of the specification.
|
||||
#
|
||||
|
|
|
@ -43,6 +43,16 @@ class Gem::Resolver::Specification
|
|||
|
||||
attr_reader :version
|
||||
|
||||
##
|
||||
# The required_ruby_version constraint for this specification.
|
||||
|
||||
attr_reader :required_ruby_version
|
||||
|
||||
##
|
||||
# The required_ruby_version constraint for this specification.
|
||||
|
||||
attr_reader :required_rubygems_version
|
||||
|
||||
##
|
||||
# Sets default instance variables for the specification.
|
||||
|
||||
|
@ -53,6 +63,8 @@ class Gem::Resolver::Specification
|
|||
@set = nil
|
||||
@source = nil
|
||||
@version = nil
|
||||
@required_ruby_version = Gem::Requirement.default
|
||||
@required_rubygems_version = Gem::Requirement.default
|
||||
end
|
||||
|
||||
##
|
||||
|
|
|
@ -79,7 +79,15 @@ class Gem::Source
|
|||
def dependency_resolver_set # :nodoc:
|
||||
return Gem::Resolver::IndexSet.new self if 'file' == uri.scheme
|
||||
|
||||
bundler_api_uri = enforce_trailing_slash(uri) + './api/v1/dependencies'
|
||||
fetch_uri = if uri.host == "rubygems.org"
|
||||
index_uri = uri.dup
|
||||
index_uri.host = "index.rubygems.org"
|
||||
index_uri
|
||||
else
|
||||
uri
|
||||
end
|
||||
|
||||
bundler_api_uri = enforce_trailing_slash(fetch_uri)
|
||||
|
||||
begin
|
||||
fetcher = Gem::RemoteFetcher.fetcher
|
||||
|
@ -87,11 +95,7 @@ class Gem::Source
|
|||
rescue Gem::RemoteFetcher::FetchError
|
||||
Gem::Resolver::IndexSet.new self
|
||||
else
|
||||
if response.respond_to? :uri
|
||||
Gem::Resolver::APISet.new response.uri
|
||||
else
|
||||
Gem::Resolver::APISet.new bundler_api_uri
|
||||
end
|
||||
Gem::Resolver::APISet.new response.uri + "./info/"
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -67,6 +67,32 @@ RSpec.describe "bundle exec" do
|
|||
expect(out).to eq(Gem::VERSION)
|
||||
end
|
||||
|
||||
it "works when exec'ing back to bundler with a lockfile that doesn't include the current platform" do
|
||||
install_gemfile <<-G
|
||||
gem "rack", "0.9.1"
|
||||
G
|
||||
|
||||
# simulate lockfile generated with old version not including specific platform
|
||||
lockfile <<-L
|
||||
GEM
|
||||
specs:
|
||||
rack (0.9.1)
|
||||
|
||||
PLATFORMS
|
||||
RUBY
|
||||
|
||||
DEPENDENCIES
|
||||
rack (= 0.9.1)
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
L
|
||||
|
||||
bundle "exec bundle cache", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
|
||||
|
||||
expect(out).to include("Updating files in vendor/cache")
|
||||
end
|
||||
|
||||
it "respects custom process title when loading through ruby" do
|
||||
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
|
||||
|
||||
|
|
|
@ -630,4 +630,47 @@ RSpec.describe "bundle install with gem sources" do
|
|||
"setting them for authentication.")
|
||||
end
|
||||
end
|
||||
|
||||
context "in a frozen bundle" do
|
||||
before do
|
||||
build_repo4 do
|
||||
build_gem "libv8", "8.4.255.0" do |s|
|
||||
s.platform = "x86_64-darwin-19"
|
||||
end
|
||||
end
|
||||
|
||||
gemfile <<-G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
|
||||
gem "libv8"
|
||||
G
|
||||
|
||||
lockfile <<-L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
libv8 (8.4.255.0-x86_64-darwin-19)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-darwin-19
|
||||
|
||||
DEPENDENCIES
|
||||
libv8
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
|
||||
bundle "config set --local deployment true"
|
||||
end
|
||||
|
||||
it "should fail loudly if the lockfile platforms don't include the current platform" do
|
||||
simulate_platform(Gem::Platform.new("x86_64-linux")) { bundle "install", :raise_on_error => false }
|
||||
|
||||
expect(err).to eq(
|
||||
"Your bundle only supports platforms [\"x86_64-darwin-19\"] but your local platform is x86_64-linux. " \
|
||||
"Add the current platform to the lockfile with `bundle lock --add-platform x86_64-linux` and try again."
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -383,6 +383,90 @@ RSpec.describe "bundle lock" do
|
|||
expect(out).to match(/Writing lockfile to.+Gemfile\.lock/)
|
||||
end
|
||||
|
||||
it "adds all more specific candidates when they all have the same dependencies" do
|
||||
build_repo4 do
|
||||
build_gem "libv8", "8.4.255.0" do |s|
|
||||
s.platform = "x86_64-darwin-19"
|
||||
end
|
||||
|
||||
build_gem "libv8", "8.4.255.0" do |s|
|
||||
s.platform = "x86_64-darwin-20"
|
||||
end
|
||||
end
|
||||
|
||||
gemfile <<-G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
|
||||
gem "libv8"
|
||||
G
|
||||
|
||||
simulate_platform(Gem::Platform.new("x86_64-darwin")) { bundle "lock" }
|
||||
|
||||
lockfile_should_be <<-G
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
libv8 (8.4.255.0-x86_64-darwin-19)
|
||||
libv8 (8.4.255.0-x86_64-darwin-20)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-darwin
|
||||
|
||||
DEPENDENCIES
|
||||
libv8
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
G
|
||||
end
|
||||
|
||||
it "respects the previous lockfile if it had a matching less specific platform already locked, and installs the best variant for each platform" do
|
||||
build_repo4 do
|
||||
build_gem "libv8", "8.4.255.0" do |s|
|
||||
s.platform = "x86_64-darwin-19"
|
||||
end
|
||||
|
||||
build_gem "libv8", "8.4.255.0" do |s|
|
||||
s.platform = "x86_64-darwin-20"
|
||||
end
|
||||
end
|
||||
|
||||
gemfile <<-G
|
||||
source "#{file_uri_for(gem_repo4)}"
|
||||
|
||||
gem "libv8"
|
||||
G
|
||||
|
||||
lockfile <<-G
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo4)}/
|
||||
specs:
|
||||
libv8 (8.4.255.0-x86_64-darwin-19)
|
||||
libv8 (8.4.255.0-x86_64-darwin-20)
|
||||
|
||||
PLATFORMS
|
||||
x86_64-darwin
|
||||
|
||||
DEPENDENCIES
|
||||
libv8
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
G
|
||||
|
||||
previous_lockfile = lockfile
|
||||
|
||||
%w[x86_64-darwin-19 x86_64-darwin-20].each do |platform|
|
||||
simulate_platform(Gem::Platform.new(platform)) do
|
||||
bundle "lock"
|
||||
expect(lockfile).to eq(previous_lockfile)
|
||||
|
||||
bundle "install"
|
||||
expect(the_bundle).to include_gem("libv8 8.4.255.0 #{platform}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "when an update is available" do
|
||||
let(:repo) { gem_repo2 }
|
||||
|
||||
|
|
|
@ -54,6 +54,56 @@ RSpec.describe "bundle install with specific platforms" do
|
|||
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
|
||||
end
|
||||
|
||||
it "understands that a non-plaform specific gem in a new lockfile locked only to RUBY doesn't necessarily mean installing the non-specific variant" do
|
||||
setup_multiplatform_gem
|
||||
|
||||
system_gems "bundler-2.1.4"
|
||||
|
||||
# Consistent location to install and look for gems
|
||||
bundle "config set --local path vendor/bundle", :env => { "BUNDLER_VERSION" => "2.1.4" }
|
||||
|
||||
gemfile google_protobuf
|
||||
|
||||
# simulate lockfile created with old bundler, which only locks for ruby platform
|
||||
lockfile <<-L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo2)}/
|
||||
specs:
|
||||
google-protobuf (3.0.0.alpha.4.0)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
google-protobuf
|
||||
|
||||
BUNDLED WITH
|
||||
2.1.4
|
||||
L
|
||||
|
||||
bundle "update", :env => { "BUNDLER_VERSION" => Bundler::VERSION }
|
||||
|
||||
# make sure the platform that the platform specific dependency is used, since we're only locked to ruby
|
||||
expect(the_bundle).to include_gem("google-protobuf 3.0.0.alpha.5.0.5.1 universal-darwin")
|
||||
|
||||
# make sure we're still only locked to ruby
|
||||
lockfile_should_be <<-L
|
||||
GEM
|
||||
remote: #{file_uri_for(gem_repo2)}/
|
||||
specs:
|
||||
google-protobuf (3.0.0.alpha.5.0.5.1)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
|
||||
DEPENDENCIES
|
||||
google-protobuf
|
||||
|
||||
BUNDLED WITH
|
||||
#{Bundler::VERSION}
|
||||
L
|
||||
end
|
||||
|
||||
it "caches the universal-darwin gem when --all-platforms is passed and properly picks it up on further bundler invocations" do
|
||||
setup_multiplatform_gem
|
||||
gemfile(google_protobuf)
|
||||
|
|
|
@ -39,7 +39,7 @@ class BundlerVCRHTTP < Net::HTTP
|
|||
response_io = ::Net::BufferedIO.new(response_file)
|
||||
::Net::HTTPResponse.read_new(response_io).tap do |response|
|
||||
response.decode_content = request.decode_content if request.respond_to?(:decode_content)
|
||||
response.uri = request.uri if request.respond_to?(:uri)
|
||||
response.uri = request.uri
|
||||
|
||||
response.reading_body(response_io, request.response_body_permitted?) do
|
||||
response_block.call(response) if response_block
|
||||
|
|
|
@ -504,6 +504,137 @@ ERROR: Possible alternatives: non_existent_with_hint
|
|||
assert_equal %w[a-2], @cmd.installed_specs.map {|spec| spec.full_name }
|
||||
end
|
||||
|
||||
def test_execute_required_ruby_version
|
||||
next_ruby = Gem.ruby_version.segments.map.with_index{|n, i| i == 1 ? n + 1 : n }.join(".")
|
||||
|
||||
local = Gem::Platform.local
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.download 'a', 2
|
||||
fetcher.download 'a', 2 do |s|
|
||||
s.required_ruby_version = "< #{RUBY_VERSION}.a"
|
||||
s.platform = local
|
||||
end
|
||||
fetcher.download 'a', 3 do |s|
|
||||
s.required_ruby_version = ">= #{next_ruby}"
|
||||
end
|
||||
fetcher.download 'a', 3 do |s|
|
||||
s.required_ruby_version = ">= #{next_ruby}"
|
||||
s.platform = local
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[a-2], @cmd.installed_specs.map {|spec| spec.full_name }
|
||||
end
|
||||
|
||||
def test_execute_required_ruby_version_upper_bound
|
||||
local = Gem::Platform.local
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2.0
|
||||
fetcher.gem 'a', 2.0 do |s|
|
||||
s.required_ruby_version = "< #{RUBY_VERSION}.a"
|
||||
s.platform = local
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[a-2.0], @cmd.installed_specs.map {|spec| spec.full_name }
|
||||
end
|
||||
|
||||
def test_execute_required_ruby_version_specific_not_met
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', '1.0' do |s|
|
||||
s.required_ruby_version = '= 1.4.6'
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::TermError do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
errs = @ui.error.split("\n")
|
||||
assert_equal "ERROR: Error installing a:", errs.shift
|
||||
assert_equal "\ta-1.0 requires Ruby version = 1.4.6. The current ruby version is #{Gem.ruby_version}.", errs.shift
|
||||
end
|
||||
|
||||
def test_execute_required_ruby_version_specific_prerelease_met
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', '1.0' do |s|
|
||||
s.required_ruby_version = '>= 1.4.6.preview2'
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::SystemExitException, @ui.error do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
assert_equal %w[a-1.0], @cmd.installed_specs.map {|spec| spec.full_name }
|
||||
end
|
||||
|
||||
def test_execute_required_ruby_version_specific_prerelease_not_met
|
||||
next_ruby_pre = Gem.ruby_version.segments.map.with_index{|n, i| i == 1 ? n + 1 : n }.join(".") + ".a"
|
||||
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', '1.0' do |s|
|
||||
s.required_ruby_version = "> #{next_ruby_pre}"
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::TermError do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
errs = @ui.error.split("\n")
|
||||
assert_equal "ERROR: Error installing a:", errs.shift
|
||||
assert_equal "\ta-1.0 requires Ruby version > #{next_ruby_pre}. The current ruby version is #{Gem.ruby_version}.", errs.shift
|
||||
end
|
||||
|
||||
def test_execute_required_rubygems_version_wrong
|
||||
spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', '1.0' do |s|
|
||||
s.required_rubygems_version = '< 0'
|
||||
end
|
||||
end
|
||||
|
||||
@cmd.options[:args] = %w[a]
|
||||
|
||||
use_ui @ui do
|
||||
assert_raises Gem::MockGemUi::TermError do
|
||||
@cmd.execute
|
||||
end
|
||||
end
|
||||
|
||||
errs = @ui.error.split("\n")
|
||||
assert_equal "ERROR: Error installing a:", errs.shift
|
||||
assert_equal "\ta-1.0 requires RubyGems version < 0. The current RubyGems version is #{Gem.rubygems_version}. Try 'gem update --system' to update RubyGems itself.", errs.shift
|
||||
end
|
||||
|
||||
def test_execute_rdoc
|
||||
specs = spec_fetcher do |fetcher|
|
||||
fetcher.gem 'a', 2
|
||||
|
|
|
@ -1172,12 +1172,16 @@ gem 'other', version
|
|||
end
|
||||
|
||||
def test_install_force
|
||||
_, missing_dep_gem = util_gem 'missing_dep', '1' do |s|
|
||||
s.add_dependency 'doesnt_exist', '1'
|
||||
end
|
||||
|
||||
use_ui @ui do
|
||||
installer = Gem::Installer.at old_ruby_required('= 1.4.6'), :force => true
|
||||
installer = Gem::Installer.at missing_dep_gem, :force => true
|
||||
installer.install
|
||||
end
|
||||
|
||||
gem_dir = File.join(@gemhome, 'gems', 'old_ruby_required-1')
|
||||
gem_dir = File.join(@gemhome, 'gems', 'missing_dep-1')
|
||||
assert_path_exists gem_dir
|
||||
end
|
||||
|
||||
|
@ -1620,54 +1624,6 @@ gem 'other', version
|
|||
end
|
||||
end
|
||||
|
||||
def test_pre_install_checks_ruby_version
|
||||
use_ui @ui do
|
||||
installer = Gem::Installer.at old_ruby_required('= 1.4.6')
|
||||
e = assert_raises Gem::RuntimeRequirementNotMetError do
|
||||
installer.pre_install_checks
|
||||
end
|
||||
rv = Gem.ruby_version
|
||||
assert_equal "old_ruby_required requires Ruby version = 1.4.6. The current ruby version is #{rv}.",
|
||||
e.message
|
||||
end
|
||||
end
|
||||
|
||||
def test_pre_install_checks_ruby_version_with_prereleases
|
||||
util_set_RUBY_VERSION '2.6.0', -1, '63539', 'ruby 2.6.0preview2 (2018-05-31 trunk 63539) [x86_64-linux]'
|
||||
|
||||
installer = Gem::Installer.at old_ruby_required('>= 2.6.0.preview2')
|
||||
assert installer.pre_install_checks
|
||||
|
||||
installer = Gem::Installer.at old_ruby_required('> 2.6.0.preview2')
|
||||
e = assert_raises Gem::RuntimeRequirementNotMetError do
|
||||
assert installer.pre_install_checks
|
||||
end
|
||||
assert_equal "old_ruby_required requires Ruby version > 2.6.0.preview2. The current ruby version is 2.6.0.preview2.",
|
||||
e.message
|
||||
ensure
|
||||
util_restore_RUBY_VERSION
|
||||
end
|
||||
|
||||
def test_pre_install_checks_wrong_rubygems_version
|
||||
spec = util_spec 'old_rubygems_required', '1' do |s|
|
||||
s.required_rubygems_version = '< 0'
|
||||
end
|
||||
|
||||
util_build_gem spec
|
||||
|
||||
gem = File.join(@gemhome, 'cache', spec.file_name)
|
||||
|
||||
use_ui @ui do
|
||||
installer = Gem::Installer.at gem
|
||||
e = assert_raises Gem::RuntimeRequirementNotMetError do
|
||||
installer.pre_install_checks
|
||||
end
|
||||
rgv = Gem::VERSION
|
||||
assert_equal "old_rubygems_required requires RubyGems version < 0. The current RubyGems version is #{rgv}. " +
|
||||
"Try 'gem update --system' to update RubyGems itself.", e.message
|
||||
end
|
||||
end
|
||||
|
||||
def test_pre_install_checks_malicious_name
|
||||
spec = util_spec '../malicious', '1'
|
||||
def spec.full_name # so the spec is buildable
|
||||
|
@ -2252,16 +2208,6 @@ gem 'other', version
|
|||
assert_kind_of(String, installer.gem)
|
||||
end
|
||||
|
||||
def old_ruby_required(requirement)
|
||||
spec = util_spec 'old_ruby_required', '1' do |s|
|
||||
s.required_ruby_version = requirement
|
||||
end
|
||||
|
||||
util_build_gem spec
|
||||
|
||||
spec.cache_file
|
||||
end
|
||||
|
||||
def util_execless
|
||||
@spec = util_spec 'z'
|
||||
util_build_gem @spec
|
||||
|
|
|
@ -6,29 +6,29 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
super
|
||||
|
||||
@DR = Gem::Resolver
|
||||
@dep_uri = URI "#{@gem_repo}api/v1/dependencies"
|
||||
@dep_uri = URI "#{@gem_repo}info/"
|
||||
end
|
||||
|
||||
def test_initialize
|
||||
set = @DR::APISet.new
|
||||
|
||||
assert_equal URI('https://rubygems.org/api/v1/dependencies'), set.dep_uri
|
||||
assert_equal URI('https://rubygems.org'), set.uri
|
||||
assert_equal Gem::Source.new(URI('https://rubygems.org')), set.source
|
||||
assert_equal URI('https://index.rubygems.org/info/'), set.dep_uri
|
||||
assert_equal URI('https://index.rubygems.org/'), set.uri
|
||||
assert_equal Gem::Source.new(URI('https://index.rubygems.org')), set.source
|
||||
end
|
||||
|
||||
def test_initialize_deeper_uri
|
||||
set = @DR::APISet.new 'https://rubygemsserver.com/mygems/api/v1/dependencies'
|
||||
set = @DR::APISet.new 'https://rubygemsserver.com/mygems/info'
|
||||
|
||||
assert_equal URI('https://rubygemsserver.com/mygems/api/v1/dependencies'), set.dep_uri
|
||||
assert_equal URI('https://rubygemsserver.com/mygems/'), set.uri
|
||||
assert_equal Gem::Source.new(URI('https://rubygemsserver.com/mygems/')), set.source
|
||||
assert_equal URI('https://rubygemsserver.com/mygems/info'), set.dep_uri
|
||||
assert_equal URI('https://rubygemsserver.com/'), set.uri
|
||||
assert_equal Gem::Source.new(URI('https://rubygemsserver.com/')), set.source
|
||||
end
|
||||
|
||||
def test_initialize_uri
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
assert_equal URI("#{@gem_repo}api/v1/dependencies"), set.dep_uri
|
||||
assert_equal URI("#{@gem_repo}info/"), set.dep_uri
|
||||
assert_equal URI("#{@gem_repo}"), set.uri
|
||||
end
|
||||
|
||||
|
@ -42,7 +42,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 "
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -69,7 +69,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1\n2.a"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
set.prerelease = true
|
||||
|
@ -94,7 +94,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 "
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -108,7 +108,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
|
||||
assert_equal expected, set.find_all(a_dep)
|
||||
|
||||
@fetcher.data.delete "#{@dep_uri}?gems=a"
|
||||
@fetcher.data.delete "#{@dep_uri}a"
|
||||
end
|
||||
|
||||
def test_find_all_local
|
||||
|
@ -123,7 +123,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
def test_find_all_missing
|
||||
spec_fetcher
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a"] = Marshal.dump []
|
||||
@fetcher.data["#{@dep_uri}a"] = "---"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -131,7 +131,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
|
||||
assert_empty set.find_all(a_dep)
|
||||
|
||||
@fetcher.data.delete "#{@dep_uri}?gems=a"
|
||||
@fetcher.data.delete "#{@dep_uri}a"
|
||||
|
||||
assert_empty set.find_all(a_dep)
|
||||
end
|
||||
|
@ -139,15 +139,8 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
def test_prefetch
|
||||
spec_fetcher
|
||||
|
||||
data = [
|
||||
{ :name => 'a',
|
||||
:number => '1',
|
||||
:platform => 'ruby',
|
||||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a,b"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}?gems=b"] = Marshal.dump []
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 \n"
|
||||
@fetcher.data["#{@dep_uri}b"] = "---"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -163,14 +156,7 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
def test_prefetch_cache
|
||||
spec_fetcher
|
||||
|
||||
data = [
|
||||
{ :name => 'a',
|
||||
:number => '1',
|
||||
:platform => 'ruby',
|
||||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 \n"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -179,8 +165,8 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
|
||||
set.prefetch [a_dep]
|
||||
|
||||
@fetcher.data.delete "#{@dep_uri}?gems=a"
|
||||
@fetcher.data["#{@dep_uri}?gems=b"] = Marshal.dump []
|
||||
@fetcher.data.delete "#{@dep_uri}a"
|
||||
@fetcher.data["#{@dep_uri}?b"] = "---"
|
||||
|
||||
set.prefetch [a_dep, b_dep]
|
||||
end
|
||||
|
@ -188,14 +174,8 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
def test_prefetch_cache_missing
|
||||
spec_fetcher
|
||||
|
||||
data = [
|
||||
{ :name => 'a',
|
||||
:number => '1',
|
||||
:platform => 'ruby',
|
||||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a,b"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 \n"
|
||||
@fetcher.data["#{@dep_uri}b"] = "---"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
|
||||
|
@ -204,7 +184,8 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
|
||||
set.prefetch [a_dep, b_dep]
|
||||
|
||||
@fetcher.data.delete "#{@dep_uri}?gems=a,b"
|
||||
@fetcher.data.delete "#{@dep_uri}a"
|
||||
@fetcher.data.delete "#{@dep_uri}b"
|
||||
|
||||
set.prefetch [a_dep, b_dep]
|
||||
end
|
||||
|
@ -212,15 +193,8 @@ class TestGemResolverAPISet < Gem::TestCase
|
|||
def test_prefetch_local
|
||||
spec_fetcher
|
||||
|
||||
data = [
|
||||
{ :name => 'a',
|
||||
:number => '1',
|
||||
:platform => 'ruby',
|
||||
:dependencies => [] },
|
||||
]
|
||||
|
||||
@fetcher.data["#{@dep_uri}?gems=a,b"] = Marshal.dump data
|
||||
@fetcher.data["#{@dep_uri}?gems=b"] = Marshal.dump []
|
||||
@fetcher.data["#{@dep_uri}a"] = "---\n1 \n"
|
||||
@fetcher.data["#{@dep_uri}b"] = "---"
|
||||
|
||||
set = @DR::APISet.new @dep_uri
|
||||
set.remote = false
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestGemResolverAPISpecification < Gem::TestCase
|
|||
|
||||
rails = specs['rails-3.0.3']
|
||||
|
||||
repo = @gem_repo + 'api/v1/dependencies'
|
||||
repo = @gem_repo + 'info'
|
||||
|
||||
set = Gem::Resolver::APISet.new repo
|
||||
|
||||
|
@ -123,7 +123,7 @@ class TestGemResolverAPISpecification < Gem::TestCase
|
|||
fetcher.spec 'a', 1
|
||||
end
|
||||
|
||||
dep_uri = URI(@gem_repo) + 'api/v1/dependencies'
|
||||
dep_uri = URI(@gem_repo) + 'info'
|
||||
set = Gem::Resolver::APISet.new dep_uri
|
||||
data = {
|
||||
:name => 'a',
|
||||
|
@ -147,7 +147,7 @@ class TestGemResolverAPISpecification < Gem::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
dep_uri = URI(@gem_repo) + 'api/v1/dependencies'
|
||||
dep_uri = URI(@gem_repo) + 'info'
|
||||
set = Gem::Resolver::APISet.new dep_uri
|
||||
data = {
|
||||
:name => 'j',
|
||||
|
|
|
@ -39,7 +39,7 @@ class TestGemResolverBestSet < Gem::TestCase
|
|||
|
||||
set = @DR::BestSet.new
|
||||
|
||||
api_uri = URI(@gem_repo) + './api/v1/dependencies'
|
||||
api_uri = URI(@gem_repo)
|
||||
|
||||
set.sets << Gem::Resolver::APISet.new(api_uri)
|
||||
|
||||
|
@ -99,12 +99,12 @@ class TestGemResolverBestSet < Gem::TestCase
|
|||
def test_replace_failed_api_set
|
||||
set = @DR::BestSet.new
|
||||
|
||||
api_uri = URI(@gem_repo) + './api/v1/dependencies'
|
||||
api_uri = URI(@gem_repo) + './info/'
|
||||
api_set = Gem::Resolver::APISet.new api_uri
|
||||
|
||||
set.sets << api_set
|
||||
|
||||
error_uri = api_uri + '?gems=a'
|
||||
error_uri = api_uri + 'a'
|
||||
|
||||
error = Gem::RemoteFetcher::FetchError.new 'bogus', error_uri
|
||||
|
||||
|
|
|
@ -44,9 +44,9 @@ class TestGemSource < Gem::TestCase
|
|||
|
||||
def test_dependency_resolver_set_bundler_api
|
||||
response = Net::HTTPResponse.new '1.1', 200, 'OK'
|
||||
response.uri = URI('http://example') if response.respond_to? :uri
|
||||
response.uri = URI('http://example')
|
||||
|
||||
@fetcher.data["#{@gem_repo}api/v1/dependencies"] = response
|
||||
@fetcher.data[@gem_repo] = response
|
||||
|
||||
set = @source.dependency_resolver_set
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@ class TestGemSourceSubpathProblem < Gem::TestCase
|
|||
|
||||
def test_dependency_resolver_set
|
||||
response = Net::HTTPResponse.new '1.1', 200, 'OK'
|
||||
response.uri = URI('http://example') if response.respond_to? :uri
|
||||
response.uri = URI('http://example')
|
||||
|
||||
@fetcher.data["#{@gem_repo}/api/v1/dependencies"] = response
|
||||
@fetcher.data["#{@gem_repo}/"] = response
|
||||
|
||||
set = @source.dependency_resolver_set
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue