Sync latest development version of bundler & rubygems

This commit is contained in:
David Rodríguez 2021-02-01 16:17:16 +01:00 committed by Hiroshi SHIBATA
parent 2ab6b7a751
commit 53468cc111
Notes: git 2021-03-08 13:47:56 +09:00
161 changed files with 2544 additions and 1016 deletions

View File

@ -63,7 +63,6 @@ module Bundler
autoload :Resolver, File.expand_path("bundler/resolver", __dir__) autoload :Resolver, File.expand_path("bundler/resolver", __dir__)
autoload :Retry, File.expand_path("bundler/retry", __dir__) autoload :Retry, File.expand_path("bundler/retry", __dir__)
autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__) autoload :RubyDsl, File.expand_path("bundler/ruby_dsl", __dir__)
autoload :RubyGemsGemInstaller, File.expand_path("bundler/rubygems_gem_installer", __dir__)
autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__) autoload :RubyVersion, File.expand_path("bundler/ruby_version", __dir__)
autoload :Runtime, File.expand_path("bundler/runtime", __dir__) autoload :Runtime, File.expand_path("bundler/runtime", __dir__)
autoload :Settings, File.expand_path("bundler/settings", __dir__) autoload :Settings, File.expand_path("bundler/settings", __dir__)
@ -441,7 +440,7 @@ EOF
end end
def local_platform def local_platform
return Gem::Platform::RUBY if settings[:force_ruby_platform] return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY]
Gem::Platform.local Gem::Platform.local
end end

View File

@ -586,6 +586,7 @@ module Bundler
method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library." method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library."
method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`."
method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`."
method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`."
method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library", method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library",
:desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`."
method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "", method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "",

View File

@ -30,6 +30,7 @@ module Bundler
require_relative "install" require_relative "install"
options = self.options.dup options = self.options.dup
options["local"] = false if Bundler.settings[:cache_all_platforms] options["local"] = false if Bundler.settings[:cache_all_platforms]
options["no-cache"] = true
Bundler::CLI::Install.new(options).run Bundler::CLI::Install.new(options).run
end end

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,7 +58,9 @@ 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",
} }
ensure_safe_gem_name(name, constant_array) ensure_safe_gem_name(name, constant_array)
@ -78,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
@ -141,12 +143,25 @@ module Bundler
templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md")
end end
if ask_and_set(:changelog, "Do you want to include a changelog?",
"A changelog is a file which contains a curated, chronologically ordered list of notable " \
"changes for each version of a project. To make it easier for users and contributors to" \
" see precisely what notable changes have been made between each release (or version) of" \
" the project. Whether consumers or developers, the end users of software are" \
" human beings who care about what's in the software. When the software changes, people " \
"want to know why and how. see https://keepachangelog.com")
config[:changelog] = true
Bundler.ui.info "Changelog enabled in config"
templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md")
end
if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?", if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?",
"RuboCop is a static code analyzer that has out-of-the-box rules for many " \ "RuboCop is a static code analyzer that has out-of-the-box rules for many " \
"of the guidelines in the community style guide. " \ "of the guidelines in the community style guide. " \
"For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) " \ "For more information, see the RuboCop docs (https://docs.rubocop.org/en/stable/) " \
"and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide).") "and the Ruby Style Guides (https://github.com/rubocop-hq/ruby-style-guide).")
config[:rubocop] = true config[:rubocop] = true
config[:rubocop_version] = Gem.ruby_version < Gem::Version.new("2.4.a") ? "0.81.0" : "1.7"
Bundler.ui.info "RuboCop enabled in config" Bundler.ui.info "RuboCop enabled in config"
templates.merge!("rubocop.yml.tt" => ".rubocop.yml") templates.merge!("rubocop.yml.tt" => ".rubocop.yml")
end end
@ -161,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
@ -188,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

@ -1,8 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../vendored_fileutils" require_relative "../vendored_fileutils"
require "stringio"
require "zlib"
module Bundler module Bundler
class CompactIndexClient class CompactIndexClient
@ -45,24 +43,18 @@ module Bundler
else else
"bytes=#{local_temp_path.size}-" "bytes=#{local_temp_path.size}-"
end end
else
# Fastly ignores Range when Accept-Encoding: gzip is set
headers["Accept-Encoding"] = "gzip"
end end
response = @fetcher.call(remote_path, headers) response = @fetcher.call(remote_path, headers)
return nil if response.is_a?(Net::HTTPNotModified) return nil if response.is_a?(Net::HTTPNotModified)
content = response.body content = response.body
if response["Content-Encoding"] == "gzip"
content = Zlib::GzipReader.new(StringIO.new(content)).read
end
SharedHelpers.filesystem_access(local_temp_path) do SharedHelpers.filesystem_access(local_temp_path) do
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

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "lockfile_parser" require_relative "lockfile_parser"
require "set"
module Bundler module Bundler
class Definition class Definition
@ -88,11 +87,7 @@ module Bundler
@lockfile_contents = Bundler.read_file(lockfile) @lockfile_contents = Bundler.read_file(lockfile)
@locked_gems = LockfileParser.new(@lockfile_contents) @locked_gems = LockfileParser.new(@lockfile_contents)
@locked_platforms = @locked_gems.platforms @locked_platforms = @locked_gems.platforms
if Bundler.settings[:force_ruby_platform] @platforms = @locked_platforms.dup
@platforms = [Gem::Platform::RUBY]
else
@platforms = @locked_platforms.dup
end
@locked_bundler_version = @locked_gems.bundler_version @locked_bundler_version = @locked_gems.bundler_version
@locked_ruby_version = @locked_gems.ruby_version @locked_ruby_version = @locked_gems.ruby_version
@ -264,23 +259,18 @@ module Bundler
def resolve def resolve
@resolve ||= begin @resolve ||= begin
last_resolve = converge_locked_specs last_resolve = converge_locked_specs
resolve = if Bundler.frozen_bundle?
if Bundler.frozen_bundle? Bundler.ui.debug "Frozen, using resolution from the lockfile"
Bundler.ui.debug "Frozen, using resolution from the lockfile" last_resolve
last_resolve elsif !unlocking? && nothing_changed?
elsif !unlocking? && nothing_changed? Bundler.ui.debug("Found no changes, using resolution from the lockfile")
Bundler.ui.debug("Found no changes, using resolution from the lockfile") last_resolve
last_resolve else
else # 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, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms)
last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) end
end
# filter out gems that _can_ be installed on multiple platforms, but don't need
# to be
resolve.for(expand_dependencies(dependencies, true), [], false, false, false)
end end
end end
@ -611,7 +601,7 @@ module Bundler
deps_for_source = @dependencies.select {|s| s.source == source } deps_for_source = @dependencies.select {|s| s.source == source }
locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source }
Set.new(deps_for_source) != Set.new(locked_deps_for_source) deps_for_source.uniq.sort != locked_deps_for_source.sort
end end
def specs_for_source_changed?(source) def specs_for_source_changed?(source)
@ -673,19 +663,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
@ -825,11 +816,6 @@ module Bundler
# commonly happens if the version changed in the gemspec # commonly happens if the version changed in the gemspec
next unless new_spec next unless new_spec
new_runtime_deps = new_spec.dependencies.select {|d| d.type != :development }
old_runtime_deps = s.dependencies.select {|d| d.type != :development }
# If the dependencies of the path source have changed and locked spec can't satisfy new dependencies, unlock it
next unless new_runtime_deps.sort == old_runtime_deps.sort || new_runtime_deps.all? {|d| satisfies_locked_spec?(d) }
s.dependencies.replace(new_spec.dependencies) s.dependencies.replace(new_spec.dependencies)
end end
@ -896,7 +882,7 @@ module Bundler
dependencies.each do |dep| dependencies.each do |dep|
dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name)
next unless remote || dep.current_platform? next unless remote || dep.current_platform?
target_platforms = dep.gem_platforms(remote ? Resolver.sort_platforms(@platforms) : [generic_local_platform]) target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform])
deps += expand_dependency_with_platforms(dep, target_platforms) deps += expand_dependency_with_platforms(dep, target_platforms)
end end
deps deps
@ -904,7 +890,7 @@ module Bundler
def expand_dependency_with_platforms(dep, platforms) def expand_dependency_with_platforms(dep, platforms)
platforms.map do |p| platforms.map do |p|
DepProxy.new(dep, p) DepProxy.get_proxy(dep, p)
end end
end end
@ -915,29 +901,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["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
@ -984,7 +959,7 @@ module Bundler
next requirements if @locked_gems.dependencies[name] != dependency next requirements if @locked_gems.dependencies[name] != dependency
next requirements if dependency.source.is_a?(Source::Path) next requirements if dependency.source.is_a?(Source::Path)
dep = Gem::Dependency.new(name, ">= #{locked_spec.version}") dep = Gem::Dependency.new(name, ">= #{locked_spec.version}")
requirements[name] = DepProxy.new(dep, locked_spec.platform) requirements[name] = DepProxy.get_proxy(dep, locked_spec.platform)
requirements requirements
end.values end.values
end end
@ -994,5 +969,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

@ -4,19 +4,18 @@ module Bundler
class DepProxy class DepProxy
attr_reader :__platform, :dep attr_reader :__platform, :dep
@proxies = {}
def self.get_proxy(dep, platform)
@proxies[[dep, platform]] ||= new(dep, platform).freeze
end
def initialize(dep, platform) def initialize(dep, platform)
@dep = dep @dep = dep
@__platform = platform @__platform = platform
end end
def hash private_class_method :new
@hash ||= [dep, __platform].hash
end
def ==(other)
return false if other.class != self.class
dep == other.dep && __platform == other.__platform
end
alias_method :eql?, :== alias_method :eql?, :==
@ -39,6 +38,14 @@ module Bundler
s s
end end
def dup
raise NoMethodError.new("DepProxy cannot be duplicated")
end
def clone
raise NoMethodError.new("DepProxy cannot be cloned")
end
private private
def method_missing(*args, &blk) def method_missing(*args, &blk)

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

@ -27,7 +27,6 @@ module Bundler
(1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } } (1..10).each {|v| define_method("bundler_#{v}_mode?") { major_version >= v } }
settings_flag(:allow_bundler_dependency_conflicts) { bundler_3_mode? }
settings_flag(:allow_offline_install) { bundler_3_mode? } settings_flag(:allow_offline_install) { bundler_3_mode? }
settings_flag(:auto_clean_without_path) { bundler_3_mode? } settings_flag(:auto_clean_without_path) { bundler_3_mode? }
settings_flag(:cache_all) { bundler_3_mode? } settings_flag(:cache_all) { bundler_3_mode? }

View File

@ -137,7 +137,6 @@ module Bundler
end end
specs.each do |name, version, platform, dependencies, metadata| specs.each do |name, version, platform, dependencies, metadata|
next if name == "bundler"
spec = if dependencies spec = if dependencies
EndpointSpecification.new(name, version, platform, dependencies, metadata) EndpointSpecification.new(name, version, platform, dependencies, metadata)
else else

View File

