mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Merge RubyGems-3.6.7 and Bundler-2.6.7
This commit is contained in:
parent
db2bf9f078
commit
e580145171
57 changed files with 721 additions and 289 deletions
|
@ -190,7 +190,7 @@ module Bundler
|
||||||
def replace(spec, checksum)
|
def replace(spec, checksum)
|
||||||
return unless checksum
|
return unless checksum
|
||||||
|
|
||||||
lock_name = spec.name_tuple.lock_name
|
lock_name = spec.lock_name
|
||||||
@store_mutex.synchronize do
|
@store_mutex.synchronize do
|
||||||
existing = fetch_checksum(lock_name, checksum.algo)
|
existing = fetch_checksum(lock_name, checksum.algo)
|
||||||
if !existing || existing.same_source?(checksum)
|
if !existing || existing.same_source?(checksum)
|
||||||
|
@ -201,10 +201,12 @@ module Bundler
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def register(spec, checksum)
|
def missing?(spec)
|
||||||
return unless checksum
|
@store[spec.lock_name].nil?
|
||||||
|
end
|
||||||
|
|
||||||
register_checksum(spec.name_tuple.lock_name, checksum)
|
def register(spec, checksum)
|
||||||
|
register_checksum(spec.lock_name, checksum)
|
||||||
end
|
end
|
||||||
|
|
||||||
def merge!(other)
|
def merge!(other)
|
||||||
|
@ -216,9 +218,9 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_lock(spec)
|
def to_lock(spec)
|
||||||
lock_name = spec.name_tuple.lock_name
|
lock_name = spec.lock_name
|
||||||
checksums = @store[lock_name]
|
checksums = @store[lock_name]
|
||||||
if checksums
|
if checksums&.any?
|
||||||
"#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}"
|
"#{lock_name} #{checksums.values.map(&:to_lock).sort.join(",")}"
|
||||||
else
|
else
|
||||||
lock_name
|
lock_name
|
||||||
|
@ -229,11 +231,15 @@ module Bundler
|
||||||
|
|
||||||
def register_checksum(lock_name, checksum)
|
def register_checksum(lock_name, checksum)
|
||||||
@store_mutex.synchronize do
|
@store_mutex.synchronize do
|
||||||
existing = fetch_checksum(lock_name, checksum.algo)
|
if checksum
|
||||||
if existing
|
existing = fetch_checksum(lock_name, checksum.algo)
|
||||||
merge_checksum(lock_name, checksum, existing)
|
if existing
|
||||||
|
merge_checksum(lock_name, checksum, existing)
|
||||||
|
else
|
||||||
|
store_checksum(lock_name, checksum)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
store_checksum(lock_name, checksum)
|
init_checksum(lock_name)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -243,7 +249,11 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def store_checksum(lock_name, checksum)
|
def store_checksum(lock_name, checksum)
|
||||||
(@store[lock_name] ||= {})[checksum.algo] = checksum
|
init_checksum(lock_name)[checksum.algo] = checksum
|
||||||
|
end
|
||||||
|
|
||||||
|
def init_checksum(lock_name)
|
||||||
|
@store[lock_name] ||= {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_checksum(lock_name, algo)
|
def fetch_checksum(lock_name, algo)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
require_relative "gem_parser"
|
require "rubygems/resolver/api_set/gem_parser"
|
||||||
|
|
||||||
module Bundler
|
module Bundler
|
||||||
class CompactIndexClient
|
class CompactIndexClient
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Bundler
|
|
||||||
class CompactIndexClient
|
|
||||||
if defined?(Gem::Resolver::APISet::GemParser)
|
|
||||||
GemParser = Gem::Resolver::APISet::GemParser
|
|
||||||
else
|
|
||||||
class GemParser
|
|
||||||
EMPTY_ARRAY = [].freeze
|
|
||||||
private_constant :EMPTY_ARRAY
|
|
||||||
|
|
||||||
def parse(line)
|
|
||||||
version_and_platform, rest = line.split(" ", 2)
|
|
||||||
version, platform = version_and_platform.split("-", 2)
|
|
||||||
dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
|
|
||||||
dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
|
|
||||||
requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
|
|
||||||
[version, platform, dependencies, requirements]
|
|
||||||
end
|
|
||||||
|
|
||||||
private
|
|
||||||
|
|
||||||
def parse_dependency(string)
|
|
||||||
dependency = string.split(":")
|
|
||||||
dependency[-1] = dependency[-1].split("&") if dependency.size > 1
|
|
||||||
dependency[0] = -dependency[0]
|
|
||||||
dependency
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -64,7 +64,7 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def gem_parser
|
def gem_parser
|
||||||
@gem_parser ||= GemParser.new
|
@gem_parser ||= Gem::Resolver::APISet::GemParser.new
|
||||||
end
|
end
|
||||||
|
|
||||||
# This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
|
# This is mostly the same as `split(" ", 3)` but it avoids allocating extra objects.
|
||||||
|
|
|
@ -95,6 +95,7 @@ module Bundler
|
||||||
@locked_ruby_version = nil
|
@locked_ruby_version = nil
|
||||||
@new_platforms = []
|
@new_platforms = []
|
||||||
@removed_platforms = []
|
@removed_platforms = []
|
||||||
|
@originally_invalid_platforms = []
|
||||||
|
|
||||||
if lockfile_exists?
|
if lockfile_exists?
|
||||||
@lockfile_contents = Bundler.read_file(lockfile)
|
@lockfile_contents = Bundler.read_file(lockfile)
|
||||||
|
@ -147,9 +148,8 @@ module Bundler
|
||||||
|
|
||||||
@current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
|
@current_platform_missing = add_current_platform unless Bundler.frozen_bundle?
|
||||||
|
|
||||||
converge_path_sources_to_gemspec_sources
|
|
||||||
@path_changes = converge_paths
|
|
||||||
@source_changes = converge_sources
|
@source_changes = converge_sources
|
||||||
|
@path_changes = converge_paths
|
||||||
|
|
||||||
if conservative
|
if conservative
|
||||||
@gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
|
@gems_to_unlock = @explicit_unlocks.any? ? @explicit_unlocks : @dependencies.map(&:name)
|
||||||
|
@ -539,12 +539,13 @@ module Bundler
|
||||||
|
|
||||||
reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
|
reason = resolve_needed? ? change_reason : "some dependencies were deleted from your gemfile"
|
||||||
|
|
||||||
msg = String.new
|
msg = String.new("#{reason.capitalize.strip}, but ")
|
||||||
msg << "#{reason.capitalize.strip}, but the lockfile can't be updated because #{update_refused_reason}"
|
msg << "the lockfile " unless msg.start_with?("Your lockfile")
|
||||||
|
msg << "can't be updated because #{update_refused_reason}"
|
||||||
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
|
msg << "\n\nYou have added to the Gemfile:\n" << added.join("\n") if added.any?
|
||||||
msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
|
msg << "\n\nYou have deleted from the Gemfile:\n" << deleted.join("\n") if deleted.any?
|
||||||
msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
|
msg << "\n\nYou have changed in the Gemfile:\n" << changed.join("\n") if changed.any?
|
||||||
msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_gemfile_path} to version control.\n" unless unlocking?
|
msg << "\n\nRun `bundle install` elsewhere and add the updated #{SharedHelpers.relative_lockfile_path} to version control.\n" unless unlocking?
|
||||||
msg
|
msg
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -563,6 +564,7 @@ module Bundler
|
||||||
@local_changes ||
|
@local_changes ||
|
||||||
@missing_lockfile_dep ||
|
@missing_lockfile_dep ||
|
||||||
@unlocking_bundler ||
|
@unlocking_bundler ||
|
||||||
|
@locked_spec_with_missing_checksums ||
|
||||||
@locked_spec_with_missing_deps ||
|
@locked_spec_with_missing_deps ||
|
||||||
@locked_spec_with_invalid_deps
|
@locked_spec_with_invalid_deps
|
||||||
end
|
end
|
||||||
|
@ -759,7 +761,11 @@ module Bundler
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@platforms = result.add_extra_platforms!(platforms) if should_add_extra_platforms?
|
if should_add_extra_platforms?
|
||||||
|
result.add_extra_platforms!(platforms)
|
||||||
|
elsif @originally_invalid_platforms.any?
|
||||||
|
result.add_originally_invalid_platforms!(platforms, @originally_invalid_platforms)
|
||||||
|
end
|
||||||
|
|
||||||
SpecSet.new(result.for(dependencies, @platforms | [Gem::Platform::RUBY]))
|
SpecSet.new(result.for(dependencies, @platforms | [Gem::Platform::RUBY]))
|
||||||
end
|
end
|
||||||
|
@ -809,13 +815,14 @@ module Bundler
|
||||||
[
|
[
|
||||||
[@source_changes, "the list of sources changed"],
|
[@source_changes, "the list of sources changed"],
|
||||||
[@dependency_changes, "the dependencies in your gemfile changed"],
|
[@dependency_changes, "the dependencies in your gemfile changed"],
|
||||||
[@current_platform_missing, "your lockfile does not include the current platform"],
|
[@current_platform_missing, "your lockfile is missing the current platform"],
|
||||||
[@new_platforms.any?, "you are adding a new platform to your lockfile"],
|
[@new_platforms.any?, "you are adding a new platform to your lockfile"],
|
||||||
[@path_changes, "the gemspecs for path gems changed"],
|
[@path_changes, "the gemspecs for path gems changed"],
|
||||||
[@local_changes, "the gemspecs for git local gems changed"],
|
[@local_changes, "the gemspecs for git local gems changed"],
|
||||||
[@missing_lockfile_dep, "your lock file is missing \"#{@missing_lockfile_dep}\""],
|
[@missing_lockfile_dep, "your lockfile is missing \"#{@missing_lockfile_dep}\""],
|
||||||
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
|
[@unlocking_bundler, "an update to the version of Bundler itself was requested"],
|
||||||
[@locked_spec_with_missing_deps, "your lock file includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"],
|
[@locked_spec_with_missing_checksums, "your lockfile is missing a CHECKSUMS entry for \"#{@locked_spec_with_missing_checksums}\""],
|
||||||
|
[@locked_spec_with_missing_deps, "your lockfile includes \"#{@locked_spec_with_missing_deps}\" but not some of its dependencies"],
|
||||||
[@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""],
|
[@locked_spec_with_invalid_deps, "your lockfile does not satisfy dependencies of \"#{@locked_spec_with_invalid_deps}\""],
|
||||||
].select(&:first).map(&:last).join(", ")
|
].select(&:first).map(&:last).join(", ")
|
||||||
end
|
end
|
||||||
|
@ -832,8 +839,8 @@ module Bundler
|
||||||
!locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source)
|
!locked || dependencies_for_source_changed?(source, locked) || specs_for_source_changed?(source)
|
||||||
end
|
end
|
||||||
|
|
||||||
def dependencies_for_source_changed?(source, locked_source = source)
|
def dependencies_for_source_changed?(source, locked_source)
|
||||||
deps_for_source = @dependencies.select {|s| s.source == source }
|
deps_for_source = @dependencies.select {|dep| dep.source == source }
|
||||||
locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source }
|
locked_deps_for_source = locked_dependencies.select {|dep| dep.source == locked_source }
|
||||||
|
|
||||||
deps_for_source.uniq.sort != locked_deps_for_source.sort
|
deps_for_source.uniq.sort != locked_deps_for_source.sort
|
||||||
|
@ -841,7 +848,7 @@ module Bundler
|
||||||
|
|
||||||
def specs_for_source_changed?(source)
|
def specs_for_source_changed?(source)
|
||||||
locked_index = Index.new
|
locked_index = Index.new
|
||||||
locked_index.use(@locked_specs.select {|s| source.can_lock?(s) })
|
locked_index.use(@locked_specs.select {|s| s.replace_source_with!(source) })
|
||||||
|
|
||||||
!locked_index.subset?(source.specs)
|
!locked_index.subset?(source.specs)
|
||||||
rescue PathError, GitError => e
|
rescue PathError, GitError => e
|
||||||
|
@ -873,21 +880,27 @@ module Bundler
|
||||||
def check_lockfile
|
def check_lockfile
|
||||||
@locked_spec_with_invalid_deps = nil
|
@locked_spec_with_invalid_deps = nil
|
||||||
@locked_spec_with_missing_deps = nil
|
@locked_spec_with_missing_deps = nil
|
||||||
|
@locked_spec_with_missing_checksums = nil
|
||||||
|
|
||||||
missing = []
|
missing_deps = []
|
||||||
|
missing_checksums = []
|
||||||
invalid = []
|
invalid = []
|
||||||
|
|
||||||
@locked_specs.each do |s|
|
@locked_specs.each do |s|
|
||||||
|
missing_checksums << s if @locked_checksums && s.source.checksum_store.missing?(s)
|
||||||
|
|
||||||
validation = @locked_specs.validate_deps(s)
|
validation = @locked_specs.validate_deps(s)
|
||||||
|
|
||||||
missing << s if validation == :missing
|
missing_deps << s if validation == :missing
|
||||||
invalid << s if validation == :invalid
|
invalid << s if validation == :invalid
|
||||||
end
|
end
|
||||||
|
|
||||||
if missing.any?
|
@locked_spec_with_missing_checksums = missing_checksums.first.name if missing_checksums.any?
|
||||||
@locked_specs.delete(missing)
|
|
||||||
|
|
||||||
@locked_spec_with_missing_deps = missing.first.name
|
if missing_deps.any?
|
||||||
|
@locked_specs.delete(missing_deps)
|
||||||
|
|
||||||
|
@locked_spec_with_missing_deps = missing_deps.first.name
|
||||||
end
|
end
|
||||||
|
|
||||||
if invalid.any?
|
if invalid.any?
|
||||||
|
@ -903,24 +916,6 @@ module Bundler
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def converge_path_source_to_gemspec_source(source)
|
|
||||||
return source unless source.instance_of?(Source::Path)
|
|
||||||
gemspec_source = sources.path_sources.find {|s| s.is_a?(Source::Gemspec) && s.as_path_source == source }
|
|
||||||
gemspec_source || source
|
|
||||||
end
|
|
||||||
|
|
||||||
def converge_path_sources_to_gemspec_sources
|
|
||||||
@locked_sources.map! do |source|
|
|
||||||
converge_path_source_to_gemspec_source(source)
|
|
||||||
end
|
|
||||||
@locked_specs.each do |spec|
|
|
||||||
spec.source &&= converge_path_source_to_gemspec_source(spec.source)
|
|
||||||
end
|
|
||||||
@locked_deps.each do |_, dep|
|
|
||||||
dep.source &&= converge_path_source_to_gemspec_source(dep.source)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def converge_sources
|
def converge_sources
|
||||||
# Replace the sources from the Gemfile with the sources from the Gemfile.lock,
|
# Replace the sources from the Gemfile with the sources from the Gemfile.lock,
|
||||||
# if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
|
# if they exist in the Gemfile.lock and are `==`. If you can't find an equivalent
|
||||||
|
@ -963,11 +958,17 @@ module Bundler
|
||||||
unless name == "bundler"
|
unless name == "bundler"
|
||||||
locked_specs = @originally_locked_specs[name]
|
locked_specs = @originally_locked_specs[name]
|
||||||
|
|
||||||
if locked_specs.any? && !dep.matches_spec?(locked_specs.first)
|
if locked_specs.empty?
|
||||||
@gems_to_unlock << name
|
@missing_lockfile_dep = name if dep_changed == false
|
||||||
dep_changed = true
|
else
|
||||||
elsif locked_specs.empty? && dep_changed == false
|
if locked_specs.map(&:source).uniq.size > 1
|
||||||
@missing_lockfile_dep = name
|
@locked_specs.delete(locked_specs.select {|s| s.source != dep.source })
|
||||||
|
end
|
||||||
|
|
||||||
|
unless dep.matches_spec?(locked_specs.first)
|
||||||
|
@gems_to_unlock << name
|
||||||
|
dep_changed = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1141,16 +1142,21 @@ module Bundler
|
||||||
def remove_invalid_platforms!
|
def remove_invalid_platforms!
|
||||||
return if Bundler.frozen_bundle?
|
return if Bundler.frozen_bundle?
|
||||||
|
|
||||||
platforms.reverse_each do |platform|
|
@originally_invalid_platforms = platforms.select do |platform|
|
||||||
next if local_platform == platform ||
|
next if local_platform == platform ||
|
||||||
@new_platforms.include?(platform) ||
|
@new_platforms.include?(platform)
|
||||||
@path_changes ||
|
|
||||||
@dependency_changes ||
|
|
||||||
@locked_spec_with_invalid_deps ||
|
|
||||||
!spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
|
|
||||||
|
|
||||||
remove_platform(platform)
|
# We should probably avoid removing non-ruby platforms, since that means
|
||||||
|
# lockfile will no longer install on those platforms, so a error to give
|
||||||
|
# heads up to the user may be better. However, we have tests expecting
|
||||||
|
# non ruby platform autoremoval to work, so leaving that in place for
|
||||||
|
# now.
|
||||||
|
next if @dependency_changes && platform != Gem::Platform::RUBY
|
||||||
|
|
||||||
|
spec_set_incomplete_for_platform?(@originally_locked_specs, platform)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@platforms -= @originally_invalid_platforms
|
||||||
end
|
end
|
||||||
|
|
||||||
def spec_set_incomplete_for_platform?(spec_set, platform)
|
def spec_set_incomplete_for_platform?(spec_set, platform)
|
||||||
|
|
|
@ -77,7 +77,7 @@ module Bundler
|
||||||
|
|
||||||
@gemspecs << spec
|
@gemspecs << spec
|
||||||
|
|
||||||
path path, "glob" => glob, "name" => spec.name do
|
path path, "glob" => glob, "name" => spec.name, "gemspec" => spec do
|
||||||
add_dependency spec.name
|
add_dependency spec.name
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -141,8 +141,7 @@ module Bundler
|
||||||
def path(path, options = {}, &blk)
|
def path(path, options = {}, &blk)
|
||||||
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"] }
|
|
||||||
)
|
)
|
||||||
|
|
||||||
source_options["global"] = true unless block_given?
|
source_options["global"] = true unless block_given?
|
||||||
|
|
|
@ -175,6 +175,14 @@ module Bundler
|
||||||
@force_ruby_platform = true
|
@force_ruby_platform = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_source_with!(gemfile_source)
|
||||||
|
return unless gemfile_source.can_lock?(self)
|
||||||
|
|
||||||
|
@source = gemfile_source
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def use_exact_resolved_specifications?
|
def use_exact_resolved_specifications?
|
||||||
|
@ -196,7 +204,7 @@ module Bundler
|
||||||
|
|
||||||
# If in frozen mode, we fallback to a non-installable candidate because by
|
# If in frozen mode, we fallback to a non-installable candidate because by
|
||||||
# doing this we avoid re-resolving and potentially end up changing the
|
# doing this we avoid re-resolving and potentially end up changing the
|
||||||
# lock file, which is not allowed. In that case, we will give a proper error
|
# lockfile, which is not allowed. In that case, we will give a proper error
|
||||||
# about the mismatch higher up the stack, right before trying to install the
|
# about the mismatch higher up the stack, right before trying to install the
|
||||||
# bad gem.
|
# bad gem.
|
||||||
def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
|
def choose_compatible(candidates, fallback_to_non_installable: Bundler.frozen_bundle?)
|
||||||
|
|
|
@ -239,7 +239,6 @@ module Bundler
|
||||||
spaces = $1
|
spaces = $1
|
||||||
return unless spaces.size == 2
|
return unless spaces.size == 2
|
||||||
checksums = $6
|
checksums = $6
|
||||||
return unless checksums
|
|
||||||
name = $2
|
name = $2
|
||||||
version = $3
|
version = $3
|
||||||
platform = $4
|
platform = $4
|
||||||
|
@ -249,10 +248,14 @@ module Bundler
|
||||||
full_name = Gem::NameTuple.new(name, version, platform).full_name
|
full_name = Gem::NameTuple.new(name, version, platform).full_name
|
||||||
return unless spec = @specs[full_name]
|
return unless spec = @specs[full_name]
|
||||||
|
|
||||||
checksums.split(",") do |lock_checksum|
|
if checksums
|
||||||
column = line.index(lock_checksum) + 1
|
checksums.split(",") do |lock_checksum|
|
||||||
checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
|
column = line.index(lock_checksum) + 1
|
||||||
spec.source.checksum_store.register(spec, checksum)
|
checksum = Checksum.from_lock(lock_checksum, "#{@lockfile_path}:#{@pos.line}:#{column}")
|
||||||
|
spec.source.checksum_store.register(spec, checksum)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
spec.source.checksum_store.register(spec, nil)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -195,7 +195,7 @@ module Bundler
|
||||||
@sources[name]
|
@sources[name]
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param [Hash] The options that are present in the lock file
|
# @param [Hash] The options that are present in the lockfile
|
||||||
# @return [API::Source] the instance of the class that handles the source
|
# @return [API::Source] the instance of the class that handles the source
|
||||||
# type passed in locked_opts
|
# type passed in locked_opts
|
||||||
def from_lock(locked_opts)
|
def from_lock(locked_opts)
|
||||||
|
|
|
@ -67,7 +67,7 @@ module Bundler
|
||||||
# to check out same version of gem later.
|
# to check out same version of gem later.
|
||||||
#
|
#
|
||||||
# There options are passed when the source plugin is created from the
|
# There options are passed when the source plugin is created from the
|
||||||
# lock file.
|
# lockfile.
|
||||||
#
|
#
|
||||||
# @return [Hash]
|
# @return [Hash]
|
||||||
def options_to_lock
|
def options_to_lock
|
||||||
|
|
|
@ -8,6 +8,14 @@ module Bundler
|
||||||
SharedHelpers.in_bundle? ? Bundler.root : Plugin.root
|
SharedHelpers.in_bundle? ? Bundler.root : Plugin.root
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def eql?(other)
|
||||||
|
return unless other.class == self.class
|
||||||
|
expanded_original_path == other.expanded_original_path &&
|
||||||
|
version == other.version
|
||||||
|
end
|
||||||
|
|
||||||
|
alias_method :==, :eql?
|
||||||
|
|
||||||
def generate_bin(spec, disable_extensions = false)
|
def generate_bin(spec, disable_extensions = false)
|
||||||
# Need to find a way without code duplication
|
# Need to find a way without code duplication
|
||||||
# For now, we can ignore this
|
# For now, we can ignore this
|
||||||
|
|
|
@ -12,6 +12,7 @@ module Bundler
|
||||||
require_relative "resolver/candidate"
|
require_relative "resolver/candidate"
|
||||||
require_relative "resolver/incompatibility"
|
require_relative "resolver/incompatibility"
|
||||||
require_relative "resolver/root"
|
require_relative "resolver/root"
|
||||||
|
require_relative "resolver/strategy"
|
||||||
|
|
||||||
include GemHelpers
|
include GemHelpers
|
||||||
|
|
||||||
|
@ -78,7 +79,7 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def solve_versions(root:, logger:)
|
def solve_versions(root:, logger:)
|
||||||
solver = PubGrub::VersionSolver.new(source: self, root: root, logger: logger)
|
solver = PubGrub::VersionSolver.new(source: self, root: root, strategy: Strategy.new(self), logger: logger)
|
||||||
result = solver.solve
|
result = solver.solve
|
||||||
resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
|
resolved_specs = result.flat_map {|package, version| version.to_specs(package, @most_specific_locked_platform) }
|
||||||
SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
|
SpecSet.new(resolved_specs).specs_with_additional_variants_from(@base.locked_specs)
|
||||||
|
@ -167,15 +168,7 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def versions_for(package, range=VersionRange.any)
|
def versions_for(package, range=VersionRange.any)
|
||||||
versions = select_sorted_versions(package, range)
|
range.select_versions(@sorted_versions[package])
|
||||||
|
|
||||||
# Conditional avoids (among other things) calling
|
|
||||||
# sort_versions_by_preferred with the root package
|
|
||||||
if versions.size > 1
|
|
||||||
sort_versions_by_preferred(package, versions)
|
|
||||||
else
|
|
||||||
versions
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_versions_incompatibility_for(package, unsatisfied_term)
|
def no_versions_incompatibility_for(package, unsatisfied_term)
|
||||||
|
@ -284,8 +277,8 @@ module Bundler
|
||||||
ruby_group = Resolver::SpecGroup.new(ruby_specs)
|
ruby_group = Resolver::SpecGroup.new(ruby_specs)
|
||||||
|
|
||||||
unless ruby_group.empty?
|
unless ruby_group.empty?
|
||||||
platform_specs.each do |specs|
|
platform_specs.each do |s|
|
||||||
ruby_group.merge(Resolver::SpecGroup.new(specs))
|
ruby_group.merge(Resolver::SpecGroup.new(s))
|
||||||
end
|
end
|
||||||
|
|
||||||
groups << Resolver::Candidate.new(version, group: ruby_group, priority: -1)
|
groups << Resolver::Candidate.new(version, group: ruby_group, priority: -1)
|
||||||
|
@ -355,6 +348,10 @@ module Bundler
|
||||||
raise GemNotFound, message
|
raise GemNotFound, message
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def sort_versions_by_preferred(package, versions)
|
||||||
|
@gem_version_promoter.sort_versions(package, versions)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def filtered_versions_for(package)
|
def filtered_versions_for(package)
|
||||||
|
@ -414,10 +411,6 @@ module Bundler
|
||||||
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
|
requirement.satisfied_by?(spec.version) || spec.source.is_a?(Source::Gemspec)
|
||||||
end
|
end
|
||||||
|
|
||||||
def sort_versions_by_preferred(package, versions)
|
|
||||||
@gem_version_promoter.sort_versions(package, versions)
|
|
||||||
end
|
|
||||||
|
|
||||||
def repository_for(package)
|
def repository_for(package)
|
||||||
source_for(package.name)
|
source_for(package.name)
|
||||||
end
|
end
|
||||||
|
@ -433,7 +426,7 @@ module Bundler
|
||||||
next [dep_package, dep_constraint] if name == "bundler"
|
next [dep_package, dep_constraint] if name == "bundler"
|
||||||
|
|
||||||
dep_range = dep_constraint.range
|
dep_range = dep_constraint.range
|
||||||
versions = select_sorted_versions(dep_package, dep_range)
|
versions = versions_for(dep_package, dep_range)
|
||||||
if versions.empty?
|
if versions.empty?
|
||||||
if dep_package.ignores_prereleases? || dep_package.prefer_local?
|
if dep_package.ignores_prereleases? || dep_package.prefer_local?
|
||||||
@all_versions.delete(dep_package)
|
@all_versions.delete(dep_package)
|
||||||
|
@ -441,7 +434,7 @@ module Bundler
|
||||||
end
|
end
|
||||||
dep_package.consider_prereleases! if dep_package.ignores_prereleases?
|
dep_package.consider_prereleases! if dep_package.ignores_prereleases?
|
||||||
dep_package.consider_remote_versions! if dep_package.prefer_local?
|
dep_package.consider_remote_versions! if dep_package.prefer_local?
|
||||||
versions = select_sorted_versions(dep_package, dep_range)
|
versions = versions_for(dep_package, dep_range)
|
||||||
end
|
end
|
||||||
|
|
||||||
if versions.empty? && select_all_versions(dep_package, dep_range).any?
|
if versions.empty? && select_all_versions(dep_package, dep_range).any?
|
||||||
|
@ -456,10 +449,6 @@ module Bundler
|
||||||
end.to_h
|
end.to_h
|
||||||
end
|
end
|
||||||
|
|
||||||
def select_sorted_versions(package, range)
|
|
||||||
range.select_versions(@sorted_versions[package])
|
|
||||||
end
|
|
||||||
|
|
||||||
def select_all_versions(package, range)
|
def select_all_versions(package, range)
|
||||||
range.select_versions(@all_versions[package])
|
range.select_versions(@all_versions[package])
|
||||||
end
|
end
|
||||||
|
|
|
@ -17,7 +17,7 @@ module Bundler
|
||||||
# Some candidates may also keep some information explicitly about the
|
# Some candidates may also keep some information explicitly about the
|
||||||
# package they refer to. These candidates are referred to as "canonical" and
|
# package they refer to. These candidates are referred to as "canonical" and
|
||||||
# are used when materializing resolution results back into RubyGems
|
# are used when materializing resolution results back into RubyGems
|
||||||
# specifications that can be installed, written to lock files, and so on.
|
# specifications that can be installed, written to lockfiles, and so on.
|
||||||
#
|
#
|
||||||
class Candidate
|
class Candidate
|
||||||
include Comparable
|
include Comparable
|
||||||
|
|
40
lib/bundler/resolver/strategy.rb
Normal file
40
lib/bundler/resolver/strategy.rb
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
module Bundler
|
||||||
|
class Resolver
|
||||||
|
class Strategy
|
||||||
|
def initialize(source)
|
||||||
|
@source = source
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_package_and_version(unsatisfied)
|
||||||
|
package, range = next_term_to_try_from(unsatisfied)
|
||||||
|
|
||||||
|
[package, most_preferred_version_of(package, range).first]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def next_term_to_try_from(unsatisfied)
|
||||||
|
unsatisfied.min_by do |package, range|
|
||||||
|
matching_versions = @source.versions_for(package, range)
|
||||||
|
higher_versions = @source.versions_for(package, range.upper_invert)
|
||||||
|
|
||||||
|
[matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def most_preferred_version_of(package, range)
|
||||||
|
versions = @source.versions_for(package, range)
|
||||||
|
|
||||||
|
# Conditional avoids (among other things) calling
|
||||||
|
# sort_versions_by_preferred with the root package
|
||||||
|
if versions.size > 1
|
||||||
|
@source.sort_versions_by_preferred(package, versions)
|
||||||
|
else
|
||||||
|
versions
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -262,6 +262,10 @@ module Gem
|
||||||
!default_gem? && !File.directory?(full_gem_path)
|
!default_gem? && !File.directory?(full_gem_path)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def lock_name
|
||||||
|
@lock_name ||= name_tuple.lock_name
|
||||||
|
end
|
||||||
|
|
||||||
unless VALIDATES_FOR_RESOLUTION
|
unless VALIDATES_FOR_RESOLUTION
|
||||||
def validate_for_resolution
|
def validate_for_resolution
|
||||||
SpecificationPolicy.new(self).validate_for_resolution
|
SpecificationPolicy.new(self).validate_for_resolution
|
||||||
|
@ -443,6 +447,17 @@ module Gem
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
unless Gem.rubygems_version >= Gem::Version.new("3.6.7")
|
||||||
|
module UnfreezeCompactIndexParsedResponse
|
||||||
|
def parse(line)
|
||||||
|
version, platform, dependencies, requirements = super
|
||||||
|
[version, platform, dependencies.frozen? ? dependencies.dup : dependencies, requirements.frozen? ? requirements.dup : requirements]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
Resolver::APISet::GemParser.prepend(UnfreezeCompactIndexParsedResponse)
|
||||||
|
end
|
||||||
|
|
||||||
if Gem.rubygems_version < Gem::Version.new("3.6.0")
|
if Gem.rubygems_version < Gem::Version.new("3.6.0")
|
||||||
class Package; end
|
class Package; end
|
||||||
require "rubygems/package/tar_reader"
|
require "rubygems/package/tar_reader"
|
||||||
|
|
|
@ -130,11 +130,14 @@ module Bundler
|
||||||
|
|
||||||
specs_to_cache.each do |spec|
|
specs_to_cache.each do |spec|
|
||||||
next if spec.name == "bundler"
|
next if spec.name == "bundler"
|
||||||
next if spec.source.is_a?(Source::Gemspec)
|
|
||||||
if spec.source.respond_to?(:migrate_cache)
|
source = spec.source
|
||||||
spec.source.migrate_cache(custom_path, local: local)
|
next if source.is_a?(Source::Gemspec)
|
||||||
elsif spec.source.respond_to?(:cache)
|
|
||||||
spec.source.cache(spec, custom_path)
|
if source.respond_to?(:migrate_cache)
|
||||||
|
source.migrate_cache(custom_path, local: local)
|
||||||
|
elsif source.respond_to?(:cache)
|
||||||
|
source.cache(spec, custom_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -4,15 +4,12 @@ module Bundler
|
||||||
class Source
|
class Source
|
||||||
class Gemspec < Path
|
class Gemspec < Path
|
||||||
attr_reader :gemspec
|
attr_reader :gemspec
|
||||||
|
attr_writer :checksum_store
|
||||||
|
|
||||||
def initialize(options)
|
def initialize(options)
|
||||||
super
|
super
|
||||||
@gemspec = options["gemspec"]
|
@gemspec = options["gemspec"]
|
||||||
end
|
end
|
||||||
|
|
||||||
def as_path_source
|
|
||||||
Path.new(options)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -185,7 +185,8 @@ module Bundler
|
||||||
_, err, status = capture(command, nil)
|
_, err, status = capture(command, nil)
|
||||||
return extra_ref if status.success?
|
return extra_ref if status.success?
|
||||||
|
|
||||||
if err.include?("Could not find remote branch")
|
if err.include?("Could not find remote branch") || # git up to 2.49
|
||||||
|
err.include?("Remote branch #{branch_option} not found") # git 2.49 or higher
|
||||||
raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
|
raise MissingGitRevisionError.new(command_with_no_credentials, nil, explicit_ref, credential_filtered_uri)
|
||||||
else
|
else
|
||||||
idx = command.index("--depth")
|
idx = command.index("--depth")
|
||||||
|
@ -262,7 +263,7 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def not_pinned?
|
def not_pinned?
|
||||||
branch || tag || ref.nil?
|
branch_option || ref.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def pinned_to_full_sha?
|
def pinned_to_full_sha?
|
||||||
|
@ -426,7 +427,7 @@ module Bundler
|
||||||
# anyways.
|
# anyways.
|
||||||
return args if @revision
|
return args if @revision
|
||||||
|
|
||||||
args += ["--branch", branch || tag] if branch || tag
|
args += ["--branch", branch_option] if branch_option
|
||||||
args
|
args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -442,6 +443,10 @@ module Bundler
|
||||||
extra_args
|
extra_args
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def branch_option
|
||||||
|
branch || tag
|
||||||
|
end
|
||||||
|
|
||||||
def full_clone?
|
def full_clone?
|
||||||
depth.nil?
|
depth.nil?
|
||||||
end
|
end
|
||||||
|
|
|
@ -60,8 +60,8 @@ module Bundler
|
||||||
end
|
end
|
||||||
|
|
||||||
def eql?(other)
|
def eql?(other)
|
||||||
return unless other.class == self.class
|
[Gemspec, Path].include?(other.class) &&
|
||||||
expanded_original_path == other.expanded_original_path &&
|
expanded_original_path == other.expanded_original_path &&
|
||||||
version == other.version
|
version == other.version
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -173,39 +173,57 @@ module Bundler
|
||||||
|
|
||||||
def map_sources(replacement_sources)
|
def map_sources(replacement_sources)
|
||||||
rubygems = @rubygems_sources.map do |source|
|
rubygems = @rubygems_sources.map do |source|
|
||||||
replace_rubygems_source(replacement_sources, source) || source
|
replace_rubygems_source(replacement_sources, source)
|
||||||
end
|
end
|
||||||
|
|
||||||
git, plugin = [@git_sources, @plugin_sources].map do |sources|
|
git, plugin = [@git_sources, @plugin_sources].map do |sources|
|
||||||
sources.map do |source|
|
sources.map do |source|
|
||||||
replacement_sources.find {|s| s == source } || source
|
replace_source(replacement_sources, source)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
path = @path_sources.map do |source|
|
path = @path_sources.map do |source|
|
||||||
replacement_sources.find {|s| s == (source.is_a?(Source::Gemspec) ? source.as_path_source : source) } || source
|
replace_path_source(replacement_sources, source)
|
||||||
end
|
end
|
||||||
|
|
||||||
[rubygems, path, git, plugin]
|
[rubygems, path, git, plugin]
|
||||||
end
|
end
|
||||||
|
|
||||||
def global_replacement_source(replacement_sources)
|
def global_replacement_source(replacement_sources)
|
||||||
replacement_source = replace_rubygems_source(replacement_sources, global_rubygems_source)
|
replace_rubygems_source(replacement_sources, global_rubygems_source, &:local!)
|
||||||
return global_rubygems_source unless replacement_source
|
|
||||||
|
|
||||||
replacement_source.local!
|
|
||||||
replacement_source
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def replace_rubygems_source(replacement_sources, gemfile_source)
|
def replace_rubygems_source(replacement_sources, gemfile_source)
|
||||||
replacement_source = replacement_sources.find {|s| s == gemfile_source }
|
replace_source(replacement_sources, gemfile_source) do |replacement_source|
|
||||||
return unless replacement_source
|
# locked sources never include credentials so always prefer remotes from the gemfile
|
||||||
|
replacement_source.remotes = gemfile_source.remotes
|
||||||
|
|
||||||
|
yield replacement_source if block_given?
|
||||||
|
|
||||||
|
replacement_source
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def replace_source(replacement_sources, gemfile_source)
|
||||||
|
replacement_source = replacement_sources.find {|s| s == gemfile_source }
|
||||||
|
return gemfile_source unless replacement_source
|
||||||
|
|
||||||
|
replacement_source = yield(replacement_source) if block_given?
|
||||||
|
|
||||||
# locked sources never include credentials so always prefer remotes from the gemfile
|
|
||||||
replacement_source.remotes = gemfile_source.remotes
|
|
||||||
replacement_source
|
replacement_source
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def replace_path_source(replacement_sources, gemfile_source)
|
||||||
|
replace_source(replacement_sources, gemfile_source) do |replacement_source|
|
||||||
|
if gemfile_source.is_a?(Source::Gemspec)
|
||||||
|
gemfile_source.checksum_store = replacement_source.checksum_store
|
||||||
|
gemfile_source
|
||||||
|
else
|
||||||
|
replacement_source
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def different_sources?(lock_sources, replacement_sources)
|
def different_sources?(lock_sources, replacement_sources)
|
||||||
!equivalent_sources?(lock_sources, replacement_sources)
|
!equivalent_sources?(lock_sources, replacement_sources)
|
||||||
end
|
end
|
||||||
|
|
|
@ -47,8 +47,17 @@ module Bundler
|
||||||
end.uniq
|
end.uniq
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def add_originally_invalid_platforms!(platforms, originally_invalid_platforms)
|
||||||
|
originally_invalid_platforms.each do |originally_invalid_platform|
|
||||||
|
platforms << originally_invalid_platform if complete_platform(originally_invalid_platform)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def add_extra_platforms!(platforms)
|
def add_extra_platforms!(platforms)
|
||||||
return platforms.concat([Gem::Platform::RUBY]).uniq if @specs.empty?
|
if @specs.empty?
|
||||||
|
platforms.concat([Gem::Platform::RUBY]).uniq
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
new_platforms = all_platforms.select do |platform|
|
new_platforms = all_platforms.select do |platform|
|
||||||
next if platforms.include?(platform)
|
next if platforms.include?(platform)
|
||||||
|
@ -56,14 +65,12 @@ module Bundler
|
||||||
|
|
||||||
complete_platform(platform)
|
complete_platform(platform)
|
||||||
end
|
end
|
||||||
return platforms if new_platforms.empty?
|
return if new_platforms.empty?
|
||||||
|
|
||||||
platforms.concat(new_platforms)
|
platforms.concat(new_platforms)
|
||||||
|
|
||||||
less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
|
less_specific_platform = new_platforms.find {|platform| platform != Gem::Platform::RUBY && Bundler.local_platform === platform && platform === Bundler.local_platform }
|
||||||
platforms.delete(Bundler.local_platform) if less_specific_platform
|
platforms.delete(Bundler.local_platform) if less_specific_platform
|
||||||
|
|
||||||
platforms
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_deps(s)
|
def validate_deps(s)
|
||||||
|
|
|
@ -160,6 +160,12 @@ class Bundler::ConnectionPool
|
||||||
@available.shutdown(reload: true, &block)
|
@available.shutdown(reload: true, &block)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
## Reaps idle connections that have been idle for over +idle_seconds+.
|
||||||
|
# +idle_seconds+ defaults to 60.
|
||||||
|
def reap(idle_seconds = 60, &block)
|
||||||
|
@available.reap(idle_seconds, &block)
|
||||||
|
end
|
||||||
|
|
||||||
# Size of this connection pool
|
# Size of this connection pool
|
||||||
attr_reader :size
|
attr_reader :size
|
||||||
# Automatically drop all connections after fork
|
# Automatically drop all connections after fork
|
||||||
|
@ -169,6 +175,11 @@ class Bundler::ConnectionPool
|
||||||
def available
|
def available
|
||||||
@available.length
|
@available.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Number of pool entries created and idle in the pool.
|
||||||
|
def idle
|
||||||
|
@available.idle
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
require_relative "connection_pool/timed_stack"
|
require_relative "connection_pool/timed_stack"
|
||||||
|
|
|
@ -41,6 +41,7 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
def push(obj, options = {})
|
def push(obj, options = {})
|
||||||
@mutex.synchronize do
|
@mutex.synchronize do
|
||||||
if @shutdown_block
|
if @shutdown_block
|
||||||
|
@created -= 1 unless @created == 0
|
||||||
@shutdown_block.call(obj)
|
@shutdown_block.call(obj)
|
||||||
else
|
else
|
||||||
store_connection obj, options
|
store_connection obj, options
|
||||||
|
@ -98,6 +99,26 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Reaps connections that were checked in more than +idle_seconds+ ago.
|
||||||
|
def reap(idle_seconds, &block)
|
||||||
|
raise ArgumentError, "reap must receive a block" unless block
|
||||||
|
raise ArgumentError, "idle_seconds must be a number" unless idle_seconds.is_a?(Numeric)
|
||||||
|
raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block
|
||||||
|
|
||||||
|
idle.times do
|
||||||
|
conn =
|
||||||
|
@mutex.synchronize do
|
||||||
|
raise Bundler::ConnectionPool::PoolShuttingDownError if @shutdown_block
|
||||||
|
|
||||||
|
reserve_idle_connection(idle_seconds)
|
||||||
|
end
|
||||||
|
break unless conn
|
||||||
|
|
||||||
|
block.call(conn)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Returns +true+ if there are no available connections.
|
# Returns +true+ if there are no available connections.
|
||||||
|
|
||||||
|
@ -112,6 +133,12 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
@max - @created + @que.length
|
@max - @created + @que.length
|
||||||
end
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# The number of connections created and available on the stack.
|
||||||
|
def idle
|
||||||
|
@que.length
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def current_time
|
def current_time
|
||||||
|
@ -133,7 +160,7 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
# This method must return a connection from the stack.
|
# This method must return a connection from the stack.
|
||||||
|
|
||||||
def fetch_connection(options = nil)
|
def fetch_connection(options = nil)
|
||||||
@que.pop
|
@que.pop&.first
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -144,9 +171,32 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
def shutdown_connections(options = nil)
|
def shutdown_connections(options = nil)
|
||||||
while connection_stored?(options)
|
while connection_stored?(options)
|
||||||
conn = fetch_connection(options)
|
conn = fetch_connection(options)
|
||||||
|
@created -= 1 unless @created == 0
|
||||||
@shutdown_block.call(conn)
|
@shutdown_block.call(conn)
|
||||||
end
|
end
|
||||||
@created = 0
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# This is an extension point for TimedStack and is called with a mutex.
|
||||||
|
#
|
||||||
|
# This method returns the oldest idle connection if it has been idle for more than idle_seconds.
|
||||||
|
# This requires that the stack is kept in order of checked in time (oldest first).
|
||||||
|
|
||||||
|
def reserve_idle_connection(idle_seconds)
|
||||||
|
return unless idle_connections?(idle_seconds)
|
||||||
|
|
||||||
|
@created -= 1 unless @created == 0
|
||||||
|
|
||||||
|
@que.shift.first
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# This is an extension point for TimedStack and is called with a mutex.
|
||||||
|
#
|
||||||
|
# Returns true if the first connection in the stack has been idle for more than idle_seconds
|
||||||
|
|
||||||
|
def idle_connections?(idle_seconds)
|
||||||
|
connection_stored? && (current_time - @que.first.last > idle_seconds)
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -155,7 +205,7 @@ class Bundler::ConnectionPool::TimedStack
|
||||||
# This method must return +obj+ to the stack.
|
# This method must return +obj+ to the stack.
|
||||||
|
|
||||||
def store_connection(obj, options = nil)
|
def store_connection(obj, options = nil)
|
||||||
@que.push obj
|
@que.push [obj, current_time]
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
class Bundler::ConnectionPool
|
class Bundler::ConnectionPool
|
||||||
VERSION = "2.4.1"
|
VERSION = "2.5.0"
|
||||||
end
|
end
|
||||||
|
|
|
@ -79,29 +79,17 @@ module Bundler::PubGrub
|
||||||
dependencies_for(@root_package, @root_version)
|
dependencies_for(@root_package, @root_version)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Override me (maybe)
|
|
||||||
#
|
|
||||||
# If not overridden, the order returned by all_versions_for will be used
|
|
||||||
#
|
|
||||||
# Returns: Array of versions in preferred order
|
|
||||||
def sort_versions_by_preferred(package, sorted_versions)
|
|
||||||
indexes = @version_indexes[package]
|
|
||||||
sorted_versions.sort_by { |version| indexes[version] }
|
|
||||||
end
|
|
||||||
|
|
||||||
def initialize
|
def initialize
|
||||||
@root_package = Package.root
|
@root_package = Package.root
|
||||||
@root_version = Package.root_version
|
@root_version = Package.root_version
|
||||||
|
|
||||||
@cached_versions = Hash.new do |h,k|
|
@sorted_versions = Hash.new do |h,k|
|
||||||
if k == @root_package
|
if k == @root_package
|
||||||
h[k] = [@root_version]
|
h[k] = [@root_version]
|
||||||
else
|
else
|
||||||
h[k] = all_versions_for(k)
|
h[k] = all_versions_for(k).sort
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@sorted_versions = Hash.new { |h,k| h[k] = @cached_versions[k].sort }
|
|
||||||
@version_indexes = Hash.new { |h,k| h[k] = @cached_versions[k].each.with_index.to_h }
|
|
||||||
|
|
||||||
@cached_dependencies = Hash.new do |packages, package|
|
@cached_dependencies = Hash.new do |packages, package|
|
||||||
if package == @root_package
|
if package == @root_package
|
||||||
|
@ -117,15 +105,7 @@ module Bundler::PubGrub
|
||||||
end
|
end
|
||||||
|
|
||||||
def versions_for(package, range=VersionRange.any)
|
def versions_for(package, range=VersionRange.any)
|
||||||
versions = range.select_versions(@sorted_versions[package])
|
range.select_versions(@sorted_versions[package])
|
||||||
|
|
||||||
# Conditional avoids (among other things) calling
|
|
||||||
# sort_versions_by_preferred with the root package
|
|
||||||
if versions.size > 1
|
|
||||||
sort_versions_by_preferred(package, versions)
|
|
||||||
else
|
|
||||||
versions
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def no_versions_incompatibility_for(_package, unsatisfied_term)
|
def no_versions_incompatibility_for(_package, unsatisfied_term)
|
||||||
|
@ -164,7 +144,7 @@ module Bundler::PubGrub
|
||||||
sorted_versions[high]
|
sorted_versions[high]
|
||||||
end
|
end
|
||||||
|
|
||||||
range = VersionRange.new(min: low, max: high, include_min: true)
|
range = VersionRange.new(min: low, max: high, include_min: !low.nil?)
|
||||||
|
|
||||||
self_constraint = VersionConstraint.new(package, range: range)
|
self_constraint = VersionConstraint.new(package, range: range)
|
||||||
|
|
||||||
|
|
42
lib/bundler/vendor/pub_grub/lib/pub_grub/strategy.rb
vendored
Normal file
42
lib/bundler/vendor/pub_grub/lib/pub_grub/strategy.rb
vendored
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
module Bundler::PubGrub
|
||||||
|
class Strategy
|
||||||
|
def initialize(source)
|
||||||
|
@source = source
|
||||||
|
|
||||||
|
@root_package = Package.root
|
||||||
|
@root_version = Package.root_version
|
||||||
|
|
||||||
|
@version_indexes = Hash.new do |h,k|
|
||||||
|
if k == @root_package
|
||||||
|
h[k] = { @root_version => 0 }
|
||||||
|
else
|
||||||
|
h[k] = @source.all_versions_for(k).each.with_index.to_h
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_package_and_version(unsatisfied)
|
||||||
|
package, range = next_term_to_try_from(unsatisfied)
|
||||||
|
|
||||||
|
[package, most_preferred_version_of(package, range)]
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def most_preferred_version_of(package, range)
|
||||||
|
versions = @source.versions_for(package, range)
|
||||||
|
|
||||||
|
indexes = @version_indexes[package]
|
||||||
|
versions.min_by { |version| indexes[version] }
|
||||||
|
end
|
||||||
|
|
||||||
|
def next_term_to_try_from(unsatisfied)
|
||||||
|
unsatisfied.min_by do |package, range|
|
||||||
|
matching_versions = @source.versions_for(package, range)
|
||||||
|
higher_versions = @source.versions_for(package, range.upper_invert)
|
||||||
|
|
||||||
|
[matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -76,6 +76,9 @@ module Bundler::PubGrub
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize(min: nil, max: nil, include_min: false, include_max: false, name: nil)
|
def initialize(min: nil, max: nil, include_min: false, include_max: false, name: nil)
|
||||||
|
raise ArgumentError, "Ranges without a lower bound cannot have include_min == true" if !min && include_min == true
|
||||||
|
raise ArgumentError, "Ranges without an upper bound cannot have include_max == true" if !max && include_max == true
|
||||||
|
|
||||||
@min = min
|
@min = min
|
||||||
@max = max
|
@max = max
|
||||||
@include_min = include_min
|
@include_min = include_min
|
||||||
|
@ -311,10 +314,19 @@ module Bundler::PubGrub
|
||||||
|
|
||||||
def contiguous_to?(other)
|
def contiguous_to?(other)
|
||||||
return false if other.empty?
|
return false if other.empty?
|
||||||
|
return true if any?
|
||||||
|
|
||||||
intersects?(other) ||
|
intersects?(other) || contiguous_below?(other) || contiguous_above?(other)
|
||||||
(min == other.max && (include_min || other.include_max)) ||
|
end
|
||||||
(max == other.min && (include_max || other.include_min))
|
|
||||||
|
def contiguous_below?(other)
|
||||||
|
return false if !max || !other.min
|
||||||
|
|
||||||
|
max == other.min && (include_max || other.include_min)
|
||||||
|
end
|
||||||
|
|
||||||
|
def contiguous_above?(other)
|
||||||
|
other.contiguous_below?(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def allows_all?(other)
|
def allows_all?(other)
|
||||||
|
@ -375,15 +387,15 @@ module Bundler::PubGrub
|
||||||
def invert
|
def invert
|
||||||
return self.class.empty if any?
|
return self.class.empty if any?
|
||||||
|
|
||||||
low = VersionRange.new(max: min, include_max: !include_min)
|
low = -> { VersionRange.new(max: min, include_max: !include_min) }
|
||||||
high = VersionRange.new(min: max, include_min: !include_max)
|
high = -> { VersionRange.new(min: max, include_min: !include_max) }
|
||||||
|
|
||||||
if !min
|
if !min
|
||||||
high
|
high.call
|
||||||
elsif !max
|
elsif !max
|
||||||
low
|
low.call
|
||||||
else
|
else
|
||||||
low.union(high)
|
low.call.union(high.call)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,20 @@ require_relative 'partial_solution'
|
||||||
require_relative 'term'
|
require_relative 'term'
|
||||||
require_relative 'incompatibility'
|
require_relative 'incompatibility'
|
||||||
require_relative 'solve_failure'
|
require_relative 'solve_failure'
|
||||||
|
require_relative 'strategy'
|
||||||
|
|
||||||
module Bundler::PubGrub
|
module Bundler::PubGrub
|
||||||
class VersionSolver
|
class VersionSolver
|
||||||
attr_reader :logger
|
attr_reader :logger
|
||||||
attr_reader :source
|
attr_reader :source
|
||||||
attr_reader :solution
|
attr_reader :solution
|
||||||
|
attr_reader :strategy
|
||||||
|
|
||||||
def initialize(source:, root: Package.root, logger: Bundler::PubGrub.logger)
|
def initialize(source:, root: Package.root, strategy: Strategy.new(source), logger: Bundler::PubGrub.logger)
|
||||||
@logger = logger
|
@logger = logger
|
||||||
|
|
||||||
@source = source
|
@source = source
|
||||||
|
@strategy = strategy
|
||||||
|
|
||||||
# { package => [incompatibility, ...]}
|
# { package => [incompatibility, ...]}
|
||||||
@incompatibilities = Hash.new do |h, k|
|
@incompatibilities = Hash.new do |h, k|
|
||||||
|
@ -36,26 +39,25 @@ module Bundler::PubGrub
|
||||||
|
|
||||||
# Returns true if there is more work to be done, false otherwise
|
# Returns true if there is more work to be done, false otherwise
|
||||||
def work
|
def work
|
||||||
return false if solved?
|
unsatisfied_terms = solution.unsatisfied
|
||||||
|
if unsatisfied_terms.empty?
|
||||||
next_package = choose_package_version
|
|
||||||
propagate(next_package)
|
|
||||||
|
|
||||||
if solved?
|
|
||||||
logger.info { "Solution found after #{solution.attempted_solutions} attempts:" }
|
logger.info { "Solution found after #{solution.attempted_solutions} attempts:" }
|
||||||
solution.decisions.each do |package, version|
|
solution.decisions.each do |package, version|
|
||||||
next if Package.root?(package)
|
next if Package.root?(package)
|
||||||
logger.info { "* #{package} #{version}" }
|
logger.info { "* #{package} #{version}" }
|
||||||
end
|
end
|
||||||
|
|
||||||
false
|
return false
|
||||||
else
|
|
||||||
true
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
next_package = choose_package_version_from(unsatisfied_terms)
|
||||||
|
propagate(next_package)
|
||||||
|
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def solve
|
def solve
|
||||||
work until solved?
|
while work; end
|
||||||
|
|
||||||
solution.decisions
|
solution.decisions
|
||||||
end
|
end
|
||||||
|
@ -105,29 +107,15 @@ module Bundler::PubGrub
|
||||||
unsatisfied.package
|
unsatisfied.package
|
||||||
end
|
end
|
||||||
|
|
||||||
def next_package_to_try
|
def choose_package_version_from(unsatisfied_terms)
|
||||||
solution.unsatisfied.min_by do |term|
|
remaining = unsatisfied_terms.map { |t| [t.package, t.constraint.range] }.to_h
|
||||||
package = term.package
|
|
||||||
range = term.constraint.range
|
|
||||||
matching_versions = source.versions_for(package, range)
|
|
||||||
higher_versions = source.versions_for(package, range.upper_invert)
|
|
||||||
|
|
||||||
[matching_versions.count <= 1 ? 0 : 1, higher_versions.count]
|
package, version = strategy.next_package_and_version(remaining)
|
||||||
end.package
|
|
||||||
end
|
|
||||||
|
|
||||||
def choose_package_version
|
|
||||||
if solution.unsatisfied.empty?
|
|
||||||
logger.info "No packages unsatisfied. Solving complete!"
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
package = next_package_to_try
|
|
||||||
unsatisfied_term = solution.unsatisfied.find { |t| t.package == package }
|
|
||||||
version = source.versions_for(package, unsatisfied_term.constraint.range).first
|
|
||||||
logger.debug { "attempting #{package} #{version}" }
|
logger.debug { "attempting #{package} #{version}" }
|
||||||
|
|
||||||
if version.nil?
|
if version.nil?
|
||||||
|
unsatisfied_term = unsatisfied_terms.find { |t| t.package == package }
|
||||||
add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term)
|
add_incompatibility source.no_versions_incompatibility_for(package, unsatisfied_term)
|
||||||
return package
|
return package
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: false
|
# frozen_string_literal: false
|
||||||
|
|
||||||
module Bundler
|
module Bundler
|
||||||
VERSION = "2.6.6".freeze
|
VERSION = "2.6.7".freeze
|
||||||
|
|
||||||
def self.bundler_major_version
|
def self.bundler_major_version
|
||||||
@bundler_major_version ||= VERSION.split(".").first.to_i
|
@bundler_major_version ||= VERSION.split(".").first.to_i
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
require "rbconfig"
|
require "rbconfig"
|
||||||
|
|
||||||
module Gem
|
module Gem
|
||||||
VERSION = "3.6.6"
|
VERSION = "3.6.7"
|
||||||
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
|
||||||
|
@ -156,6 +156,13 @@ module Gem
|
||||||
specifications/default
|
specifications/default
|
||||||
].freeze
|
].freeze
|
||||||
|
|
||||||
|
##
|
||||||
|
# The default value for SOURCE_DATE_EPOCH if not specified.
|
||||||
|
# We want a date after 1980-01-01, to prevent issues with Zip files.
|
||||||
|
# This particular timestamp is for 1980-01-02 00:00:00 GMT.
|
||||||
|
|
||||||
|
DEFAULT_SOURCE_DATE_EPOCH = 315_619_200
|
||||||
|
|
||||||
@@win_platform = nil
|
@@win_platform = nil
|
||||||
|
|
||||||
@configuration = nil
|
@configuration = nil
|
||||||
|
@ -1155,8 +1162,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
|
||||||
|
|
||||||
##
|
##
|
||||||
# If the SOURCE_DATE_EPOCH environment variable is set, returns it's value.
|
# If the SOURCE_DATE_EPOCH environment variable is set, returns it's value.
|
||||||
# Otherwise, returns the time that +Gem.source_date_epoch_string+ was
|
# Otherwise, returns DEFAULT_SOURCE_DATE_EPOCH as a string.
|
||||||
# first called in the same format as SOURCE_DATE_EPOCH.
|
|
||||||
#
|
#
|
||||||
# NOTE(@duckinator): The implementation is a tad weird because we want to:
|
# NOTE(@duckinator): The implementation is a tad weird because we want to:
|
||||||
# 1. Make builds reproducible by default, by having this function always
|
# 1. Make builds reproducible by default, by having this function always
|
||||||
|
@ -1171,15 +1177,12 @@ An Array (#{env.inspect}) was passed in from #{caller[3]}
|
||||||
# https://reproducible-builds.org/specs/source-date-epoch/
|
# https://reproducible-builds.org/specs/source-date-epoch/
|
||||||
|
|
||||||
def self.source_date_epoch_string
|
def self.source_date_epoch_string
|
||||||
# The value used if $SOURCE_DATE_EPOCH is not set.
|
|
||||||
@default_source_date_epoch ||= Time.now.to_i.to_s
|
|
||||||
|
|
||||||
specified_epoch = ENV["SOURCE_DATE_EPOCH"]
|
specified_epoch = ENV["SOURCE_DATE_EPOCH"]
|
||||||
|
|
||||||
# If it's empty or just whitespace, treat it like it wasn't set at all.
|
# If it's empty or just whitespace, treat it like it wasn't set at all.
|
||||||
specified_epoch = nil if !specified_epoch.nil? && specified_epoch.strip.empty?
|
specified_epoch = nil if !specified_epoch.nil? && specified_epoch.strip.empty?
|
||||||
|
|
||||||
epoch = specified_epoch || @default_source_date_epoch
|
epoch = specified_epoch || DEFAULT_SOURCE_DATE_EPOCH.to_s
|
||||||
|
|
||||||
epoch.strip
|
epoch.strip
|
||||||
end
|
end
|
||||||
|
|
|
@ -195,7 +195,7 @@ to the same gem path as user-installed gems.
|
||||||
argv = ARGV.clone
|
argv = ARGV.clone
|
||||||
ARGV.replace options[:args]
|
ARGV.replace options[:args]
|
||||||
|
|
||||||
exe = executable = options[:executable]
|
executable = options[:executable]
|
||||||
|
|
||||||
contains_executable = Gem.loaded_specs.values.select do |spec|
|
contains_executable = Gem.loaded_specs.values.select do |spec|
|
||||||
spec.executables.include?(executable)
|
spec.executables.include?(executable)
|
||||||
|
@ -206,13 +206,22 @@ to the same gem path as user-installed gems.
|
||||||
end
|
end
|
||||||
|
|
||||||
if contains_executable.empty?
|
if contains_executable.empty?
|
||||||
if (spec = Gem.loaded_specs[executable]) && (exe = spec.executable)
|
spec = Gem.loaded_specs[executable]
|
||||||
contains_executable << spec
|
|
||||||
else
|
if spec.nil? || spec.executables.empty?
|
||||||
alert_error "Failed to load executable `#{executable}`," \
|
alert_error "Failed to load executable `#{executable}`," \
|
||||||
" are you sure the gem `#{options[:gem_name]}` contains it?"
|
" are you sure the gem `#{options[:gem_name]}` contains it?"
|
||||||
terminate_interaction 1
|
terminate_interaction 1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if spec.executables.size > 1
|
||||||
|
alert_error "Ambiguous which executable from gem `#{executable}` should be run: " \
|
||||||
|
"the options are #{spec.executables.sort}, specify one via COMMAND, and use `-g` and `-v` to specify gem and version"
|
||||||
|
terminate_interaction 1
|
||||||
|
end
|
||||||
|
|
||||||
|
contains_executable << spec
|
||||||
|
executable = spec.executable
|
||||||
end
|
end
|
||||||
|
|
||||||
if contains_executable.size > 1
|
if contains_executable.size > 1
|
||||||
|
@ -223,8 +232,8 @@ to the same gem path as user-installed gems.
|
||||||
end
|
end
|
||||||
|
|
||||||
old_exe = $0
|
old_exe = $0
|
||||||
$0 = exe
|
$0 = executable
|
||||||
load Gem.activate_bin_path(contains_executable.first.name, exe, ">= 0.a")
|
load Gem.activate_bin_path(contains_executable.first.name, executable, ">= 0.a")
|
||||||
ensure
|
ensure
|
||||||
$0 = old_exe if old_exe
|
$0 = old_exe if old_exe
|
||||||
ARGV.replace argv
|
ARGV.replace argv
|
||||||
|
|
|
@ -239,7 +239,7 @@ module Gem
|
||||||
# Enables automatic installation into user directory
|
# Enables automatic installation into user directory
|
||||||
|
|
||||||
def self.default_user_install # :nodoc:
|
def self.default_user_install # :nodoc:
|
||||||
if !ENV.key?("GEM_HOME") && (File.exist?(Gem.dir) && !File.writable?(Gem.dir))
|
if !ENV.key?("GEM_HOME") && File.exist?(Gem.dir) && !File.writable?(Gem.dir)
|
||||||
Gem.ui.say "Defaulting to user installation because default installation directory (#{Gem.dir}) is not writable."
|
Gem.ui.say "Defaulting to user installation because default installation directory (#{Gem.dir}) is not writable."
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,15 +1,12 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Gem::Resolver::APISet::GemParser
|
class Gem::Resolver::APISet::GemParser
|
||||||
EMPTY_ARRAY = [].freeze
|
|
||||||
private_constant :EMPTY_ARRAY
|
|
||||||
|
|
||||||
def parse(line)
|
def parse(line)
|
||||||
version_and_platform, rest = line.split(" ", 2)
|
version_and_platform, rest = line.split(" ", 2)
|
||||||
version, platform = version_and_platform.split("-", 2)
|
version, platform = version_and_platform.split("-", 2)
|
||||||
dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
|
dependencies, requirements = rest.split("|", 2).map! {|s| s.split(",") } if rest
|
||||||
dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
|
dependencies = dependencies ? dependencies.map! {|d| parse_dependency(d) } : []
|
||||||
requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : EMPTY_ARRAY
|
requirements = requirements ? requirements.map! {|d| parse_dependency(d) } : []
|
||||||
[version, platform, dependencies, requirements]
|
[version, platform, dependencies, requirements]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -2144,11 +2144,11 @@ class Gem::Specification < Gem::BasicSpecification
|
||||||
@files.concat(@extra_rdoc_files)
|
@files.concat(@extra_rdoc_files)
|
||||||
end
|
end
|
||||||
|
|
||||||
@files = @files.uniq if @files
|
@files = @files.uniq.sort if @files
|
||||||
@extensions = @extensions.uniq if @extensions
|
@extensions = @extensions.uniq.sort if @extensions
|
||||||
@test_files = @test_files.uniq if @test_files
|
@test_files = @test_files.uniq.sort if @test_files
|
||||||
@executables = @executables.uniq if @executables
|
@executables = @executables.uniq.sort if @executables
|
||||||
@extra_rdoc_files = @extra_rdoc_files.uniq if @extra_rdoc_files
|
@extra_rdoc_files = @extra_rdoc_files.uniq.sort if @extra_rdoc_files
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
|
|
@ -368,13 +368,13 @@ class Gem::Version
|
||||||
|
|
||||||
lhsize = lhsegments.size
|
lhsize = lhsegments.size
|
||||||
rhsize = rhsegments.size
|
rhsize = rhsegments.size
|
||||||
limit = (lhsize > rhsize ? lhsize : rhsize) - 1
|
limit = (lhsize > rhsize ? rhsize : lhsize)
|
||||||
|
|
||||||
i = 0
|
i = 0
|
||||||
|
|
||||||
while i <= limit
|
while i < limit
|
||||||
lhs = lhsegments[i] || 0
|
lhs = lhsegments[i]
|
||||||
rhs = rhsegments[i] || 0
|
rhs = rhsegments[i]
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
next if lhs == rhs
|
next if lhs == rhs
|
||||||
|
@ -384,6 +384,24 @@ class Gem::Version
|
||||||
return lhs <=> rhs
|
return lhs <=> rhs
|
||||||
end
|
end
|
||||||
|
|
||||||
|
lhs = lhsegments[i]
|
||||||
|
|
||||||
|
if lhs.nil?
|
||||||
|
rhs = rhsegments[i]
|
||||||
|
|
||||||
|
while i < rhsize
|
||||||
|
return 1 if String === rhs
|
||||||
|
return -1 unless rhs.zero?
|
||||||
|
rhs = rhsegments[i += 1]
|
||||||
|
end
|
||||||
|
else
|
||||||
|
while i < lhsize
|
||||||
|
return -1 if String === lhs
|
||||||
|
return 1 unless lhs.zero?
|
||||||
|
lhs = lhsegments[i += 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
0
|
0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ RSpec.describe Bundler::Definition do
|
||||||
before { Bundler::Definition.no_lock = true }
|
before { Bundler::Definition.no_lock = true }
|
||||||
after { Bundler::Definition.no_lock = false }
|
after { Bundler::Definition.no_lock = false }
|
||||||
|
|
||||||
it "does not create a lock file" do
|
it "does not create a lockfile" do
|
||||||
subject.lock
|
subject.lock
|
||||||
expect(bundled_app_lock).not_to be_file
|
expect(bundled_app_lock).not_to be_file
|
||||||
end
|
end
|
||||||
|
|
|
@ -138,7 +138,7 @@ RSpec.describe Bundler::LockfileParser do
|
||||||
expect(subject.ruby_version).to eq ruby_version
|
expect(subject.ruby_version).to eq ruby_version
|
||||||
rake_spec = specs.last
|
rake_spec = specs.last
|
||||||
checksums = subject.sources.last.checksum_store.to_lock(specs.last)
|
checksums = subject.sources.last.checksum_store.to_lock(specs.last)
|
||||||
expect(checksums).to eq("#{rake_spec.name_tuple.lock_name} #{rake_checksums.map(&:to_lock).sort.join(",")}")
|
expect(checksums).to eq("#{rake_spec.lock_name} #{rake_checksums.map(&:to_lock).sort.join(",")}")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ RSpec.describe Bundler::SharedHelpers do
|
||||||
|
|
||||||
before { allow(subject).to receive(:default_gemfile).and_return(gemfile_path) }
|
before { allow(subject).to receive(:default_gemfile).and_return(gemfile_path) }
|
||||||
|
|
||||||
it "returns the lock file path" do
|
it "returns the lockfile path" do
|
||||||
expect(subject.default_lockfile).to eq(expected_lockfile_path)
|
expect(subject.default_lockfile).to eq(expected_lockfile_path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -258,7 +258,7 @@ RSpec.describe "bundle check" do
|
||||||
expect(err).not_to include("Unfortunately, a fatal error has occurred. ")
|
expect(err).not_to include("Unfortunately, a fatal error has occurred. ")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "fails when there's no lock file and frozen is set" do
|
it "fails when there's no lockfile and frozen is set" do
|
||||||
install_gemfile <<-G
|
install_gemfile <<-G
|
||||||
source "https://gem.repo1"
|
source "https://gem.repo1"
|
||||||
gem "foo"
|
gem "foo"
|
||||||
|
|
|
@ -49,7 +49,7 @@ RSpec.describe "bundle install with gem sources" do
|
||||||
expect(bundled_app(".bundle")).not_to exist
|
expect(bundled_app(".bundle")).not_to exist
|
||||||
end
|
end
|
||||||
|
|
||||||
it "creates lock files based on the Gemfile name" do
|
it "creates lockfiles based on the Gemfile name" do
|
||||||
gemfile bundled_app("OmgFile"), <<-G
|
gemfile bundled_app("OmgFile"), <<-G
|
||||||
source "https://gem.repo1"
|
source "https://gem.repo1"
|
||||||
gem "myrack", "1.0"
|
gem "myrack", "1.0"
|
||||||
|
@ -1368,7 +1368,7 @@ RSpec.describe "bundle install with gem sources" do
|
||||||
it "adds the current platform to the lockfile" do
|
it "adds the current platform to the lockfile" do
|
||||||
bundle "install --verbose"
|
bundle "install --verbose"
|
||||||
|
|
||||||
expect(out).to include("re-resolving dependencies because your lockfile does not include the current platform")
|
expect(out).to include("re-resolving dependencies because your lockfile is missing the current platform")
|
||||||
expect(out).not_to include("you are adding a new platform to your lockfile")
|
expect(out).not_to include("you are adding a new platform to your lockfile")
|
||||||
|
|
||||||
expect(lockfile).to eq <<~L
|
expect(lockfile).to eq <<~L
|
||||||
|
|
|
@ -80,7 +80,7 @@ RSpec.describe "bundle update" do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe "with --gemfile" do
|
describe "with --gemfile" do
|
||||||
it "creates lock files based on the Gemfile name" do
|
it "creates lockfiles based on the Gemfile name" do
|
||||||
gemfile bundled_app("OmgFile"), <<-G
|
gemfile bundled_app("OmgFile"), <<-G
|
||||||
source "https://gem.repo1"
|
source "https://gem.repo1"
|
||||||
gem "myrack", "1.0"
|
gem "myrack", "1.0"
|
||||||
|
@ -640,7 +640,7 @@ RSpec.describe "bundle update" do
|
||||||
myrack
|
myrack
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
#{local_platform}
|
x86-darwin-100
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
activesupport
|
activesupport
|
||||||
|
|
|
@ -321,7 +321,7 @@ RSpec.describe "install in deployment or frozen mode" do
|
||||||
L
|
L
|
||||||
|
|
||||||
bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
|
bundle :install, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false, artifice: "compact_index"
|
||||||
expect(err).to include("Your lock file is missing \"bar\", but the lockfile can't be updated because frozen mode is set")
|
expect(err).to include("Your lockfile is missing \"bar\", but can't be updated because frozen mode is set")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "explodes if a path gem is missing" do
|
it "explodes if a path gem is missing" do
|
||||||
|
@ -550,7 +550,7 @@ RSpec.describe "install in deployment or frozen mode" do
|
||||||
pristine_system_gems :bundler
|
pristine_system_gems :bundler
|
||||||
bundle "config set --local deployment true"
|
bundle "config set --local deployment true"
|
||||||
bundle "install --verbose"
|
bundle "install --verbose"
|
||||||
expect(out).not_to include("but the lockfile can't be updated because frozen mode is set")
|
expect(out).not_to include("can't be updated because frozen mode is set")
|
||||||
expect(out).not_to include("You have added to the Gemfile")
|
expect(out).not_to include("You have added to the Gemfile")
|
||||||
expect(out).not_to include("You have deleted from the Gemfile")
|
expect(out).not_to include("You have deleted from the Gemfile")
|
||||||
expect(out).to include("vendor/cache/foo")
|
expect(out).to include("vendor/cache/foo")
|
||||||
|
|
|
@ -273,7 +273,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
|
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0", source: "remote3")
|
||||||
|
|
||||||
# In https://github.com/bundler/bundler/issues/3585 this failed
|
# In https://github.com/bundler/bundler/issues/3585 this failed
|
||||||
# when there is already a lock file, and the gems are missing, so try again
|
# when there is already a lockfile, and the gems are missing, so try again
|
||||||
system_gems []
|
system_gems []
|
||||||
bundle :install, artifice: "compact_index"
|
bundle :install, artifice: "compact_index"
|
||||||
|
|
||||||
|
@ -482,7 +482,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
|
expect(the_bundle).to include_gems("depends_on_myrack 1.0.1", "myrack 1.0.0")
|
||||||
|
|
||||||
# In https://github.com/rubygems/bundler/issues/3585 this failed
|
# In https://github.com/rubygems/bundler/issues/3585 this failed
|
||||||
# when there is already a lock file, and the gems are missing, so try again
|
# when there is already a lockfile, and the gems are missing, so try again
|
||||||
system_gems []
|
system_gems []
|
||||||
bundle :install, artifice: "compact_index"
|
bundle :install, artifice: "compact_index"
|
||||||
|
|
||||||
|
@ -1221,7 +1221,7 @@ RSpec.describe "bundle install with gems on multiple sources" do
|
||||||
|
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
myrack!
|
myrack!
|
||||||
#{checksums_section}
|
|
||||||
BUNDLED WITH
|
BUNDLED WITH
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
L
|
L
|
||||||
|
|
|
@ -91,7 +91,7 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
#{Bundler::VERSION}
|
#{Bundler::VERSION}
|
||||||
L
|
L
|
||||||
|
|
||||||
# force strict usage of the lock file by setting frozen mode
|
# force strict usage of the lockfile by setting frozen mode
|
||||||
bundle "config set --local frozen true"
|
bundle "config set --local frozen true"
|
||||||
|
|
||||||
# make sure the platform that got actually installed with the old bundler is used
|
# make sure the platform that got actually installed with the old bundler is used
|
||||||
|
@ -752,6 +752,80 @@ RSpec.describe "bundle install with specific platforms" do
|
||||||
L
|
L
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "automatically fixes the lockfile when adding a gem that introduces dependencies with no ruby platform variants transitively" do
|
||||||
|
simulate_platform "x86_64-linux" do
|
||||||
|
build_repo4 do
|
||||||
|
build_gem "nokogiri", "1.18.2"
|
||||||
|
|
||||||
|
build_gem "nokogiri", "1.18.2" do |s|
|
||||||
|
s.platform = "x86_64-linux"
|
||||||
|
end
|
||||||
|
|
||||||
|
build_gem("sorbet", "0.5.11835") do |s|
|
||||||
|
s.add_dependency "sorbet-static", "= 0.5.11835"
|
||||||
|
end
|
||||||
|
|
||||||
|
build_gem "sorbet-static", "0.5.11835" do |s|
|
||||||
|
s.platform = "x86_64-linux"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
gemfile <<~G
|
||||||
|
source "https://gem.repo4"
|
||||||
|
|
||||||
|
gem "nokogiri"
|
||||||
|
gem "sorbet"
|
||||||
|
G
|
||||||
|
|
||||||
|
lockfile <<~L
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo4/
|
||||||
|
specs:
|
||||||
|
nokogiri (1.18.2)
|
||||||
|
nokogiri (1.18.2-x86_64-linux)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
nokogiri
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
|
||||||
|
bundle "lock"
|
||||||
|
|
||||||
|
checksums = checksums_section_when_enabled do |c|
|
||||||
|
c.checksum gem_repo4, "nokogiri", "1.18.2", "x86_64-linux"
|
||||||
|
c.checksum gem_repo4, "sorbet", "0.5.11835"
|
||||||
|
c.checksum gem_repo4, "sorbet-static", "0.5.11835", "x86_64-linux"
|
||||||
|
end
|
||||||
|
|
||||||
|
expect(lockfile).to eq <<~L
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo4/
|
||||||
|
specs:
|
||||||
|
nokogiri (1.18.2)
|
||||||
|
nokogiri (1.18.2-x86_64-linux)
|
||||||
|
sorbet (0.5.11835)
|
||||||
|
sorbet-static (= 0.5.11835)
|
||||||
|
sorbet-static (0.5.11835-x86_64-linux)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
x86_64-linux
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
nokogiri
|
||||||
|
sorbet
|
||||||
|
#{checksums}
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do
|
it "automatically fixes the lockfile if multiple platforms locked, but no valid versions of direct dependencies for all of them" do
|
||||||
simulate_platform "x86_64-linux" do
|
simulate_platform "x86_64-linux" do
|
||||||
build_repo4 do
|
build_repo4 do
|
||||||
|
|
|
@ -96,7 +96,6 @@ RSpec.describe "compact index api" do
|
||||||
bundle :install, artifice: "compact_index"
|
bundle :install, artifice: "compact_index"
|
||||||
|
|
||||||
bundle "config set --local deployment true"
|
bundle "config set --local deployment true"
|
||||||
bundle "config set --local path vendor/bundle"
|
|
||||||
bundle :install, artifice: "compact_index"
|
bundle :install, artifice: "compact_index"
|
||||||
expect(out).to include("Fetching gem metadata from #{source_uri}")
|
expect(out).to include("Fetching gem metadata from #{source_uri}")
|
||||||
expect(the_bundle).to include_gems "myrack 1.0.0"
|
expect(the_bundle).to include_gems "myrack 1.0.0"
|
||||||
|
@ -1090,4 +1089,11 @@ Running `bundle update rails` should fix the problem.
|
||||||
count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS
|
count = lockfile.match?("CHECKSUMS") ? 2 : 1 # Once in the specs, and once in CHECKSUMS
|
||||||
expect(lockfile.scan(/activemerchant \(/).size).to eq(count)
|
expect(lockfile.scan(/activemerchant \(/).size).to eq(count)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "handles an API that does not provide checksums info (undocumented, support may get removed)" do
|
||||||
|
install_gemfile <<-G, artifice: "compact_index_no_checksums"
|
||||||
|
source "https://gem.repo1"
|
||||||
|
gem "rake"
|
||||||
|
G
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -61,7 +61,6 @@ RSpec.describe "gemcutter's dependency API" do
|
||||||
bundle :install, artifice: "endpoint"
|
bundle :install, artifice: "endpoint"
|
||||||
|
|
||||||
bundle "config set --local deployment true"
|
bundle "config set --local deployment true"
|
||||||
bundle "config set --local path vendor/bundle"
|
|
||||||
bundle :install, artifice: "endpoint"
|
bundle :install, artifice: "endpoint"
|
||||||
expect(out).to include("Fetching gem metadata from #{source_uri}")
|
expect(out).to include("Fetching gem metadata from #{source_uri}")
|
||||||
expect(the_bundle).to include_gems "myrack 1.0.0"
|
expect(the_bundle).to include_gems "myrack 1.0.0"
|
||||||
|
|
|
@ -394,7 +394,7 @@ RSpec.describe "bundle install with install-time dependencies" do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context "with a Gemfile and lock file that don't resolve under the current platform" do
|
context "with a Gemfile and lockfile that don't resolve under the current platform" do
|
||||||
before do
|
before do
|
||||||
build_repo4 do
|
build_repo4 do
|
||||||
build_gem "sorbet", "0.5.10554" do |s|
|
build_gem "sorbet", "0.5.10554" do |s|
|
||||||
|
|
|
@ -248,6 +248,7 @@ RSpec.describe "global gem caching" do
|
||||||
describe "extension caching" do
|
describe "extension caching" do
|
||||||
it "works" do
|
it "works" do
|
||||||
skip "gets incorrect ref in path" if Gem.win_platform?
|
skip "gets incorrect ref in path" if Gem.win_platform?
|
||||||
|
skip "fails for unknown reason when run by ruby-core" if ruby_core?
|
||||||
|
|
||||||
build_git "very_simple_git_binary", &:add_c_extension
|
build_git "very_simple_git_binary", &:add_c_extension
|
||||||
build_lib "very_simple_path_binary", &:add_c_extension
|
build_lib "very_simple_path_binary", &:add_c_extension
|
||||||
|
|
|
@ -24,7 +24,7 @@ RSpec.describe "process lock spec" do
|
||||||
context "when creating a lock raises Errno::ENOTSUP" do
|
context "when creating a lock raises Errno::ENOTSUP" do
|
||||||
before { allow(File).to receive(:open).and_raise(Errno::ENOTSUP) }
|
before { allow(File).to receive(:open).and_raise(Errno::ENOTSUP) }
|
||||||
|
|
||||||
it "skips creating the lock file and yields" do
|
it "skips creating the lockfile and yields" do
|
||||||
processed = false
|
processed = false
|
||||||
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ RSpec.describe "process lock spec" do
|
||||||
context "when creating a lock raises Errno::EPERM" do
|
context "when creating a lock raises Errno::EPERM" do
|
||||||
before { allow(File).to receive(:open).and_raise(Errno::EPERM) }
|
before { allow(File).to receive(:open).and_raise(Errno::EPERM) }
|
||||||
|
|
||||||
it "skips creating the lock file and yields" do
|
it "skips creating the lockfile and yields" do
|
||||||
processed = false
|
processed = false
|
||||||
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ RSpec.describe "process lock spec" do
|
||||||
context "when creating a lock raises Errno::EROFS" do
|
context "when creating a lock raises Errno::EROFS" do
|
||||||
before { allow(File).to receive(:open).and_raise(Errno::EROFS) }
|
before { allow(File).to receive(:open).and_raise(Errno::EROFS) }
|
||||||
|
|
||||||
it "skips creating the lock file and yields" do
|
it "skips creating the lockfile and yields" do
|
||||||
processed = false
|
processed = false
|
||||||
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
Bundler::ProcessLock.lock(default_bundle_path) { processed = true }
|
||||||
|
|
||||||
|
|
|
@ -1613,6 +1613,39 @@ RSpec.describe "the lockfile format" do
|
||||||
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
|
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "raises a clear error when frozen mode is set and lockfile is missing entries in CHECKSUMS section, and does not install any gems" do
|
||||||
|
lockfile <<-L
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo2/
|
||||||
|
specs:
|
||||||
|
myrack_middleware (1.0)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
#{lockfile_platforms}
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
myrack_middleware
|
||||||
|
|
||||||
|
CHECKSUMS
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
|
||||||
|
install_gemfile <<-G, env: { "BUNDLE_FROZEN" => "true" }, raise_on_error: false
|
||||||
|
source "https://gem.repo2"
|
||||||
|
gem "myrack_middleware"
|
||||||
|
G
|
||||||
|
|
||||||
|
expect(err).to eq <<~L.strip
|
||||||
|
Your lockfile is missing a checksums entry for \"myrack_middleware\", but can't be updated because frozen mode is set
|
||||||
|
|
||||||
|
Run `bundle install` elsewhere and add the updated Gemfile.lock to version control.
|
||||||
|
L
|
||||||
|
|
||||||
|
expect(the_bundle).not_to include_gems "myrack_middleware 1.0"
|
||||||
|
end
|
||||||
|
|
||||||
it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do
|
it "automatically fixes the lockfile when it's missing deps, they conflict with other locked deps, but conflicts are fixable" do
|
||||||
build_repo4 do
|
build_repo4 do
|
||||||
build_gem "other_dep", "0.9"
|
build_gem "other_dep", "0.9"
|
||||||
|
@ -1875,6 +1908,120 @@ RSpec.describe "the lockfile format" do
|
||||||
L
|
L
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "automatically fixes the lockfile when it includes a gem under the correct GIT section, but also under an incorrect GEM section, with a higher version, and with no explicit Gemfile requirement" do
|
||||||
|
git = build_git "foo"
|
||||||
|
|
||||||
|
gemfile <<~G
|
||||||
|
source "https://gem.repo1/"
|
||||||
|
gem "foo", git: "#{lib_path("foo-1.0")}"
|
||||||
|
G
|
||||||
|
|
||||||
|
# If the lockfile erroneously lists platform versions of the gem
|
||||||
|
# that don't match the locked version of the git repo we should remove them.
|
||||||
|
|
||||||
|
lockfile <<~L
|
||||||
|
GIT
|
||||||
|
remote: #{lib_path("foo-1.0")}
|
||||||
|
revision: #{git.ref_for("main")}
|
||||||
|
specs:
|
||||||
|
foo (1.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo1/
|
||||||
|
specs:
|
||||||
|
foo (1.1-x86_64-linux-gnu)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
#{lockfile_platforms}
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
foo!
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
|
||||||
|
bundle "install"
|
||||||
|
|
||||||
|
expect(lockfile).to eq <<~L
|
||||||
|
GIT
|
||||||
|
remote: #{lib_path("foo-1.0")}
|
||||||
|
revision: #{git.ref_for("main")}
|
||||||
|
specs:
|
||||||
|
foo (1.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo1/
|
||||||
|
specs:
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
#{lockfile_platforms}
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
foo!
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
end
|
||||||
|
|
||||||
|
it "automatically fixes the lockfile when it includes a gem under the correct GIT section, but also under an incorrect GEM section, with a higher version" do
|
||||||
|
git = build_git "foo"
|
||||||
|
|
||||||
|
gemfile <<~G
|
||||||
|
source "https://gem.repo1/"
|
||||||
|
gem "foo", "= 1.0", git: "#{lib_path("foo-1.0")}"
|
||||||
|
G
|
||||||
|
|
||||||
|
# If the lockfile erroneously lists platform versions of the gem
|
||||||
|
# that don't match the locked version of the git repo we should remove them.
|
||||||
|
|
||||||
|
lockfile <<~L
|
||||||
|
GIT
|
||||||
|
remote: #{lib_path("foo-1.0")}
|
||||||
|
revision: #{git.ref_for("main")}
|
||||||
|
specs:
|
||||||
|
foo (1.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo1/
|
||||||
|
specs:
|
||||||
|
foo (1.1-x86_64-linux-gnu)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
#{lockfile_platforms}
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
foo (= 1.0)!
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
|
||||||
|
bundle "install"
|
||||||
|
|
||||||
|
expect(lockfile).to eq <<~L
|
||||||
|
GIT
|
||||||
|
remote: #{lib_path("foo-1.0")}
|
||||||
|
revision: #{git.ref_for("main")}
|
||||||
|
specs:
|
||||||
|
foo (1.0)
|
||||||
|
|
||||||
|
GEM
|
||||||
|
remote: https://gem.repo1/
|
||||||
|
specs:
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
#{lockfile_platforms}
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
foo (= 1.0)!
|
||||||
|
|
||||||
|
BUNDLED WITH
|
||||||
|
#{Bundler::VERSION}
|
||||||
|
L
|
||||||
|
end
|
||||||
|
|
||||||
it "automatically fixes the lockfile when it has incorrect deps, keeping the locked version" do
|
it "automatically fixes the lockfile when it has incorrect deps, keeping the locked version" do
|
||||||
build_repo4 do
|
build_repo4 do
|
||||||
build_gem "net-smtp", "0.5.0" do |s|
|
build_gem "net-smtp", "0.5.0" do |s|
|
||||||
|
@ -2030,7 +2177,7 @@ RSpec.describe "the lockfile format" do
|
||||||
L
|
L
|
||||||
|
|
||||||
bundle "install --verbose"
|
bundle "install --verbose"
|
||||||
expect(out).to include("re-resolving dependencies because your lock file includes \"minitest-bisect\" but not some of its dependencies")
|
expect(out).to include("re-resolving dependencies because your lockfile includes \"minitest-bisect\" but not some of its dependencies")
|
||||||
|
|
||||||
expect(lockfile).to eq <<~L
|
expect(lockfile).to eq <<~L
|
||||||
GEM
|
GEM
|
||||||
|
|
|
@ -67,7 +67,7 @@ RSpec.describe "real source plugins" do
|
||||||
expect(the_bundle).to include_gems("a-path-gem 1.0")
|
expect(the_bundle).to include_gems("a-path-gem 1.0")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "writes to lock file" do
|
it "writes to lockfile" do
|
||||||
bundle "install"
|
bundle "install"
|
||||||
|
|
||||||
checksums = checksums_section_when_enabled do |c|
|
checksums = checksums_section_when_enabled do |c|
|
||||||
|
@ -336,7 +336,7 @@ RSpec.describe "real source plugins" do
|
||||||
expect(the_bundle).to include_gems("ma-gitp-gem 1.0")
|
expect(the_bundle).to include_gems("ma-gitp-gem 1.0")
|
||||||
end
|
end
|
||||||
|
|
||||||
it "writes to lock file" do
|
it "writes to lockfile" do
|
||||||
revision = revision_for(lib_path("ma-gitp-gem-1.0"))
|
revision = revision_for(lib_path("ma-gitp-gem-1.0"))
|
||||||
bundle "install"
|
bundle "install"
|
||||||
|
|
||||||
|
|
|
@ -1683,7 +1683,7 @@ end
|
||||||
RUBY
|
RUBY
|
||||||
end
|
end
|
||||||
|
|
||||||
expect(err).to include("Your lockfile does not include the current platform, but the lockfile can't be updated because file system is read-only")
|
expect(err).to include("Your lockfile is missing the current platform, but can't be updated because file system is read-only")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
16
spec/bundler/support/artifice/compact_index_no_checksums.rb
Normal file
16
spec/bundler/support/artifice/compact_index_no_checksums.rb
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require_relative "helpers/compact_index"
|
||||||
|
|
||||||
|
class CompactIndexNoChecksums < CompactIndexAPI
|
||||||
|
get "/info/:name" do
|
||||||
|
etag_response do
|
||||||
|
gem = gems.find {|g| g.name == params[:name] }
|
||||||
|
gem.versions.map(&:number).join("\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require_relative "helpers/artifice"
|
||||||
|
|
||||||
|
Artifice.activate_with(CompactIndexNoChecksums)
|
|
@ -370,8 +370,11 @@ class TestGemCommandsExecCommand < Gem::TestCase
|
||||||
util_clear_gems
|
util_clear_gems
|
||||||
|
|
||||||
use_ui @ui do
|
use_ui @ui do
|
||||||
@cmd.invoke "a:2"
|
e = assert_raise Gem::MockGemUi::TermError do
|
||||||
assert_equal "a-2 foo\n", @ui.output
|
@cmd.invoke "a:2"
|
||||||
|
end
|
||||||
|
assert_equal 1, e.exit_code
|
||||||
|
assert_equal "ERROR: Ambiguous which executable from gem `a` should be run: the options are [\"bar\", \"foo\"], specify one via COMMAND, and use `-g` and `-v` to specify gem and version\n", @ui.error
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ class TestGemExtCmakeBuilder < Gem::TestCase
|
||||||
def test_self_build
|
def test_self_build
|
||||||
File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists|
|
File.open File.join(@ext, "CMakeLists.txt"), "w" do |cmakelists|
|
||||||
cmakelists.write <<-EO_CMAKE
|
cmakelists.write <<-EO_CMAKE
|
||||||
cmake_minimum_required(VERSION 2.6)
|
cmake_minimum_required(VERSION 3.5)
|
||||||
project(self_build NONE)
|
project(self_build NONE)
|
||||||
install (FILES test.txt DESTINATION bin)
|
install (FILES test.txt DESTINATION bin)
|
||||||
EO_CMAKE
|
EO_CMAKE
|
||||||
|
|
|
@ -33,7 +33,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
f.write "a" * 10
|
f.write "a" * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
end
|
end
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -54,7 +54,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
Time.stub :now, Time.at(1_458_518_157) do
|
Time.stub :now, Time.at(1_458_518_157) do
|
||||||
@tar_writer.add_symlink "x", "y", 0o644
|
@tar_writer.add_symlink "x", "y", 0o644
|
||||||
|
|
||||||
assert_headers_equal(tar_symlink_header("x", "", 0o644, Time.now, "y"),
|
assert_headers_equal(tar_symlink_header("x", "", 0o644, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc, "y"),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
end
|
end
|
||||||
assert_equal 512, @io.pos
|
assert_equal 512, @io.pos
|
||||||
|
@ -86,7 +86,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
"e1cf14b0",
|
"e1cf14b0",
|
||||||
digests["SHA512"].hexdigest
|
digests["SHA512"].hexdigest
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
end
|
end
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -109,7 +109,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
"e1cf14b0",
|
"e1cf14b0",
|
||||||
digests["SHA512"].hexdigest
|
digests["SHA512"].hexdigest
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
end
|
end
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -126,7 +126,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
io.write "a" * 10
|
io.write "a" * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
|
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -137,7 +137,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
signature = signer.sign digest.digest
|
signature = signer.sign digest.digest
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x.sig", "", 0o444, signature.length,
|
assert_headers_equal(tar_file_header("x.sig", "", 0o444, signature.length,
|
||||||
Time.now),
|
Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[1024, 512])
|
@io.string[1024, 512])
|
||||||
assert_equal "#{signature}#{"\0" * (512 - signature.length)}",
|
assert_equal "#{signature}#{"\0" * (512 - signature.length)}",
|
||||||
@io.string[1536, 512]
|
@io.string[1536, 512]
|
||||||
|
@ -154,7 +154,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
io.write "a" * 10
|
io.write "a" * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
end
|
end
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -168,7 +168,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
io.write "a" * 10
|
io.write "a" * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.now),
|
assert_headers_equal(tar_file_header("x", "", 0o644, 10, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512])
|
@io.string[0, 512])
|
||||||
|
|
||||||
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
assert_equal "aaaaaaaaaa#{"\0" * 502}", @io.string[512, 512]
|
||||||
|
@ -192,7 +192,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
Time.stub :now, Time.at(1_458_518_157) do
|
Time.stub :now, Time.at(1_458_518_157) do
|
||||||
@tar_writer.add_file_simple "x", 0, 100
|
@tar_writer.add_file_simple "x", 0, 100
|
||||||
|
|
||||||
assert_headers_equal tar_file_header("x", "", 0, 100, Time.now),
|
assert_headers_equal tar_file_header("x", "", 0, 100, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512]
|
@io.string[0, 512]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ class TestGemPackageTarWriter < Gem::Package::TarTestCase
|
||||||
Time.stub :now, Time.at(1_458_518_157) do
|
Time.stub :now, Time.at(1_458_518_157) do
|
||||||
@tar_writer.mkdir "foo", 0o644
|
@tar_writer.mkdir "foo", 0o644
|
||||||
|
|
||||||
assert_headers_equal tar_dir_header("foo", "", 0o644, Time.now),
|
assert_headers_equal tar_dir_header("foo", "", 0o644, Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc),
|
||||||
@io.string[0, 512]
|
@io.string[0, 512]
|
||||||
|
|
||||||
assert_equal 512, @io.pos
|
assert_equal 512, @io.pos
|
||||||
|
|
|
@ -16,7 +16,7 @@ rubygems_version: "1.0"
|
||||||
name: keyedlist
|
name: keyedlist
|
||||||
version: !ruby/object:Gem::Version
|
version: !ruby/object:Gem::Version
|
||||||
version: 0.4.0
|
version: 0.4.0
|
||||||
date: 2004-03-28 15:37:49.828000 +02:00
|
date: 1980-01-02 00:00:00 UTC
|
||||||
platform:
|
platform:
|
||||||
summary: A Hash which automatically computes keys.
|
summary: A Hash which automatically computes keys.
|
||||||
require_paths:
|
require_paths:
|
||||||
|
@ -75,7 +75,7 @@ end
|
||||||
def assert_date(date)
|
def assert_date(date)
|
||||||
assert_kind_of Time, date
|
assert_kind_of Time, date
|
||||||
assert_equal [0, 0, 0], [date.hour, date.min, date.sec]
|
assert_equal [0, 0, 0], [date.hour, date.min, date.sec]
|
||||||
assert_operator (Gem::Specification::TODAY..Time.now), :cover?, date
|
assert_equal Time.at(Gem::DEFAULT_SOURCE_DATE_EPOCH).utc, date
|
||||||
end
|
end
|
||||||
|
|
||||||
def setup
|
def setup
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue