Merge RubyGems-3.2.13 and Bundler-2.2.13

This commit is contained in:
Hiroshi SHIBATA 2021-03-08 12:17:52 +09:00 committed by NARUSE, Yui
parent 06cd5711e0
commit 7efc7afcae
24 changed files with 477 additions and 267 deletions

View file

@ -39,11 +39,11 @@ module Bundler
constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase } constant_name = name.gsub(/-[_-]*(?![_-]|$)/) { "::" }.gsub(/([_-]+|(::)|^)(.|$)/) { $2.to_s + $3.upcase }
constant_array = constant_name.split("::") constant_array = constant_name.split("::")
git_installed = Bundler.git_present? use_git = Bundler.git_present? && options[:git]
git_author_name = git_installed ? `git config user.name`.chomp : "" git_author_name = use_git ? `git config user.name`.chomp : ""
github_username = git_installed ? `git config github.user`.chomp : "" github_username = use_git ? `git config github.user`.chomp : ""
git_user_email = git_installed ? `git config user.email`.chomp : "" git_user_email = use_git ? `git config user.email`.chomp : ""
config = { config = {
:name => name, :name => name,
@ -58,6 +58,7 @@ module Bundler
:ext => options[:ext], :ext => options[:ext],
:exe => options[:exe], :exe => options[:exe],
:bundler_version => bundler_dependency_version, :bundler_version => bundler_dependency_version,
:git => use_git,
:github_username => github_username.empty? ? "[USERNAME]" : github_username, :github_username => github_username.empty? ? "[USERNAME]" : github_username,
:required_ruby_version => Gem.ruby_version < Gem::Version.new("2.4.a") ? "2.3.0" : "2.4.0", :required_ruby_version => Gem.ruby_version < Gem::Version.new("2.4.a") ? "2.3.0" : "2.4.0",
} }
@ -79,7 +80,7 @@ module Bundler
bin/setup bin/setup
] ]
templates.merge!("gitignore.tt" => ".gitignore") if Bundler.git_present? templates.merge!("gitignore.tt" => ".gitignore") if use_git
if test_framework = ask_and_set_test_framework if test_framework = ask_and_set_test_framework
config[:test] = test_framework config[:test] = test_framework
@ -175,24 +176,31 @@ module Bundler
) )
end end
if File.exist?(target) && !File.directory?(target)
Bundler.ui.error "Couldn't create a new gem named `#{gem_name}` because there's an existing file named `#{gem_name}`."
exit Bundler::BundlerError.all_errors[Bundler::GenericSystemCallError]
end
if use_git
Bundler.ui.info "Initializing git repo in #{target}"
`git init #{target}`
config[:git_default_branch] = File.read("#{target}/.git/HEAD").split("/").last.chomp
end
templates.each do |src, dst| templates.each do |src, dst|
destination = target.join(dst) destination = target.join(dst)
SharedHelpers.filesystem_access(destination) do thor.template("newgem/#{src}", destination, config)
thor.template("newgem/#{src}", destination, config)
end
end end
executables.each do |file| executables.each do |file|
SharedHelpers.filesystem_access(target.join(file)) do |path| path = target.join(file)
executable = (path.stat.mode | 0o111) executable = (path.stat.mode | 0o111)
path.chmod(executable) path.chmod(executable)
end
end end
if Bundler.git_present? && options[:git] if use_git
Bundler.ui.info "Initializing git repo in #{target}"
Dir.chdir(target) do Dir.chdir(target) do
`git init`
`git add .` `git add .`
end end
end end
@ -202,8 +210,6 @@ module Bundler
Bundler.ui.info "Gem '#{name}' was successfully created. " \ Bundler.ui.info "Gem '#{name}' was successfully created. " \
"For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html" "For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html"
rescue Errno::EEXIST => e
raise GenericSystemCallError.new(e, "There was a conflict while creating the new gem.")
end end
private private

View file

@ -264,7 +264,7 @@ module Bundler
# Run a resolve against the locally available gems # Run a resolve against the locally available gems
Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}")
expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote)
Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) Resolver.resolve(expanded_dependencies, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
end end
end end
end end
@ -656,19 +656,20 @@ module Bundler
def converge_rubygems_sources def converge_rubygems_sources
return false if Bundler.feature_flag.disable_multisource? return false if Bundler.feature_flag.disable_multisource?
changes = false
# Get the RubyGems sources from the Gemfile.lock # Get the RubyGems sources from the Gemfile.lock
locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) } locked_gem_sources = @locked_sources.select {|s| s.is_a?(Source::Rubygems) }
return false if locked_gem_sources.empty?
# Get the RubyGems remotes from the Gemfile # Get the RubyGems remotes from the Gemfile
actual_remotes = sources.rubygems_remotes actual_remotes = sources.rubygems_remotes
return false if actual_remotes.empty?
changes = false
# If there is a RubyGems source in both # If there is a RubyGems source in both
if !locked_gem_sources.empty? && !actual_remotes.empty? locked_gem_sources.each do |locked_gem|
locked_gem_sources.each do |locked_gem| # Merge the remotes from the Gemfile into the Gemfile.lock
# Merge the remotes from the Gemfile into the Gemfile.lock changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
changes |= locked_gem.replace_remotes(actual_remotes, Bundler.settings[:allow_deployment_source_credential_changes])
end
end end
changes changes
@ -893,30 +894,18 @@ module Bundler
# Record the specs available in each gem's source, so that those # Record the specs available in each gem's source, so that those
# specs will be available later when the resolver knows where to # specs will be available later when the resolver knows where to
# look for that gemspec (or its dependencies) # look for that gemspec (or its dependencies)
default = sources.default_source source_requirements = { :default => sources.default_source }.merge(dependency_source_requirements)
source_requirements = { :default => default }
default = nil unless Bundler.feature_flag.disable_multisource?
dependencies.each do |dep|
next unless source = dep.source || default
source_requirements[dep.name] = source
end
metadata_dependencies.each do |dep| metadata_dependencies.each do |dep|
source_requirements[dep.name] = sources.metadata_source source_requirements[dep.name] = sources.metadata_source
end end
source_requirements[:global] = index unless Bundler.feature_flag.disable_multisource?
source_requirements[:default_bundler] = source_requirements["bundler"] || source_requirements[:default] source_requirements[:default_bundler] = source_requirements["bundler"] || source_requirements[:default]
source_requirements["bundler"] = sources.metadata_source # needs to come last to override source_requirements["bundler"] = sources.metadata_source # needs to come last to override
source_requirements source_requirements
end end
def pinned_spec_names(skip = nil) def pinned_spec_names(skip = nil)
pinned_names = [] dependency_source_requirements.reject {|_, source| source == skip }.keys
default = Bundler.feature_flag.disable_multisource? && sources.default_source
@dependencies.each do |dep|
next unless dep_source = dep.source || default
next if dep_source == skip
pinned_names << dep.name
end
pinned_names
end end
def requested_groups def requested_groups
@ -973,5 +962,17 @@ module Bundler
Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes) Bundler.settings[:allow_deployment_source_credential_changes] && source.equivalent_remotes?(sources.rubygems_remotes)
end end
def dependency_source_requirements
@dependency_source_requirements ||= begin
source_requirements = {}
default = sources.default_source
dependencies.each do |dep|
dep_source = dep.source || default
source_requirements[dep.name] = dep_source
end
source_requirements
end
end
end end
end end

