Merge RubyGems and Bundler master

from 0635c1423d
This commit is contained in:
Hiroshi SHIBATA 2023-01-10 13:53:41 +09:00
parent 89fb61f9a3
commit a43f1d90c2
Notes: git 2023-01-10 06:53:36 +00:00
64 changed files with 529 additions and 361 deletions

View File

@ -40,7 +40,7 @@ module Bundler
SUDO_MUTEX = Thread::Mutex.new SUDO_MUTEX = Thread::Mutex.new
SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash].freeze SAFE_MARSHAL_CLASSES = [Symbol, TrueClass, String, Array, Hash].freeze
SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed.".freeze SAFE_MARSHAL_ERROR = "Unexpected class %s present in marshaled data. Only %s are allowed."
SAFE_MARSHAL_PROC = proc do |object| SAFE_MARSHAL_PROC = proc do |object|
object.tap do object.tap do
unless SAFE_MARSHAL_CLASSES.include?(object.class) unless SAFE_MARSHAL_CLASSES.include?(object.class)
@ -506,7 +506,7 @@ EOF
if File.file?(executable) && File.executable?(executable) if File.file?(executable) && File.executable?(executable)
executable executable
elsif paths = ENV["PATH"] elsif paths = ENV["PATH"]
quote = '"'.freeze quote = '"'
paths.split(File::PATH_SEPARATOR).find do |path| paths.split(File::PATH_SEPARATOR).find do |path|
path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote) path = path[1..-2] if path.start_with?(quote) && path.end_with?(quote)
executable_path = File.expand_path(executable, path) executable_path = File.expand_path(executable, path)

View File

@ -79,6 +79,7 @@ module Bundler
@locked_bundler_version = nil @locked_bundler_version = nil
@locked_ruby_version = nil @locked_ruby_version = nil
@new_platform = nil @new_platform = nil
@removed_platform = nil
if lockfile && File.exist?(lockfile) if lockfile && File.exist?(lockfile)
@lockfile_contents = Bundler.read_file(lockfile) @lockfile_contents = Bundler.read_file(lockfile)
@ -129,7 +130,7 @@ module Bundler
end end
@unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version) @unlocking ||= @unlock[:ruby] ||= (!@locked_ruby_version ^ !@ruby_version)
add_current_platform unless current_ruby_platform_locked? || Bundler.frozen_bundle? add_current_platform unless Bundler.frozen_bundle?
converge_path_sources_to_gemspec_sources converge_path_sources_to_gemspec_sources
@path_changes = converge_paths @path_changes = converge_paths
@ -267,7 +268,7 @@ module Bundler
SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps)) SpecSet.new(filter_specs(@locked_specs, @dependencies - deleted_deps))
else else
Bundler.ui.debug "Found no changes, using resolution from the lockfile" Bundler.ui.debug "Found no changes, using resolution from the lockfile"
if @locked_gems.may_include_redundant_platform_specific_gems? if @removed_platform || @locked_gems.may_include_redundant_platform_specific_gems?
SpecSet.new(filter_specs(@locked_specs, @dependencies)) SpecSet.new(filter_specs(@locked_specs, @dependencies))
else else
@locked_specs @locked_specs
@ -446,7 +447,9 @@ module Bundler
end end
def remove_platform(platform) def remove_platform(platform)
return if @platforms.delete(Gem::Platform.new(platform)) removed_platform = @platforms.delete(Gem::Platform.new(platform))
@removed_platform ||= removed_platform
return if removed_platform
raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}" raise InvalidOption, "Unable to remove the platform `#{platform}` since the only platforms are #{@platforms.join ", "}"
end end
@ -584,6 +587,8 @@ module Bundler
end end
def add_current_platform def add_current_platform
return if current_ruby_platform_locked?
add_platform(local_platform) add_platform(local_platform)
end end

View File

@ -277,8 +277,8 @@ module Bundler
if repo_name =~ GITHUB_PULL_REQUEST_URL if repo_name =~ GITHUB_PULL_REQUEST_URL
{ {
"git" => "https://github.com/#{$1}.git", "git" => "https://github.com/#{$1}.git",
"branch" => "refs/pull/#{$2}/head", "branch" => nil,
"ref" => nil, "ref" => "refs/pull/#{$2}/head",
"tag" => nil, "tag" => nil,
} }
else else

View File

@ -2,7 +2,7 @@
module Bundler module Bundler
class EnvironmentPreserver class EnvironmentPreserver
INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL".freeze INTENTIONALLY_NIL = "BUNDLER_ENVIRONMENT_PRESERVER_INTENTIONALLY_NIL"
BUNDLER_KEYS = %w[ BUNDLER_KEYS = %w[
BUNDLE_BIN_PATH BUNDLE_BIN_PATH
BUNDLE_GEMFILE BUNDLE_GEMFILE
@ -16,7 +16,7 @@ module Bundler
RUBYLIB RUBYLIB
RUBYOPT RUBYOPT
].map(&:freeze).freeze ].map(&:freeze).freeze
BUNDLER_PREFIX = "BUNDLER_ORIG_".freeze BUNDLER_PREFIX = "BUNDLER_ORIG_"
def self.from_env def self.from_env
new(env_to_hash(ENV), BUNDLER_KEYS) new(env_to_hash(ENV), BUNDLER_KEYS)

View File

@ -13,8 +13,8 @@ module Bundler
attr_reader :specs, :all_specs, :sources attr_reader :specs, :all_specs, :sources
protected :specs, :all_specs protected :specs, :all_specs
RUBY = "ruby".freeze RUBY = "ruby"
NULL = "\0".freeze NULL = "\0"
def initialize def initialize
@sources = [] @sources = []

View File

@ -2,7 +2,7 @@
module Bundler module Bundler
class Injector class Injector
INJECTED_GEMS = "injected gems".freeze INJECTED_GEMS = "injected gems"
def self.inject(new_deps, options = {}) def self.inject(new_deps, options = {})
injector = new(new_deps, options) injector = new(new_deps, options)

View File

@ -16,7 +16,6 @@ module Bundler
@dependencies = [] @dependencies = []
@platform = platform || Gem::Platform::RUBY @platform = platform || Gem::Platform::RUBY
@source = source @source = source
@specification = nil
@force_ruby_platform = default_force_ruby_platform @force_ruby_platform = default_force_ruby_platform
end end
@ -80,37 +79,41 @@ module Bundler
def materialize_for_installation def materialize_for_installation
source.local! source.local!
candidates = if source.is_a?(Source::Path) || !ruby_platform_materializes_to_ruby_platform? matching_specs = source.specs.search(use_exact_resolved_specifications? ? self : [name, version])
return self if matching_specs.empty?
candidates = if use_exact_resolved_specifications?
matching_specs
else
target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform target_platform = ruby_platform_materializes_to_ruby_platform? ? platform : local_platform
GemHelpers.select_best_platform_match(source.specs.search([name, version]), target_platform) installable_candidates = GemHelpers.select_best_platform_match(matching_specs, target_platform)
else
source.specs.search(self)
end
return self if candidates.empty? specification = __materialize__(installable_candidates)
return specification unless specification.nil?
if target_platform != platform
installable_candidates = GemHelpers.select_best_platform_match(matching_specs, platform)
end
installable_candidates
end
__materialize__(candidates) __materialize__(candidates)
end end
def __materialize__(candidates) def __materialize__(candidates)
@specification = begin search = candidates.reverse.find do |spec|
search = candidates.reverse.find do |spec| spec.is_a?(StubSpecification) ||
spec.is_a?(StubSpecification) || (spec.matches_current_ruby? &&
(spec.matches_current_ruby? && spec.matches_current_rubygems?)
spec.matches_current_rubygems?)
end
if search.nil? && Bundler.frozen_bundle?
search = candidates.last
else
search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification))
end
search
end end
end if search.nil? && Bundler.frozen_bundle?
search = candidates.last
def respond_to?(*args) else
super || @specification ? @specification.respond_to?(*args) : nil search.dependencies = dependencies if search && search.full_name == full_name && (search.is_a?(RemoteSpecification) || search.is_a?(EndpointSpecification))
end
search
end end
def to_s def to_s
@ -132,16 +135,8 @@ module Bundler
private private
def to_ary def use_exact_resolved_specifications?
nil @use_exact_resolved_specifications ||= !source.is_a?(Source::Path) && ruby_platform_materializes_to_ruby_platform?
end
def method_missing(method, *args, &blk)
raise "LazySpecification has not been materialized yet (calling :#{method} #{args.inspect})" unless @specification
return super unless respond_to?(method)
@specification.send(method, *args, &blk)
end end
# #

