Merge RubyGems-3.2.14 and Bundler-2.2.14

This commit is contained in:
Hiroshi SHIBATA 2021-03-10 12:08:20 +09:00 committed by NARUSE, Yui
parent 7efc7afcae
commit 0476ce0370
32 changed files with 716 additions and 371 deletions

View file

@ -54,7 +54,7 @@ module Bundler
if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero? if response.is_a?(Net::HTTPPartialContent) && local_temp_path.size.nonzero?
local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) } local_temp_path.open("a") {|f| f << slice_body(content, 1..-1) }
else else
local_temp_path.open("w") {|f| f << content } local_temp_path.open("wb") {|f| f << content }
end end
end end

View file

@ -106,6 +106,17 @@ module Bundler
@locked_platforms = [] @locked_platforms = []
end end
@locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
@disable_multisource = @locked_gem_sources.all?(&:disable_multisource?)
unless @disable_multisource
msg = "Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. You should run `bundle update` or generate your lockfile from scratch."
Bundler::SharedHelpers.major_deprecation 2, msg
@sources.merged_gem_lockfile_sections!
end
@unlock[:gems] ||= [] @unlock[:gems] ||= []
@unlock[:sources] ||= [] @unlock[:sources] ||= []
@unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object @unlock[:ruby] ||= if @ruby_version && locked_ruby_version_object
@ -145,6 +156,10 @@ module Bundler
end end
end end
def disable_multisource?
@disable_multisource
end
def resolve_with_cache! def resolve_with_cache!
raise "Specs already loaded" if @specs raise "Specs already loaded" if @specs
sources.cached! sources.cached!
@ -530,6 +545,9 @@ module Bundler
attr_reader :sources attr_reader :sources
private :sources private :sources
attr_reader :locked_gem_sources
private :locked_gem_sources
def nothing_changed? def nothing_changed?
!@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform !@source_changes && !@dependency_changes && !@new_platform && !@path_changes && !@local_changes && !@locked_specs_incomplete_for_platform
end end
@ -654,10 +672,8 @@ module Bundler
end end
def converge_rubygems_sources def converge_rubygems_sources
return false if Bundler.feature_flag.disable_multisource? return false if disable_multisource?
# Get the RubyGems sources from the Gemfile.lock
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
return false if locked_gem_sources.empty? return false if locked_gem_sources.empty?
# Get the RubyGems remotes from the Gemfile # Get the RubyGems remotes from the Gemfile

View file

@ -460,19 +460,16 @@ repo_name ||= user_name
@sources.add_rubygems_remote(source) @sources.add_rubygems_remote(source)
end end
if Bundler.feature_flag.disable_multisource? if Bundler.feature_flag.bundler_3_mode?
msg = "This Gemfile contains multiple primary sources. " \ msg = "This Gemfile contains multiple primary sources. " \
"Each source after the first must include a block to indicate which gems " \ "Each source after the first must include a block to indicate which gems " \
"should come from that source. To downgrade this error to a warning, run " \ "should come from that source"
"`bundle config unset disable_multisource`"
raise GemfileEvalError, msg raise GemfileEvalError, msg
else else
Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \ Bundler::SharedHelpers.major_deprecation 2, "Your Gemfile contains multiple primary sources. " \
"Using `source` more than once without a block is a security risk, and " \ "Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \ "may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source. " \ "a block to indicate which gems should come from the secondary source."
"To upgrade this warning to an error, run `bundle config set --local " \
"disable_multisource true`."
end end
end end

View file

@ -27,13 +27,8 @@ module Bundler
state == :failed state == :failed
end end
def installation_attempted?
installed? || failed?
end
# Only true when spec in neither installed nor already enqueued
def ready_to_enqueue? def ready_to_enqueue?
!enqueued? && !installation_attempted? state == :none
end end
def has_post_install_message? def has_post_install_message?
@ -93,6 +88,11 @@ module Bundler
def call def call
check_for_corrupt_lockfile check_for_corrupt_lockfile
if @rake
do_install(@rake, 0)
Gem::Specification.reset
end
if @size > 1 if @size > 1
install_with_worker install_with_worker
else else
@ -217,8 +217,6 @@ module Bundler
# are installed. # are installed.
def enqueue_specs def enqueue_specs
@specs.select(&:ready_to_enqueue?).each do |spec| @specs.select(&:ready_to_enqueue?).each do |spec|
next if @rake && !@rake.installed? && spec.name != @rake.name
if spec.dependencies_installed? @specs if spec.dependencies_installed? @specs
spec.state = :enqueued spec.state = :enqueued
worker_pool.enq spec worker_pool.enq spec

View file

@ -131,18 +131,8 @@ module Bundler
@sources << @current_source @sources << @current_source
end end
when GEM when GEM
source_remotes = Array(@opts["remote"]) @opts["remotes"] = Array(@opts.delete("remote")).reverse
@current_source = TYPES[@type].from_lock(@opts)
if source_remotes.size == 1
@opts["remotes"] = @opts.delete("remote")
@current_source = TYPES[@type].from_lock(@opts)
else
source_remotes.each do |url|
rubygems_aggregate.add_remote(url)
end
@current_source = rubygems_aggregate
end
@sources << @current_source @sources << @current_source
when PLUGIN when PLUGIN
@current_source = Plugin.source_from_lock(@opts) @current_source = Plugin.source_from_lock(@opts)
@ -245,9 +235,5 @@ module Bundler
def parse_ruby(line) def parse_ruby(line)
@ruby_version = line.strip @ruby_version = line.strip
end end
def rubygems_aggregate
@rubygems_aggregate ||= Source::Rubygems.new
end
end end
end end

View file

@ -140,6 +140,13 @@ module Bundler
end end
end end
# Set internal representation to fetch the gems/specs locally.
#
# When this is called, the source should try to fetch the specs and
# install from the local system.
def local!
end
# Set internal representation to fetch the gems/specs from remote. # Set internal representation to fetch the gems/specs from remote.
# #
# When this is called, the source should try to fetch the specs and # When this is called, the source should try to fetch the specs and

View file

@ -33,6 +33,12 @@ module Bundler
spec.source == self spec.source == self
end end
def local!; end
def cached!; end
def remote!; end
# it's possible that gems from one source depend on gems from some # it's possible that gems from one source depend on gems from some
# other source, so now we download gemspecs and iterate over those # other source, so now we download gemspecs and iterate over those
# dependencies, looking for gems we don't have info on yet. # dependencies, looking for gems we don't have info on yet.

View file

@ -33,10 +33,6 @@ module Bundler
end end
end end
def cached!; end
def remote!; end
def options def options
{} {}
end end

View file

@ -20,17 +20,29 @@ module Bundler
@dependency_names = [] @dependency_names = []
@allow_remote = false @allow_remote = false
@allow_cached = false @allow_cached = false
@allow_local = options["allow_local"] || false
@caches = [cache_path, *Bundler.rubygems.gem_cache] @caches = [cache_path, *Bundler.rubygems.gem_cache]
Array(options["remotes"] || []).reverse_each {|r| add_remote(r) } Array(options["remotes"]).reverse_each {|r| add_remote(r) }
end
def local!
return if @allow_local
@specs = nil
@allow_local = true
end end
def remote! def remote!
return if @allow_remote
@specs = nil @specs = nil
@allow_remote = true @allow_remote = true
end end
def cached! def cached!
return if @allow_cached
@specs = nil @specs = nil
@allow_cached = true @allow_cached = true
end end
@ -49,8 +61,12 @@ module Bundler
o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty? o.is_a?(Rubygems) && (o.credless_remotes - credless_remotes).empty?
end end
def disable_multisource?
@remotes.size <= 1
end
def can_lock?(spec) def can_lock?(spec)
return super if Bundler.feature_flag.disable_multisource? return super if disable_multisource?
spec.source.is_a?(Rubygems) spec.source.is_a?(Rubygems)
end end
@ -87,7 +103,7 @@ module Bundler
# small_idx.use large_idx. # small_idx.use large_idx.
idx = @allow_remote ? remote_specs.dup : Index.new idx = @allow_remote ? remote_specs.dup : Index.new
idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote idx.use(cached_specs, :override_dupes) if @allow_cached || @allow_remote
idx.use(installed_specs, :override_dupes) idx.use(installed_specs, :override_dupes) if @allow_local
idx idx
end end
end end
@ -365,7 +381,7 @@ module Bundler
def cached_specs def cached_specs
@cached_specs ||= begin @cached_specs ||= begin
idx = installed_specs.dup idx = @allow_local ? installed_specs.dup : Index.new
Dir["#{cache_path}/*.gem"].each do |gemfile| Dir["#{cache_path}/*.gem"].each do |gemfile|
next if gemfile =~ /^bundler\-[\d\.]+?\.gem/ next if gemfile =~ /^bundler\-[\d\.]+?\.gem/

View file

@ -9,7 +9,7 @@ module Bundler
:metadata_source :metadata_source
def global_rubygems_source def global_rubygems_source
@global_rubygems_source ||= rubygems_aggregate_class.new @global_rubygems_source ||= rubygems_aggregate_class.new("allow_local" => true)
end end
def initialize def initialize
@ -20,6 +20,16 @@ module Bundler
@global_path_source = nil @global_path_source = nil
@rubygems_sources = [] @rubygems_sources = []
@metadata_source = Source::Metadata.new @metadata_source = Source::Metadata.new
@disable_multisource = true
end
def disable_multisource?
@disable_multisource
end
def merged_gem_lockfile_sections!
@disable_multisource = false
end end
def add_path_source(options = {}) def add_path_source(options = {})
@ -47,7 +57,7 @@ module Bundler
end end
def global_rubygems_source=(uri) def global_rubygems_source=(uri)
@global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri) @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri, "allow_local" => true)
end end
def add_rubygems_remote(uri) def add_rubygems_remote(uri)
@ -77,7 +87,7 @@ module Bundler
def lock_sources def lock_sources
lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s) lock_sources = (path_sources + git_sources + plugin_sources).sort_by(&:to_s)
if Bundler.feature_flag.disable_multisource? if disable_multisource?
lock_sources + rubygems_sources.sort_by(&:to_s) lock_sources + rubygems_sources.sort_by(&:to_s)
else else
lock_sources << combine_rubygems_sources lock_sources << combine_rubygems_sources
@ -94,7 +104,7 @@ module Bundler
end end
end end
replacement_rubygems = !Bundler.feature_flag.disable_multisource? && replacement_rubygems = !disable_multisource? &&
replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } replacement_sources.detect {|s| s.is_a?(Source::Rubygems) }
@global_rubygems_source = replacement_rubygems if replacement_rubygems @global_rubygems_source = replacement_rubygems if replacement_rubygems

View file

@ -82,6 +82,7 @@ module Bundler
materialized.map! do |s| materialized.map! do |s|
next s unless s.is_a?(LazySpecification) next s unless s.is_a?(LazySpecification)
s.source.dependency_names = deps if s.source.respond_to?(:dependency_names=) s.source.dependency_names = deps if s.source.respond_to?(:dependency_names=)
s.source.local!
spec = s.__materialize__ spec = s.__materialize__
unless spec unless spec
unless missing_specs unless missing_specs
@ -102,6 +103,7 @@ module Bundler
@specs.map do |s| @specs.map do |s|
next s unless s.is_a?(LazySpecification) next s unless s.is_a?(LazySpecification)
s.source.dependency_names = names if s.source.respond_to?(:dependency_names=) s.source.dependency_names = names if s.source.respond_to?(:dependency_names=)
s.source.local!
s.source.remote! s.source.remote!
spec = s.__materialize__ spec = s.__materialize__
raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec raise GemNotFound, "Could not find #{s.full_name} in any of the sources" unless spec

View file

@ -1,7 +1,7 @@
# frozen_string_literal: false # frozen_string_literal: false
module Bundler module Bundler
VERSION = "2.2.13".freeze VERSION = "2.2.14".freeze
def self.bundler_major_version def self.bundler_major_version
@bundler_major_version ||= VERSION.split(".").first.to_i @bundler_major_version ||= VERSION.split(".").first.to_i

View file

@ -8,7 +8,7 @@
require 'rbconfig' require 'rbconfig'
module Gem module Gem
VERSION = "3.2.13".freeze VERSION = "3.2.14".freeze
end end
# Must be first since it unloads the prelude from 1.9.2 # Must be first since it unloads the prelude from 1.9.2

View file