@ -116,19 +116,21 @@ module Bundler
def git_push(remote = nil) def git_push(remote = nil)
remote ||= default_remote remote ||= default_remote
perform_git_push remote perform_git_push "#{remote} refs/heads/#{current_branch}"
perform_git_push "#{remote} refs/tags/#{version_tag}" perform_git_push "#{remote} refs/tags/#{version_tag}"
Bundler.ui.confirm "Pushed git commits and release tag." Bundler.ui.confirm "Pushed git commits and release tag."
end end
def default_remote def default_remote
remote_for_branch, status = sh_with_status(%W[git config --get branch.#{current_branch}.remote])
return "origin" unless status.success?
remote_for_branch.strip
end
def current_branch
# We can replace this with `git branch --show-current` once we drop support for git < 2.22.0 # We can replace this with `git branch --show-current` once we drop support for git < 2.22.0
current_branch = sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip sh(%w[git rev-parse --abbrev-ref HEAD]).gsub(%r{\Aheads/}, "").strip
remote_for_branch = sh(%W[git config --get branch.#{current_branch}.remote]).strip
return "origin" if remote_for_branch.empty?
remote_for_branch
end end
def allowed_push_host def allowed_push_host

View File

@ -81,8 +81,8 @@ module Bundler
sort_dep_specs(spec_groups, locked_spec) sort_dep_specs(spec_groups, locked_spec)
end.tap do |specs| end.tap do |specs|
if DEBUG if DEBUG
warn before_result puts before_result
warn " after sort_versions: #{debug_format_result(dep, specs).inspect}" puts " after sort_versions: #{debug_format_result(dep, specs).inspect}"
end end
end end
end end

View File

@ -1,7 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require "set"
module Bundler module Bundler
class Index class Index
include Enumerable include Enumerable
@ -65,11 +63,14 @@ module Bundler
def unsorted_search(query, base) def unsorted_search(query, base)
results = local_search(query, base) results = local_search(query, base)
seen = results.map(&:full_name).to_set unless @sources.empty? seen = results.map(&:full_name).uniq unless @sources.empty?
@sources.each do |source| @sources.each do |source|
source.unsorted_search(query, base).each do |spec| source.unsorted_search(query, base).each do |spec|
results << spec if seen.add?(spec.full_name) next if seen.include?(spec.full_name)
seen << spec.full_name
results << spec
end end
end end
@ -170,7 +171,7 @@ module Bundler
def dependencies_eql?(spec, other_spec) def dependencies_eql?(spec, other_spec)
deps = spec.dependencies.select {|d| d.type != :development } deps = spec.dependencies.select {|d| d.type != :development }
other_deps = other_spec.dependencies.select {|d| d.type != :development } other_deps = other_spec.dependencies.select {|d| d.type != :development }
Set.new(deps) == Set.new(other_deps) deps.sort == other_deps.sort
end end
def add_source(index) def add_source(index)

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

@ -82,7 +82,6 @@ module Bundler
if resolve_if_needed(options) if resolve_if_needed(options)
ensure_specs_are_compatible! ensure_specs_are_compatible!
warn_on_incompatible_bundler_deps
load_plugins load_plugins
options.delete(:jobs) options.delete(:jobs)
else else
@ -90,6 +89,8 @@ module Bundler
end end
install(options) install(options)
Gem::Specification.reset # invalidate gem specification cache so that installed gems are immediately available
lock unless Bundler.frozen_bundle? lock unless Bundler.frozen_bundle?
Standalone.new(options[:standalone], @definition).generate if options[:standalone] Standalone.new(options[:standalone], @definition).generate if options[:standalone]
end end
@ -265,22 +266,6 @@ module Bundler
end end
end end
def warn_on_incompatible_bundler_deps
bundler_version = Gem::Version.create(Bundler::VERSION)
@definition.specs.each do |spec|
spec.dependencies.each do |dep|
next if dep.type == :development
next unless dep.name == "bundler".freeze
next if dep.requirement.satisfied_by?(bundler_version)
Bundler.ui.warn "#{spec.name} (#{spec.version}) has dependency" \
" #{SharedHelpers.pretty_dependency(dep)}" \
", which is unsatisfied by the current bundler version #{VERSION}" \
", so the dependency is being ignored"
end
end
end
def install_in_parallel(size, standalone, force = false) def install_in_parallel(size, standalone, force = false)
spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force) spec_installations = ParallelInstaller.call(self, @definition.specs, size, standalone, force)
spec_installations.each do |installation| spec_installations.each do |installation|

View File

@ -15,6 +15,7 @@ module Bundler
file.puts "ruby_engine = RUBY_ENGINE" file.puts "ruby_engine = RUBY_ENGINE"
file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]" file.puts "ruby_version = RbConfig::CONFIG[\"ruby_version\"]"
file.puts "path = File.expand_path('..', __FILE__)" file.puts "path = File.expand_path('..', __FILE__)"
file.puts reverse_rubygems_kernel_mixin
paths.each do |path| paths.each do |path|
file.puts %($:.unshift File.expand_path("\#{path}/#{path}")) file.puts %($:.unshift File.expand_path("\#{path}/#{path}"))
end end
@ -48,5 +49,19 @@ module Bundler
error_message = "#{spec.name} #{spec.version} has an invalid gemspec" error_message = "#{spec.name} #{spec.version} has an invalid gemspec"
raise Gem::InvalidSpecificationException.new(error_message) raise Gem::InvalidSpecificationException.new(error_message)
end end
def reverse_rubygems_kernel_mixin
<<~END
kernel = (class << ::Kernel; self; end)
[kernel, ::Kernel].each do |k|
if k.private_method_defined?(:gem_original_require)
private_require = k.private_method_defined?(:require)
k.send(:remove_method, :require)
k.send(:define_method, :require, k.instance_method(:gem_original_require))
k.send(:private, :require) if private_require
end
end
END
end
end end
end end

View File

@ -4,22 +4,6 @@ require_relative "match_platform"
module Bundler module Bundler
class LazySpecification class LazySpecification
Identifier = Struct.new(:name, :version, :platform)
class Identifier
include Comparable
def <=>(other)
return unless other.is_a?(Identifier)
[name, version, platform_string] <=> [other.name, other.version, other.platform_string]
end
protected
def platform_string
platform_string = platform.to_s
platform_string == Index::RUBY ? Index::NULL : platform_string
end
end
include MatchPlatform include MatchPlatform
attr_reader :name, :version, :dependencies, :platform attr_reader :name, :version, :dependencies, :platform
@ -108,7 +92,7 @@ module Bundler
end end
def identifier def identifier
@__identifier ||= Identifier.new(name, version, platform) @__identifier ||= [name, version, platform_string]
end end
def git_version def git_version
@ -116,6 +100,13 @@ module Bundler
" #{source.revision[0..6]}" " #{source.revision[0..6]}"
end end
protected
def platform_string
platform_string = platform.to_s
platform_string == Index::RUBY ? Index::NULL : platform_string
end
private private
def to_ary def to_ary
@ -140,7 +131,7 @@ module Bundler
# explicitly add a more specific platform. # explicitly add a more specific platform.
# #
def ruby_platform_materializes_to_ruby_platform? def ruby_platform_materializes_to_ruby_platform?
!Bundler.most_specific_locked_platform?(Gem::Platform::RUBY) !Bundler.most_specific_locked_platform?(Gem::Platform::RUBY) || Bundler.settings[:force_ruby_platform]
end end
end end
end end

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

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-ADD" "1" "December 2020" "" "" .TH "BUNDLE\-ADD" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install \fBbundle\-add\fR \- Add gem to the Gemfile and run bundle install

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-BINSTUBS" "1" "December 2020" "" "" .TH "BUNDLE\-BINSTUBS" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-binstubs\fR \- Install the binstubs of the listed gems \fBbundle\-binstubs\fR \- Install the binstubs of the listed gems

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-CACHE" "1" "December 2020" "" "" .TH "BUNDLE\-CACHE" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application \fBbundle\-cache\fR \- Package your needed \fB\.gem\fR files into your application

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-CHECK" "1" "December 2020" "" "" .TH "BUNDLE\-CHECK" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems \fBbundle\-check\fR \- Verifies if dependencies are satisfied by installed gems

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-CLEAN" "1" "December 2020" "" "" .TH "BUNDLE\-CLEAN" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory \fBbundle\-clean\fR \- Cleans up unused gems in your bundler directory

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-CONFIG" "1" "December 2020" "" "" .TH "BUNDLE\-CONFIG" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-config\fR \- Set bundler configuration options \fBbundle\-config\fR \- Set bundler configuration options
@ -136,9 +136,6 @@ Any periods in the configuration keys must be replaced with two underscores when
The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\. The following is a list of all configuration keys and their purpose\. You can learn more about their operation in bundle install(1) \fIbundle\-install\.1\.html\fR\.
. .
.IP "\(bu" 4 .IP "\(bu" 4
\fBallow_bundler_dependency_conflicts\fR (\fBBUNDLE_ALLOW_BUNDLER_DEPENDENCY_CONFLICTS\fR): Allow resolving to specifications that have dependencies on \fBbundler\fR that are incompatible with the running Bundler version\.
.
.IP "\(bu" 4
\fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR \fBallow_deployment_source_credential_changes\fR (\fBBUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES\fR): When in deployment mode, allow changing the credentials to a gem\'s source\. Ex: \fBhttps://some\.host\.com/gems/path/\fR \-> \fBhttps://user_name:password@some\.host\.com/gems/path\fR
. .
.IP "\(bu" 4 .IP "\(bu" 4
@ -184,6 +181,9 @@ The following is a list of all configuration keys and their purpose\. You can le
\fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\. \fBdisable_local_branch_check\fR (\fBBUNDLE_DISABLE_LOCAL_BRANCH_CHECK\fR): Allow Bundler to use a local git override without a branch specified in the Gemfile\.
. .
.IP "\(bu" 4 .IP "\(bu" 4
\fBdisable_local_revision_check\fR (\fBBUNDLE_DISABLE_LOCAL_REVISION_CHECK\fR): Allow Bundler to use a local git override without checking if the revision present in the lockfile is present in the repository\.
.
.IP "\(bu" 4
\fBdisable_multisource\fR (\fBBUNDLE_DISABLE_MULTISOURCE\fR): When set, Gemfiles containing multiple sources will produce errors instead of warnings\. Use \fBbundle config unset disable_multisource\fR to unset\. \fBdisable_multisource\fR (\fBBUNDLE_DISABLE_MULTISOURCE\fR): When set, Gemfiles containing multiple sources will produce errors instead of warnings\. Use \fBbundle config unset disable_multisource\fR to unset\.
. .
.IP "\(bu" 4 .IP "\(bu" 4

View File

@ -133,9 +133,6 @@ the environment variable `BUNDLE_LOCAL__RACK`.
The following is a list of all configuration keys and their purpose. You can The following is a list of all configuration keys and their purpose. You can
learn more about their operation in [bundle install(1)](bundle-install.1.html). learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `allow_bundler_dependency_conflicts` (`BUNDLE_ALLOW_BUNDLER_DEPENDENCY_CONFLICTS`):
Allow resolving to specifications that have dependencies on `bundler` that
are incompatible with the running Bundler version.
* `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`): * `allow_deployment_source_credential_changes` (`BUNDLE_ALLOW_DEPLOYMENT_SOURCE_CREDENTIAL_CHANGES`):
When in deployment mode, allow changing the credentials to a gem's source. When in deployment mode, allow changing the credentials to a gem's source.
Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path` Ex: `https://some.host.com/gems/path/` -> `https://user_name:password@some.host.com/gems/path`
@ -178,6 +175,9 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html).
* `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`): * `disable_local_branch_check` (`BUNDLE_DISABLE_LOCAL_BRANCH_CHECK`):
Allow Bundler to use a local git override without a branch specified in the Allow Bundler to use a local git override without a branch specified in the
Gemfile. Gemfile.
* `disable_local_revision_check` (`BUNDLE_DISABLE_LOCAL_REVISION_CHECK`):
Allow Bundler to use a local git override without checking if the revision
present in the lockfile is present in the repository.
* `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`): * `disable_multisource` (`BUNDLE_DISABLE_MULTISOURCE`):
When set, Gemfiles containing multiple sources will produce errors When set, Gemfiles containing multiple sources will produce errors
instead of warnings. instead of warnings.

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-DOCTOR" "1" "December 2020" "" "" .TH "BUNDLE\-DOCTOR" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-doctor\fR \- Checks the bundle for common problems \fBbundle\-doctor\fR \- Checks the bundle for common problems

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-EXEC" "1" "December 2020" "" "" .TH "BUNDLE\-EXEC" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-exec\fR \- Execute a command in the context of the bundle \fBbundle\-exec\fR \- Execute a command in the context of the bundle

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-GEM" "1" "December 2020" "" "" .TH "BUNDLE\-GEM" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem \fBbundle\-gem\fR \- Generate a project skeleton for creating a rubygem

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-INFO" "1" "December 2020" "" "" .TH "BUNDLE\-INFO" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-info\fR \- Show information for the given gem in your bundle \fBbundle\-info\fR \- Show information for the given gem in your bundle

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-INIT" "1" "December 2020" "" "" .TH "BUNDLE\-INIT" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-init\fR \- Generates a Gemfile into the current working directory \fBbundle\-init\fR \- Generates a Gemfile into the current working directory

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-INJECT" "1" "December 2020" "" "" .TH "BUNDLE\-INJECT" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile \fBbundle\-inject\fR \- Add named gem(s) with version requirements to Gemfile

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-INSTALL" "1" "December 2020" "" "" .TH "BUNDLE\-INSTALL" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-install\fR \- Install the dependencies specified in your Gemfile \fBbundle\-install\fR \- Install the dependencies specified in your Gemfile

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-LIST" "1" "December 2020" "" "" .TH "BUNDLE\-LIST" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-list\fR \- List all the gems in the bundle \fBbundle\-list\fR \- List all the gems in the bundle

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-LOCK" "1" "December 2020" "" "" .TH "BUNDLE\-LOCK" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-lock\fR \- Creates / Updates a lockfile without installing \fBbundle\-lock\fR \- Creates / Updates a lockfile without installing

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-OPEN" "1" "December 2020" "" "" .TH "BUNDLE\-OPEN" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-open\fR \- Opens the source directory for a gem in your bundle \fBbundle\-open\fR \- Opens the source directory for a gem in your bundle

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-OUTDATED" "1" "December 2020" "" "" .TH "BUNDLE\-OUTDATED" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-outdated\fR \- List installed gems with newer versions available \fBbundle\-outdated\fR \- List installed gems with newer versions available

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-PLATFORM" "1" "December 2020" "" "" .TH "BUNDLE\-PLATFORM" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-platform\fR \- Displays platform compatibility information \fBbundle\-platform\fR \- Displays platform compatibility information

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-PRISTINE" "1" "December 2020" "" "" .TH "BUNDLE\-PRISTINE" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-pristine\fR \- Restores installed gems to their pristine condition \fBbundle\-pristine\fR \- Restores installed gems to their pristine condition

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-REMOVE" "1" "December 2020" "" "" .TH "BUNDLE\-REMOVE" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-remove\fR \- Removes gems from the Gemfile \fBbundle\-remove\fR \- Removes gems from the Gemfile

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-SHOW" "1" "December 2020" "" "" .TH "BUNDLE\-SHOW" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem \fBbundle\-show\fR \- Shows all the gems in your bundle, or the path to a gem

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-UPDATE" "1" "December 2020" "" "" .TH "BUNDLE\-UPDATE" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-update\fR \- Update your gems to the latest available versions \fBbundle\-update\fR \- Update your gems to the latest available versions

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE\-VIZ" "1" "December 2020" "" "" .TH "BUNDLE\-VIZ" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile \fBbundle\-viz\fR \- Generates a visual dependency graph for your Gemfile

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "BUNDLE" "1" "December 2020" "" "" .TH "BUNDLE" "1" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBbundle\fR \- Ruby Dependency Management \fBbundle\fR \- Ruby Dependency Management