View File

@ -45,7 +45,7 @@ module Bundler
# gems with the same name, but different platform # gems with the same name, but different platform
# are ordered consistently # are ordered consistently
specs.sort_by(&:full_name).each do |spec| specs.sort_by(&:full_name).each do |spec|
next if spec.name == "bundler".freeze next if spec.name == "bundler"
out << spec.to_lock out << spec.to_lock
end end
end end

View File

@ -4,15 +4,15 @@ module Bundler
class LockfileParser class LockfileParser
attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version attr_reader :sources, :dependencies, :specs, :platforms, :bundler_version, :ruby_version
BUNDLED = "BUNDLED WITH".freeze BUNDLED = "BUNDLED WITH"
DEPENDENCIES = "DEPENDENCIES".freeze DEPENDENCIES = "DEPENDENCIES"
PLATFORMS = "PLATFORMS".freeze PLATFORMS = "PLATFORMS"
RUBY = "RUBY VERSION".freeze RUBY = "RUBY VERSION"
GIT = "GIT".freeze GIT = "GIT"
GEM = "GEM".freeze GEM = "GEM"
PATH = "PATH".freeze PATH = "PATH"
PLUGIN = "PLUGIN SOURCE".freeze PLUGIN = "PLUGIN SOURCE"
SPECS = " specs:".freeze SPECS = " specs:"
OPTIONS = /^ ([a-z]+): (.*)$/i.freeze OPTIONS = /^ ([a-z]+): (.*)$/i.freeze
SOURCE = [GIT, GEM, PATH, PLUGIN].freeze SOURCE = [GIT, GEM, PATH, PLUGIN].freeze

View File

@ -15,7 +15,7 @@ module Bundler
class UnknownSourceError < PluginError; end class UnknownSourceError < PluginError; end
class PluginInstallError < PluginError; end class PluginInstallError < PluginError; end
PLUGIN_FILE_NAME = "plugins.rb".freeze PLUGIN_FILE_NAME = "plugins.rb"
module_function module_function

View File

@ -337,7 +337,8 @@ module Bundler
def requirement_to_range(requirement) def requirement_to_range(requirement)
ranges = requirement.requirements.map do |(op, version)| ranges = requirement.requirements.map do |(op, version)|
ver = Resolver::Candidate.new(version) ver = Resolver::Candidate.new(version).generic!
platform_ver = Resolver::Candidate.new(version).platform_specific!
case op case op
when "~>" when "~>"
@ -345,17 +346,17 @@ module Bundler
bump = Resolver::Candidate.new(version.bump.to_s + ".A") bump = Resolver::Candidate.new(version.bump.to_s + ".A")
PubGrub::VersionRange.new(:name => name, :min => ver, :max => bump, :include_min => true) PubGrub::VersionRange.new(:name => name, :min => ver, :max => bump, :include_min => true)
when ">" when ">"
PubGrub::VersionRange.new(:min => ver) PubGrub::VersionRange.new(:min => platform_ver)
when ">=" when ">="
PubGrub::VersionRange.new(:min => ver, :include_min => true) PubGrub::VersionRange.new(:min => ver, :include_min => true)
when "<" when "<"
PubGrub::VersionRange.new(:max => ver) PubGrub::VersionRange.new(:max => ver)
when "<=" when "<="
PubGrub::VersionRange.new(:max => ver, :include_max => true) PubGrub::VersionRange.new(:max => platform_ver, :include_max => true)
when "=" when "="
PubGrub::VersionRange.new(:min => ver, :max => ver, :include_min => true, :include_max => true) PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true)
when "!=" when "!="
PubGrub::VersionRange.new(:min => ver, :max => ver, :include_min => true, :include_max => true).invert PubGrub::VersionRange.new(:min => ver, :max => platform_ver, :include_min => true, :include_max => true).invert
else else
raise "bad version specifier: #{op}" raise "bad version specifier: #{op}"
end end

View File

@ -41,6 +41,18 @@ module Bundler
@spec_group.to_specs(package.force_ruby_platform?) @spec_group.to_specs(package.force_ruby_platform?)
end end
def generic!
@ruby_only = true
self
end
def platform_specific!
@ruby_only = false
self
end
def prerelease? def prerelease?
@version.prerelease? @version.prerelease?
end end
@ -53,27 +65,20 @@ module Bundler
[@version, @ruby_only ? -1 : 1] [@version, @ruby_only ? -1 : 1]
end end
def canonical?
!@spec_group.empty?
end
def <=>(other) def <=>(other)
return unless other.is_a?(self.class) return unless other.is_a?(self.class)
return @version <=> other.version unless canonical? && other.canonical?
sort_obj <=> other.sort_obj sort_obj <=> other.sort_obj
end end
def ==(other) def ==(other)
return unless other.is_a?(self.class) return unless other.is_a?(self.class)
return @version == other.version unless canonical? && other.canonical?
sort_obj == other.sort_obj sort_obj == other.sort_obj
end end
def eql?(other) def eql?(other)
return unless other.is_a?(self.class) return unless other.is_a?(self.class)
return @version.eql?(other.version) unless canonical? || other.canonical?
sort_obj.eql?(other.sort_obj) sort_obj.eql?(other.sort_obj)
end end

View File

@ -11,7 +11,7 @@ module Bundler
protected :original_path protected :original_path
DEFAULT_GLOB = "{,*,*/*}.gemspec".freeze DEFAULT_GLOB = "{,*,*/*}.gemspec"
def initialize(options) def initialize(options)
@options = options.dup @options = options.dup

View File

@ -1,5 +1,5 @@
# This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is # This Cargo.toml is here to let externals tools (IDEs, etc.) know that this is
# a Rust project. Your extensions depedencies should be added to the Cargo.toml # a Rust project. Your extensions dependencies should be added to the Cargo.toml
# in the ext/ directory. # in the ext/ directory.
[workspace] [workspace]

View File

@ -20,6 +20,10 @@ module Bundler::PubGrub
range.eql?(other.range) range.eql?(other.range)
end end
def ==(other)
package == other.package && range == other.range
end
class << self class << self
def exact(package, version) def exact(package, version)
range = VersionRange.new(min: version, max: version, include_min: true, include_max: true) range = VersionRange.new(min: version, max: version, include_min: true, include_max: true)

View File

@ -397,7 +397,7 @@ module Bundler::PubGrub
def constraints def constraints
return ["any"] if any? return ["any"] if any?
return ["= #{min}"] if min == max return ["= #{min}"] if min.to_s == max.to_s
c = [] c = []
c << "#{include_min ? ">=" : ">"} #{min}" if min c << "#{include_min ? ">=" : ">"} #{min}" if min

View File

@ -148,7 +148,7 @@ module Bundler::PubGrub
while !ranges.empty? while !ranges.empty?
ne = [] ne = []
range = ranges.shift range = ranges.shift
while !ranges.empty? && ranges[0].min == range.max while !ranges.empty? && ranges[0].min.to_s == range.max.to_s
ne << range.max ne << range.max
range = range.span(ranges.shift) range = range.span(ranges.shift)
end end

View File

@ -8,7 +8,7 @@
require "rbconfig" require "rbconfig"
module Gem module Gem
VERSION = "3.5.0.dev".freeze VERSION = "3.5.0.dev"
end end
# Must be first since it unloads the prelude from 1.9.2 # Must be first since it unloads the prelude from 1.9.2
@ -822,7 +822,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
def self.env_requirement(gem_name) def self.env_requirement(gem_name)
@env_requirements_by_name ||= {} @env_requirements_by_name ||= {}
@env_requirements_by_name[gem_name] ||= begin @env_requirements_by_name[gem_name] ||= begin
req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0".freeze req = ENV["GEM_REQUIREMENT_#{gem_name.upcase}"] || ">= 0"
Gem::Requirement.create(req) Gem::Requirement.create(req)
end end
end end
@ -1290,7 +1290,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
## ##
# Location of Marshal quick gemspecs on remote repositories # Location of Marshal quick gemspecs on remote repositories
MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/".freeze MARSHAL_SPEC_DIR = "quick/Marshal.#{Gem.marshal_version}/"
autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__) autoload :ConfigFile, File.expand_path("rubygems/config_file", __dir__)
autoload :Dependency, File.expand_path("rubygems/dependency", __dir__) autoload :Dependency, File.expand_path("rubygems/dependency", __dir__)