View file

@ -24,6 +24,9 @@ module Bundler
def initialize def initialize
@source = nil @source = nil
@sources = SourceList.new @sources = SourceList.new
@global_rubygems_sources = []
@git_sources = {} @git_sources = {}
@dependencies = [] @dependencies = []
@groups = [] @groups = []
@ -45,6 +48,7 @@ module Bundler
@gemfiles << expanded_gemfile_path @gemfiles << expanded_gemfile_path
contents ||= Bundler.read_file(@gemfile.to_s) contents ||= Bundler.read_file(@gemfile.to_s)
instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1) instance_eval(contents.dup.tap{|x| x.untaint if RUBY_VERSION < "2.7" }, gemfile.to_s, 1)
check_primary_source_safety
rescue Exception => e # rubocop:disable Lint/RescueException rescue Exception => e # rubocop:disable Lint/RescueException
message = "There was an error " \ message = "There was an error " \
"#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \ "#{e.is_a?(GemfileEvalError) ? "evaluating" : "parsing"} " \
@ -164,8 +168,7 @@ module Bundler
elsif block_given? elsif block_given?
with_source(@sources.add_rubygems_source("remotes" => source), &blk) with_source(@sources.add_rubygems_source("remotes" => source), &blk)
else else
check_primary_source_safety(@sources) @global_rubygems_sources << source
@sources.global_rubygems_source = source
end end
end end
@ -183,24 +186,14 @@ module Bundler
end end
def path(path, options = {}, &blk) def path(path, options = {}, &blk)
unless block_given?
msg = "You can no longer specify a path source by itself. Instead, \n" \
"either use the :path option on a gem, or specify the gems that \n" \
"bundler should find in the path source by passing a block to \n" \
"the path method, like: \n\n" \
" path 'dir/containing/rails' do\n" \
" gem 'rails'\n" \
" end\n\n"
raise DeprecatedError, msg if Bundler.feature_flag.disable_multisource?
SharedHelpers.major_deprecation(2, msg.strip)
end
source_options = normalize_hash(options).merge( source_options = normalize_hash(options).merge(
"path" => Pathname.new(path), "path" => Pathname.new(path),
"root_path" => gemfile_root, "root_path" => gemfile_root,
"gemspec" => gemspecs.find {|g| g.name == options["name"] } "gemspec" => gemspecs.find {|g| g.name == options["name"] }
) )
source_options["global"] = true unless block_given?
source = @sources.add_path_source(source_options) source = @sources.add_path_source(source_options)
with_source(source, &blk) with_source(source, &blk)
end end
@ -279,6 +272,11 @@ module Bundler
raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile" raise GemfileError, "Undefined local variable or method `#{name}' for Gemfile"
end end
def check_primary_source_safety
check_path_source_safety
check_rubygems_source_safety
end
private private
def add_git_sources def add_git_sources
@ -440,17 +438,33 @@ repo_name ||= user_name
end end
end end
def check_primary_source_safety(source_list) def check_path_source_safety
return if source_list.rubygems_primary_remotes.empty? && source_list.global_rubygems_source.nil? return if @sources.global_path_source.nil?
msg = "You can no longer specify a path source by itself. Instead, \n" \
"either use the :path option on a gem, or specify the gems that \n" \
"bundler should find in the path source by passing a block to \n" \
"the path method, like: \n\n" \
" path 'dir/containing/rails' do\n" \
" gem 'rails'\n" \
" end\n\n"
SharedHelpers.major_deprecation(2, msg.strip)
end
def check_rubygems_source_safety
@sources.global_rubygems_source = @global_rubygems_sources.shift
return if @global_rubygems_sources.empty?
@global_rubygems_sources.each do |source|
@sources.add_rubygems_remote(source)
end
if Bundler.feature_flag.disable_multisource? if Bundler.feature_flag.disable_multisource?
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" "should come from that source. To downgrade this error to a warning, run " \
unless Bundler.feature_flag.bundler_2_mode? "`bundle config unset disable_multisource`"
msg += ". To downgrade this error to a warning, run " \
"`bundle config unset disable_multisource`"
end
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. " \

View file

@ -50,6 +50,7 @@ def gemfile(install = false, options = {}, &gemfile)
Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins? Bundler::Plugin.gemfile_install(&gemfile) if Bundler.feature_flag.plugins?
builder = Bundler::Dsl.new builder = Bundler::Dsl.new
builder.instance_eval(&gemfile) builder.instance_eval(&gemfile)
builder.check_primary_source_safety
Bundler.settings.temporary(:frozen => false) do Bundler.settings.temporary(:frozen => false) do
definition = builder.to_definition(nil, true) definition = builder.to_definition(nil, true)

View file

@ -64,8 +64,6 @@ module Bundler
@state = nil @state = nil
@specs = {} @specs = {}
@rubygems_aggregate = Source::Rubygems.new
if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/) if lockfile.match(/<<<<<<<|=======|>>>>>>>|\|\|\|\|\|\|\|/)
raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \ raise LockfileError, "Your #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)} contains merge conflicts.\n" \
"Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock." "Run `git checkout HEAD -- #{Bundler.default_lockfile.relative_path_from(SharedHelpers.pwd)}` first to get a clean lock."
@ -89,7 +87,6 @@ module Bundler
send("parse_#{@state}", line) send("parse_#{@state}", line)
end end
end end
@sources << @rubygems_aggregate unless Bundler.feature_flag.disable_multisource?
@specs = @specs.values.sort_by(&:identifier) @specs = @specs.values.sort_by(&:identifier)
warn_for_outdated_bundler_version warn_for_outdated_bundler_version
rescue ArgumentError => e rescue ArgumentError => e
@ -134,16 +131,19 @@ module Bundler
@sources << @current_source @sources << @current_source
end end
when GEM when GEM
if Bundler.feature_flag.disable_multisource? source_remotes = Array(@opts["remote"])
if source_remotes.size == 1
@opts["remotes"] = @opts.delete("remote") @opts["remotes"] = @opts.delete("remote")
@current_source = TYPES[@type].from_lock(@opts) @current_source = TYPES[@type].from_lock(@opts)
@sources << @current_source
else else
Array(@opts["remote"]).each do |url| source_remotes.each do |url|
@rubygems_aggregate.add_remote(url) rubygems_aggregate.add_remote(url)
end end
@current_source = @rubygems_aggregate @current_source = rubygems_aggregate
end end
@sources << @current_source
when PLUGIN when PLUGIN
@current_source = Plugin.source_from_lock(@opts) @current_source = Plugin.source_from_lock(@opts)
@sources << @current_source @sources << @current_source
@ -245,5 +245,9 @@ 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

@ -105,6 +105,7 @@ module Bundler
else else
builder.eval_gemfile(gemfile) builder.eval_gemfile(gemfile)
end end
builder.check_primary_source_safety
definition = builder.to_definition(nil, true) definition = builder.to_definition(nil, true)
return if definition.dependencies.empty? return if definition.dependencies.empty?

View file

@ -16,15 +16,13 @@ module Bundler
version = options[:version] || [">= 0"] version = options[:version] || [">= 0"]
Bundler.settings.temporary(:disable_multisource => false) do if options[:git]
if options[:git] install_git(names, version, options)
install_git(names, version, options) elsif options[:local_git]
elsif options[:local_git] install_local_git(names, version, options)
install_local_git(names, version, options) else
else sources = options[:source] || Bundler.rubygems.sources
sources = options[:source] || Bundler.rubygems.sources install_rubygems(names, version, sources)
install_rubygems(names, version, sources)
end
end end
end end
@ -79,7 +77,7 @@ module Bundler
source_list = SourceList.new source_list = SourceList.new
source_list.add_git_source(git_source_options) if git_source_options source_list.add_git_source(git_source_options) if git_source_options
source_list.add_rubygems_source("remotes" => rubygems_source) if rubygems_source source_list.global_rubygems_source = rubygems_source if rubygems_source
deps = names.map {|name| Dependency.new name, version } deps = names.map {|name| Dependency.new name, version }

View file

@ -17,6 +17,10 @@ module Bundler
path_sources + git_sources + rubygems_sources + [metadata_source] path_sources + git_sources + rubygems_sources + [metadata_source]
end end
def default_source
git_sources.first || global_rubygems_source
end
private private
def rubygems_aggregate_class def rubygems_aggregate_class

View file

@ -17,16 +17,21 @@ module Bundler
# ==== Returns # ==== Returns
# <GemBundle>,nil:: If the list of dependencies can be resolved, a # <GemBundle>,nil:: If the list of dependencies can be resolved, a
# collection of gemspecs is returned. Otherwise, nil is returned. # collection of gemspecs is returned. Otherwise, nil is returned.
def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) def self.resolve(requirements, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil)
base = SpecSet.new(base) unless base.is_a?(SpecSet) base = SpecSet.new(base) unless base.is_a?(SpecSet)
resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) resolver = new(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
result = resolver.start(requirements) result = resolver.start(requirements)
SpecSet.new(result) SpecSet.new(result)
end end
def initialize(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) def initialize(source_requirements, base, gem_version_promoter, additional_base_requirements, platforms)
@index = index
@source_requirements = source_requirements @source_requirements = source_requirements
@index_requirements = source_requirements.each_with_object({}) do |source_requirement, index_requirements|
name, source = source_requirement
index_requirements[name] = name == :global ? source : source.specs
end
@base = base @base = base
@resolver = Molinillo::Resolver.new(self, self) @resolver = Molinillo::Resolver.new(self, self)
@search_for = {} @search_for = {}
@ -40,7 +45,7 @@ module Bundler
@resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
@gem_version_promoter = gem_version_promoter @gem_version_promoter = gem_version_promoter
@use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major?
@lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource? @no_aggregate_global_source = @source_requirements[:global].nil?
@variant_specific_names = [] @variant_specific_names = []
@generic_names = ["Ruby\0", "RubyGems\0"] @generic_names = ["Ruby\0", "RubyGems\0"]
@ -125,8 +130,7 @@ module Bundler
dependency = dependency_proxy.dep dependency = dependency_proxy.dep
name = dependency.name name = dependency.name
search_result = @search_for[dependency_proxy] ||= begin search_result = @search_for[dependency_proxy] ||= begin
index = index_for(dependency) results = results_for(dependency, @base[name])
results = index.search(dependency, @base[name])
if vertex = @base_dg.vertex_named(name) if vertex = @base_dg.vertex_named(name)
locked_requirement = vertex.payload.requirement locked_requirement = vertex.payload.requirement
@ -196,22 +200,22 @@ module Bundler
end end
def index_for(dependency) def index_for(dependency)
source = @source_requirements[dependency.name] source = @index_requirements[dependency.name]
if source if source
source.specs source
elsif @lockfile_uses_separate_rubygems_sources elsif @no_aggregate_global_source
Index.build do |idx| Index.build do |idx|
if dependency.all_sources dependency.all_sources.each {|s| idx.add_source(s.specs) }
dependency.all_sources.each {|s| idx.add_source(s.specs) if s }
else
idx.add_source @source_requirements[:default].specs
end
end end
else else
@index @index_requirements[:global]
end end
end end
def results_for(dependency, base)
index_for(dependency).search(dependency, base)
end
def name_for(dependency) def name_for(dependency)
dependency.name dependency.name
end end
@ -239,18 +243,20 @@ module Bundler
def relevant_sources_for_vertex(vertex) def relevant_sources_for_vertex(vertex)
if vertex.root? if vertex.root?
[@source_requirements[vertex.name]] [@source_requirements[vertex.name]]
elsif @lockfile_uses_separate_rubygems_sources elsif @no_aggregate_global_source
vertex.recursive_predecessors.map do |v| vertex.recursive_predecessors.map do |v|
@source_requirements[v.name] @source_requirements[v.name]
end << @source_requirements[:default] end.compact << @source_requirements[:default]
else
[]
end end
end end
def sort_dependencies(dependencies, activated, conflicts) def sort_dependencies(dependencies, activated, conflicts)
dependencies.sort_by do |dependency| dependencies.sort_by do |dependency|
dependency.all_sources = relevant_sources_for_vertex(activated.vertex_named(dependency.name))
name = name_for(dependency) name = name_for(dependency)
vertex = activated.vertex_named(name) vertex = activated.vertex_named(name)
dependency.all_sources = relevant_sources_for_vertex(vertex)
[ [
@base_dg.vertex_named(name) ? 0 : 1, @base_dg.vertex_named(name) ? 0 : 1,
vertex.payload ? 0 : 1, vertex.payload ? 0 : 1,
@ -317,7 +323,7 @@ module Bundler
"If you are updating multiple gems in your Gemfile at once,\n" \ "If you are updating multiple gems in your Gemfile at once,\n" \
"try passing them all to `bundle update`" "try passing them all to `bundle update`"
elsif source = @source_requirements[name] elsif source = @source_requirements[name]
specs = source.specs[name] specs = source.specs.search(name)
versions_with_platforms = specs.map {|s| [s.version, s.platform] } versions_with_platforms = specs.map {|s| [s.version, s.platform] }
message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n") message = String.new("Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in #{source}#{cache_message}.\n")
message << if versions_with_platforms.any? message << if versions_with_platforms.any?
@ -326,7 +332,7 @@ module Bundler
"The source does not contain any versions of '#{name}'" "The source does not contain any versions of '#{name}'"
end end
else else
message = "Could not find gem '#{requirement}' in any of the gem sources " \ message = "Could not find gem '#{SharedHelpers.pretty_dependency(requirement)}' in any of the gem sources " \
"listed in your Gemfile#{cache_message}." "listed in your Gemfile#{cache_message}."
end end
raise GemNotFound, message raise GemNotFound, message
@ -392,7 +398,7 @@ module Bundler
if other_bundler_required if other_bundler_required
o << "\n\n" o << "\n\n"
candidate_specs = @source_requirements[:default_bundler].specs.search(conflict_dependency) candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency)
if candidate_specs.any? if candidate_specs.any?
target_version = candidate_specs.last.version target_version = candidate_specs.last.version
new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ") new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
@ -411,14 +417,8 @@ module Bundler
relevant_sources = if conflict.requirement.source relevant_sources = if conflict.requirement.source
[conflict.requirement.source] [conflict.requirement.source]
elsif conflict.requirement.all_sources
conflict.requirement.all_sources
elsif @lockfile_uses_separate_rubygems_sources
# every conflict should have an explicit group of sources when we
# enforce strict pinning
raise "no source set for #{conflict}"
else else
[] conflict.requirement.all_sources
end.compact.map(&:to_s).uniq.sort end.compact.map(&:to_s).uniq.sort
metadata_requirement = name.end_with?("\0") metadata_requirement = name.end_with?("\0")
@ -455,23 +455,21 @@ module Bundler
def validate_resolved_specs!(resolved_specs) def validate_resolved_specs!(resolved_specs)
resolved_specs.each do |v| resolved_specs.each do |v|
name = v.name name = v.name
next unless sources = relevant_sources_for_vertex(v) sources = relevant_sources_for_vertex(v)
sources.compact! next unless sources.any?
if default_index = sources.index(@source_requirements[:default]) if default_index = sources.index(@source_requirements[:default])
sources.delete_at(default_index) sources.delete_at(default_index)
end end
sources.reject! {|s| s.specs[name].empty? } sources.reject! {|s| s.specs.search(name).empty? }
sources.uniq! sources.uniq!
next if sources.size <= 1 next if sources.size <= 1
multisource_disabled = Bundler.feature_flag.disable_multisource?
msg = ["The gem '#{name}' was found in multiple relevant sources."] msg = ["The gem '#{name}' was found in multiple relevant sources."]
msg.concat sources.map {|s| " * #{s}" }.sort msg.concat sources.map {|s| " * #{s}" }.sort
msg << "You #{multisource_disabled ? :must : :should} add this gem to the source block for the source you wish it to be installed from." msg << "You #{@no_aggregate_global_source ? :must : :should} add this gem to the source block for the source you wish it to be installed from."
msg = msg.join("\n") msg = msg.join("\n")
raise SecurityError, msg if multisource_disabled raise SecurityError, msg if @no_aggregate_global_source
Bundler.ui.warn "Warning: #{msg}" Bundler.ui.warn "Warning: #{msg}"
end end
end end

View file

@ -5,15 +5,19 @@ module Bundler
attr_reader :path_sources, attr_reader :path_sources,
:git_sources, :git_sources,
:plugin_sources, :plugin_sources,
:global_rubygems_source, :global_path_source,
:metadata_source :metadata_source
def global_rubygems_source
@global_rubygems_source ||= rubygems_aggregate_class.new
end
def initialize def initialize
@path_sources = [] @path_sources = []
@git_sources = [] @git_sources = []
@plugin_sources = [] @plugin_sources = []
@global_rubygems_source = nil @global_rubygems_source = nil
@rubygems_aggregate = rubygems_aggregate_class.new @global_path_source = nil
@rubygems_sources = [] @rubygems_sources = []
@metadata_source = Source::Metadata.new @metadata_source = Source::Metadata.new
end end
@ -22,7 +26,9 @@ module Bundler
if options["gemspec"] if options["gemspec"]
add_source_to_list Source::Gemspec.new(options), path_sources add_source_to_list Source::Gemspec.new(options), path_sources
else else
add_source_to_list Source::Path.new(options), path_sources path_source = add_source_to_list Source::Path.new(options), path_sources
@global_path_source ||= path_source if options["global"]
path_source
end end
end end
@ -41,24 +47,20 @@ module Bundler
end end
def global_rubygems_source=(uri) def global_rubygems_source=(uri)
if Bundler.feature_flag.disable_multisource? @global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri)
@global_rubygems_source ||= rubygems_aggregate_class.new("remotes" => uri)
end
add_rubygems_remote(uri)
end end
def add_rubygems_remote(uri) def add_rubygems_remote(uri)
return if Bundler.feature_flag.disable_multisource? global_rubygems_source.add_remote(uri)
@rubygems_aggregate.add_remote(uri) global_rubygems_source
@rubygems_aggregate
end end
def default_source def default_source
global_rubygems_source || @rubygems_aggregate global_path_source || global_rubygems_source
end end
def rubygems_sources def rubygems_sources
@rubygems_sources + [default_source] @rubygems_sources + [global_rubygems_source]
end end
def rubygems_remotes def rubygems_remotes
@ -94,10 +96,9 @@ module Bundler
replacement_rubygems = !Bundler.feature_flag.disable_multisource? && replacement_rubygems = !Bundler.feature_flag.disable_multisource? &&
replacement_sources.detect {|s| s.is_a?(Source::Rubygems) } replacement_sources.detect {|s| s.is_a?(Source::Rubygems) }
@rubygems_aggregate = replacement_rubygems if replacement_rubygems @global_rubygems_source = replacement_rubygems if replacement_rubygems
return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources)
return true if replacement_rubygems && rubygems_remotes.sort_by(&:to_s) != replacement_rubygems.remotes.sort_by(&:to_s)
false false
end end
@ -110,10 +111,6 @@ module Bundler
all_sources.each(&:remote!) all_sources.each(&:remote!)
end end
def rubygems_primary_remotes
@rubygems_aggregate.remotes
end
private private
def rubygems_aggregate_class def rubygems_aggregate_class