View File

@ -1,7 +1,7 @@
.\" generated with Ronn/v0.7.3 .\" generated with Ronn/v0.7.3
.\" http://github.com/rtomayko/ronn/tree/0.7.3 .\" http://github.com/rtomayko/ronn/tree/0.7.3
. .
.TH "GEMFILE" "5" "December 2020" "" "" .TH "GEMFILE" "5" "January 2021" "" ""
. .
.SH "NAME" .SH "NAME"
\fBGemfile\fR \- A format for describing gem dependencies for Ruby programs \fBGemfile\fR \- A format for describing gem dependencies for Ruby programs

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

@ -5,6 +5,8 @@ module Bundler
require_relative "vendored_molinillo" require_relative "vendored_molinillo"
require_relative "resolver/spec_group" require_relative "resolver/spec_group"
include GemHelpers
# Figures out the best possible configuration of gems that satisfies # Figures out the best possible configuration of gems that satisfies
# the list of passed dependencies and any child dependencies without # the list of passed dependencies and any child dependencies without
# causing any gem activation errors. # causing any gem activation errors.
@ -15,31 +17,38 @@ 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)
platforms = Set.new(platforms) if platforms
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 = {}
@base_dg = Molinillo::DependencyGraph.new @base_dg = Molinillo::DependencyGraph.new
@base.each do |ls| @base.each do |ls|
dep = Dependency.new(ls.name, ls.version) dep = Dependency.new(ls.name, ls.version)
@base_dg.add_vertex(ls.name, DepProxy.new(dep, ls.platform), true) @base_dg.add_vertex(ls.name, DepProxy.get_proxy(dep, ls.platform), true)
end end
additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) }
@platforms = platforms @platforms = platforms.reject {|p| p != Gem::Platform::RUBY && (platforms - [p]).any? {|pl| generic(pl) == p } }
@resolving_only_for_ruby = platforms == [Gem::Platform::RUBY]
@gem_version_promoter = gem_version_promoter @gem_version_promoter = gem_version_promoter
@allow_bundler_dependency_conflicts = Bundler.feature_flag.allow_bundler_dependency_conflicts?
@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 = []
@generic_names = ["Ruby\0", "RubyGems\0"]
end end
def start(requirements) def start(requirements)
@ -75,7 +84,7 @@ module Bundler
return unless debug? return unless debug?
debug_info = yield debug_info = yield
debug_info = debug_info.inspect unless debug_info.is_a?(String) debug_info = debug_info.inspect unless debug_info.is_a?(String)
puts debug_info.split("\n").map {|s| "BUNDLER: " + " " * depth + s } puts debug_info.split("\n").map {|s| depth == 0 ? "BUNDLER: #{s}" : "BUNDLER(#{depth}): #{s}" }
end end
def debug? def debug?
@ -103,16 +112,25 @@ module Bundler
include Molinillo::SpecificationProvider include Molinillo::SpecificationProvider
def dependencies_for(specification) def dependencies_for(specification)
specification.dependencies_for_activated_platforms all_dependencies = specification.dependencies_for_activated_platforms
if @variant_specific_names.include?(specification.name)
@variant_specific_names |= all_dependencies.map(&:name) - @generic_names
else
generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms
@variant_specific_names |= variant_specific_names - @generic_names
@generic_names |= generic_names
end
all_dependencies
end end
def search_for(dependency_proxy) def search_for(dependency_proxy)
platform = dependency_proxy.__platform platform = dependency_proxy.__platform
dependency = dependency_proxy.dep dependency = dependency_proxy.dep
@search_for[dependency_proxy] ||= begin name = dependency.name
name = dependency.name 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
@ -137,55 +155,67 @@ module Bundler
end end
nested.reduce([]) do |groups, (version, specs)| nested.reduce([]) do |groups, (version, specs)|
next groups if locked_requirement && !locked_requirement.satisfied_by?(version) next groups if locked_requirement && !locked_requirement.satisfied_by?(version)
spec_group = SpecGroup.new(specs)
spec_group.ignores_bundler_dependencies = @allow_bundler_dependency_conflicts specs_by_platform = Hash.new do |current_specs, current_platform|
groups << spec_group current_specs[current_platform] = select_best_platform_match(specs, current_platform)
end
spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY)
groups << spec_group_ruby if spec_group_ruby
next groups if @resolving_only_for_ruby
spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform)
groups << spec_group if spec_group
groups
end end
else else
[] []
end end
# GVP handles major itself, but it's still a bit risky to trust it with it # GVP handles major itself, but it's still a bit risky to trust it with it
# until we get it settled with new behavior. For 2.x it can take over all cases. # until we get it settled with new behavior. For 2.x it can take over all cases.
search = if !@use_gvp if !@use_gvp
spec_groups spec_groups
else else
@gem_version_promoter.sort_versions(dependency, spec_groups) @gem_version_promoter.sort_versions(dependency, spec_groups)
end end
selected_sgs = []
search.each do |sg|
next unless sg.for?(platform)
sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse)
next unless sg_all_platforms
selected_sgs << sg_all_platforms
next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY]
# Add a spec group for "non platform specific spec" as the fallback
# spec group.
sg_ruby = sg.copy_for([Gem::Platform::RUBY])
selected_sgs.insert(-2, sg_ruby) if sg_ruby
end
selected_sgs
end end
unless search_result.empty?
specific_dependency = @variant_specific_names.include?(name)
return search_result unless specific_dependency
search_result.each do |sg|
if @generic_names.include?(name)
@variant_specific_names -= [name]
sg.activate_all_platforms!
else
sg.activate_platform!(platform)
end
end
end
search_result
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
@ -206,21 +236,27 @@ module Bundler
requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec) requirement.matches_spec?(spec) || spec.source.is_a?(Source::Gemspec)
end end
def dependencies_equal?(dependencies, other_dependencies)
dependencies.map(&:dep) == other_dependencies.map(&:dep)
end
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,
@ -233,13 +269,6 @@ module Bundler
end end
end end
# Sort platforms from most general to most specific
def self.sort_platforms(platforms)
platforms.sort_by do |platform|
platform_sort_key(platform)
end
end
def self.platform_sort_key(platform) def self.platform_sort_key(platform)
# Prefer specific platform to not specific platform # Prefer specific platform to not specific platform
return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform
@ -294,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?
@ -303,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
@ -324,10 +353,16 @@ module Bundler
def version_conflict_message(e) def version_conflict_message(e)
# only show essential conflicts, if possible # only show essential conflicts, if possible
conflicts = e.conflicts.dup conflicts = e.conflicts.dup
conflicts.delete_if do |_name, conflict|
deps = conflict.requirement_trees.map(&:last).flatten(1) if conflicts["bundler"]
!Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement))) conflicts.replace("bundler" => conflicts["bundler"])
else
conflicts.delete_if do |_name, conflict|
deps = conflict.requirement_trees.map(&:last).flatten(1)
!Bundler::VersionRanges.empty?(*Bundler::VersionRanges.for_many(deps.map(&:requirement)))
end
end end
e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty? e = Molinillo::VersionConflict.new(conflicts, e.specification_provider) unless conflicts.empty?
solver_name = "Bundler" solver_name = "Bundler"
@ -355,15 +390,25 @@ module Bundler
:additional_message_for_conflict => lambda do |o, name, conflict| :additional_message_for_conflict => lambda do |o, name, conflict|
if name == "bundler" if name == "bundler"
o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION})) o << %(\n Current Bundler version:\n bundler (#{Bundler::VERSION}))
other_bundler_required = !conflict.requirement.requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
end
if name == "bundler" && other_bundler_required conflict_dependency = conflict.requirement
o << "\n" conflict_requirement = conflict_dependency.requirement
o << "This Gemfile requires a different version of Bundler.\n" other_bundler_required = !conflict_requirement.satisfied_by?(Gem::Version.new(Bundler::VERSION))
o << "Perhaps you need to update Bundler by running `gem install bundler`?\n"
end if other_bundler_required
if conflict.locked_requirement o << "\n\n"
candidate_specs = @index_requirements[:default_bundler].search(conflict_dependency)
if candidate_specs.any?
target_version = candidate_specs.last.version
new_command = [File.basename($PROGRAM_NAME), "_#{target_version}_", *ARGV].join(" ")
o << "Your bundle requires a different version of Bundler than the one you're running.\n"
o << "Install the necessary version with `gem install bundler:#{target_version}` and rerun bundler using `#{new_command}`\n"
else
o << "Your bundle requires a different version of Bundler than the one you're running, and that version could not be found.\n"
end
end
elsif conflict.locked_requirement
o << "\n" o << "\n"
o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n) o << %(Running `bundle update` will rebuild your snapshot from scratch, using only\n)
o << %(the gems in your Gemfile, which may resolve the conflict.\n) o << %(the gems in your Gemfile, which may resolve the conflict.\n)
@ -372,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")
@ -416,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

@ -3,28 +3,37 @@
module Bundler module Bundler
class Resolver class Resolver
class SpecGroup class SpecGroup
include GemHelpers
attr_accessor :name, :version, :source attr_accessor :name, :version, :source
attr_accessor :ignores_bundler_dependencies, :activated_platforms attr_accessor :activated_platforms
def initialize(all_specs) def self.create_for(specs, all_platforms, specific_platform)
@all_specs = all_specs specific_platform_specs = specs[specific_platform]
raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first return unless specific_platform_specs.any?
platforms = all_platforms.select {|p| specs[p].any? }
new(specific_platform_specs.first, specs, platforms)
end
def initialize(exemplary_spec, specs, relevant_platforms)
@exemplary_spec = exemplary_spec
@name = exemplary_spec.name @name = exemplary_spec.name
@version = exemplary_spec.version @version = exemplary_spec.version
@source = exemplary_spec.source @source = exemplary_spec.source
@activated_platforms = [] @all_platforms = relevant_platforms
@dependencies = nil @activated_platforms = relevant_platforms
@specs = Hash.new do |specs, platform| @dependencies = Hash.new do |dependencies, platforms|
specs[platform] = select_best_platform_match(all_specs, platform) dependencies[platforms] = dependencies_for(platforms)
end end
@ignores_bundler_dependencies = true @partitioned_dependency_names = Hash.new do |partitioned_dependency_names, platforms|
partitioned_dependency_names[platforms] = partitioned_dependency_names_for(platforms)
end
@specs = specs
end end
def to_specs def to_specs
@activated_platforms.map do |p| activated_platforms.map do |p|
specs = @specs[p] specs = @specs[p]
next unless specs.any? next unless specs.any?
@ -36,18 +45,12 @@ module Bundler
end.flatten.compact.uniq end.flatten.compact.uniq
end end
def copy_for(platforms) def activate_platform!(platform)
platforms.select! {|p| for?(p) } self.activated_platforms = [platform]
return unless platforms.any?
copied_sg = self.class.new(@all_specs)
copied_sg.ignores_bundler_dependencies = @ignores_bundler_dependencies
copied_sg.activated_platforms = platforms
copied_sg
end end
def for?(platform) def activate_all_platforms!
@specs[platform].any? self.activated_platforms = @all_platforms
end end
def to_s def to_s
@ -56,11 +59,11 @@ module Bundler
end end
def dependencies_for_activated_platforms def dependencies_for_activated_platforms
dependencies = @activated_platforms.map {|p| __dependencies[p] } @dependencies[activated_platforms]
metadata_dependencies = @activated_platforms.map do |platform| end
metadata_dependencies(@specs[platform].first, platform)
end def partitioned_dependency_names_for_activated_platforms
dependencies.concat(metadata_dependencies).flatten @partitioned_dependency_names[activated_platforms]
end end
def ==(other) def ==(other)
@ -86,34 +89,43 @@ module Bundler
protected protected
def sorted_activated_platforms def sorted_activated_platforms
@activated_platforms.sort_by(&:to_s) activated_platforms.sort_by(&:to_s)
end end
private private
def __dependencies def dependencies_for(platforms)
@dependencies = Hash.new do |dependencies, platform| platforms.map do |platform|
dependencies[platform] = [] __dependencies(platform) + metadata_dependencies(platform)
specs = @specs[platform] end.flatten
if spec = specs.first
spec.dependencies.each do |dep|
next if dep.type == :development
next if @ignores_bundler_dependencies && dep.name == "bundler".freeze
dependencies[platform] << DepProxy.new(dep, platform)
end
end
dependencies[platform]
end
end end
def metadata_dependencies(spec, platform) def partitioned_dependency_names_for(platforms)
return [] unless spec && spec.is_a?(Gem::Specification) return @dependencies[platforms].map(&:name), [] if platforms.size == 1
@dependencies[platforms].partition do |dep_proxy|
@dependencies[platforms].count {|dp| dp.dep == dep_proxy.dep } == platforms.size
end.map {|deps| deps.map(&:name) }
end
def __dependencies(platform)
dependencies = []
@specs[platform].first.dependencies.each do |dep|
next if dep.type == :development
dependencies << DepProxy.get_proxy(dep, platform)
end
dependencies
end
def metadata_dependencies(platform)
spec = @specs[platform].first
return [] unless spec.is_a?(Gem::Specification)
dependencies = [] dependencies = []
if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform) dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform)
end end
if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none? if !spec.required_rubygems_version.nil? && !spec.required_rubygems_version.none?
dependencies << DepProxy.new(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform) dependencies << DepProxy.get_proxy(Gem::Dependency.new("RubyGems\0", spec.required_rubygems_version), platform)
end end
dependencies dependencies
end end

View File

@ -158,6 +158,22 @@ module Gem
end end
end end
if Gem::Requirement.new("~> 2.0").hash == Gem::Requirement.new("~> 2.0.0").hash
class Requirement
module CorrectHashForLambdaOperator
def hash
if requirements.any? {|r| r.first == "~>" }
requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash
else
super
end
end
end
prepend CorrectHashForLambdaOperator
end
end
class Platform class Platform
JAVA = Gem::Platform.new("java") unless defined?(JAVA) JAVA = Gem::Platform.new("java") unless defined?(JAVA)
MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN) MSWIN = Gem::Platform.new("mswin32") unless defined?(MSWIN)

View File

@ -8,6 +8,53 @@ module Bundler
# Bundler needs to install gems regardless of binstub overwriting # Bundler needs to install gems regardless of binstub overwriting
end end
def install
pre_install_checks
run_pre_install_hooks
spec.loaded_from = spec_file
# Completely remove any previous gem files
FileUtils.rm_rf gem_dir
FileUtils.rm_rf spec.extension_dir
FileUtils.mkdir_p gem_dir, :mode => 0o755
extract_files
build_extensions
write_build_info_file
run_post_build_hooks
generate_bin
generate_plugins
write_spec
write_cache_file
say spec.post_install_message unless spec.post_install_message.nil?
run_post_install_hooks
spec
end
def generate_plugins
return unless Gem::Installer.instance_methods(false).include?(:generate_plugins)
latest = Gem::Specification.stubs_for(spec.name).first
return if latest && latest.version > spec.version
ensure_writable_dir @plugins_dir
if spec.plugins.empty?
remove_plugins_for(spec, @plugins_dir)
else
regenerate_plugins_for(spec, @plugins_dir)
end
end
def pre_install_checks def pre_install_checks
super && validate_bundler_checksum(options[:bundler_expected_checksum]) super && validate_bundler_checksum(options[:bundler_expected_checksum])
end end

View File

@ -7,7 +7,6 @@ module Bundler
autoload :Validator, File.expand_path("settings/validator", __dir__) autoload :Validator, File.expand_path("settings/validator", __dir__)
BOOL_KEYS = %w[ BOOL_KEYS = %w[
allow_bundler_dependency_conflicts
allow_deployment_source_credential_changes allow_deployment_source_credential_changes
allow_offline_install allow_offline_install
auto_clean_without_path auto_clean_without_path
@ -20,6 +19,7 @@ module Bundler
disable_checksum_validation disable_checksum_validation
disable_exec_load disable_exec_load
disable_local_branch_check disable_local_branch_check
disable_local_revision_check
disable_multisource disable_multisource
disable_shared_gems disable_shared_gems
disable_version_check disable_version_check

View File

@ -187,11 +187,11 @@ module Bundler
return @md5_available if defined?(@md5_available) return @md5_available if defined?(@md5_available)
@md5_available = begin @md5_available = begin
require "openssl" require "openssl"
OpenSSL::Digest.digest("MD5", "") ::OpenSSL::Digest.digest("MD5", "")
true true
rescue LoadError rescue LoadError
true true
rescue OpenSSL::Digest::DigestError rescue ::OpenSSL::Digest::DigestError
false false
end end
end end

View File

@ -22,7 +22,7 @@ module Bundler
@uri = options["uri"] || "" @uri = options["uri"] || ""
@safe_uri = URICredentialsFilter.credential_filtered_uri(@uri) @safe_uri = URICredentialsFilter.credential_filtered_uri(@uri)
@branch = options["branch"] @branch = options["branch"]
@ref = options["ref"] || options["branch"] || options["tag"] || "master" @ref = options["ref"] || options["branch"] || options["tag"]
@submodules = options["submodules"] @submodules = options["submodules"]
@name = options["name"] @name = options["name"]
@version = options["version"].to_s.strip.gsub("-", ".pre.") @version = options["version"].to_s.strip.gsub("-", ".pre.")
@ -60,25 +60,27 @@ module Bundler
alias_method :==, :eql? alias_method :==, :eql?
def to_s def to_s
at = if local? begin
path at = if local?
elsif user_ref = options["ref"] path
if ref =~ /\A[a-z0-9]{4,}\z/i elsif user_ref = options["ref"]
shortref_for_display(user_ref) if ref =~ /\A[a-z0-9]{4,}\z/i
shortref_for_display(user_ref)
else
user_ref
end
elsif ref
ref
else else
user_ref git_proxy.branch
end end
else
ref rev = " (at #{at}@#{shortref_for_display(revision)})"
rescue GitError
""
end end
rev = begin "#{@safe_uri}#{rev}"
"@#{shortref_for_display(revision)}"
rescue GitError
nil
end
"#{@safe_uri} (at #{at}#{rev})"
end end
def name def name
@ -146,7 +148,7 @@ module Bundler
changed = cached_revision && cached_revision != git_proxy.revision changed = cached_revision && cached_revision != git_proxy.revision
if changed && !@unlocked && !git_proxy.contains?(cached_revision) if !Bundler.settings[:disable_local_revision_check] && changed && !@unlocked && !git_proxy.contains?(cached_revision)
raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \ raise GitError, "The Gemfile lock is pointing to revision #{shortref_for_display(cached_revision)} " \
"but the current branch in your local override for #{name} does not contain such commit. " \ "but the current branch in your local override for #{name} does not contain such commit. " \
"Please make sure your branch is up to date." "Please make sure your branch is up to date."

View File

@ -17,7 +17,7 @@ module Bundler
class GitNotAllowedError < GitError class GitNotAllowedError < GitError
def initialize(command) def initialize(command)
msg = String.new msg = String.new
msg << "Bundler is trying to run a `git #{command}` at runtime. You probably need to run `bundle install`. However, " msg << "Bundler is trying to run `#{command}` at runtime. You probably need to run `bundle install`. However, "
msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md " msg << "this error message could probably be more useful. Please submit a ticket at https://github.com/rubygems/rubygems/issues/new?labels=Bundler&template=bundler-related-issue.md "
msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}" msg << "with steps to reproduce as well as the following\n\nCALLER: #{caller.join("\n")}"
super msg super msg
@ -27,11 +27,11 @@ module Bundler
class GitCommandError < GitError class GitCommandError < GitError
attr_reader :command attr_reader :command
def initialize(command, path, destination_path, extra_info = nil) def initialize(command, path, extra_info = nil)
@command = command @command = command
msg = String.new msg = String.new
msg << "Git error: command `git #{command}` in directory #{destination_path} has failed." msg << "Git error: command `#{command}` in directory #{path} has failed."
msg << "\n#{extra_info}" if extra_info msg << "\n#{extra_info}" if extra_info
msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist? msg << "\nIf this error persists you could try removing the cache directory '#{path}'" if path.exist?
super msg super msg
@ -39,9 +39,9 @@ module Bundler
end end
class MissingGitRevisionError < GitCommandError class MissingGitRevisionError < GitCommandError
def initialize(command, path, destination_path, ref, repo) def initialize(command, destination_path, ref, repo)
msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?" msg = "Revision #{ref} does not exist in the repository #{repo}. Maybe you misspelled it?"
super command, path, destination_path, msg super command, destination_path, msg
end end
end end
@ -132,7 +132,7 @@ module Bundler
begin begin
git "reset", "--hard", @revision, :dir => destination git "reset", "--hard", @revision, :dir => destination
rescue GitCommandError => e rescue GitCommandError => e
raise MissingGitRevisionError.new(e.command, path, destination, @revision, URICredentialsFilter.credential_filtered_uri(uri)) raise MissingGitRevisionError.new(e.command, destination, @revision, URICredentialsFilter.credential_filtered_uri(uri))
end end
if submodules if submodules
@ -145,32 +145,36 @@ module Bundler
private private
def git_null(*command, dir: SharedHelpers.pwd) def git_null(*command, dir: nil)
check_allowed(command) check_allowed(command)
out, status = SharedHelpers.with_clean_git_env do out, status = SharedHelpers.with_clean_git_env do
capture_and_ignore_stderr("git", "-C", dir.to_s, *command) capture_and_ignore_stderr(*capture3_args_for(command, dir))
end end
[URICredentialsFilter.credential_filtered_string(out, uri), status] [URICredentialsFilter.credential_filtered_string(out, uri), status]
end end
def git_retry(*command, dir: SharedHelpers.pwd) def git_retry(*command, dir: nil)
Bundler::Retry.new("`git -C #{dir} #{URICredentialsFilter.credential_filtered_string(command.shelljoin, uri)}`", GitNotAllowedError).attempts do command_with_no_credentials = check_allowed(command)
Bundler::Retry.new("`#{command_with_no_credentials}` at #{dir || SharedHelpers.pwd}").attempts do
git(*command, :dir => dir) git(*command, :dir => dir)
end end
end end
def git(*command, dir: SharedHelpers.pwd) def git(*command, dir: nil)
command_with_no_credentials = check_allowed(command) command_with_no_credentials = check_allowed(command)
out, status = SharedHelpers.with_clean_git_env do out, status = SharedHelpers.with_clean_git_env do
capture_and_filter_stderr("git", "-C", dir.to_s, *command) capture_and_filter_stderr(*capture3_args_for(command, dir))
end end
raise GitCommandError.new(command_with_no_credentials, path, dir) unless status.success? filtered_out = URICredentialsFilter.credential_filtered_string(out, uri)
URICredentialsFilter.credential_filtered_string(out, uri) raise GitCommandError.new(command_with_no_credentials, dir || SharedHelpers.pwd, filtered_out) unless status.success?
filtered_out
end end
def has_revision_cached? def has_revision_cached?
@ -187,10 +191,10 @@ module Bundler
def find_local_revision def find_local_revision
allowed_with_path do allowed_with_path do
git("rev-parse", "--verify", ref, :dir => path).strip git("rev-parse", "--verify", ref || "HEAD", :dir => path).strip
end end
rescue GitCommandError => e rescue GitCommandError => e
raise MissingGitRevisionError.new(e.command, path, path, ref, URICredentialsFilter.credential_filtered_uri(uri)) raise MissingGitRevisionError.new(e.command, path, ref, URICredentialsFilter.credential_filtered_uri(uri))
end end
# Adds credentials to the URI as Fetcher#configured_uri_for does # Adds credentials to the URI as Fetcher#configured_uri_for does
@ -220,7 +224,7 @@ module Bundler
end end
def check_allowed(command) def check_allowed(command)
command_with_no_credentials = URICredentialsFilter.credential_filtered_string(command.shelljoin, uri) command_with_no_credentials = URICredentialsFilter.credential_filtered_string("git #{command.shelljoin}", uri)
raise GitNotAllowedError.new(command_with_no_credentials) unless allow? raise GitNotAllowedError.new(command_with_no_credentials) unless allow?
command_with_no_credentials command_with_no_credentials
end end
@ -237,6 +241,20 @@ module Bundler
return_value, _, status = Open3.capture3(*cmd) return_value, _, status = Open3.capture3(*cmd)
[return_value, status] [return_value, status]
end end
def capture3_args_for(cmd, dir)
return ["git", *cmd] unless dir
if Bundler.feature_flag.bundler_3_mode? || supports_minus_c?
["git", "-C", dir.to_s, *cmd]
else
["git", *cmd, { :chdir => dir.to_s }]
end
end
def supports_minus_c?
@supports_minus_c ||= Gem::Version.new(version) >= Gem::Version.new("1.8.5")
end
end end
end end
end end

View File

@ -1,5 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
require_relative "../../rubygems_gem_installer"
module Bundler module Bundler
class Source class Source
class Path class Path

View File

@ -145,6 +145,8 @@ module Bundler
Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5") Bundler.mkdir_p bin_path, :no_sudo => true unless spec.executables.empty? || Bundler.rubygems.provides?(">= 2.7.5")
require_relative "../rubygems_gem_installer"
installed_spec = Bundler::RubyGemsGemInstaller.at( installed_spec = Bundler::RubyGemsGemInstaller.at(
path, path,
:install_dir => install_path.to_s, :install_dir => install_path.to_s,
@ -351,7 +353,6 @@ module Bundler
def installed_specs def installed_specs
@installed_specs ||= Index.build do |idx| @installed_specs ||= Index.build do |idx|
Bundler.rubygems.all_specs.reverse_each do |spec| Bundler.rubygems.all_specs.reverse_each do |spec|
next if spec.name == "bundler"
spec.source = self spec.source = self
if Bundler.rubygems.spec_missing_extensions?(spec, false) if Bundler.rubygems.spec_missing_extensions?(spec, false)
Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions" Bundler.ui.debug "Source #{self} is ignoring #{spec} because it is missing extensions"

View File

@ -1,21 +1,23 @@
# frozen_string_literal: true # frozen_string_literal: true
require "set"
module Bundler module Bundler
class SourceList class SourceList
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
@ -24,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
@ -43,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
@ -96,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.to_set != replacement_rubygems.remotes.to_set
false false
end end
@ -112,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
@ -153,7 +148,7 @@ module Bundler
end end
def equal_sources?(lock_sources, replacement_sources) def equal_sources?(lock_sources, replacement_sources)
lock_sources.to_set == replacement_sources.to_set lock_sources.sort_by(&:to_s) == replacement_sources.sort_by(&:to_s)
end end
def equal_source?(source, other_source) def equal_source?(source, other_source)

View File

@ -1,7 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
require "tsort" require "tsort"
require "set"
module Bundler module Bundler
class SpecSet class SpecSet
@ -13,14 +12,16 @@ module Bundler
end end
def for(dependencies, skip = [], check = false, match_current_platform = false, raise_on_missing = true) def for(dependencies, skip = [], check = false, match_current_platform = false, raise_on_missing = true)
handled = Set.new handled = []
deps = dependencies.dup deps = dependencies.dup
specs = [] specs = []
skip += ["bundler"] skip += ["bundler"]
loop do loop do
break unless dep = deps.shift break unless dep = deps.shift
next if !handled.add?(dep) || skip.include?(dep.name) next if handled.include?(dep) || skip.include?(dep.name)
handled << dep
specs_for_dep = spec_for_dependency(dep, match_current_platform) specs_for_dep = spec_for_dependency(dep, match_current_platform)
if specs_for_dep.any? if specs_for_dep.any?
@ -28,7 +29,7 @@ module Bundler
specs_for_dep.first.dependencies.each do |d| specs_for_dep.first.dependencies.each do |d|
next if d.type == :development next if d.type == :development
d = DepProxy.new(d, dep.__platform) unless match_current_platform d = DepProxy.get_proxy(d, dep.__platform) unless match_current_platform
deps << d deps << d
end end
elsif check elsif check

View File

@ -26,11 +26,19 @@ module Bundler
# @!group Stub Delegates # @!group Stub Delegates
def manually_installed?
# This is for manually installed gems which are gems that were fixed in place after a
# failed installation. Once the issue was resolved, the user then manually created
# the gem specification using the instructions provided by `gem help install`
installed_by_version == Gem::Version.new(0)
end
# This is defined directly to avoid having to loading the full spec # This is defined directly to avoid having to loading the full spec
def missing_extensions? def missing_extensions?
return false if default_gem? return false if default_gem?
return false if extensions.empty? return false if extensions.empty?
return false if File.exist? gem_build_complete_path return false if File.exist? gem_build_complete_path
return false if manually_installed?
true true
end end

View File

@ -0,0 +1,5 @@
## [Unreleased]
## [0.1.0] - <%= Time.now.strftime('%F') %>
- Initial release

View File

@ -16,5 +16,5 @@ gem "<%= config[:test] %>", "~> <%= config[:test_framework_version] %>"
<%- end -%> <%- end -%>
<%- if config[:rubocop] -%> <%- if config[:rubocop] -%>
gem "rubocop", "~> 0.80" gem "rubocop", "~> <%= config[:rubocop_version] %>"
<%- end -%> <%- end -%>

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

@ -14,7 +14,7 @@ Gem::Specification.new do |spec|
<%- if config[:mit] -%> <%- if config[:mit] -%>
spec.license = "MIT" spec.license = "MIT"
<%- end -%> <%- end -%>
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0") spec.required_ruby_version = Gem::Requirement.new(">= <%= config[:required_ruby_version] %>")
spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'" spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"

View File

@ -1,3 +1,6 @@
AllCops:
TargetRubyVersion: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %>
Style/StringLiterals: Style/StringLiterals:
Enabled: true Enabled: true
EnforcedStyle: double_quotes EnforcedStyle: double_quotes

View File

@ -26,6 +26,13 @@ module Bundler::Molinillo
end end
end end
# (see Bundler::Molinillo::SpecificationProvider#dependencies_equal?)
def dependencies_equal?(dependencies, other_dependencies)
with_no_such_dependency_error_handling do
specification_provider.dependencies_equal?(dependencies, other_dependencies)
end
end
# (see Bundler::Molinillo::SpecificationProvider#name_for) # (see Bundler::Molinillo::SpecificationProvider#name_for)
def name_for(dependency) def name_for(dependency)
with_no_such_dependency_error_handling do with_no_such_dependency_error_handling do

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'set'
require 'tsort' require 'tsort'
require_relative 'dependency_graph/log' require_relative 'dependency_graph/log'

View File

@ -59,7 +59,7 @@ module Bundler::Molinillo
# @param [Set<Vertex>] vertices the set to add the predecessors to # @param [Set<Vertex>] vertices the set to add the predecessors to
# @return [Set<Vertex>] the vertices of {#graph} where `self` is a # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
# {#descendent?} # {#descendent?}
def _recursive_predecessors(vertices = Set.new) def _recursive_predecessors(vertices = new_vertex_set)
incoming_edges.each do |edge| incoming_edges.each do |edge|
vertex = edge.origin vertex = edge.origin
next unless vertices.add?(vertex) next unless vertices.add?(vertex)
@ -85,7 +85,7 @@ module Bundler::Molinillo
# @param [Set<Vertex>] vertices the set to add the successors to # @param [Set<Vertex>] vertices the set to add the successors to
# @return [Set<Vertex>] the vertices of {#graph} where `self` is an # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
# {#ancestor?} # {#ancestor?}
def _recursive_successors(vertices = Set.new) def _recursive_successors(vertices = new_vertex_set)
outgoing_edges.each do |edge| outgoing_edges.each do |edge|
vertex = edge.destination vertex = edge.destination
next unless vertices.add?(vertex) next unless vertices.add?(vertex)
@ -128,7 +128,7 @@ module Bundler::Molinillo
# Is there a path from `self` to `other` following edges in the # Is there a path from `self` to `other` following edges in the
# dependency graph? # dependency graph?
# @return true iff there is a path following edges within this {#graph} # @return whether there is a path following edges within this {#graph}
def path_to?(other) def path_to?(other)
_path_to?(other) _path_to?(other)
end end
@ -138,7 +138,7 @@ module Bundler::Molinillo
# @param [Vertex] other the vertex to check if there's a path to # @param [Vertex] other the vertex to check if there's a path to
# @param [Set<Vertex>] visited the vertices of {#graph} that have been visited # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
# @return [Boolean] whether there is a path to `other` from `self` # @return [Boolean] whether there is a path to `other` from `self`
def _path_to?(other, visited = Set.new) def _path_to?(other, visited = new_vertex_set)
return false unless visited.add?(self) return false unless visited.add?(self)
return true if equal?(other) return true if equal?(other)
successors.any? { |v| v._path_to?(other, visited) } successors.any? { |v| v._path_to?(other, visited) }
@ -147,12 +147,18 @@ module Bundler::Molinillo
# Is there a path from `other` to `self` following edges in the # Is there a path from `other` to `self` following edges in the
# dependency graph? # dependency graph?
# @return true iff there is a path following edges within this {#graph} # @return whether there is a path following edges within this {#graph}
def ancestor?(other) def ancestor?(other)
other.path_to?(self) other.path_to?(self)
end end
alias is_reachable_from? ancestor? alias is_reachable_from? ancestor?
def new_vertex_set
require 'set'
Set.new
end
private :new_vertex_set
end end
end end
end end

View File

@ -34,7 +34,7 @@ module Bundler::Molinillo
# An error caused by attempting to fulfil a dependency that was circular # An error caused by attempting to fulfil a dependency that was circular
# #
# @note This exception will be thrown iff a {Vertex} is added to a # @note This exception will be thrown if and only if a {Vertex} is added to a
# {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an
# existing {DependencyGraph::Vertex} # existing {DependencyGraph::Vertex}
class CircularDependencyError < ResolverError class CircularDependencyError < ResolverError
@ -121,7 +121,7 @@ module Bundler::Molinillo
t = ''.dup t = ''.dup
depth = 2 depth = 2
tree.each do |req| tree.each do |req|
t << ' ' * depth << req.to_s t << ' ' * depth << printable_requirement.call(req)
unless tree.last == req unless tree.last == req
if spec = conflict.activated_by_name[name_for(req)] if spec = conflict.activated_by_name[name_for(req)]
t << %( was resolved to #{version_for_spec.call(spec)}, which) t << %( was resolved to #{version_for_spec.call(spec)}, which)

View File

@ -45,6 +45,17 @@ module Bundler::Molinillo
true true
end end
# Determines whether two arrays of dependencies are equal, and thus can be
# grouped.
#
# @param [Array<Object>] dependencies
# @param [Array<Object>] other_dependencies
# @return [Boolean] whether `dependencies` and `other_dependencies` should
# be considered equal.
def dependencies_equal?(dependencies, other_dependencies)
dependencies == other_dependencies
end
# Returns the name for the given `dependency`. # Returns the name for the given `dependency`.
# @note This method should be 'pure', i.e. the return value should depend # @note This method should be 'pure', i.e. the return value should depend
# only on the `dependency` parameter. # only on the `dependency` parameter.

View File

@ -329,11 +329,11 @@ module Bundler::Molinillo
# Look for past conflicts that could be unwound to affect the # Look for past conflicts that could be unwound to affect the
# requirement tree for the current conflict # requirement tree for the current conflict
all_reqs = last_detail_for_current_unwind.all_requirements
all_reqs_size = all_reqs.size
relevant_unused_unwinds = unused_unwind_options.select do |alternative| relevant_unused_unwinds = unused_unwind_options.select do |alternative|
intersecting_requirements = diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
last_detail_for_current_unwind.all_requirements & next if diff_reqs.size == all_reqs_size
alternative.requirements_unwound_to_instead
next if intersecting_requirements.empty?
# Find the highest index unwind whilst looping through # Find the highest index unwind whilst looping through
current_detail = alternative if alternative > current_detail current_detail = alternative if alternative > current_detail
alternative alternative
@ -344,8 +344,12 @@ module Bundler::Molinillo
state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
# Update the requirements_unwound_to_instead on any relevant unused unwinds # Update the requirements_unwound_to_instead on any relevant unused unwinds
relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } relevant_unused_unwinds.each do |d|
unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
unwind_details.each do |d|
(d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
current_detail current_detail
end end
@ -803,7 +807,7 @@ module Bundler::Molinillo
possibilities.reverse_each do |possibility| possibilities.reverse_each do |possibility|
dependencies = dependencies_for(possibility) dependencies = dependencies_for(possibility)
if current_possibility_set && current_possibility_set.dependencies == dependencies if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
current_possibility_set.possibilities.unshift(possibility) current_possibility_set.possibilities.unshift(possibility)
else else
possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))

View File

@ -1,7 +1,7 @@
require "set"
require_relative "thor/base" require_relative "thor/base"
class Bundler::Thor class Bundler::Thor
$thor_runner ||= false
class << self class << self
# Allows for custom "Command" package naming. # Allows for custom "Command" package naming.
# #
@ -323,7 +323,7 @@ class Bundler::Thor
# ==== Parameters # ==== Parameters
# Symbol ...:: A list of commands that should be affected. # Symbol ...:: A list of commands that should be affected.
def stop_on_unknown_option!(*command_names) def stop_on_unknown_option!(*command_names)
stop_on_unknown_option.merge(command_names) @stop_on_unknown_option = stop_on_unknown_option | command_names
end end
def stop_on_unknown_option?(command) #:nodoc: def stop_on_unknown_option?(command) #:nodoc:
@ -337,7 +337,7 @@ class Bundler::Thor
# ==== Parameters # ==== Parameters
# Symbol ...:: A list of commands that should be affected. # Symbol ...:: A list of commands that should be affected.
def disable_required_check!(*command_names) def disable_required_check!(*command_names)
disable_required_check.merge(command_names) @disable_required_check = disable_required_check | command_names
end end
def disable_required_check?(command) #:nodoc: def disable_required_check?(command) #:nodoc:
@ -347,12 +347,12 @@ class Bundler::Thor
protected protected
def stop_on_unknown_option #:nodoc: def stop_on_unknown_option #:nodoc:
@stop_on_unknown_option ||= Set.new @stop_on_unknown_option ||= []
end end
# help command has the required check disabled by default. # help command has the required check disabled by default.
def disable_required_check #:nodoc: def disable_required_check #:nodoc:
@disable_required_check ||= Set.new([:help]) @disable_required_check ||= [:help]
end end
# The method responsible for dispatching given the args. # The method responsible for dispatching given the args.
@ -398,7 +398,6 @@ class Bundler::Thor
# the namespace should be displayed as arguments. # the namespace should be displayed as arguments.
# #
def banner(command, namespace = nil, subcommand = false) def banner(command, namespace = nil, subcommand = false)
$thor_runner ||= false
command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage| command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage|
"#{basename} #{formatted_usage}" "#{basename} #{formatted_usage}"
end.join("\n") end.join("\n")

View File

@ -219,7 +219,7 @@ class Bundler::Thor
contents = if is_uri contents = if is_uri
require "open-uri" require "open-uri"
open(path, "Accept" => "application/x-thor-template", &:read) URI.open(path, "Accept" => "application/x-thor-template", &:read)
else else
open(path, &:read) open(path, &:read)
end end

View File

@ -251,7 +251,8 @@ class Bundler::Thor
# path<String>:: path of the file to be changed # path<String>:: path of the file to be changed
# flag<Regexp|String>:: the regexp or string to be replaced # flag<Regexp|String>:: the regexp or string to be replaced
# replacement<String>:: the replacement, can be also given as a block # replacement<String>:: the replacement, can be also given as a block
# config<Hash>:: give :verbose => false to not log the status. # config<Hash>:: give :verbose => false to not log the status, and
# :force => true, to force the replacement regardles of runner behavior.
# #
# ==== Example # ==== Example
# #
@ -262,9 +263,10 @@ class Bundler::Thor
# end # end
# #
def gsub_file(path, flag, *args, &block) def gsub_file(path, flag, *args, &block)
return unless behavior == :invoke
config = args.last.is_a?(Hash) ? args.pop : {} config = args.last.is_a?(Hash) ? args.pop : {}
return unless behavior == :invoke || config.fetch(:force, false)
path = File.expand_path(path, destination_root) path = File.expand_path(path, destination_root)
say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true)

View File

@ -1,5 +1,5 @@
class Bundler::Thor class Bundler::Thor
Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName
# In order to support versions of Ruby that don't have keyword # In order to support versions of Ruby that don't have keyword
# arguments, we need our own spell checker class that doesn't take key # arguments, we need our own spell checker class that doesn't take key
# words. Even though this code wouldn't be hit because of the check # words. Even though this code wouldn't be hit because of the check

View File

@ -30,7 +30,11 @@ class Bundler::Thor
arguments.each do |argument| arguments.each do |argument|
if !argument.default.nil? if !argument.default.nil?
@assigns[argument.human_name] = argument.default begin
@assigns[argument.human_name] = argument.default.dup
rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4
@assigns[argument.human_name] = argument.default
end
elsif argument.required? elsif argument.required?
@non_assigned_required << argument @non_assigned_required << argument
end end

View File

@ -133,15 +133,16 @@ class Bundler::Thor
protected protected
def assign_result!(option, result) def assign_result!(option, result)
if option.repeatable && option.type == :hash if option.repeatable && option.type == :hash
(@assigns[option.human_name] ||= {}).merge!(result) (@assigns[option.human_name] ||= {}).merge!(result)
elsif option.repeatable elsif option.repeatable
(@assigns[option.human_name] ||= []) << result (@assigns[option.human_name] ||= []) << result
else else
@assigns[option.human_name] = result @assigns[option.human_name] = result
end
end end
end
# Check if the current value in peek is a registered switch. # Check if the current value in peek is a registered switch.
# #
# Two booleans are returned. The first is true if the current value # Two booleans are returned. The first is true if the current value

View File

@ -94,6 +94,8 @@ class Bundler::Thor
# say("I know you knew that.") # say("I know you knew that.")
# #
def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/))
return if quiet?
buffer = prepare_message(message, *color) buffer = prepare_message(message, *color)
buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") buffer << "\n" if force_new_line && !message.to_s.end_with?("\n")
@ -230,8 +232,9 @@ class Bundler::Thor
paras = message.split("\n\n") paras = message.split("\n\n")
paras.map! do |unwrapped| paras.map! do |unwrapped|
counter = 0 words = unwrapped.split(" ")
unwrapped.split(" ").inject do |memo, word| counter = words.first.length
words.inject do |memo, word|
word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n") word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n")
counter = 0 if word.include? "\n" counter = 0 if word.include? "\n"
if (counter + word.length + 1) < width if (counter + word.length + 1) < width