View File

@ -21,7 +21,7 @@ module Gem::BundlerVersionFinder
end end
def self.bundle_update_bundler_version def self.bundle_update_bundler_version
return unless File.basename($0) == "bundle".freeze return unless File.basename($0) == "bundle"
return unless "update".start_with?(ARGV.first || " ") return unless "update".start_with?(ARGV.first || " ")
bundler_version = nil bundler_version = nil
update_index = nil update_index = nil

View File

@ -624,7 +624,7 @@ class Gem::Command
# :stopdoc: # :stopdoc:
HELP = <<-HELP.freeze HELP = <<-HELP
RubyGems is a package manager for Ruby. RubyGems is a package manager for Ruby.
Usage: Usage:

View File

@ -3,7 +3,7 @@ require_relative "../command"
class Gem::Commands::HelpCommand < Gem::Command class Gem::Commands::HelpCommand < Gem::Command
# :stopdoc: # :stopdoc:
EXAMPLES = <<-EOF.freeze EXAMPLES = <<-EOF
Some examples of 'gem' usage. Some examples of 'gem' usage.
* Install 'rake', either from local directory or remote server: * Install 'rake', either from local directory or remote server:
@ -52,7 +52,7 @@ Some examples of 'gem' usage.
gem update --system gem update --system
EOF EOF
GEM_DEPENDENCIES = <<-EOF.freeze GEM_DEPENDENCIES = <<-EOF
A gem dependencies file allows installation of a consistent set of gems across A gem dependencies file allows installation of a consistent set of gems across
multiple environments. The RubyGems implementation is designed to be multiple environments. The RubyGems implementation is designed to be
compatible with Bundler's Gemfile format. You can see additional compatible with Bundler's Gemfile format. You can see additional
@ -229,7 +229,7 @@ default. This may be overridden with the :development_group option:
EOF EOF
PLATFORMS = <<-'EOF'.freeze PLATFORMS = <<-'EOF'
RubyGems platforms are composed of three parts, a CPU, an OS, and a RubyGems platforms are composed of three parts, a CPU, an OS, and a
version. These values are taken from values in rbconfig.rb. You can view version. These values are taken from values in rbconfig.rb. You can view
your current platform by running `gem environment`. your current platform by running `gem environment`.

View File

@ -15,7 +15,7 @@ The owner command lets you add and remove owners of a gem on a push
server (the default is https://rubygems.org). Multiple owners can be server (the default is https://rubygems.org). Multiple owners can be
added or removed at the same time, if the flag is given multiple times. added or removed at the same time, if the flag is given multiple times.
The supported user identifiers are dependant on the push server. The supported user identifiers are dependent on the push server.
For rubygems.org, both e-mail and handle are supported, even though the For rubygems.org, both e-mail and handle are supported, even though the
user identifier field is called "email". user identifier field is called "email".

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
module Gem module Gem
DEFAULT_HOST = "https://rubygems.org".freeze DEFAULT_HOST = "https://rubygems.org"
@post_install_hooks ||= [] @post_install_hooks ||= []
@done_installing_hooks ||= [] @done_installing_hooks ||= []

View File

@ -299,7 +299,7 @@ class Gem::Dependency
end end
def prioritizes_bundler? def prioritizes_bundler?
name == "bundler".freeze && !specific? name == "bundler" && !specific?
end end
def to_specs def to_specs

View File

@ -203,7 +203,7 @@ class Gem::Ext::CargoBuilder < Gem::Ext::Builder
!!Gem::WIN_PATTERNS.find {|r| target_platform =~ r } !!Gem::WIN_PATTERNS.find {|r| target_platform =~ r }
end end
# Interpolate substition vars in the arg (i.e. $(DEFFILE)) # Interpolate substitution vars in the arg (i.e. $(DEFFILE))
def maybe_resolve_ldflag_variable(input_arg, dest_dir) def maybe_resolve_ldflag_variable(input_arg, dest_dir)
var_matches = input_arg.match(/\$\((\w+)\)/) var_matches = input_arg.match(/\$\((\w+)\)/)

View File

@ -158,7 +158,7 @@ class Gem::Platform
# Of note, this method is not commutative. Indeed the OS 'linux' has a # Of note, this method is not commutative. Indeed the OS 'linux' has a
# special case: the version is the libc name, yet while "no version" stands # special case: the version is the libc name, yet while "no version" stands
# as a wildcard for a binary gem platform (as for other OSes), for the # as a wildcard for a binary gem platform (as for other OSes), for the
# runtime platform "no version" stands for 'gnu'. To be able to disinguish # runtime platform "no version" stands for 'gnu'. To be able to distinguish
# these, the method receiver is the gem platform, while the argument is # these, the method receiver is the gem platform, while the argument is
# the runtime platform. # the runtime platform.
# #
@ -235,11 +235,11 @@ class Gem::Platform
# A pure-Ruby gem that may use Gem::Specification#extensions to build # A pure-Ruby gem that may use Gem::Specification#extensions to build
# binary files. # binary files.
RUBY = "ruby".freeze RUBY = "ruby"
## ##
# A platform-specific gem that is built for the packaging Ruby's platform. # A platform-specific gem that is built for the packaging Ruby's platform.
# This will be replaced with Gem::Platform::local. # This will be replaced with Gem::Platform::local.
CURRENT = "current".freeze CURRENT = "current"
end end

View File

@ -22,7 +22,7 @@ class Gem::Requirement
SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc: SOURCE_SET_REQUIREMENT = Struct.new(:for_lockfile).new "!" # :nodoc:
quoted = OPS.keys.map {|k| Regexp.quote k }.join "|" quoted = OPS.keys.map {|k| Regexp.quote k }.join "|"
PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*".freeze # :nodoc: PATTERN_RAW = "\\s*(#{quoted})?\\s*(#{Gem::Version::VERSION_PATTERN})\\s*" # :nodoc:
## ##
# A regular expression that matches a requirement # A regular expression that matches a requirement

View File

@ -32,7 +32,7 @@ class Gem::Resolver::Stats
@iterations += 1 @iterations += 1
end end
PATTERN = "%20s: %d\n".freeze PATTERN = "%20s: %d\n"
def display def display
$stdout.puts "=== Resolver Statistics ===" $stdout.puts "=== Resolver Statistics ==="

View File

@ -6,10 +6,10 @@
class Gem::StubSpecification < Gem::BasicSpecification class Gem::StubSpecification < Gem::BasicSpecification
# :nodoc: # :nodoc:
PREFIX = "# stub: ".freeze PREFIX = "# stub: "
# :nodoc: # :nodoc:
OPEN_MODE = "r:UTF-8:-".freeze OPEN_MODE = "r:UTF-8:-"
class StubLine # :nodoc: all class StubLine # :nodoc: all
attr_reader :name, :version, :platform, :require_paths, :extensions, attr_reader :name, :version, :platform, :require_paths, :extensions,
@ -19,9 +19,9 @@ class Gem::StubSpecification < Gem::BasicSpecification
# These are common require paths. # These are common require paths.
REQUIRE_PATHS = { # :nodoc: REQUIRE_PATHS = { # :nodoc:
"lib" => "lib".freeze, "lib" => "lib",
"test" => "test".freeze, "test" => "test",
"ext" => "ext".freeze, "ext" => "ext",
}.freeze }.freeze
# These are common require path lists. This hash is used to optimize # These are common require path lists. This hash is used to optimize
@ -33,7 +33,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
}.freeze }.freeze
def initialize(data, extensions) def initialize(data, extensions)
parts = data[PREFIX.length..-1].split(" ".freeze, 4) parts = data[PREFIX.length..-1].split(" ", 4)
@name = parts[0].freeze @name = parts[0].freeze
@version = if Gem::Version.correct?(parts[1]) @version = if Gem::Version.correct?(parts[1])
Gem::Version.new(parts[1]) Gem::Version.new(parts[1])
@ -50,7 +50,7 @@ class Gem::StubSpecification < Gem::BasicSpecification
end end
path_list = parts.last path_list = parts.last
@require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0".freeze).map! do |x| @require_paths = REQUIRE_PATH_LIST[path_list] || path_list.split("\0").map! do |x|
REQUIRE_PATHS[x] || x REQUIRE_PATHS[x] || x
end end
end end

View File

@ -9,7 +9,7 @@ module Gem::Text
# Remove any non-printable characters and make the text suitable for # Remove any non-printable characters and make the text suitable for
# printing. # printing.
def clean_text(text) def clean_text(text)
text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".".freeze) text.gsub(/[\000-\b\v-\f\016-\037\177]/, ".")
end end
def truncate_text(text, description, max_length = 100_000) def truncate_text(text, description, max_length = 100_000)

View File

@ -4,8 +4,8 @@ require_relative "../text"
class Gem::Licenses class Gem::Licenses
extend Gem::Text extend Gem::Text
NONSTANDARD = "Nonstandard".freeze NONSTANDARD = "Nonstandard"
LICENSE_REF = "LicenseRef-.+".freeze LICENSE_REF = "LicenseRef-.+"
# Software Package Data Exchange (SPDX) standard open-source software # Software Package Data Exchange (SPDX) standard open-source software
# license identifiers # license identifiers

View File

@ -155,7 +155,7 @@ require_relative "deprecate"
class Gem::Version class Gem::Version
include Comparable include Comparable
VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?'.freeze # :nodoc: VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc:
ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze # :nodoc: ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})?\s*\z/.freeze # :nodoc:
## ##

View File

@ -29,7 +29,7 @@ RSpec.describe Bundler::Dsl do
subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5") subject.gem("sparks", :github => "https://github.com/indirect/sparks/pull/5")
github_uri = "https://github.com/indirect/sparks.git" github_uri = "https://github.com/indirect/sparks.git"
expect(subject.dependencies.first.source.uri).to eq(github_uri) expect(subject.dependencies.first.source.uri).to eq(github_uri)
expect(subject.dependencies.first.source.branch).to eq("refs/pull/5/head") expect(subject.dependencies.first.source.ref).to eq("refs/pull/5/head")
end end
it "rejects :github PR URI with a branch, ref or tag" do it "rejects :github PR URI with a branch, ref or tag" do

View File

@ -140,7 +140,7 @@ RSpec.describe Bundler::Plugin::Index do
describe "after conflict" do describe "after conflict" do
let(:commands) { ["foo"] } let(:commands) { ["foo"] }
let(:sources) { ["bar"] } let(:sources) { ["bar"] }
let(:hooks) { ["hoook"] } let(:hooks) { ["thehook"] }
shared_examples "it cleans up" do shared_examples "it cleans up" do
it "the path" do it "the path" do
@ -156,7 +156,7 @@ RSpec.describe Bundler::Plugin::Index do
end end
it "the hook" do it "the hook" do
expect(index.hook_plugins("xhoook")).to be_empty expect(index.hook_plugins("xthehook")).to be_empty
end end
end end
@ -164,7 +164,7 @@ RSpec.describe Bundler::Plugin::Index do
before do before do
expect do expect do
path = lib_path("cplugin") path = lib_path("cplugin")
index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["xbar"], ["xhoook"]) index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["xbar"], ["xthehook"])
end.to raise_error(Index::CommandConflict) end.to raise_error(Index::CommandConflict)
end end
@ -175,7 +175,7 @@ RSpec.describe Bundler::Plugin::Index do
before do before do
expect do expect do
path = lib_path("cplugin") path = lib_path("cplugin")
index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["xfoo"], ["bar"], ["xhoook"]) index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["xfoo"], ["bar"], ["xthehook"])
end.to raise_error(Index::SourceConflict) end.to raise_error(Index::SourceConflict)
end end
@ -186,7 +186,7 @@ RSpec.describe Bundler::Plugin::Index do
before do before do
expect do expect do
path = lib_path("cplugin") path = lib_path("cplugin")
index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["bar"], ["xhoook"]) index.register_plugin("cplugin", path.to_s, [path.join("lib").to_s], ["foo"], ["bar"], ["xthehook"])
end.to raise_error(Index::CommandConflict) end.to raise_error(Index::CommandConflict)
end end

View File

@ -3,8 +3,19 @@
RSpec.describe Bundler::Resolver::Candidate do RSpec.describe Bundler::Resolver::Candidate do
it "compares fine" do it "compares fine" do
version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }]) version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
version2 = described_class.new("1.12.5") version2 = described_class.new("1.12.5") # passing no specs creates a platform specific candidate, so sorts higher
expect(version1 >= version2).to be true expect(version2 >= version1).to be true
expect(version1.generic! == version2.generic!).to be true
expect(version1.platform_specific! == version2.platform_specific!).to be true
expect(version1.platform_specific! >= version2.generic!).to be true
expect(version2.platform_specific! >= version1.generic!).to be true
version1 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::RUBY }])
version2 = described_class.new("1.12.5", :specs => [Gem::Specification.new("foo", "1.12.5") {|s| s.platform = Gem::Platform::X64_LINUX }])
expect(version2 >= version1).to be true
end end
end end

View File

@ -27,7 +27,7 @@ RSpec.describe Bundler::Settings do
"gem.mit" => "false", "gem.mit" => "false",
"gem.test" => "minitest", "gem.test" => "minitest",
"thingy" => <<-EOS.tr("\n", " "), "thingy" => <<-EOS.tr("\n", " "),
--asdf --fdsa --ty=oh man i hope this doesnt break bundler because --asdf --fdsa --ty=oh man i hope this doesn't break bundler because
that would suck --ehhh=oh geez it looks like i might have broken bundler somehow that would suck --ehhh=oh geez it looks like i might have broken bundler somehow
--very-important-option=DontDeleteRoo --very-important-option=DontDeleteRoo
--very-important-option=DontDeleteRoo --very-important-option=DontDeleteRoo

View File

@ -288,7 +288,7 @@ RSpec.describe Bundler::SharedHelpers do
if Gem.respond_to?(:path_separator) if Gem.respond_to?(:path_separator)
allow(Gem).to receive(:path_separator).and_return(":") allow(Gem).to receive(:path_separator).and_return(":")
else else
stub_const("File::PATH_SEPARATOR", ":".freeze) stub_const("File::PATH_SEPARATOR", ":")
end end
allow(Bundler).to receive(:bundle_path) { Pathname.new("so:me/dir/bin") } allow(Bundler).to receive(:bundle_path) { Pathname.new("so:me/dir/bin") }
expect { subject.send(:validate_bundle_path) }.to raise_error( expect { subject.send(:validate_bundle_path) }.to raise_error(

View File

@ -144,7 +144,7 @@ RSpec.describe "bundle add" do
end end
describe "with --github" do describe "with --github" do
it "adds dependency with specified github source" do it "adds dependency with specified github source", :realworld do
bundle "add rake --github=ruby/rake" bundle "add rake --github=ruby/rake"
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake"}) expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake"})
@ -152,7 +152,7 @@ RSpec.describe "bundle add" do
end end
describe "with --github and --branch" do describe "with --github and --branch" do
it "adds dependency with specified github source and branch" do it "adds dependency with specified github source and branch", :realworld do
bundle "add rake --github=ruby/rake --branch=master" bundle "add rake --github=ruby/rake --branch=master"
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :branch => "master"}) expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :branch => "master"})
@ -160,7 +160,7 @@ RSpec.describe "bundle add" do
end end
describe "with --github and --ref" do describe "with --github and --ref" do
it "adds dependency with specified github source and ref" do it "adds dependency with specified github source and ref", :realworld do
bundle "add rake --github=ruby/rake --ref=5c60da8" bundle "add rake --github=ruby/rake --ref=5c60da8"
expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :ref => "5c60da8"}) expect(bundled_app_gemfile.read).to match(%r{gem "rake", "~> 13\.0", :github => "ruby\/rake", :ref => "5c60da8"})

View File

@ -188,7 +188,7 @@ RSpec.describe "bundle binstubs <gem>" do
lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.3.0") lockfile lockfile.gsub(/BUNDLED WITH\n .*$/m, "BUNDLED WITH\n 2.3.0")
end end
it "installs and runs the exact version of bundler", :rubygems => ">= 3.3.0.dev" do it "installs and runs the exact version of bundler", :rubygems => ">= 3.3.0.dev", :realworld => true do
sys_exec "bin/bundle install --verbose", :artifice => "vcr" sys_exec "bin/bundle install --verbose", :artifice => "vcr"
expect(exitstatus).not_to eq(42) expect(exitstatus).not_to eq(42)
expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.") expect(out).to include("Bundler 2.999.999 is running, but your lockfile was generated with 2.3.0. Installing Bundler 2.3.0 and restarting using that version.")
@ -224,7 +224,7 @@ RSpec.describe "bundle binstubs <gem>" do
context "when update --bundler is called" do context "when update --bundler is called" do
before { lockfile.gsub(system_bundler_version, "1.1.1") } before { lockfile.gsub(system_bundler_version, "1.1.1") }
it "calls through to the latest bundler version" do it "calls through to the latest bundler version", :realworld do
sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" } sys_exec "bin/bundle update --bundler", :env => { "DEBUG" => "1" }
using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out) using_bundler_line = /Using bundler ([\w\.]+)\n/.match(out)
expect(using_bundler_line).to_not be_nil expect(using_bundler_line).to_not be_nil