@ -66,7 +66,7 @@ class Gem::Platform
when String then when String then
arch = arch.split '-' arch = arch.split '-'
if arch.length > 2 and arch.last !~ /\d+(\.\d+)?$/ # reassemble x86-linux-{libc} if arch.length > 2 and arch.last !~ /\d/ # reassemble x86-linux-gnu
extra = arch.pop extra = arch.pop
arch.last << "-#{extra}" arch.last << "-#{extra}"
end end
@ -146,8 +146,7 @@ class Gem::Platform
## ##
# Does +other+ match this platform? Two platforms match if they have the # Does +other+ match this platform? Two platforms match if they have the
# same CPU, or either has a CPU of 'universal', they have the same OS, and # same CPU, or either has a CPU of 'universal', they have the same OS, and
# they have the same version, or either has no version (except for 'linux' # they have the same version, or either has no version.
# where the version is the libc name, with no version standing for 'gnu')
# #
# Additionally, the platform will match if the local CPU is 'arm' and the # Additionally, the platform will match if the local CPU is 'arm' and the
# other CPU starts with "arm" (for generic ARM family support). # other CPU starts with "arm" (for generic ARM family support).
@ -163,10 +162,7 @@ class Gem::Platform
@os == other.os and @os == other.os and
# version # version
( (@version.nil? or other.version.nil? or @version == other.version)
(@os != 'linux' and (@version.nil? or other.version.nil?)) or
@version == other.version
)
end end
## ##

View file

@ -51,6 +51,7 @@ class Gem::RemoteFetcher
class UnknownHostError < FetchError class UnknownHostError < FetchError
end end
deprecate_constant(:UnknownHostError)
@fetcher = nil @fetcher = nil
@ -262,15 +263,9 @@ class Gem::RemoteFetcher
end end
data data
rescue Timeout::Error rescue Timeout::Error, IOError, SocketError, SystemCallError,
raise UnknownHostError.new('timed out', uri)
rescue IOError, SocketError, SystemCallError,
*(OpenSSL::SSL::SSLError if Gem::HAVE_OPENSSL) => e *(OpenSSL::SSL::SSLError if Gem::HAVE_OPENSSL) => e
if e.message =~ /getaddrinfo/ raise FetchError.new("#{e.class}: #{e}", uri)
raise UnknownHostError.new('no such name', uri)
else
raise FetchError.new("#{e.class}: #{e}", uri)
end
end end
def fetch_s3(uri, mtime = nil, head = false) def fetch_s3(uri, mtime = nil, head = false)

View file

@ -46,4 +46,25 @@ RSpec.describe Bundler::CompactIndexClient::Updater do
end.to raise_error(Bundler::PermissionError) end.to raise_error(Bundler::PermissionError)
end end
end end
context "when receiving non UTF-8 data and default internal encoding set to ASCII" do
let(:response) { double(:response, :body => "\x8B".b) }
it "works just fine" do
old_verbose = $VERBOSE
previous_internal_encoding = Encoding.default_internal
begin
$VERBOSE = false
Encoding.default_internal = "ASCII"
expect(response).to receive(:[]).with("ETag") { nil }
expect(fetcher).to receive(:call) { response }
updater.update(local_path, remote_path)
ensure
Encoding.default_internal = previous_internal_encoding
$VERBOSE = old_verbose
end
end
end
end end

View file