View File

@ -97,7 +97,11 @@ class Bundler::Thor
protected protected
def can_display_colors? def can_display_colors?
stdout.tty? && !are_colors_disabled? are_colors_supported? && !are_colors_disabled?
end
def are_colors_supported?
stdout.tty? && ENV["TERM"] != "dumb"
end end
def are_colors_disabled? def are_colors_disabled?

View File

@ -1,3 +1,3 @@
class Bundler::Thor class Bundler::Thor
VERSION = "1.0.1" VERSION = "1.1.0"
end end

View File

@ -275,7 +275,7 @@ module Gem
unless spec = specs.first unless spec = specs.first
msg = "can't find gem #{dep} with executable #{exec_name}" msg = "can't find gem #{dep} with executable #{exec_name}"
if name == "bundler" && bundler_message = Gem::BundlerVersionFinder.missing_version_message if dep.filters_bundler? && bundler_message = Gem::BundlerVersionFinder.missing_version_message
msg = bundler_message msg = bundler_message
end end
raise Gem::GemNotFoundException, msg raise Gem::GemNotFoundException, msg
@ -469,7 +469,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
next if File.exist? subdir next if File.exist? subdir
begin begin
FileUtils.mkdir_p subdir, **options FileUtils.mkdir_p subdir, **options
rescue Errno::EACCES rescue SystemCallError
end end
end end
ensure ensure

View File