View File

@ -625,7 +625,7 @@ RSpec.describe "bundle clean" do
expect(out).to eq("1.0") expect(out).to eq("1.0")
end end
it "when using --force, it doesn't remove default gem binaries" do it "when using --force, it doesn't remove default gem binaries", :realworld do
skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0" skip "does not work on old rubies because the realworld gems that need to be installed don't support them" if RUBY_VERSION < "2.7.0"
skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2 skip "does not work on rubygems versions where `--install_dir` doesn't respect --default" unless Gem::Installer.for_spec(loaded_gemspec, :install_dir => "/foo").default_spec_file == "/foo/specifications/default/bundler-#{Bundler::VERSION}.gemspec" # Since rubygems 3.2.0.rc.2

View File

@ -134,7 +134,7 @@ RSpec.describe "bundle doctor" do
end end
end end
context "when home contains filesname with special characters" do context "when home contains filenames with special characters" do
it "escape filename before command execute" do it "escape filename before command execute" do
doctor = Bundler::CLI::Doctor.new({}) doctor = Bundler::CLI::Doctor.new({})
expect(doctor).to receive(:`).with("/usr/bin/otool -L \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string") expect(doctor).to receive(:`).with("/usr/bin/otool -L \\$\\(date\\)\\ \\\"\\'\\\\.bundle").and_return("dummy string")

View File

@ -319,6 +319,61 @@ RSpec.describe "bundle lock" do
expect(lockfile.platforms).to match_array([x86_mingw32, specific_local_platform].uniq) expect(lockfile.platforms).to match_array([x86_mingw32, specific_local_platform].uniq)
end end
it "also cleans up redundant platform gems when removing platforms" do
build_repo4 do
build_gem "nokogiri", "1.12.0"
build_gem "nokogiri", "1.12.0" do |s|
s.platform = "x86_64-darwin"
end
end
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
end
lockfile <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
PLATFORMS
ruby
x86_64-darwin
DEPENDENCIES
nokogiri
BUNDLED WITH
#{Bundler::VERSION}
L
simulate_platform "x86_64-darwin-22" do
bundle "lock --remove-platform ruby"
end
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0-x86_64-darwin)
PLATFORMS
x86_64-darwin
DEPENDENCIES
nokogiri
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "errors when removing all platforms" do it "errors when removing all platforms" do
bundle "lock --remove-platform #{specific_local_platform}", :raise_on_error => false bundle "lock --remove-platform #{specific_local_platform}", :raise_on_error => false
expect(err).to include("Removing all platforms from the bundle is not allowed") expect(err).to include("Removing all platforms from the bundle is not allowed")

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot") do RSpec.describe "bundle viz", :bundler => "< 3", :if => Bundler.which("dot"), :realworld => true do
before do before do
realworld_system_gems "ruby-graphviz --version 1.2.5" realworld_system_gems "ruby-graphviz --version 1.2.5"
end end

View File

@ -1481,8 +1481,6 @@ In Gemfile:
describe "without git installed" do describe "without git installed" do
it "prints a better error message when installing" do it "prints a better error message when installing" do
build_git "foo"
gemfile <<-G gemfile <<-G
source "#{file_uri_for(gem_repo1)}" source "#{file_uri_for(gem_repo1)}"

View File

@ -36,7 +36,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
end end
it "fails", :bundler => "3" do it "fails", :bundler => "3" do
bundle :instal, :artifice => "compact_index", :raise_on_error => false bundle :install, :artifice => "compact_index", :raise_on_error => false
expect(err).to include("Each source after the first must include a block") expect(err).to include("Each source after the first must include a block")
expect(exitstatus).to eq(4) expect(exitstatus).to eq(4)
end end
@ -1320,7 +1320,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(out).to include("Using example 0.1.0") expect(out).to include("Using example 0.1.0")
end end
it "fails inmmediately with a helpful error when a rubygems source does not exist and bundler/setup is required" do it "fails immediately with a helpful error when a rubygems source does not exist and bundler/setup is required" do
gemfile <<-G gemfile <<-G
source "https://gem.repo1" source "https://gem.repo1"
@ -1339,7 +1339,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
expect(err).to include("Could not find gem 'example' in locally installed gems.") expect(err).to include("Could not find gem 'example' in locally installed gems.")
end end
it "fails inmmediately with a helpful error when a non retriable network error happens while resolving sources" do it "fails immediately with a helpful error when a non retriable network error happens while resolving sources" do
gemfile <<-G gemfile <<-G
source "https://gem.repo1" source "https://gem.repo1"

View File

@ -104,6 +104,47 @@ RSpec.describe "bundle install with specific platforms" do
L L
end end
it "still installs the generic RUBY variant if necessary even when running on a legacy lockfile locked only to RUBY" do
build_repo4 do
build_gem "nokogiri", "1.3.10"
build_gem "nokogiri", "1.3.10" do |s|
s.platform = "arm64-darwin"
s.required_ruby_version = "< #{Gem.ruby_version}"
end
build_gem "bundler", "2.1.4"
end
gemfile <<~G
source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
G
lockfile <<-L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.3.10)
PLATFORMS
ruby
DEPENDENCIES
nokogiri
RUBY VERSION
2.5.3p105
BUNDLED WITH
2.1.4
L
simulate_platform "arm64-darwin-22" do
bundle "update --bundler", :artifice => "compact_index", :env => { "BUNDLER_SPEC_GEM_REPO" => gem_repo4.to_s }
end
end
it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do it "doesn't discard previously installed platform specific gem and fall back to ruby on subsequent bundles" do
build_repo2 do build_repo2 do
build_gem("libv8", "8.4.255.0") build_gem("libv8", "8.4.255.0")
@ -148,7 +189,7 @@ RSpec.describe "bundle install with specific platforms" do
expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)") expect(out).to include("Using libv8 8.4.255.0 (universal-darwin)")
end end
it "chooses platform specific gems even when resolving upon materialization and the API returns more specific plaforms first" do it "chooses platform specific gems even when resolving upon materialization and the API returns more specific platforms first" do
build_repo4 do build_repo4 do
build_gem("grpc", "1.50.0") build_gem("grpc", "1.50.0")
build_gem("grpc", "1.50.0") {|s| s.platform = "universal-darwin" } build_gem("grpc", "1.50.0") {|s| s.platform = "universal-darwin" }
@ -268,7 +309,7 @@ RSpec.describe "bundle install with specific platforms" do
]) ])
end end
it "falls back on plain ruby when that version doesnt have a platform-specific gem" do it "falls back on plain ruby when that version doesn't have a platform-specific gem" do
setup_multiplatform_gem setup_multiplatform_gem
install_gemfile(google_protobuf) install_gemfile(google_protobuf)
bundle "lock --add-platform=#{java}" bundle "lock --add-platform=#{java}"
@ -483,6 +524,75 @@ RSpec.describe "bundle install with specific platforms" do
L L
end end
it "automatically fixes the lockfile if both RUBY platform and a more specific platform are locked, and some gem has no RUBY variant available" do
build_repo4 do
build_gem "nokogiri", "1.12.0"
build_gem "nokogiri", "1.12.0" do |s|
s.platform = "x86_64-darwin"
end
build_gem "nokogiri", "1.13.0"
build_gem "nokogiri", "1.13.0" do |s|
s.platform = "x86_64-darwin"
end
build_gem("sorbet-static", "0.5.10601") do |s|
s.platform = "x86_64-darwin"
end
end
simulate_platform "x86_64-darwin-22" do
install_gemfile <<~G
source "#{file_uri_for(gem_repo4)}"
gem "nokogiri"
gem "sorbet-static"
G
end
lockfile <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.12.0)
nokogiri (1.12.0-x86_64-darwin)
sorbet-static (0.5.10601-x86_64-darwin)
PLATFORMS
ruby
x86_64-darwin
DEPENDENCIES
nokogiri
sorbet
BUNDLED WITH
#{Bundler::VERSION}
L
simulate_platform "x86_64-darwin-22" do
bundle "update --conservative nokogiri"
end
expect(lockfile).to eq <<~L
GEM
remote: #{file_uri_for(gem_repo4)}/
specs:
nokogiri (1.13.0-x86_64-darwin)
sorbet-static (0.5.10601-x86_64-darwin)
PLATFORMS
x86_64-darwin
DEPENDENCIES
nokogiri
sorbet-static
BUNDLED WITH
#{Bundler::VERSION}
L
end
it "automatically fixes the lockfile if only RUBY platform is locked and some gem has no RUBY variant available" do it "automatically fixes the lockfile if only RUBY platform is locked and some gem has no RUBY variant available" do
build_repo4 do build_repo4 do
build_gem("sorbet-static-and-runtime", "0.5.10160") do |s| build_gem("sorbet-static-and-runtime", "0.5.10160") do |s|
@ -607,7 +717,7 @@ RSpec.describe "bundle install with specific platforms" do
G G
# simulate lockfile which includes both a precompiled gem with: # simulate lockfile which includes both a precompiled gem with:
# - Gem the current platform (with imcompatible ruby version) # - Gem the current platform (with incompatible ruby version)
# - A source gem with compatible ruby version # - A source gem with compatible ruby version
lockfile <<-L lockfile <<-L
GEM GEM

View File

@ -157,7 +157,7 @@ RSpec.shared_examples "bundle install --standalone" do
bundle "lock", :dir => cwd, :artifice => "compact_index" bundle "lock", :dir => cwd, :artifice => "compact_index"
end end
it "works and points to the vendored copies, not to the default copies" do it "works and points to the vendored copies, not to the default copies", :realworld do
bundle "config set --local path #{bundled_app("bundle")}" bundle "config set --local path #{bundled_app("bundle")}"
bundle :install, :standalone => true, :dir => cwd, :artifice => "compact_index", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s } bundle :install, :standalone => true, :dir => cwd, :artifice => "compact_index", :env => { "BUNDLER_GEM_DEFAULT_DIR" => system_gem_path.to_s }

View File

@ -587,7 +587,7 @@ RSpec.describe "major deprecations" do
pending "fails with a helpful message", :bundler => "3" pending "fails with a helpful message", :bundler => "3"
end end
context "bundle viz" do context "bundle viz", :realworld do
before do before do
realworld_system_gems "ruby-graphviz --version 1.2.5" realworld_system_gems "ruby-graphviz --version 1.2.5"
create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\"" create_file "gems.rb", "source \"#{file_uri_for(gem_repo1)}\""

View File

@ -219,14 +219,14 @@ RSpec.describe "real world edgecases", :realworld => true do
end end
it "doesn't hang on big gemfile" do it "doesn't hang on big gemfile" do
skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM.include?("darwin") skip "Only for ruby 2.7" unless RUBY_VERSION.start_with?("2.7")
gemfile <<~G gemfile <<~G
# frozen_string_literal: true # frozen_string_literal: true
source "https://rubygems.org" source "https://rubygems.org"
ruby "2.7.3" ruby "~> 2.7.7"
gem "rails" gem "rails"
gem "pg", ">= 0.18", "< 2.0" gem "pg", ">= 0.18", "< 2.0"
@ -321,17 +321,17 @@ RSpec.describe "real world edgecases", :realworld => true do
G G
if Bundler.feature_flag.bundler_3_mode? if Bundler.feature_flag.bundler_3_mode?
# Conflicts on bundler version, so fails earlier # Conflicts on bundler version, so we count attempts differently
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }, :raise_on_error => false
expect(out).to display_total_steps_of(435) expect(out.split("\n").grep(/backtracking to/).count).to eq(8)
else else
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" } bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
expect(out).to display_total_steps_of(1025) expect(out).to include("Solution found after 7 attempts")
end end
end end
it "doesn't hang on tricky gemfile" do it "doesn't hang on tricky gemfile" do
skip "Only for ruby 2.7.3" if RUBY_VERSION != "2.7.3" || RUBY_PLATFORM.include?("darwin") skip "Only for ruby 2.7" unless RUBY_VERSION.start_with?("2.7")
gemfile <<~G gemfile <<~G
source 'https://rubygems.org' source 'https://rubygems.org'
@ -349,190 +349,168 @@ RSpec.describe "real world edgecases", :realworld => true do
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" } bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
if Bundler.feature_flag.bundler_3_mode? expect(out).to include("Solution found after 6 attempts")
expect(out).to display_total_steps_of(890)
else
expect(out).to display_total_steps_of(891)
end
end end
it "doesn't hang on nix gemfile" do it "doesn't hang on nix gemfile" do
skip "Only for ruby 3.0.1" if RUBY_VERSION != "3.0.1" || RUBY_PLATFORM.include?("darwin") skip "Only for ruby 3.0" unless RUBY_VERSION.start_with?("3.0")
gemfile <<~G gemfile <<~G
source "https://rubygems.org" do source "https://rubygems.org"
gem "addressable"
gem "atk" gem "addressable"
gem "awesome_print" gem "atk"
gem "bacon" gem "awesome_print"
gem "byebug" gem "bacon"
gem "cairo" gem "byebug"
gem "cairo-gobject" gem "cairo"
gem "camping" gem "cairo-gobject"
gem "charlock_holmes" gem "camping"
gem "cld3" gem "charlock_holmes"
gem "cocoapods" gem "cld3"
gem "cocoapods-acknowledgements" gem "cocoapods"
gem "cocoapods-art" gem "cocoapods-acknowledgements"
gem "cocoapods-bin" gem "cocoapods-art"
gem "cocoapods-browser" gem "cocoapods-bin"
gem "cocoapods-bugsnag" gem "cocoapods-browser"
gem "cocoapods-check" gem "cocoapods-bugsnag"
gem "cocoapods-clean" gem "cocoapods-check"
gem "cocoapods-clean_build_phases_scripts" gem "cocoapods-clean"
gem "cocoapods-core" gem "cocoapods-clean_build_phases_scripts"
gem "cocoapods-coverage" gem "cocoapods-core"
gem "cocoapods-deintegrate" gem "cocoapods-coverage"
gem "cocoapods-dependencies" gem "cocoapods-deintegrate"
gem "cocoapods-deploy" gem "cocoapods-dependencies"
gem "cocoapods-downloader" gem "cocoapods-deploy"
gem "cocoapods-expert-difficulty" gem "cocoapods-downloader"
gem "cocoapods-fix-react-native" gem "cocoapods-expert-difficulty"
gem "cocoapods-generate" gem "cocoapods-fix-react-native"
gem "cocoapods-git_url_rewriter" gem "cocoapods-generate"
gem "cocoapods-keys" gem "cocoapods-git_url_rewriter"
gem "cocoapods-no-dev-schemes" gem "cocoapods-keys"
gem "cocoapods-open" gem "cocoapods-no-dev-schemes"
gem "cocoapods-packager" gem "cocoapods-open"
gem "cocoapods-playgrounds" gem "cocoapods-packager"
gem "cocoapods-plugins" gem "cocoapods-playgrounds"
gem "cocoapods-prune-localizations" gem "cocoapods-plugins"
gem "cocoapods-rome" gem "cocoapods-prune-localizations"
gem "cocoapods-search" gem "cocoapods-rome"
gem "cocoapods-sorted-search" gem "cocoapods-search"
gem "cocoapods-static-swift-framework" gem "cocoapods-sorted-search"
gem "cocoapods-stats" gem "cocoapods-static-swift-framework"
gem "cocoapods-tdfire-binary" gem "cocoapods-stats"
gem "cocoapods-testing" gem "cocoapods-tdfire-binary"
gem "cocoapods-trunk" gem "cocoapods-testing"
gem "cocoapods-try" gem "cocoapods-trunk"
gem "cocoapods-try-release-fix" gem "cocoapods-try"
gem "cocoapods-update-if-you-dare" gem "cocoapods-try-release-fix"
gem "cocoapods-whitelist" gem "cocoapods-update-if-you-dare"
gem "cocoapods-wholemodule" gem "cocoapods-whitelist"
gem "coderay" gem "cocoapods-wholemodule"
gem "concurrent-ruby" gem "coderay"
gem "curb" gem "concurrent-ruby"
gem "curses" gem "curb"
gem "daemons" gem "curses"
gem "dep-selector-libgecode" gem "daemons"
gem "digest-sha3" gem "dep-selector-libgecode"
gem "domain_name" gem "digest-sha3"
gem "do_sqlite3" gem "domain_name"
gem "ethon" gem "do_sqlite3"
gem "eventmachine" gem "ethon"
gem "excon" gem "eventmachine"
gem "faraday" gem "excon"
gem "ffi" gem "faraday"
gem "ffi-rzmq-core" gem "ffi"
gem "fog-dnsimple" gem "ffi-rzmq-core"
gem "gdk_pixbuf2" gem "fog-dnsimple"
gem "gio2" gem "gdk_pixbuf2"
gem "gitlab-markup" gem "gio2"
gem "glib2" gem "gitlab-markup"
gem "gpgme" gem "glib2"
gem "gtk2" gem "gpgme"
gem "hashie" gem "gtk2"
gem "highline" gem "hashie"
gem "hike" gem "highline"
gem "hitimes" gem "hike"
gem "hpricot" gem "hitimes"
gem "httpclient" gem "hpricot"
gem "http-cookie" gem "httpclient"
gem "iconv" gem "http-cookie"
gem "idn-ruby" gem "iconv"
gem "jbuilder" gem "idn-ruby"
gem "jekyll" gem "jbuilder"
gem "jmespath" gem "jekyll"
gem "jwt" gem "jmespath"
gem "libv8" gem "jwt"
gem "libxml-ruby" gem "libv8"
gem "magic" gem "libxml-ruby"
gem "markaby" gem "magic"
gem "method_source" gem "markaby"
gem "mini_magick" gem "method_source"
gem "msgpack" gem "mini_magick"
gem "mysql2" gem "msgpack"
gem "ncursesw" gem "mysql2"
gem "netrc" gem "ncursesw"
gem "net-scp" gem "netrc"
gem "net-ssh" gem "net-scp"
gem "nokogiri" gem "net-ssh"
gem "opus-ruby" gem "nokogiri"
gem "ovirt-engine-sdk" gem "opus-ruby"
gem "pango" gem "ovirt-engine-sdk"
gem "patron" gem "pango"
gem "pcaprub" gem "patron"
gem "pg" gem "pcaprub"
gem "pry" gem "pg"
gem "pry-byebug" gem "pry"
gem "pry-doc" gem "pry-byebug"
gem "public_suffix" gem "pry-doc"
gem "puma" gem "public_suffix"
gem "rails" gem "puma"
gem "rainbow" gem "rails"
gem "rbnacl" gem "rainbow"
gem "rb-readline" gem "rbnacl"
gem "re2" gem "rb-readline"
gem "redis" gem "re2"
gem "redis-rack" gem "redis"
gem "rest-client" gem "redis-rack"
gem "rmagick" gem "rest-client"
gem "rpam2" gem "rmagick"
gem "rspec" gem "rpam2"
gem "rubocop" gem "rspec"
gem "rubocop-performance" gem "rubocop"
gem "ruby-libvirt" gem "rubocop-performance"
gem "ruby-lxc" gem "ruby-libvirt"
gem "ruby-progressbar" gem "ruby-lxc"
gem "ruby-terminfo" gem "ruby-progressbar"
gem "ruby-vips" gem "ruby-terminfo"
gem "rubyzip" gem "ruby-vips"
gem "rugged" gem "rubyzip"
gem "sassc" gem "rugged"
gem "scrypt" gem "sassc"
gem "semian" gem "scrypt"
gem "sequel" gem "semian"
gem "sequel_pg" gem "sequel"
gem "simplecov" gem "sequel_pg"
gem "sinatra" gem "simplecov"
gem "slop" gem "sinatra"
gem "snappy" gem "slop"
gem "sqlite3" gem "snappy"
gem "taglib-ruby" gem "sqlite3"
gem "thrift" gem "taglib-ruby"
gem "tilt" gem "thrift"
gem "tiny_tds" gem "tilt"
gem "treetop" gem "tiny_tds"
gem "typhoeus" gem "treetop"
gem "tzinfo" gem "typhoeus"
gem "unf_ext" gem "tzinfo"
gem "uuid4r" gem "unf_ext"
gem "whois" gem "uuid4r"
gem "zookeeper" gem "whois"
end gem "zookeeper"
G G
bundle :lock, :env => { "DEBUG_RESOLVER" => "1" } bundle :lock, :env => { "DEBUG_RESOLVER" => "1" }
if Bundler.feature_flag.bundler_3_mode? expect(out).to include("Solution found after 4 attempts")
expect(out).to display_total_steps_of(1874)
else
expect(out).to display_total_steps_of(1922)
end
end
private
RSpec::Matchers.define :display_total_steps_of do |expected_steps|
match do |out|
out.include?("BUNDLER: Finished resolution (#{expected_steps} steps)")
end
failure_message do |out|
actual_steps = out.scan(/BUNDLER: Finished resolution \((\d+) steps\)/).first.first
"Expected resolution to finish in #{expected_steps} steps, but took #{actual_steps}"
end
end end
end end