@ -372,26 +372,7 @@ RSpec.describe Bundler::SourceList do
source_list.add_git_source("uri" => "git://first-git.org/path.git") source_list.add_git_source("uri" => "git://first-git.org/path.git")
end end
it "combines the rubygems sources into a single instance, removing duplicate remotes from the end", :bundler => "< 3" do it "returns all sources, without combining rubygems sources" do
expect(source_list.lock_sources).to eq [
Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"),
Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"),
Bundler::Source::Git.new("uri" => "git://third-git.org/path.git"),
ASourcePlugin.new("uri" => "https://second-plugin.org/random"),
ASourcePlugin.new("uri" => "https://third-bar.org/foo"),
Bundler::Source::Path.new("path" => "/first/path/to/gem"),
Bundler::Source::Path.new("path" => "/second/path/to/gem"),
Bundler::Source::Path.new("path" => "/third/path/to/gem"),
Bundler::Source::Rubygems.new("remotes" => [
"https://duplicate-rubygems.org",
"https://first-rubygems.org",
"https://second-rubygems.org",
"https://third-rubygems.org",
]),
]
end
it "returns all sources, without combining rubygems sources", :bundler => "3" do
expect(source_list.lock_sources).to eq [ expect(source_list.lock_sources).to eq [
Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"), Bundler::Source::Git.new("uri" => "git://first-git.org/path.git"),
Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"), Bundler::Source::Git.new("uri" => "git://second-git.org/path.git"),

View file

@ -86,7 +86,7 @@ RSpec.describe "bundle lock" do
it "does not fetch remote specs when using the --local option" do it "does not fetch remote specs when using the --local option" do
bundle "lock --update --local", :raise_on_error => false bundle "lock --update --local", :raise_on_error => false
expect(err).to match(/sources listed in your Gemfile|installed locally/) expect(err).to match(/installed locally/)
end end
it "works with --gemfile flag" do it "works with --gemfile flag" do

View file

@ -126,21 +126,21 @@ RSpec.describe "install in deployment or frozen mode" do
bundle "config --local path vendor/bundle" bundle "config --local path vendor/bundle"
bundle "install" bundle "install"
gemfile <<-G gemfile <<-G
source "http://user_name:password@localgemserver.test/" source "http://user_name:password@localgemserver.test/"
gem "rack" gem "rack"
G G
lockfile <<-G lockfile <<-G
GEM GEM
remote: http://localgemserver.test/ remote: http://localgemserver.test/
specs: specs:
rack (1.0.0) rack (1.0.0)
PLATFORMS PLATFORMS
#{local} #{local}
DEPENDENCIES DEPENDENCIES
rack rack
G G
bundle "config set --local deployment true" bundle "config set --local deployment true"

View file

@ -141,23 +141,84 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "when a pinned gem has an indirect dependency" do context "when a pinned gem has an indirect dependency in the pinned source" do
before do before do
build_repo gem_repo3 do build_repo gem_repo3 do
build_gem "depends_on_rack", "1.0.1" do |s| build_gem "depends_on_rack", "1.0.1" do |s|
s.add_dependency "rack" s.add_dependency "rack"
end end
end end
# we need a working rack gem in repo3
update_repo gem_repo3 do
build_gem "rack", "1.0.0"
end
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo3)}" do
gem "depends_on_rack"
end
G
end end
context "when the indirect dependency is in the pinned source" do context "and not in any other sources" do
before do before do
# we need a working rack gem in repo3 build_repo(gem_repo2) {}
update_repo gem_repo3 do end
build_gem "rack", "1.0.0"
end
gemfile <<-G it "installs from the same source without any warning" do
bundle :install
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
context "and in another source" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
build_gem "rack", "1.0.0" do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs from the same source without any warning" do
bundle :install
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
bundle :install
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
end
context "when a pinned gem has an indirect dependency in a different source" do
before do
# In these tests, we need a working rack gem in repo2 and not repo3
build_repo gem_repo3 do
build_gem "depends_on_rack", "1.0.1" do |s|
s.add_dependency "rack"
end
end
build_repo gem_repo2 do
build_gem "rack", "1.0.0"
end
end
context "and not in any other sources" do
before do
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}" source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo3)}" do source "#{file_uri_for(gem_repo3)}" do
gem "depends_on_rack" gem "depends_on_rack"
@ -165,132 +226,74 @@ RSpec.describe "bundle install with gems on multiple sources" do
G G
end end
context "and not in any other sources" do it "installs from the other source without any warning" do
before do expect(err).not_to include("Warning")
build_repo(gem_repo2) {} expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
it "installs from the same source without any warning" do
bundle :install
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end
context "and in another source" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
build_gem "rack", "1.0.0" do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end
end
it "installs from the same source without any warning" do
bundle :install
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
# In https://github.com/bundler/bundler/issues/3585 this failed
# when there is already a lock file, and the gems are missing, so try again
system_gems []
bundle :install
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
end
end end
end end
context "when the indirect dependency is in a different source" do context "and in yet another source" do
before do before do
# In these tests, we need a working rack gem in repo2 and not repo3 gemfile <<-G
build_repo gem_repo2 do source "#{file_uri_for(gem_repo1)}"
build_gem "rack", "1.0.0" source "#{file_uri_for(gem_repo2)}"
end source "#{file_uri_for(gem_repo3)}" do
end gem "depends_on_rack"
context "and not in any other sources" do
before do
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo3)}" do
gem "depends_on_rack"
end
G
end
it "installs from the other source without any warning" do
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
end
context "and in yet another source" do
before do
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo3)}" do
gem "depends_on_rack"
end
G
end
it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
bundle :install
expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
it "fails", :bundler => "3" do
bundle :install, :raise_on_error => false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
end
context "and only the dependency is pinned" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
build_gem "rack", "1.0.0" do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end end
G
end
gemfile <<-G it "installs from the other source and warns about ambiguous gems", :bundler => "< 3" do
source "#{file_uri_for(gem_repo3)}" # contains depends_on_rack bundle :install
source "#{file_uri_for(gem_repo2)}" # contains broken rack expect(err).to include("Warning: the gem 'rack' was found in multiple sources.")
expect(err).to include("Installed from: #{file_uri_for(gem_repo2)}")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
gem "depends_on_rack" # installed from gem_repo3 it "fails", :bundler => "3" do
gem "rack", :source => "#{file_uri_for(gem_repo1)}" bundle :install, :raise_on_error => false
G expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end
end
context "and only the dependency is pinned" do
before do
# need this to be broken to check for correct source ordering
build_repo gem_repo2 do
build_gem "rack", "1.0.0" do |s|
s.write "lib/rack.rb", "RACK = 'FAIL'"
end
end end
it "installs the dependency from the pinned source without warning", :bundler => "< 3" do gemfile <<-G
bundle :install source "#{file_uri_for(gem_repo3)}" # contains depends_on_rack
source "#{file_uri_for(gem_repo2)}" # contains broken rack
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") gem "depends_on_rack" # installed from gem_repo3
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") gem "rack", :source => "#{file_uri_for(gem_repo1)}"
G
end
# In https://github.com/rubygems/bundler/issues/3585 this failed it "installs the dependency from the pinned source without warning", :bundler => "< 3" do
# when there is already a lock file, and the gems are missing, so try again bundle :install
system_gems []
bundle :install
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
it "fails", :bundler => "3" do # In https://github.com/rubygems/bundler/issues/3585 this failed
bundle :install, :raise_on_error => false # when there is already a lock file, and the gems are missing, so try again
expect(err).to include("Each source after the first must include a block") system_gems []
expect(exitstatus).to eq(4) bundle :install
end
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0")
end
it "fails", :bundler => "3" do
bundle :install, :raise_on_error => false
expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4)
end end
end end
end end
@ -511,9 +514,149 @@ RSpec.describe "bundle install with gems on multiple sources" do
L L
end end
it "upgrades gems when running bundle update, without printing any warnings or errors" do it "does not install newer versions or generate lockfile changes when running bundle install, and warns", :bundler => "< 3" do
initial_lockfile = lockfile
bundle :install
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
expect(the_bundle).to include_gems("tzinfo 1.2.9")
expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.9")
expect(lockfile).to eq(initial_lockfile)
end
it "fails when running bundle install", :bundler => "3" do
initial_lockfile = lockfile
bundle :install, :raise_on_error => false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(lockfile).to eq(initial_lockfile)
end
it "splits sections and upgrades gems when running bundle update, and doesn't warn" do
bundle "update --all" bundle "update --all"
expect(err).to be_empty expect(err).to be_empty
expect(the_bundle).not_to include_gems("activesupport 6.0.3.4")
expect(the_bundle).to include_gems("activesupport 6.1.2.1")
expect(the_bundle).not_to include_gems("tzinfo 1.2.9")
expect(the_bundle).to include_gems("tzinfo 2.0.4")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
activesupport (6.1.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
tzinfo (~> 2.0)
zeitwerk (~> 2.3)
concurrent-ruby (1.1.9)
connection_pool (2.2.3)
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
tzinfo (2.0.4)
concurrent-ruby (~> 1.0)
zeitwerk (2.4.2)
GEM
remote: #{file_uri_for(gem_repo3)}/
specs:
sidekiq-pro (5.2.1)
connection_pool (>= 2.2.3)
sidekiq (>= 6.1.0)
PLATFORMS
#{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "it keeps the currrent lockfile format and upgrades the requested gem when running bundle update with an argument, and warns", :bundler => "< 3" do
bundle "update concurrent-ruby"
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(the_bundle).to include_gems("activesupport 6.0.3.4")
expect(the_bundle).not_to include_gems("activesupport 6.1.2.1")
expect(the_bundle).to include_gems("tzinfo 1.2.9")
expect(the_bundle).not_to include_gems("tzinfo 2.0.4")
expect(the_bundle).to include_gems("concurrent-ruby 1.1.9")
expect(the_bundle).not_to include_gems("concurrent-ruby 1.1.8")
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo2)}/
remote: #{file_uri_for(gem_repo3)}/
specs:
activesupport (6.0.3.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
concurrent-ruby (1.1.9)
connection_pool (2.2.3)
i18n (1.8.9)
concurrent-ruby (~> 1.0)
minitest (5.14.3)
rack (2.2.3)
redis (4.2.5)
sidekiq (6.1.3)
connection_pool (>= 2.2.2)
rack (~> 2.0)
redis (>= 4.2.0)
sidekiq-pro (5.2.1)
connection_pool (>= 2.2.3)
sidekiq (>= 6.1.0)
thread_safe (0.3.6)
tzinfo (1.2.9)
thread_safe (~> 0.1)
zeitwerk (2.4.2)
PLATFORMS
#{specific_local_platform}
DEPENDENCIES
activesupport
sidekiq-pro!
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "fails when running bundle update with an argument", :bundler => "3" do
initial_lockfile = lockfile
bundle "update concurrent-ruby", :raise_on_error => false
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(lockfile).to eq(initial_lockfile)
end end
end end
end end
@ -551,7 +694,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source ", :bundler => "< 3" do context "when a pinned gem has an indirect dependency with more than one level of indirection in the default source " do
before do before do
build_repo gem_repo3 do build_repo gem_repo3 do
build_gem "handsoap", "0.2.5.5" do |s| build_gem "handsoap", "0.2.5.5" do |s|
@ -578,12 +721,38 @@ RSpec.describe "bundle install with gems on multiple sources" do
G G
end end
it "installs from the proper sources without any warnings or errors" do it "installs from the default source without any warnings or errors and generates a proper lockfile" do
expected_lockfile = <<~L
GEM
remote: #{file_uri_for(gem_repo2)}/
specs:
nokogiri (1.11.1)
racca (~> 1.4)
racca (1.5.2)
GEM
remote: #{file_uri_for(gem_repo3)}/
specs:
handsoap (0.2.5.5)
nokogiri (>= 1.2.3)
PLATFORMS
#{specific_local_platform}
DEPENDENCIES
handsoap!
nokogiri
BUNDLED WITH
#{Bundler::VERSION}
L
bundle "install --verbose" bundle "install --verbose"
expect(err).not_to include("Warning") expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2") expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
# Even if the gems are already installed # Even if the gems are already installed
FileUtils.rm bundled_app_lock FileUtils.rm bundled_app_lock
@ -592,6 +761,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2") expect(the_bundle).to include_gems("handsoap 0.2.5.5", "nokogiri 1.11.1", "racca 1.5.2")
expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3") expect(the_bundle).to include_gems("handsoap 0.2.5.5", :source => "remote3")
expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2") expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
expect(lockfile).to eq(expected_lockfile)
end end
end end
@ -619,6 +789,9 @@ RSpec.describe "bundle install with gems on multiple sources" do
lockfile <<-L lockfile <<-L
GEM GEM
remote: #{file_uri_for(gem_repo1)} remote: #{file_uri_for(gem_repo1)}
specs:
GEM
remote: #{file_uri_for(gem_repo3)} remote: #{file_uri_for(gem_repo3)}
specs: specs:
rack (0.9.1) rack (0.9.1)
@ -644,6 +817,84 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "with a lockfile with aggregated rubygems sources" do
let(:aggregate_gem_section_lockfile) do
<<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
remote: #{file_uri_for(gem_repo3)}/
specs:
rack (0.9.1)
PLATFORMS
#{specific_local_platform}
DEPENDENCIES
rack!
BUNDLED WITH
#{Bundler::VERSION}
L
end
let(:split_gem_section_lockfile) do
<<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
specs:
GEM
remote: #{file_uri_for(gem_repo3)}/
specs:
rack (0.9.1)
PLATFORMS
#{specific_local_platform}
DEPENDENCIES
rack!
BUNDLED WITH
#{Bundler::VERSION}
L
end
before do
build_repo gem_repo3 do
build_gem "rack", "0.9.1"
end
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
source "#{file_uri_for(gem_repo3)}" do
gem 'rack'
end
G
lockfile aggregate_gem_section_lockfile
end
it "installs the existing lockfile but prints a warning", :bundler => "< 3" do
bundle "config set --local deployment true"
bundle "install"
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(the_bundle).to include_gems("rack 0.9.1", :source => "remote3")
end
it "refuses to install the existing lockfile and prints an error", :bundler => "3" do
bundle "config set --local deployment true"
bundle "install", :raise_on_error =>false
expect(lockfile).to eq(aggregate_gem_section_lockfile)
expect(err).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure.")
expect(out).to be_empty
end
end
context "with a path gem in the same Gemfile" do context "with a path gem in the same Gemfile" do
before do before do
build_lib "foo" build_lib "foo"
@ -825,15 +1076,36 @@ RSpec.describe "bundle install with gems on multiple sources" do
G G
end end
it "keeps the old version", :bundler => "< 3" do it "installs the higher version in the new repo" do
expect(the_bundle).to include_gems("rack 1.0.0")
end
it "installs the higher version in the new repo", :bundler => "3" do
expect(the_bundle).to include_gems("rack 1.2") expect(the_bundle).to include_gems("rack 1.2")
end end
end end
it "doesn't update version when a gem uses a source block but a higher version from another source is already installed locally" do
build_repo2 do
build_gem "example", "0.1.0"
end
build_repo4 do
build_gem "example", "1.0.2"
end
install_gemfile <<-G
source "#{file_uri_for(gem_repo4)}"
gem "example", :source => "#{file_uri_for(gem_repo2)}"
G
bundle "info example"
expect(out).to include("example (0.1.0)")
system_gems "example-1.0.2", :path => default_bundle_path, :gem_repo => gem_repo4
bundle "update example --verbose"
expect(out).not_to include("Using example 1.0.2")
expect(out).to include("Using example 0.1.0")
end
context "when a gem is available from multiple ambiguous sources", :bundler => "3" do context "when a gem is available from multiple ambiguous sources", :bundler => "3" do
it "raises, suggesting a source block" do it "raises, suggesting a source block" do
build_repo4 do build_repo4 do

View file

@ -245,37 +245,7 @@ RSpec.describe "bundle flex_install" do
end end
describe "when adding a new source" do describe "when adding a new source" do
it "updates the lockfile", :bundler => "< 3" do it "updates the lockfile" do
build_repo2
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
gem "rack"
G
install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
source "#{file_uri_for(gem_repo2)}"
gem "rack"
G
lockfile_should_be <<-L
GEM
remote: #{file_uri_for(gem_repo1)}/
remote: #{file_uri_for(gem_repo2)}/
specs:
rack (1.0.0)
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "updates the lockfile", :bundler => "3" do
build_repo2 build_repo2
install_gemfile <<-G install_gemfile <<-G
source "#{file_uri_for(gem_repo1)}" source "#{file_uri_for(gem_repo1)}"

View file

@ -3,6 +3,32 @@
RSpec.describe "bundle install with install-time dependencies" do RSpec.describe "bundle install with install-time dependencies" do
before do before do
build_repo2 do build_repo2 do
build_gem "with_implicit_rake_dep" do |s|
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
path = File.expand_path("../lib", __FILE__)
FileUtils.mkdir_p(path)
File.open("\#{path}/implicit_rake_dep.rb", "w") do |f|
f.puts "IMPLICIT_RAKE_DEP = 'YES'"
end
end
RUBY
end
build_gem "another_implicit_rake_dep" do |s|
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
path = File.expand_path("../lib", __FILE__)
FileUtils.mkdir_p(path)
File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f|
f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'"
end
end
RUBY
end
# Test complicated gem dependencies for install # Test complicated gem dependencies for install
build_gem "net_a" do |s| build_gem "net_a" do |s|
s.add_dependency "net_b" s.add_dependency "net_b"
@ -55,6 +81,25 @@ RSpec.describe "bundle install with install-time dependencies" do
expect(out).to eq("YES\nYES") expect(out).to eq("YES\nYES")
end end
it "installs gems with implicit rake dependencies without rake previously installed" do
with_path_as("") do
install_gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "with_implicit_rake_dep"
gem "another_implicit_rake_dep"
gem "rake"
G
end
run <<-R
require 'implicit_rake_dep'
require 'another_implicit_rake_dep'
puts IMPLICIT_RAKE_DEP
puts ANOTHER_IMPLICIT_RAKE_DEP
R
expect(out).to eq("YES\nYES")
end
it "installs gems with a dependency with no type" do it "installs gems with a dependency with no type" do
skip "incorrect data check error" if Gem.win_platform? skip "incorrect data check error" if Gem.win_platform?

View file

@ -49,8 +49,23 @@ RSpec.describe "when using sudo", :sudo => true do
end end
it "installs rake and a gem dependent on rake in the same session" do it "installs rake and a gem dependent on rake in the same session" do
build_repo2 do
build_gem "another_implicit_rake_dep" do |s|
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
path = File.expand_path("../lib", __FILE__)
FileUtils.mkdir_p(path)
File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f|
f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'"
end
end
RUBY
end
end
gemfile <<-G gemfile <<-G
source "#{file_uri_for(gem_repo1)}" source "#{file_uri_for(gem_repo2)}"
gem "rake" gem "rake"
gem "another_implicit_rake_dep" gem "another_implicit_rake_dep"
G G

View file

@ -318,40 +318,7 @@ RSpec.describe "the lockfile format" do
G G
end end
it "generates a lockfile without credentials for a configured source", :bundler => "< 3" do it "generates a lockfile without credentials for a configured source" do
bundle "config set http://localgemserver.test/ user:pass"
install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)
source "http://localgemserver.test/" do
end
source "http://user:pass@othergemserver.test/" do
gem "rack-obama", ">= 1.0"
end
G
lockfile_should_be <<-G
GEM
remote: http://localgemserver.test/
remote: http://user:pass@othergemserver.test/
specs:
rack (1.0.0)
rack-obama (1.0)
rack
PLATFORMS
#{lockfile_platforms}
DEPENDENCIES
rack-obama (>= 1.0)!
BUNDLED WITH
#{Bundler::VERSION}
G
end
it "generates a lockfile without credentials for a configured source", :bundler => "3" do
bundle "config set http://localgemserver.test/ user:pass" bundle "config set http://localgemserver.test/ user:pass"
install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true) install_gemfile(<<-G, :artifice => "endpoint_strict_basic_authentication", :quiet => true)