View file

@ -29,19 +29,21 @@ TODO: Write usage instructions here
After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %> After checking out the repo, run `bin/setup` to install dependencies.<% if config[:test] %> Then, run `rake <%= config[:test].sub('mini', '').sub('rspec', 'spec') %>` to run the tests.<% end %> You can also run `bin/console` for an interactive prompt that will allow you to experiment.<% if config[:bin] %> Run `bundle exec <%= config[:name] %>` to use the gem in this directory, ignoring other installed copies of this gem.<% end %>
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org). To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
<% if config[:git] -%>
## Contributing ## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md).<% end %> Bug reports and pull requests are welcome on GitHub at https://github.com/<%= config[:github_username] %>/<%= config[:name] %>.<% if config[:coc] %> This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).<% end %>
<% end -%>
<% if config[:mit] -%> <% if config[:mit] -%>
## License ## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT). The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
<% end -%> <% end -%>
<% if config[:coc] -%> <% if config[:git] && config[:coc] -%>
## Code of Conduct ## Code of Conduct
Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/master/CODE_OF_CONDUCT.md). Everyone interacting in the <%= config[:constant_name] %> project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/<%= config[:github_username] %>/<%= config[:name] %>/blob/<%= config[:git_default_branch] %>/CODE_OF_CONDUCT.md).
<% end -%> <% end -%>

View file

@ -1,7 +1,7 @@
# frozen_string_literal: false # frozen_string_literal: false
module Bundler module Bundler
VERSION = "2.2.12".freeze VERSION = "2.2.13".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.12".freeze VERSION = "3.2.13".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

@ -13,12 +13,13 @@ module CoreExtensions
def initialize(host, serv, *rest) def initialize(host, serv, *rest)
mutex = Mutex.new mutex = Mutex.new
addrs = [] addrs = []
threads = []
cond_var = ConditionVariable.new cond_var = ConditionVariable.new
Addrinfo.foreach(host, serv, nil, :STREAM) do |addr| Addrinfo.foreach(host, serv, nil, :STREAM) do |addr|
Thread.report_on_exception = false if defined? Thread.report_on_exception = () Thread.report_on_exception = false if defined? Thread.report_on_exception = ()
Thread.new(addr) do threads << Thread.new(addr) do
# give head start to ipv6 addresses # give head start to ipv6 addresses
sleep IPV4_DELAY_SECONDS if addr.ipv4? sleep IPV4_DELAY_SECONDS if addr.ipv4?
@ -40,6 +41,8 @@ module CoreExtensions
host = addrs.shift unless addrs.empty? host = addrs.shift unless addrs.empty?
end end
threads.each {|t| t.kill.join if t.alive? }
super(host, serv, *rest) super(host, serv, *rest)
end end
end end

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/ # reassemble x86-linux-gnu if arch.length > 2 and arch.last !~ /\d+(\.\d+)?$/ # reassemble x86-linux-{libc}
extra = arch.pop extra = arch.pop
arch.last << "-#{extra}" arch.last << "-#{extra}"
end end
@ -146,7 +146,8 @@ 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. # they have the same version, or either has no version (except for 'linux'
# 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).
@ -162,7 +163,10 @@ 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