View File

@ -1,6 +1,6 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.describe "loading dinamically linked library on a bundle exec context", :realworld => true do RSpec.describe "loading dynamically linked library on a bundle exec context", :realworld => true do
it "passes ENV right after argv in memory" do it "passes ENV right after argv in memory" do
create_file "foo.rb", <<~RUBY create_file "foo.rb", <<~RUBY
require 'ffi' require 'ffi'

View File

@ -0,0 +1,11 @@
# frozen_string_literal: true
RSpec.describe "github source", :realworld => true do
it "properly fetches PRs" do
install_gemfile <<-G
source "https://rubygems.org"
gem "reline", github: "https://github.com/ruby/reline/pull/488"
G
end
end

View File

@ -155,21 +155,32 @@ RSpec.describe "Resolving platform craziness" do
end end
end end
it "takes the latest ruby gem if the platform specific gem doesn't match the required_ruby_version" do context "when the platform specific gem doesn't match the required_ruby_version" do
@index = build_index do before do
gem "foo", "1.0.0" @index = build_index do
gem "foo", "1.0.0", "x64-mingw32" gem "foo", "1.0.0"
gem "foo", "1.1.0" gem "foo", "1.0.0", "x64-mingw32"
gem "foo", "1.1.0", "x64-mingw32" do |s| gem "foo", "1.1.0"
s.required_ruby_version = [">= 2.0", "< 2.4"] gem "foo", "1.1.0", "x64-mingw32" do |s|
s.required_ruby_version = [">= 2.0", "< 2.4"]
end
gem "Ruby\0", "2.5.1"
end end
gem "Ruby\0", "2.5.1" dep "Ruby\0", "2.5.1"
platforms "x64-mingw32"
end end
dep "foo"
dep "Ruby\0", "2.5.1"
platforms "x64-mingw32"
should_resolve_as %w[foo-1.1.0] it "takes the latest ruby gem" do
dep "foo"
should_resolve_as %w[foo-1.1.0]
end
it "takes the latest ruby gem, even if requirement does not match previous versions with the same ruby requirement" do
dep "foo", "1.1.0"
should_resolve_as %w[foo-1.1.0]
end
end end
it "takes the latest ruby gem with required_ruby_version if the platform specific gem doesn't match the required_ruby_version" do it "takes the latest ruby gem with required_ruby_version if the platform specific gem doesn't match the required_ruby_version" do

View File

@ -436,7 +436,7 @@ RSpec.describe "bundler/inline#gemfile" do
expect(err).to be_empty expect(err).to be_empty
end end
it "when requiring fileutils after does not show redefinition warnings" do it "when requiring fileutils after does not show redefinition warnings", :realworld do
dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false dependency_installer_loads_fileutils = ruby "require 'rubygems/dependency_installer'; puts $LOADED_FEATURES.grep(/fileutils/)", :raise_on_error => false
skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty? skip "does not work if rubygems/dependency_installer loads fileutils, which happens until rubygems 3.2.0" unless dependency_installer_loads_fileutils.empty?

View File

@ -91,7 +91,7 @@ RSpec.describe "Self management", :rubygems => ">= 3.3.0.dev", :realworld => tru
expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION) expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION)
end end
it "shows a discreet message if locked bundler does not exist" do it "shows a discrete message if locked bundler does not exist" do
missing_minor ="#{Bundler::VERSION[0]}.999.999" missing_minor ="#{Bundler::VERSION[0]}.999.999"
lockfile_bundled_with(missing_minor) lockfile_bundled_with(missing_minor)

View File