View file

@ -383,15 +383,53 @@ RSpec.describe "major deprecations" do
"Your Gemfile contains multiple primary sources. " \ "Your Gemfile contains multiple primary sources. " \
"Using `source` more than once without a block is a security risk, and " \ "Using `source` more than once without a block is a security risk, and " \
"may result in installing unexpected gems. To resolve this warning, use " \ "may result in installing unexpected gems. To resolve this warning, use " \
"a block to indicate which gems should come from the secondary source. " \ "a block to indicate which gems should come from the secondary source."
"To upgrade this warning to an error, run `bundle config set --local " \
"disable_multisource true`."
) )
end end
pending "fails with a helpful error", :bundler => "3" pending "fails with a helpful error", :bundler => "3"
end end
context "bundle install with a lockfile with a single rubygems section with multiple remotes" do
before do
build_repo gem_repo3 do
build_gem "rack", "0.9.1"
end
gemfile <<-G
source "#{file_uri_for(gem_repo1)}"
source "#{file_uri_for(gem_repo3)}" do
gem 'rack'
end
G
lockfile <<~L
GEM
remote: #{file_uri_for(gem_repo1)}/
remote: #{file_uri_for(gem_repo3)}/
specs:
rack (0.9.1)
PLATFORMS
ruby
DEPENDENCIES
rack!
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "shows a deprecation", :bundler => "< 3" do
bundle "install"
expect(deprecations).to include("Your lockfile contains a single rubygems source section with multiple remotes, which is insecure. You should run `bundle update` or generate your lockfile from scratch.")
end
pending "fails with a helpful error", :bundler => "3"
end
context "when Bundler.setup is run in a ruby script" do context "when Bundler.setup is run in a ruby script" do
before do before do
create_file "gems.rb" create_file "gems.rb"