@ -112,6 +112,7 @@ RSpec.describe Bundler::Plugin do
before do before do
allow(Plugin::DSL).to receive(:new) { builder } allow(Plugin::DSL).to receive(:new) { builder }
allow(builder).to receive(:eval_gemfile).with(gemfile) allow(builder).to receive(:eval_gemfile).with(gemfile)
allow(builder).to receive(:check_primary_source_safety)
allow(builder).to receive(:to_definition) { definition } allow(builder).to receive(:to_definition) { definition }
allow(builder).to receive(:inferred_plugins) { [] } allow(builder).to receive(:inferred_plugins) { [] }
end end

View file

@ -668,29 +668,40 @@ RSpec.describe "bundle exec" do
subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false } subject { bundle "exec #{path} arg1 arg2", :raise_on_error => false }
shared_examples_for "it runs" do it "runs" do
it "like a normally executed executable" do skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject subject
expect(exitstatus).to eq(exit_code) expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err) expect(err).to eq(expected_err)
expect(out).to eq(expected) expect(out).to eq(expected)
end
end end
it_behaves_like "it runs"
context "the executable exits explicitly" do context "the executable exits explicitly" do
let(:executable) { super() << "\nexit #{exit_code}\nputs 'POST_EXIT'\n" } let(:executable) { super() << "\nexit #{exit_code}\nputs 'POST_EXIT'\n" }
context "with exit 0" do context "with exit 0" do
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "with exit 99" do context "with exit 99" do
let(:exit_code) { 99 } let(:exit_code) { 99 }
it_behaves_like "it runs"
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
end end
@ -707,7 +718,15 @@ RSpec.describe "bundle exec" do
# this is specified by C99 # this is specified by C99
128 + 15 128 + 15
end end
it_behaves_like "it runs"
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "the executable is empty" do context "the executable is empty" do
@ -716,7 +735,15 @@ RSpec.describe "bundle exec" do
let(:exit_code) { 0 } let(:exit_code) { 0 }
let(:expected_err) { "#{path} is empty" } let(:expected_err) { "#{path} is empty" }
let(:expected) { "" } let(:expected) { "" }
it_behaves_like "it runs"
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "the executable raises" do context "the executable raises" do
@ -743,12 +770,27 @@ RSpec.describe "bundle exec" do
let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\n#{system_gem_path("bin/bundle")}: Err (Err)" } let(:expected_err) { "bundler: failed to load command: #{path} (#{path})\n#{system_gem_path("bin/bundle")}: Err (Err)" }
let(:expected) { super() } let(:expected) { super() }
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when the file uses the current ruby shebang" do context "when the file uses the current ruby shebang" do
let(:shebang) { "#!#{Gem.ruby}" } let(:shebang) { "#!#{Gem.ruby}" }
it_behaves_like "it runs"
it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when Bundler.setup fails", :bundler => "< 3" do context "when Bundler.setup fails", :bundler => "< 3" do
@ -762,11 +804,19 @@ RSpec.describe "bundle exec" do
let(:exit_code) { Bundler::GemNotFound.new.status_code } let(:exit_code) { Bundler::GemNotFound.new.status_code }
let(:expected) { "" } let(:expected) { "" }
let(:expected_err) { <<-EOS.strip } let(:expected_err) { <<-EOS.strip }
\e[31mCould not find gem 'rack (= 2)' in any of the gem sources listed in your Gemfile.\e[0m \e[31mCould not find gem 'rack (= 2)' in locally installed gems.
The source contains the following versions of 'rack': 0.9.1, 1.0.0\e[0m
\e[33mRun `bundle install` to install missing gems.\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m
EOS EOS
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when Bundler.setup fails", :bundler => "3" do context "when Bundler.setup fails", :bundler => "3" do
@ -785,14 +835,28 @@ The source contains the following versions of 'rack': 1.0.0\e[0m
\e[33mRun `bundle install` to install missing gems.\e[0m \e[33mRun `bundle install` to install missing gems.\e[0m
EOS EOS
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when the executable exits non-zero via at_exit" do context "when the executable exits non-zero via at_exit" do
let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" } let(:executable) { super() + "\n\nat_exit { $! ? raise($!) : exit(1) }" }
let(:exit_code) { 1 } let(:exit_code) { 1 }
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when disable_exec_load is set" do context "when disable_exec_load is set" do
@ -803,7 +867,14 @@ The source contains the following versions of 'rack': 1.0.0\e[0m
bundle "config set disable_exec_load true" bundle "config set disable_exec_load true"
end end
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "regarding $0 and __FILE__" do context "regarding $0 and __FILE__" do
@ -819,12 +890,26 @@ $0: #{path.to_s.inspect}
__FILE__: #{path.to_s.inspect} __FILE__: #{path.to_s.inspect}
EOS EOS
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
context "when the path is relative" do context "when the path is relative" do
let(:path) { super().relative_path_from(bundled_app) } let(:path) { super().relative_path_from(bundled_app) }
it_behaves_like "it runs" it "runs" do
skip "https://github.com/rubygems/rubygems/issues/3351" if Gem.win_platform?
subject
expect(exitstatus).to eq(exit_code)
expect(err).to eq(expected_err)
expect(out).to eq(expected)
end
end end
context "when the path is relative with a leading ./" do context "when the path is relative with a leading ./" do

View file

@ -28,44 +28,9 @@ RSpec.describe "bundle gem" do
let(:require_path) { "mygem" } let(:require_path) { "mygem" }
before do before do
git_config_content = <<-EOF sys_exec("git config --global user.name 'Bundler User'")
[user] sys_exec("git config --global user.email user@example.com")
name = "Bundler User" sys_exec("git config --global github.user bundleuser")
email = user@example.com
[github]
user = bundleuser
EOF
@git_config_location = ENV["GIT_CONFIG"]
path = "#{tmp}/test_git_config.txt"
File.open(path, "w") {|f| f.write(git_config_content) }
ENV["GIT_CONFIG"] = path
end
after do
FileUtils.rm(ENV["GIT_CONFIG"]) if File.exist?(ENV["GIT_CONFIG"])
ENV["GIT_CONFIG"] = @git_config_location
end
shared_examples_for "git config is present" do
context "git config user.{name,email} present" do
it "sets gemspec author to git user.name if available" do
expect(generated_gemspec.authors.first).to eq("Bundler User")
end
it "sets gemspec email to git user.email if available" do
expect(generated_gemspec.email.first).to eq("user@example.com")
end
end
end
shared_examples_for "git config is absent" do
it "sets gemspec author to default message if git user.name is not set or empty" do
expect(generated_gemspec.authors.first).to eq("TODO: Write your name")
end
it "sets gemspec email to default message if git user.email is not set or empty" do
expect(generated_gemspec.email.first).to eq("TODO: Write your email address")
end
end end
describe "git repo initialization" do describe "git repo initialization" do
@ -125,19 +90,24 @@ RSpec.describe "bundle gem" do
end end
shared_examples_for "--coc flag" do shared_examples_for "--coc flag" do
before do
bundle "gem #{gem_name} --coc"
end
it "generates a gem skeleton with MIT license" do it "generates a gem skeleton with MIT license" do
bundle "gem #{gem_name} --coc"
gem_skeleton_assertions gem_skeleton_assertions
expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to exist expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to exist
end end
describe "README additions" do it "generates the README with a section for the Code of Conduct" do
it "generates the README with a section for the Code of Conduct" do bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct") expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md") expect(bundled_app("#{gem_name}/README.md").read).to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
end end
it "generates the README with a section for the Code of Conduct, respecting the configured git default branch" do
sys_exec("git config --global init.defaultBranch main")
bundle "gem #{gem_name} --coc"
expect(bundled_app("#{gem_name}/README.md").read).to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).to include("https://github.com/bundleuser/#{gem_name}/blob/main/CODE_OF_CONDUCT.md")
end end
end end
@ -150,11 +120,9 @@ RSpec.describe "bundle gem" do
expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to_not exist expect(bundled_app("#{gem_name}/CODE_OF_CONDUCT.md")).to_not exist
end end
describe "README additions" do it "generates the README without a section for the Code of Conduct" do
it "generates the README without a section for the Code of Conduct" do expect(bundled_app("#{gem_name}/README.md").read).not_to include("## Code of Conduct")
expect(bundled_app("#{gem_name}/README.md").read).not_to include("## Code of Conduct") expect(bundled_app("#{gem_name}/README.md").read).not_to match(%r{https://github\.com/bundleuser/#{gem_name}/blob/.*/CODE_OF_CONDUCT.md})
expect(bundled_app("#{gem_name}/README.md").read).not_to include("https://github.com/bundleuser/#{gem_name}/blob/master/CODE_OF_CONDUCT.md")
end
end end
end end
@ -302,7 +270,7 @@ RSpec.describe "bundle gem" do
context "git config github.user is absent" do context "git config github.user is absent" do
before do before do
sys_exec("git config --unset github.user") sys_exec("git config --global --unset github.user")
bundle "gem #{gem_name}" bundle "gem #{gem_name}"
end end
@ -413,17 +381,29 @@ RSpec.describe "bundle gem" do
bundle "gem #{gem_name}" bundle "gem #{gem_name}"
end end
it_should_behave_like "git config is present" it "sets gemspec author to git user.name if available" do
expect(generated_gemspec.authors.first).to eq("Bundler User")
end
it "sets gemspec email to git user.email if available" do
expect(generated_gemspec.email.first).to eq("user@example.com")
end
end end
context "git config user.{name,email} is not set" do context "git config user.{name,email} is not set" do
before do before do
sys_exec("git config --unset user.name", :dir => bundled_app) sys_exec("git config --global --unset user.name")
sys_exec("git config --unset user.email", :dir => bundled_app) sys_exec("git config --global --unset user.email")
bundle "gem #{gem_name}" bundle "gem #{gem_name}"
end end
it_should_behave_like "git config is absent" it "sets gemspec author to default message if git user.name is not set or empty" do
expect(generated_gemspec.authors.first).to eq("TODO: Write your name")
end
it "sets gemspec email to default message if git user.email is not set or empty" do
expect(generated_gemspec.email.first).to eq("TODO: Write your email address")
end
end end
it "sets gemspec metadata['allowed_push_host']" do it "sets gemspec metadata['allowed_push_host']" do
@ -1140,7 +1120,7 @@ Usage: "bundle gem NAME [OPTIONS]"
it "should fail gracefully" do it "should fail gracefully" do
FileUtils.touch(bundled_app("conflict-foobar")) FileUtils.touch(bundled_app("conflict-foobar"))
bundle "gem conflict-foobar", :raise_on_error => false bundle "gem conflict-foobar", :raise_on_error => false
expect(err).to include("Errno::ENOTDIR") expect(err).to eq("Couldn't create a new gem named `conflict-foobar` because there's an existing file named `conflict-foobar`.")
expect(exitstatus).to eql(32) expect(exitstatus).to eql(32)
end end
end end

View file

@ -113,16 +113,7 @@ RSpec.describe "post bundle message" do
bundle "config set force_ruby_platform true" bundle "config set force_ruby_platform true"
end end
it "should report a helpful error message", :bundler => "< 3" do it "should report a helpful error message" do
install_gemfile <<-G, :raise_on_error => false
source "#{file_uri_for(gem_repo1)}"
gem "rack"
gem "not-a-gem", :group => :development
G
expect(err).to include("Could not find gem 'not-a-gem' in any of the gem sources listed in your Gemfile.")
end
it "should report a helpful error message", :bundler => "3" do
install_gemfile <<-G, :raise_on_error => false install_gemfile <<-G, :raise_on_error => false
source "#{file_uri_for(gem_repo1)}" source "#{file_uri_for(gem_repo1)}"
gem "rack" gem "rack"

View file

@ -422,14 +422,13 @@ RSpec.describe "bundle install from an existing gemspec" do
end end
end end
%w[ruby jruby].each do |platform| gemfile <<-G
simulate_platform(platform) do source "#{file_uri_for(gem_repo2)}"
install_gemfile <<-G gemspec
source "#{file_uri_for(gem_repo2)}" G
gemspec
G simulate_platform("ruby") { bundle "install" }
end simulate_platform("jruby") { bundle "install" }
end
end end
context "on ruby" do context "on ruby" do

View file

@ -173,7 +173,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
it "installs from the same source without any warning" do it "installs from the same source without any warning" do
bundle :install bundle :install
expect(err).not_to include("Warning") expect(err).not_to include("Warning")
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", :source => "remote3")
end end
end end
@ -187,25 +187,19 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "when disable_multisource is set" do it "installs from the same source without any warning" do
before do bundle :install
bundle "config set disable_multisource true"
end
it "installs from the same source without any warning" do expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
bundle :install expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.") # In https://github.com/bundler/bundler/issues/3585 this failed
expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0") # when there is already a lock file, and the gems are missing, so try again
system_gems []
bundle :install
# In https://github.com/bundler/bundler/issues/3585 this failed expect(err).not_to include("Warning: the gem 'rack' was found in multiple sources.")
# when there is already a lock file, and the gems are missing, so try again expect(the_bundle).to include_gems("depends_on_rack 1.0.1", "rack 1.0.0", :source => "remote3")
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")
end
end end
end end
end end
@ -301,6 +295,33 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "when a top-level gem can only be found in an scoped source" do
before do
build_repo2
build_repo gem_repo3 do
build_gem "private_gem_1", "1.0.0"
build_gem "private_gem_2", "1.0.0"
end
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gem "private_gem_1"
source "#{file_uri_for(gem_repo3)}" do
gem "private_gem_2"
end
G
end
it "fails" do
bundle :install, :raise_on_error => false
expect(err).to include("Could not find gem 'private_gem_1' in rubygems repository #{file_uri_for(gem_repo2)}/ or installed locally.")
expect(err).to include("The source does not contain any versions of 'private_gem_1'")
end
end
context "when a top-level gem has an indirect dependency" do context "when a top-level gem has an indirect dependency" do
context "when disable_multisource is set" do context "when disable_multisource is set" do
before do before do
@ -497,6 +518,83 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
end end
context "when a top-level gem has an indirect dependency present in the default source, but with a different version from the one resolved", :bundler => "< 3" do
before do
build_lib "activesupport", "7.0.0.alpha", :path => lib_path("rails/activesupport")
build_lib "rails", "7.0.0.alpha", :path => lib_path("rails") do |s|
s.add_dependency "activesupport", "= 7.0.0.alpha"
end
build_repo gem_repo2 do
build_gem "activesupport", "6.1.2"
build_gem "webpacker", "5.2.1" do |s|
s.add_dependency "activesupport", ">= 5.2"
end
end
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
gemspec :path => "#{lib_path("rails")}"
gem "webpacker", "~> 5.0"
G
end
it "installs all gems without warning" do
bundle :install
expect(err).not_to include("Warning")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", "rails 7.0.0.alpha")
expect(the_bundle).to include_gems("activesupport 7.0.0.alpha", :source => "path@#{lib_path("rails/activesupport")}")
expect(the_bundle).to include_gems("rails 7.0.0.alpha", :source => "path@#{lib_path("rails")}")
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
before do
build_repo gem_repo3 do
build_gem "handsoap", "0.2.5.5" do |s|
s.add_dependency "nokogiri", ">= 1.2.3"
end
end
update_repo gem_repo2 do
build_gem "nokogiri", "1.11.1" do |s|
s.add_dependency "racca", "~> 1.4"
end
build_gem "racca", "1.5.2"
end
gemfile <<-G
source "#{file_uri_for(gem_repo2)}"
source "#{file_uri_for(gem_repo3)}" do
gem "handsoap"
end
gem "nokogiri"
G
end
it "installs from the proper sources without any warnings or errors" do
bundle "install --verbose"
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", :source => "remote3")
expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
# Even if the gems are already installed
FileUtils.rm bundled_app_lock
bundle "install --verbose"
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", :source => "remote3")
expect(the_bundle).to include_gems("nokogiri 1.11.1", "racca 1.5.2", :source => "remote2")
end
end
context "with a gem that is only found in the wrong source" do context "with a gem that is only found in the wrong source" do
before do before do
build_repo gem_repo3 do build_repo gem_repo3 do

View file

@ -30,7 +30,7 @@ module Spec
args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter args[1] ||= Bundler::GemVersionPromoter.new # gem_version_promoter
args[2] ||= [] # additional_base_requirements args[2] ||= [] # additional_base_requirements
args[3] ||= @platforms # platforms args[3] ||= @platforms # platforms
Bundler::Resolver.resolve(deps, @index, source_requirements, *args) Bundler::Resolver.resolve(deps, source_requirements, *args)
end end
def should_resolve_as(specs) def should_resolve_as(specs)

View file

@ -1958,15 +1958,9 @@ class TestGem < Gem::TestCase
io.write 'gem "a"' io.write 'gem "a"'
end end
platform = Bundler::GemHelpers.generic_local_platform
if platform == Gem::Platform::RUBY
platform = ''
else
platform = " #{platform}"
end
expected = <<-EXPECTED expected = <<-EXPECTED
Could not find gem 'a#{platform}' in any of the gem sources listed in your Gemfile. Could not find gem 'a' in locally installed gems.
The source does not contain any versions of 'a'
You may need to `gem install -g` to install missing gems You may need to `gem install -g` to install missing gems
EXPECTED EXPECTED

View file

@ -134,7 +134,9 @@ 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],
@ -143,6 +145,7 @@ 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
@ -261,6 +264,32 @@ 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'