@ -556,12 +556,12 @@ RSpec.describe "Bundler.setup" do
gemfile <<-G gemfile <<-G
source "#{file_uri_for(gem_repo1)}" source "#{file_uri_for(gem_repo1)}"
gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistant" gem "rack", :git => "#{lib_path("rack-0.8")}", :ref => "main", :branch => "nonexistent"
G G
bundle %(config set local.rack #{lib_path("local-rack")}) bundle %(config set local.rack #{lib_path("local-rack")})
run "require 'rack'", :raise_on_error => false run "require 'rack'", :raise_on_error => false
expect(err).to match(/is using branch main but Gemfile specifies nonexistant/) expect(err).to match(/is using branch main but Gemfile specifies nonexistent/)
end end
end end

View File

@ -4,6 +4,7 @@ require "net/http"
require_relative "../path" require_relative "../path"
CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes" CASSETTE_PATH = "#{Spec::Path.spec_dir}/support/artifice/vcr_cassettes"
USED_CASSETTES_PATH = "#{Spec::Path.spec_dir}/support/artifice/used_cassettes.txt"
CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" } CASSETTE_NAME = ENV.fetch("BUNDLER_SPEC_VCR_CASSETTE_NAME") { "realworld" }
class BundlerVCRHTTP < Net::HTTP class BundlerVCRHTTP < Net::HTTP
@ -22,6 +23,10 @@ class BundlerVCRHTTP < Net::HTTP
@__vcr_request_handler = handler @__vcr_request_handler = handler
end end
File.open(USED_CASSETTES_PATH, "a+") do |f|
f.puts request_pair_paths.map {|path| Pathname.new(path).relative_path_from(Spec::Path.source_root).to_s }.join("\n")
end
if recorded_response? if recorded_response?
recorded_response recorded_response
else else
@ -74,27 +79,10 @@ class BundlerVCRHTTP < Net::HTTP
def request_pair_paths def request_pair_paths
%w[request response].map do |kind| %w[request response].map do |kind|
File.join(CASSETTE_PATH, CASSETTE_NAME, file_name_for_key(key + [kind])) File.join(CASSETTE_PATH, CASSETTE_NAME, file_name_for_key(key), kind)
end end
end end
def read_stored_request(path)
contents = File.binread(path)
headers = {}
method = nil
path = nil
contents.lines.grep(/^> /).each do |line|
if line =~ /^> (GET|HEAD|POST|PATCH|PUT|DELETE) (.*)/
method = $1
path = $2.strip
elsif line =~ /^> (.*?): (.*)/
headers[$1] = $2
end
end
body = contents =~ /^([^>].*)/m && $1
Net::HTTP.const_get(method.capitalize).new(path, headers).tap {|r| r.body = body if body }
end
def request_to_string(request) def request_to_string(request)
request_string = [] request_string = []
request_string << "> #{request.method.upcase} #{request.path}" request_string << "> #{request.method.upcase} #{request.path}"

View File

@ -298,10 +298,6 @@ module Spec
end end
end end
def build_dep(name, requirements = Gem::Requirement.default, type = :runtime)
Bundler::Dependency.new(name, :version => requirements)
end
def build_lib(name, *args, &blk) def build_lib(name, *args, &blk)
build_with(LibBuilder, name, args, &blk) build_with(LibBuilder, name, args, &blk)
end end

View File

@ -1555,7 +1555,7 @@ Also, a list:
# :stopdoc: # :stopdoc:
# only available in RubyGems tests # only available in RubyGems tests
PRIVATE_KEY_PASSPHRASE = "Foo bar".freeze PRIVATE_KEY_PASSPHRASE = "Foo bar"
begin begin
PRIVATE_KEY = load_key "private" PRIVATE_KEY = load_key "private"

View File

@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
SIMPLE_GEM = <<-GEMDATA.freeze SIMPLE_GEM = <<-GEMDATA
MD5SUM = "989bf34a1cbecd52e0ea66b662b3a405" MD5SUM = "989bf34a1cbecd52e0ea66b662b3a405"
if $0 == __FILE__ if $0 == __FILE__
require 'optparse' require 'optparse'

View File

@ -8,7 +8,7 @@ class TestGemCommandsSetupCommand < Gem::TestCase
if File.exist?(bundler_gemspec) if File.exist?(bundler_gemspec)
BUNDLER_VERS = File.read(bundler_gemspec).match(/VERSION = "(#{Gem::Version::VERSION_PATTERN})"/)[1] BUNDLER_VERS = File.read(bundler_gemspec).match(/VERSION = "(#{Gem::Version::VERSION_PATTERN})"/)[1]
else else
BUNDLER_VERS = "2.0.1".freeze BUNDLER_VERS = "2.0.1"
end end
def setup def setup

View File

@ -28,7 +28,7 @@ require "rubygems/package"
class TestGemRemoteFetcher < Gem::TestCase class TestGemRemoteFetcher < Gem::TestCase
include Gem::DefaultUserInteraction include Gem::DefaultUserInteraction
SERVER_DATA = <<-EOY.freeze SERVER_DATA = <<-EOY
--- !ruby/object:Gem::Cache --- !ruby/object:Gem::Cache
gems: gems:
rake-0.4.11: !ruby/object:Gem::Specification rake-0.4.11: !ruby/object:Gem::Specification

View File

@ -275,7 +275,7 @@ DEPENDENCIES
Gem::Resolver::LockSet === set Gem::Resolver::LockSet === set
end end
refute lockfile_set, "fount a LockSet" refute lockfile_set, "found a LockSet"
git_set = @set.sets.find do |set| git_set = @set.sets.find do |set|
Gem::Resolver::GitSet === set Gem::Resolver::GitSet === set
@ -318,7 +318,7 @@ DEPENDENCIES
Gem::Resolver::LockSet === set Gem::Resolver::LockSet === set
end end
refute lockfile_set, "fount a LockSet" refute lockfile_set, "found a LockSet"
git_set = @set.sets.find do |set| git_set = @set.sets.find do |set|
Gem::Resolver::GitSet === set Gem::Resolver::GitSet === set
@ -355,7 +355,7 @@ DEPENDENCIES
Gem::Resolver::LockSet === set Gem::Resolver::LockSet === set
end end
refute lockfile_set, "fount a LockSet" refute lockfile_set, "found a LockSet"
git_set = @set.sets.find do |set| git_set = @set.sets.find do |set|
Gem::Resolver::GitSet === set Gem::Resolver::GitSet === set
@ -392,7 +392,7 @@ DEPENDENCIES
Gem::Resolver::LockSet === set Gem::Resolver::LockSet === set
end end
refute lockfile_set, "fount a LockSet" refute lockfile_set, "found a LockSet"
git_set = @set.sets.find do |set| git_set = @set.sets.find do |set|
Gem::Resolver::GitSet === set Gem::Resolver::GitSet === set

View File

@ -10,7 +10,7 @@ require "rubygems/installer"
require "rubygems/platform" require "rubygems/platform"
class TestGemSpecification < Gem::TestCase class TestGemSpecification < Gem::TestCase
LEGACY_YAML_SPEC = <<-EOF.freeze LEGACY_YAML_SPEC = <<-EOF
--- !ruby/object:Gem::Specification --- !ruby/object:Gem::Specification
rubygems_version: "1.0" rubygems_version: "1.0"
name: keyedlist name: keyedlist
@ -29,7 +29,7 @@ email: flgr@ccan.de
has_rdoc: true has_rdoc: true
EOF EOF
LEGACY_RUBY_SPEC = <<-EOF.freeze LEGACY_RUBY_SPEC = <<-EOF
Gem::Specification.new do |s| Gem::Specification.new do |s|
s.name = %q{keyedlist} s.name = %q{keyedlist}
s.version = %q{0.4.0} s.version = %q{0.4.0}

View File

@ -43,7 +43,7 @@ class TestGemVersion < Gem::TestCase
assert_equal v("5.1"), Gem::Version.create("5.1") assert_equal v("5.1"), Gem::Version.create("5.1")
ver = "1.1".freeze ver = "1.1"
assert_equal v("1.1"), Gem::Version.create(ver) assert_equal v("1.1"), Gem::Version.create(ver)
end end
@ -88,7 +88,7 @@ class TestGemVersion < Gem::TestCase
end end
def test_initialize def test_initialize
["1.0", "1.0 ", " 1.0 ", "1.0\n", "\n1.0\n", "1.0".freeze].each do |good| ["1.0", "1.0 ", " 1.0 ", "1.0\n", "\n1.0\n", "1.0"].each do |good|
assert_version_equal "1.0", good assert_version_equal "1.0", good
end end