View file

@ -6,7 +6,7 @@ PATH
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
jruby-jars (9.2.14.0) jruby-jars (9.2.16.0)
jruby-rack (1.1.21) jruby-rack (1.1.21)
rake (13.0.1) rake (13.0.1)
rubyzip (1.3.0) rubyzip (1.3.0)
@ -19,6 +19,7 @@ GEM
PLATFORMS PLATFORMS
java java
ruby ruby
universal-java-11
DEPENDENCIES DEPENDENCIES
demo! demo!
@ -26,4 +27,4 @@ DEPENDENCIES
warbler (~> 2.0) warbler (~> 2.0)
BUNDLED WITH BUNDLED WITH
2.2.0.rc.2 2.3.0.dev

View file

@ -89,6 +89,8 @@ RSpec.configure do |config|
end end
config.before :all do config.before :all do
check_test_gems!
build_repo1 build_repo1
reset_paths! reset_paths!

View file

@ -30,7 +30,11 @@ module Spec
end end
def build_repo1 def build_repo1
rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
build_repo gem_repo1 do build_repo gem_repo1 do
FileUtils.cp rake_path, "#{gem_repo1}/gems/"
build_gem "rack", %w[0.9.1 1.0.0] do |s| build_gem "rack", %w[0.9.1 1.0.0] do |s|
s.executables = "rackup" s.executables = "rackup"
s.post_install_message = "Rack's post install message" s.post_install_message = "Rack's post install message"
@ -150,32 +154,6 @@ module Spec
build_gem "duradura", "7.0" build_gem "duradura", "7.0"
build_gem "with_implicit_rake_dep" do |s|
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
path = File.expand_path("../lib", __FILE__)
FileUtils.mkdir_p(path)
File.open("\#{path}/implicit_rake_dep.rb", "w") do |f|
f.puts "IMPLICIT_RAKE_DEP = 'YES'"
end
end
RUBY
end
build_gem "another_implicit_rake_dep" do |s|
s.extensions << "Rakefile"
s.write "Rakefile", <<-RUBY
task :default do
path = File.expand_path("../lib", __FILE__)
FileUtils.mkdir_p(path)
File.open("\#{path}/another_implicit_rake_dep.rb", "w") do |f|
f.puts "ANOTHER_IMPLICIT_RAKE_DEP = 'YES'"
end
end
RUBY
end
build_gem "very_simple_binary", &:add_c_extension build_gem "very_simple_binary", &:add_c_extension
build_gem "simple_binary", &:add_c_extension build_gem "simple_binary", &:add_c_extension
@ -255,6 +233,13 @@ module Spec
def build_repo(path, &blk) def build_repo(path, &blk)
return if File.directory?(path) return if File.directory?(path)
FileUtils.mkdir_p("#{path}/gems")
update_repo(path, &blk)
end
def check_test_gems!
rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
if rake_path.nil? if rake_path.nil?
@ -263,14 +248,9 @@ module Spec
rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first rake_path = Dir["#{Path.base_system_gems}/**/rake*.gem"].first
end end
if rake_path if rake_path.nil?
FileUtils.mkdir_p("#{path}/gems")
FileUtils.cp rake_path, "#{path}/gems/"
else
abort "Your test gems are missing! Run `rm -rf #{tmp}` and try again." abort "Your test gems are missing! Run `rm -rf #{tmp}` and try again."
end end
update_repo(path, &blk)
end end
def update_repo(path) def update_repo(path)