@ -634,6 +634,7 @@ RubyGems is a package manager for Ruby.
gem install rake gem install rake
gem list --local gem list --local
gem build package.gemspec gem build package.gemspec
gem push package-0.0.1.gem
gem help install gem help install
Further help: Further help:

View File

@ -45,6 +45,7 @@ class Gem::ConfigFile
DEFAULT_UPDATE_SOURCES = true DEFAULT_UPDATE_SOURCES = true
DEFAULT_CONCURRENT_DOWNLOADS = 8 DEFAULT_CONCURRENT_DOWNLOADS = 8
DEFAULT_CERT_EXPIRATION_LENGTH_DAYS = 365 DEFAULT_CERT_EXPIRATION_LENGTH_DAYS = 365
DEFAULT_IPV4_FALLBACK_ENABLED = false
## ##
# For Ruby packagers to set configuration defaults. Set in # For Ruby packagers to set configuration defaults. Set in
@ -140,6 +141,12 @@ class Gem::ConfigFile
attr_accessor :cert_expiration_length_days attr_accessor :cert_expiration_length_days
##
# == Experimental ==
# Fallback to IPv4 when IPv6 is not reachable or slow (default: false)
attr_accessor :ipv4_fallback_enabled
## ##
# Path name of directory or file of openssl client certificate, used for remote https connection with client authentication # Path name of directory or file of openssl client certificate, used for remote https connection with client authentication
@ -175,6 +182,7 @@ class Gem::ConfigFile
@update_sources = DEFAULT_UPDATE_SOURCES @update_sources = DEFAULT_UPDATE_SOURCES
@concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS @concurrent_downloads = DEFAULT_CONCURRENT_DOWNLOADS
@cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS @cert_expiration_length_days = DEFAULT_CERT_EXPIRATION_LENGTH_DAYS
@ipv4_fallback_enabled = ENV['IPV4_FALLBACK_ENABLED'] == 'true' || DEFAULT_IPV4_FALLBACK_ENABLED
operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS) operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS)
platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS) platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS)
@ -203,6 +211,7 @@ class Gem::ConfigFile
@disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server @disable_default_gem_server = @hash[:disable_default_gem_server] if @hash.key? :disable_default_gem_server
@sources = @hash[:sources] if @hash.key? :sources @sources = @hash[:sources] if @hash.key? :sources
@cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days @cert_expiration_length_days = @hash[:cert_expiration_length_days] if @hash.key? :cert_expiration_length_days
@ipv4_fallback_enabled = @hash[:ipv4_fallback_enabled] if @hash.key? :ipv4_fallback_enabled
@ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode @ssl_verify_mode = @hash[:ssl_verify_mode] if @hash.key? :ssl_verify_mode
@ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert @ssl_ca_cert = @hash[:ssl_ca_cert] if @hash.key? :ssl_ca_cert

View File

@ -0,0 +1,52 @@
require 'socket'
module CoreExtensions
module TCPSocketExt
def self.prepended(base)
base.prepend Initializer
end
module Initializer
CONNECTION_TIMEOUT = 5
IPV4_DELAY_SECONDS = 0.1
def initialize(host, serv, *rest)
mutex = Mutex.new
addrs = []
threads = []
cond_var = ConditionVariable.new
Addrinfo.foreach(host, serv, nil, :STREAM) do |addr|
Thread.report_on_exception = false if defined? Thread.report_on_exception = ()
threads << Thread.new(addr) do
# give head start to ipv6 addresses
sleep IPV4_DELAY_SECONDS if addr.ipv4?
# raises Errno::ECONNREFUSED when ip:port is unreachable
Socket.tcp(addr.ip_address, serv, connect_timeout: CONNECTION_TIMEOUT).close
mutex.synchronize do
addrs << addr.ip_address
cond_var.signal
end
end
end
mutex.synchronize do
timeout_time = CONNECTION_TIMEOUT + Time.now.to_f
while addrs.empty? && (remaining_time = timeout_time - Time.now.to_f) > 0
cond_var.wait(mutex, remaining_time)
end
host = addrs.shift unless addrs.empty?
end
threads.each {|t| t.kill.join if t.alive? }
super(host, serv, *rest)
end
end
end
end
TCPSocket.prepend CoreExtensions::TCPSocketExt

View File

@ -277,7 +277,7 @@ class Gem::Dependency
requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version) requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version)
end.map(&:to_spec) end.map(&:to_spec)
Gem::BundlerVersionFinder.filter!(matches) if name == "bundler".freeze && !requirement.specific? Gem::BundlerVersionFinder.filter!(matches) if filters_bundler?
if platform_only if platform_only
matches.reject! do |spec| matches.reject! do |spec|
@ -295,6 +295,10 @@ class Gem::Dependency
@requirement.specific? @requirement.specific?
end end
def filters_bundler?
name == "bundler".freeze && !specific?
end
def to_specs def to_specs
matches = matching_specs true matches = matching_specs true

View File

@ -28,13 +28,14 @@ class Gem::Ext::Builder
unless make_program unless make_program
make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make' make_program = (/mswin/ =~ RUBY_PLATFORM) ? 'nmake' : 'make'
end end
make_program = Shellwords.split(make_program)
destdir = 'DESTDIR=%s' % ENV['DESTDIR'] destdir = 'DESTDIR=%s' % ENV['DESTDIR']
['clean', '', 'install'].each do |target| ['clean', '', 'install'].each do |target|
# Pass DESTDIR via command line to override what's in MAKEFLAGS # Pass DESTDIR via command line to override what's in MAKEFLAGS
cmd = [ cmd = [
make_program, *make_program,
destdir, destdir,
target, target,
].reject(&:empty?) ].reject(&:empty?)

View File

@ -6,11 +6,16 @@
module Gem::InstallerUninstallerUtils module Gem::InstallerUninstallerUtils
def regenerate_plugins_for(spec, plugins_dir) def regenerate_plugins_for(spec, plugins_dir)
plugins = spec.plugins
return if plugins.empty?
require 'pathname'
spec.plugins.each do |plugin| spec.plugins.each do |plugin|
plugin_script_path = File.join plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}" plugin_script_path = File.join plugins_dir, "#{spec.name}_plugin#{File.extname(plugin)}"
File.open plugin_script_path, 'wb' do |file| File.open plugin_script_path, 'wb' do |file|
file.puts "require '#{plugin}'" file.puts "require_relative '#{Pathname.new(plugin).relative_path_from(Pathname.new(plugins_dir))}'"
end end
verbose plugin_script_path verbose plugin_script_path

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
@ -121,10 +121,6 @@ class Gem::Platform
end end
end end
def inspect
"%s @cpu=%p, @os=%p, @version=%p>" % [super[0..-2], *to_a]
end
def to_a def to_a
[@cpu, @os, @version] [@cpu, @os, @version]
end end
@ -150,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).
@ -166,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

@ -78,6 +78,7 @@ class Gem::RemoteFetcher
# fetching the gem. # fetching the gem.
def initialize(proxy=nil, dns=nil, headers={}) def initialize(proxy=nil, dns=nil, headers={})
require 'rubygems/core_ext/tcpsocket_init' if Gem.configuration.ipv4_fallback_enabled
require 'net/http' require 'net/http'
require 'stringio' require 'stringio'
require 'uri' require 'uri'
@ -295,7 +296,7 @@ class Gem::RemoteFetcher
data = fetch_path(uri, mtime) data = fetch_path(uri, mtime)
if data == nil # indicates the server returned 304 Not Modified if data.nil? # indicates the server returned 304 Not Modified
return Gem.read_binary(path) return Gem.read_binary(path)
end end

View File

@ -190,7 +190,7 @@ class Gem::Requirement
end end
def hash # :nodoc: def hash # :nodoc:
requirements.sort.hash requirements.map {|r| r.first == "~>" ? [r[0], r[1].to_s] : r }.sort.hash
end end
def marshal_dump # :nodoc: def marshal_dump # :nodoc:

View File

@ -35,9 +35,12 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
## ##
# The required_ruby_version constraint for this specification # The required_ruby_version constraint for this specification
#
# A fallback is included because when generated, some marshalled specs have it
# set to +nil+.
def required_ruby_version def required_ruby_version
spec.required_ruby_version spec.required_ruby_version || Gem::Requirement.default
end end
## ##

View File

@ -26,6 +26,13 @@ module Gem::Resolver::Molinillo
end end
end end
# (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_equal?)
def dependencies_equal?(dependencies, other_dependencies)
with_no_such_dependency_error_handling do
specification_provider.dependencies_equal?(dependencies, other_dependencies)
end
end
# (see Gem::Resolver::Molinillo::SpecificationProvider#name_for) # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for)
def name_for(dependency) def name_for(dependency)
with_no_such_dependency_error_handling do with_no_such_dependency_error_handling do

View File

@ -1,6 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
require 'set'
require 'tsort' require 'tsort'
require_relative 'dependency_graph/log' require_relative 'dependency_graph/log'

View File

@ -59,7 +59,7 @@ module Gem::Resolver::Molinillo
# @param [Set<Vertex>] vertices the set to add the predecessors to # @param [Set<Vertex>] vertices the set to add the predecessors to
# @return [Set<Vertex>] the vertices of {#graph} where `self` is a # @return [Set<Vertex>] the vertices of {#graph} where `self` is a
# {#descendent?} # {#descendent?}
def _recursive_predecessors(vertices = Set.new) def _recursive_predecessors(vertices = new_vertex_set)
incoming_edges.each do |edge| incoming_edges.each do |edge|
vertex = edge.origin vertex = edge.origin
next unless vertices.add?(vertex) next unless vertices.add?(vertex)
@ -85,7 +85,7 @@ module Gem::Resolver::Molinillo
# @param [Set<Vertex>] vertices the set to add the successors to # @param [Set<Vertex>] vertices the set to add the successors to
# @return [Set<Vertex>] the vertices of {#graph} where `self` is an # @return [Set<Vertex>] the vertices of {#graph} where `self` is an
# {#ancestor?} # {#ancestor?}
def _recursive_successors(vertices = Set.new) def _recursive_successors(vertices = new_vertex_set)
outgoing_edges.each do |edge| outgoing_edges.each do |edge|
vertex = edge.destination vertex = edge.destination
next unless vertices.add?(vertex) next unless vertices.add?(vertex)
@ -138,7 +138,7 @@ module Gem::Resolver::Molinillo
# @param [Vertex] other the vertex to check if there's a path to # @param [Vertex] other the vertex to check if there's a path to
# @param [Set<Vertex>] visited the vertices of {#graph} that have been visited # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited
# @return [Boolean] whether there is a path to `other` from `self` # @return [Boolean] whether there is a path to `other` from `self`
def _path_to?(other, visited = Set.new) def _path_to?(other, visited = new_vertex_set)
return false unless visited.add?(self) return false unless visited.add?(self)
return true if equal?(other) return true if equal?(other)
successors.any? { |v| v._path_to?(other, visited) } successors.any? { |v| v._path_to?(other, visited) }
@ -147,12 +147,18 @@ module Gem::Resolver::Molinillo
# Is there a path from `other` to `self` following edges in the # Is there a path from `other` to `self` following edges in the
# dependency graph? # dependency graph?
# @return true iff there is a path following edges within this {#graph} # @return whether there is a path following edges within this {#graph}
def ancestor?(other) def ancestor?(other)
other.path_to?(self) other.path_to?(self)
end end
alias is_reachable_from? ancestor? alias is_reachable_from? ancestor?
def new_vertex_set
require 'set'
Set.new
end
private :new_vertex_set
end end
end end
end end

View File