View file

@ -130,7 +130,7 @@ module Spec
def ruby(ruby, options = {}) def ruby(ruby, options = {})
ruby_cmd = build_ruby_cmd ruby_cmd = build_ruby_cmd
escaped_ruby = RUBY_PLATFORM == "java" ? ruby.shellescape.dump : ruby.shellescape escaped_ruby = ruby.shellescape
sys_exec(%(#{ruby_cmd} -w -e #{escaped_ruby}), options) sys_exec(%(#{ruby_cmd} -w -e #{escaped_ruby}), options)
end end

View file

@ -114,30 +114,49 @@ module Spec
match do match do
opts = names.last.is_a?(Hash) ? names.pop : {} opts = names.last.is_a?(Hash) ? names.pop : {}
source = opts.delete(:source) source = opts.delete(:source)
groups = Array(opts[:groups]) groups = Array(opts.delete(:groups)).map(&:inspect).join(", ")
opts[:raise_on_error] = false opts[:raise_on_error] = false
groups << opts @errors = names.map do |full_name|
@errors = names.map do |name| name, version, platform = full_name.split(/\s+/)
name, version, platform = name.split(/\s+/)
require_path = name == "bundler" ? "#{lib_dir}/bundler" : name.tr("-", "/") require_path = name == "bundler" ? "#{lib_dir}/bundler" : name.tr("-", "/")
version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name) version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name)
code = [] source_const = "#{Spec::Builders.constantize(name)}_SOURCE"
code << "require '#{require_path}.rb'" ruby <<~R, opts
code << "puts #{version_const}" require '#{lib_dir}/bundler'
run code.join("; "), *groups Bundler.setup(#{groups})
actual_version, actual_platform = out.strip.split(/\s+/, 2)
unless Gem::Version.new(actual_version) == Gem::Version.new(version) require '#{require_path}.rb'
actual_version, actual_platform = #{version_const}.split(/\s+/, 2)
unless Gem::Version.new(actual_version) == Gem::Version.new('#{version}')
puts actual_version
exit 64
end
unless actual_platform.to_s == '#{platform}'
puts actual_platform
exit 65
end
require '#{require_path}/source'
exit 0 if #{source.nil?}
actual_source = #{source_const}
unless actual_source == '#{source}'
puts actual_source
exit 66
end
R
next if exitstatus == 0
if exitstatus == 64
actual_version = out.split("\n").last
next "#{name} was expected to be at version #{version} but was #{actual_version}" next "#{name} was expected to be at version #{version} but was #{actual_version}"
end end
unless actual_platform == platform if exitstatus == 65
actual_platform = out.split("\n").last
next "#{name} was expected to be of platform #{platform} but was #{actual_platform}" next "#{name} was expected to be of platform #{platform} but was #{actual_platform}"
end end
next unless source if exitstatus == 66
source_const = "#{Spec::Builders.constantize(name)}_SOURCE" actual_source = out.split("\n").last
run "require '#{require_path}/source'; puts #{source_const}", *groups next "Expected #{name} (#{version}) to be installed from `#{source}`, was actually from `#{actual_source}`"
unless out.strip == source
next "Expected #{name} (#{version}) to be installed from `#{source}`, was actually from `#{out}`"
end end
next "Command to check forgem inclusion of gem #{full_name} failed"
end.compact end.compact
@errors.empty? @errors.empty?

View file

@ -134,9 +134,7 @@ class TestGemPlatform < Gem::TestCase
'i386-solaris2.8' => ['x86', 'solaris', '2.8'], 'i386-solaris2.8' => ['x86', 'solaris', '2.8'],
'mswin32' => ['x86', 'mswin32', nil], 'mswin32' => ['x86', 'mswin32', nil],
'x86_64-linux' => ['x86_64', 'linux', nil], 'x86_64-linux' => ['x86_64', 'linux', nil],
'x86_64-linux-gnu' => ['x86_64', 'linux', nil],
'x86_64-linux-musl' => ['x86_64', 'linux', 'musl'], 'x86_64-linux-musl' => ['x86_64', 'linux', 'musl'],
'x86_64-linux-uclibc' => ['x86_64', 'linux', 'uclibc'],
'x86_64-openbsd3.9' => ['x86_64', 'openbsd', '3.9'], 'x86_64-openbsd3.9' => ['x86_64', 'openbsd', '3.9'],
'x86_64-openbsd4.0' => ['x86_64', 'openbsd', '4.0'], 'x86_64-openbsd4.0' => ['x86_64', 'openbsd', '4.0'],
'x86_64-openbsd' => ['x86_64', 'openbsd', nil], 'x86_64-openbsd' => ['x86_64', 'openbsd', nil],
@ -145,7 +143,6 @@ class TestGemPlatform < Gem::TestCase
test_cases.each do |arch, expected| test_cases.each do |arch, expected|
platform = Gem::Platform.new arch platform = Gem::Platform.new arch
assert_equal expected, platform.to_a, arch.inspect assert_equal expected, platform.to_a, arch.inspect
assert_equal expected, Gem::Platform.new(platform.to_s).to_a, arch.inspect
end end
end end
@ -264,32 +261,6 @@ class TestGemPlatform < Gem::TestCase
assert((with_x86_arch === with_nil_arch), 'x86 =~ nil') assert((with_x86_arch === with_nil_arch), 'x86 =~ nil')
end end
def test_nil_version_is_treated_as_any_version
x86_darwin_8 = Gem::Platform.new 'i686-darwin8.0'
x86_darwin_nil = Gem::Platform.new 'i686-darwin'
assert((x86_darwin_8 === x86_darwin_nil), '8.0 =~ nil')
assert((x86_darwin_nil === x86_darwin_8), 'nil =~ 8.0')
end
def test_nil_version_is_stricter_for_linux_os
x86_linux = Gem::Platform.new 'i686-linux'
x86_linux_gnu = Gem::Platform.new 'i686-linux-gnu'
x86_linux_musl = Gem::Platform.new 'i686-linux-musl'
x86_linux_uclibc = Gem::Platform.new 'i686-linux-uclibc'
assert((x86_linux === x86_linux_gnu), 'linux =~ linux-gnu')
assert((x86_linux_gnu === x86_linux), 'linux-gnu =~ linux')
assert(!(x86_linux_gnu === x86_linux_musl), 'linux-gnu =~ linux-musl')
assert(!(x86_linux_musl === x86_linux_gnu), 'linux-musl =~ linux-gnu')
assert(!(x86_linux_uclibc === x86_linux_musl), 'linux-uclibc =~ linux-musl')
assert(!(x86_linux_musl === x86_linux_uclibc), 'linux-musl =~ linux-uclibc')
assert(!(x86_linux === x86_linux_musl), 'linux =~ linux-musl')
assert(!(x86_linux_musl === x86_linux), 'linux-musl =~ linux')
assert(!(x86_linux === x86_linux_uclibc), 'linux =~ linux-uclibc')
assert(!(x86_linux_uclibc === x86_linux), 'linux-uclibc =~ linux')
end
def test_equals3_cpu_arm def test_equals3_cpu_arm
arm = Gem::Platform.new 'arm-linux' arm = Gem::Platform.new 'arm-linux'
armv5 = Gem::Platform.new 'armv5-linux' armv5 = Gem::Platform.new 'armv5-linux'

View file

@ -496,6 +496,44 @@ PeIQQkFng2VVot/WAQbv3ePqWq07g1BBcwIBAg==
assert_equal url, e.uri assert_equal url, e.uri
end end
def test_fetch_path_timeout_error
fetcher = Gem::RemoteFetcher.new nil
@fetcher = fetcher
def fetcher.fetch_http(uri, mtime = nil, head = nil)
raise Timeout::Error, 'timed out'
end
url = 'http://example.com/uri'
e = assert_raises Gem::RemoteFetcher::FetchError do
fetcher.fetch_path url
end
assert_match %r{Timeout::Error: timed out \(#{Regexp.escape url}\)\z},
e.message
assert_equal url, e.uri
end
def test_fetch_path_getaddrinfo_error
fetcher = Gem::RemoteFetcher.new nil
@fetcher = fetcher
def fetcher.fetch_http(uri, mtime = nil, head = nil)
raise SocketError, 'getaddrinfo: nodename nor servname provided'
end
url = 'http://example.com/uri'
e = assert_raises Gem::RemoteFetcher::FetchError do
fetcher.fetch_path url
end
assert_match %r{SocketError: getaddrinfo: nodename nor servname provided \(#{Regexp.escape url}\)\z},
e.message
assert_equal url, e.uri
end
def test_fetch_path_openssl_ssl_sslerror def test_fetch_path_openssl_ssl_sslerror
fetcher = Gem::RemoteFetcher.new nil fetcher = Gem::RemoteFetcher.new nil
@fetcher = fetcher @fetcher = fetcher