@ -121,7 +121,7 @@ module Gem::Resolver::Molinillo
t = ''.dup t = ''.dup
depth = 2 depth = 2
tree.each do |req| tree.each do |req|
t << ' ' * depth << req.to_s t << ' ' * depth << printable_requirement.call(req)
unless tree.last == req unless tree.last == req
if spec = conflict.activated_by_name[name_for(req)] if spec = conflict.activated_by_name[name_for(req)]
t << %( was resolved to #{version_for_spec.call(spec)}, which) t << %( was resolved to #{version_for_spec.call(spec)}, which)

View File

@ -45,6 +45,17 @@ module Gem::Resolver::Molinillo
true true
end end
# Determines whether two arrays of dependencies are equal, and thus can be
# grouped.
#
# @param [Array<Object>] dependencies
# @param [Array<Object>] other_dependencies
# @return [Boolean] whether `dependencies` and `other_dependencies` should
# be considered equal.
def dependencies_equal?(dependencies, other_dependencies)
dependencies == other_dependencies
end
# Returns the name for the given `dependency`. # Returns the name for the given `dependency`.
# @note This method should be 'pure', i.e. the return value should depend # @note This method should be 'pure', i.e. the return value should depend
# only on the `dependency` parameter. # only on the `dependency` parameter.

View File

@ -329,11 +329,11 @@ module Gem::Resolver::Molinillo
# Look for past conflicts that could be unwound to affect the # Look for past conflicts that could be unwound to affect the
# requirement tree for the current conflict # requirement tree for the current conflict
all_reqs = last_detail_for_current_unwind.all_requirements
all_reqs_size = all_reqs.size
relevant_unused_unwinds = unused_unwind_options.select do |alternative| relevant_unused_unwinds = unused_unwind_options.select do |alternative|
intersecting_requirements = diff_reqs = all_reqs - alternative.requirements_unwound_to_instead
last_detail_for_current_unwind.all_requirements & next if diff_reqs.size == all_reqs_size
alternative.requirements_unwound_to_instead
next if intersecting_requirements.empty?
# Find the highest index unwind whilst looping through # Find the highest index unwind whilst looping through
current_detail = alternative if alternative > current_detail current_detail = alternative if alternative > current_detail
alternative alternative
@ -344,8 +344,12 @@ module Gem::Resolver::Molinillo
state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 }
# Update the requirements_unwound_to_instead on any relevant unused unwinds # Update the requirements_unwound_to_instead on any relevant unused unwinds
relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } relevant_unused_unwinds.each do |d|
unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
unwind_details.each do |d|
(d.requirements_unwound_to_instead << current_detail.state_requirement).uniq!
end
current_detail current_detail
end end
@ -803,7 +807,7 @@ module Gem::Resolver::Molinillo
possibilities.reverse_each do |possibility| possibilities.reverse_each do |possibility|
dependencies = dependencies_for(possibility) dependencies = dependencies_for(possibility)
if current_possibility_set && current_possibility_set.dependencies == dependencies if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies)
current_possibility_set.possibilities.unshift(possibility) current_possibility_set.possibilities.unshift(possibility)
else else
possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility]))

View File

@ -182,6 +182,7 @@ class Gem::Specification < Gem::BasicSpecification
@@default_value[k].nil? @@default_value[k].nil?
end end
@@stubs = nil
@@stubs_by_name = {} @@stubs_by_name = {}
# Sentinel object to represent "not found" stubs # Sentinel object to represent "not found" stubs
@ -665,6 +666,9 @@ class Gem::Specification < Gem::BasicSpecification
# #
# # Only prereleases or final releases after 2.6.0.preview2 # # Only prereleases or final releases after 2.6.0.preview2
# spec.required_ruby_version = '> 2.6.0.preview2' # spec.required_ruby_version = '> 2.6.0.preview2'
#
# # This gem will work with 2.3.0 or greater, including major version 3, but lesser than 4.0.0
# spec.required_ruby_version = '>= 2.3', '< 4'
def required_ruby_version=(req) def required_ruby_version=(req)
@required_ruby_version = Gem::Requirement.create req @required_ruby_version = Gem::Requirement.create req
@ -800,10 +804,8 @@ class Gem::Specification < Gem::BasicSpecification
def self.stubs def self.stubs
@@stubs ||= begin @@stubs ||= begin
pattern = "*.gemspec" pattern = "*.gemspec"
stubs = installed_stubs(dirs, pattern) + default_stubs(pattern) stubs = stubs_for_pattern(pattern, false)
stubs = stubs.uniq {|stub| stub.full_name }
_resort!(stubs)
@@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name) @@stubs_by_name = stubs.select {|s| Gem::Platform.match_spec? s }.group_by(&:name)
stubs stubs
end end
@ -820,31 +822,40 @@ class Gem::Specification < Gem::BasicSpecification
end end
end end
EMPTY = [].freeze # :nodoc:
## ##
# Returns a Gem::StubSpecification for installed gem named +name+ # Returns a Gem::StubSpecification for installed gem named +name+
# only returns stubs that match Gem.platforms # only returns stubs that match Gem.platforms
def self.stubs_for(name) def self.stubs_for(name)
if @@stubs_by_name[name] if @@stubs
@@stubs_by_name[name] @@stubs_by_name[name] || []
else else
pattern = "#{name}-*.gemspec" @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s|
stubs = installed_stubs(dirs, pattern).select {|s| Gem::Platform.match_spec? s } + default_stubs(pattern) s.name == name
stubs = stubs.uniq {|stub| stub.full_name }.group_by(&:name) end
stubs.each_value {|v| _resort!(v) }
@@stubs_by_name.merge! stubs
@@stubs_by_name[name] ||= EMPTY
end end
end end
##
# Finds stub specifications matching a pattern from the standard locations,
# optionally filtering out specs not matching the current platform
#
def self.stubs_for_pattern(pattern, match_platform = true) # :nodoc:
installed_stubs = installed_stubs(Gem::Specification.dirs, pattern)
installed_stubs.select! {|s| Gem::Platform.match_spec? s } if match_platform
stubs = installed_stubs + default_stubs(pattern)
stubs = stubs.uniq {|stub| stub.full_name }
_resort!(stubs)
stubs
end
def self._resort!(specs) # :nodoc: def self._resort!(specs) # :nodoc:
specs.sort! do |a, b| specs.sort! do |a, b|
names = a.name <=> b.name names = a.name <=> b.name
next names if names.nonzero? next names if names.nonzero?
b.version <=> a.version versions = b.version <=> a.version
next versions if versions.nonzero?
b.platform == Gem::Platform::RUBY ? -1 : 1
end end
end end
@ -1080,20 +1091,15 @@ class Gem::Specification < Gem::BasicSpecification
end end
def self._latest_specs(specs, prerelease = false) # :nodoc: def self._latest_specs(specs, prerelease = false) # :nodoc:
result = Hash.new {|h,k| h[k] = {} } result = {}
native = {}
specs.reverse_each do |spec| specs.reverse_each do |spec|
next if spec.version.prerelease? unless prerelease next if spec.version.prerelease? unless prerelease
native[spec.name] = spec.version if spec.platform == Gem::Platform::RUBY result[spec.name] = spec
result[spec.name][spec.platform] = spec
end end
result.map(&:last).map(&:values).flatten.reject do |spec| result.map(&:last).flatten.sort_by{|tup| tup.name }
minimum = native[spec.name]
minimum && spec.version < minimum
end.sort_by{|tup| tup.name }
end end
## ##
@ -1552,7 +1558,6 @@ class Gem::Specification < Gem::BasicSpecification
def build_extensions # :nodoc: def build_extensions # :nodoc:
return if default_gem? return if default_gem?
return if extensions.empty? return if extensions.empty?
return if installed_by_version < Gem::Version.new('2.2.0.preview.2')
return if File.exist? gem_build_complete_path return if File.exist? gem_build_complete_path
return if !File.writable?(base_dir) return if !File.writable?(base_dir)
return if !File.exist?(File.join(base_dir, 'extensions')) return if !File.exist?(File.join(base_dir, 'extensions'))
@ -2123,7 +2128,6 @@ class Gem::Specification < Gem::BasicSpecification
def missing_extensions? def missing_extensions?
return false if default_gem? return false if default_gem?
return false if extensions.empty? return false if extensions.empty?
return false if installed_by_version < Gem::Version.new('2.2.0.preview.2')
return false if File.exist? gem_build_complete_path return false if File.exist? gem_build_complete_path
true true
@ -2548,7 +2552,7 @@ class Gem::Specification < Gem::BasicSpecification
begin begin
dependencies.each do |dep| dependencies.each do |dep|
next unless dep.runtime? next unless dep.runtime?
dep.to_specs.each do |dep_spec| dep.matching_specs(true).each do |dep_spec|
next if visited.has_key?(dep_spec) next if visited.has_key?(dep_spec)
visited[dep_spec] = true visited[dep_spec] = true
trail.push(dep_spec) trail.push(dep_spec)

View File

@ -301,7 +301,9 @@ class Gem::TestCase < Minitest::Test
def setup def setup
@orig_env = ENV.to_hash @orig_env = ENV.to_hash
@tmp = Dir.mktmpdir("tmp", Dir.pwd) @tmp = File.expand_path("tmp")
FileUtils.mkdir_p @tmp
ENV['GEM_VENDOR'] = nil ENV['GEM_VENDOR'] = nil
ENV['GEMRC'] = nil ENV['GEMRC'] = nil
@ -310,7 +312,6 @@ class Gem::TestCase < Minitest::Test
ENV['XDG_DATA_HOME'] = nil ENV['XDG_DATA_HOME'] = nil
ENV['SOURCE_DATE_EPOCH'] = nil ENV['SOURCE_DATE_EPOCH'] = nil
ENV['BUNDLER_VERSION'] = nil ENV['BUNDLER_VERSION'] = nil
ENV["TMPDIR"] = @tmp
@current_dir = Dir.pwd @current_dir = Dir.pwd
@fetcher = nil @fetcher = nil
@ -321,13 +322,10 @@ class Gem::TestCase < Minitest::Test
# capture output # capture output
Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new
tmpdir = File.realpath Dir.tmpdir @tempdir = Dir.mktmpdir("test_rubygems_", @tmp)
tmpdir.tap(&Gem::UNTAINT)
@tempdir = File.join(tmpdir, "test_rubygems_#{$$}")
@tempdir.tap(&Gem::UNTAINT) @tempdir.tap(&Gem::UNTAINT)
FileUtils.mkdir_p @tempdir ENV["TMPDIR"] = @tempdir
@orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE @orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE
Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE
@ -366,7 +364,9 @@ class Gem::TestCase < Minitest::Test
Dir.chdir @tempdir Dir.chdir @tempdir
ENV['HOME'] = @userhome ENV['HOME'] = @userhome
Gem.instance_variable_set :@config_file, nil
Gem.instance_variable_set :@user_home, nil Gem.instance_variable_set :@user_home, nil
Gem.instance_variable_set :@config_home, nil
Gem.instance_variable_set :@data_home, nil Gem.instance_variable_set :@data_home, nil
Gem.instance_variable_set :@gemdeps, nil Gem.instance_variable_set :@gemdeps, nil
Gem.instance_variable_set :@env_requirements_by_name, nil Gem.instance_variable_set :@env_requirements_by_name, nil
@ -449,7 +449,6 @@ class Gem::TestCase < Minitest::Test
Dir.chdir @current_dir Dir.chdir @current_dir
FileUtils.rm_rf @tempdir FileUtils.rm_rf @tempdir
FileUtils.rm_rf @tmp
ENV.replace(@orig_env) ENV.replace(@orig_env)

View File

@ -138,12 +138,12 @@ RSpec.describe "bundle executable" do
it "doesn't print defaults" do it "doesn't print defaults" do
install_gemfile "", :verbose => true install_gemfile "", :verbose => true
expect(out).to start_with("Running `bundle install --retry 0 --verbose` with bundler #{Bundler::VERSION}") expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end end
it "doesn't print defaults" do it "doesn't print defaults" do
install_gemfile "", :verbose => true install_gemfile "", :verbose => true
expect(out).to start_with("Running `bundle install --retry 0 --verbose` with bundler #{Bundler::VERSION}") expect(out).to start_with("Running `bundle install --verbose` with bundler #{Bundler::VERSION}")
end end
end end

Some files were not shown because too many files have changed in this diff Show More