diff options
author | Hiroshi SHIBATA <[email protected]> | 2021-02-09 22:53:57 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2021-02-09 22:53:57 +0900 |
commit | 09c681ab38df33468570534bef7609222e49c6f4 (patch) | |
tree | 52f9edbbb1d0c984e370d2ae35729a16e51890b8 | |
parent | 9aba46d8d80473594e567dff1652626e7b2a77b0 (diff) |
Merge RubyGems 3.2.9 and Bundler 2.2.9 (#4158)
60 files changed, 714 insertions, 285 deletions
diff --git a/lib/bundler.rb b/lib/bundler.rb index b299cc8a28..d370d8a53a 100644 --- a/lib/bundler.rb +++ b/lib/bundler.rb @@ -440,7 +440,7 @@ EOF end def local_platform - return Gem::Platform::RUBY if settings[:force_ruby_platform] + return Gem::Platform::RUBY if settings[:force_ruby_platform] || Gem.platforms == [Gem::Platform::RUBY] Gem::Platform.local end diff --git a/lib/bundler/cli.rb b/lib/bundler/cli.rb index 249f5b2027..421f42cb52 100644 --- a/lib/bundler/cli.rb +++ b/lib/bundler/cli.rb @@ -586,6 +586,7 @@ module Bundler method_option :git, :type => :boolean, :default => true, :desc => "Initialize a git repo inside your library." method_option :mit, :type => :boolean, :desc => "Generate an MIT license file. Set a default with `bundle config set --global gem.mit true`." method_option :rubocop, :type => :boolean, :desc => "Add rubocop to the generated Rakefile and gemspec. Set a default with `bundle config set --global gem.rubocop true`." + method_option :changelog, :type => :boolean, :desc => "Generate changelog file. Set a default with `bundle config set --global gem.changelog true`." method_option :test, :type => :string, :lazy_default => Bundler.settings["gem.test"] || "", :aliases => "-t", :banner => "Use the specified test framework for your library", :desc => "Generate a test directory for your library, either rspec, minitest or test-unit. Set a default with `bundle config set --global gem.test (rspec|minitest|test-unit)`." method_option :ci, :type => :string, :lazy_default => Bundler.settings["gem.ci"] || "", diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 17b4956fa0..0d773579e5 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -142,6 +142,18 @@ module Bundler templates.merge!("CODE_OF_CONDUCT.md.tt" => "CODE_OF_CONDUCT.md") end + if ask_and_set(:changelog, "Do you want to include a changelog?", + "A changelog is a file which contains a curated, chronologically ordered list of notable " \ + "changes for each version of a project. To make it easier for users and contributors to" \ + " see precisely what notable changes have been made between each release (or version) of" \ + " the project. Whether consumers or developers, the end users of software are" \ + " human beings who care about what's in the software. When the software changes, people " \ + "want to know why and how. see https://keepachangelog.com") + config[:changelog] = true + Bundler.ui.info "Changelog enabled in config" + templates.merge!("CHANGELOG.md.tt" => "CHANGELOG.md") + end + if ask_and_set(:rubocop, "Do you want to add rubocop as a dependency for gems you generate?", "RuboCop is a static code analyzer that has out-of-the-box rules for many " \ "of the guidelines in the community style guide. " \ diff --git a/lib/bundler/definition.rb b/lib/bundler/definition.rb index 9f9a938dce..3c25149d33 100644 --- a/lib/bundler/definition.rb +++ b/lib/bundler/definition.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require_relative "lockfile_parser" -require "set" module Bundler class Definition @@ -83,11 +82,7 @@ module Bundler @lockfile_contents = Bundler.read_file(lockfile) @locked_gems = LockfileParser.new(@lockfile_contents) @locked_platforms = @locked_gems.platforms - if Bundler.settings[:force_ruby_platform] - @platforms = [Gem::Platform::RUBY] - else - @platforms = @locked_platforms.dup - end + @platforms = @locked_platforms.dup @locked_bundler_version = @locked_gems.bundler_version @locked_ruby_version = @locked_gems.ruby_version @@ -259,23 +254,18 @@ module Bundler def resolve @resolve ||= begin last_resolve = converge_locked_specs - resolve = - if Bundler.frozen_bundle? - Bundler.ui.debug "Frozen, using resolution from the lockfile" - last_resolve - elsif !unlocking? && nothing_changed? - Bundler.ui.debug("Found no changes, using resolution from the lockfile") - last_resolve - else - # Run a resolve against the locally available gems - Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") - expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) - last_resolve.merge Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) - end - - # filter out gems that _can_ be installed on multiple platforms, but don't need - # to be - resolve.for(expand_dependencies(dependencies, true), [], false, false, false) + if Bundler.frozen_bundle? + Bundler.ui.debug "Frozen, using resolution from the lockfile" + last_resolve + elsif !unlocking? && nothing_changed? + Bundler.ui.debug("Found no changes, using resolution from the lockfile") + last_resolve + else + # Run a resolve against the locally available gems + Bundler.ui.debug("Found changes from the lockfile, re-resolving dependencies because #{change_reason}") + expanded_dependencies = expand_dependencies(dependencies + metadata_dependencies, @remote) + Resolver.resolve(expanded_dependencies, index, source_requirements, last_resolve, gem_version_promoter, additional_base_requirements_for_resolve, platforms) + end end end @@ -604,7 +594,7 @@ module Bundler deps_for_source = @dependencies.select {|s| s.source == source } locked_deps_for_source = @locked_deps.values.select {|dep| dep.source == locked_source } - Set.new(deps_for_source) != Set.new(locked_deps_for_source) + deps_for_source.sort != locked_deps_for_source.sort end def specs_for_source_changed?(source) @@ -884,7 +874,7 @@ module Bundler dependencies.each do |dep| dep = Dependency.new(dep, ">= 0") unless dep.respond_to?(:name) next unless remote || dep.current_platform? - target_platforms = dep.gem_platforms(remote ? Resolver.sort_platforms(@platforms) : [generic_local_platform]) + target_platforms = dep.gem_platforms(remote ? @platforms : [generic_local_platform]) deps += expand_dependency_with_platforms(dep, target_platforms) end deps diff --git a/lib/bundler/index.rb b/lib/bundler/index.rb index f26f542fde..f945176037 100644 --- a/lib/bundler/index.rb +++ b/lib/bundler/index.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "set" - module Bundler class Index include Enumerable @@ -65,11 +63,14 @@ module Bundler def unsorted_search(query, base) results = local_search(query, base) - seen = results.map(&:full_name).to_set unless @sources.empty? + seen = results.map(&:full_name).uniq unless @sources.empty? @sources.each do |source| source.unsorted_search(query, base).each do |spec| - results << spec if seen.add?(spec.full_name) + next if seen.include?(spec.full_name) + + seen << spec.full_name + results << spec end end @@ -170,7 +171,7 @@ module Bundler def dependencies_eql?(spec, other_spec) deps = spec.dependencies.select {|d| d.type != :development } other_deps = other_spec.dependencies.select {|d| d.type != :development } - Set.new(deps) == Set.new(other_deps) + deps.sort == other_deps.sort end def add_source(index) diff --git a/lib/bundler/installer/standalone.rb b/lib/bundler/installer/standalone.rb index 11d5c490ab..2a3f5cfe35 100644 --- a/lib/bundler/installer/standalone.rb +++ b/lib/bundler/installer/standalone.rb @@ -55,9 +55,10 @@ module Bundler kernel = (class << ::Kernel; self; end) [kernel, ::Kernel].each do |k| if k.private_method_defined?(:gem_original_require) + private_require = k.private_method_defined?(:require) k.send(:remove_method, :require) k.send(:define_method, :require, k.instance_method(:gem_original_require)) - k.send(:private, :require) + k.send(:private, :require) if private_require end end END diff --git a/lib/bundler/lazy_specification.rb b/lib/bundler/lazy_specification.rb index 59689c609c..04ba2a2364 100644 --- a/lib/bundler/lazy_specification.rb +++ b/lib/bundler/lazy_specification.rb @@ -4,22 +4,6 @@ require_relative "match_platform" module Bundler class LazySpecification - Identifier = Struct.new(:name, :version, :platform) - class Identifier - include Comparable - def <=>(other) - return unless other.is_a?(Identifier) - [name, version, platform_string] <=> [other.name, other.version, other.platform_string] - end - - protected - - def platform_string - platform_string = platform.to_s - platform_string == Index::RUBY ? Index::NULL : platform_string - end - end - include MatchPlatform attr_reader :name, :version, :dependencies, :platform @@ -108,7 +92,7 @@ module Bundler end def identifier - @__identifier ||= Identifier.new(name, version, platform) + @__identifier ||= [name, version, platform_string] end def git_version @@ -116,6 +100,13 @@ module Bundler " #{source.revision[0..6]}" end + protected + + def platform_string + platform_string = platform.to_s + platform_string == Index::RUBY ? Index::NULL : platform_string + end + private def to_ary diff --git a/lib/bundler/resolver.rb b/lib/bundler/resolver.rb index 8812ba5ede..0f17ba3afb 100644 --- a/lib/bundler/resolver.rb +++ b/lib/bundler/resolver.rb @@ -5,6 +5,8 @@ module Bundler require_relative "vendored_molinillo" require_relative "resolver/spec_group" + include GemHelpers + # Figures out the best possible configuration of gems that satisfies # the list of passed dependencies and any child dependencies without # causing any gem activation errors. @@ -16,7 +18,6 @@ module Bundler # <GemBundle>,nil:: If the list of dependencies can be resolved, a # collection of gemspecs is returned. Otherwise, nil is returned. def self.resolve(requirements, index, source_requirements = {}, base = [], gem_version_promoter = GemVersionPromoter.new, additional_base_requirements = [], platforms = nil) - platforms = Set.new(platforms) if platforms base = SpecSet.new(base) unless base.is_a?(SpecSet) resolver = new(index, source_requirements, base, gem_version_promoter, additional_base_requirements, platforms) result = resolver.start(requirements) @@ -36,9 +37,13 @@ module Bundler end additional_base_requirements.each {|d| @base_dg.add_vertex(d.name, d) } @platforms = platforms + @resolving_only_for_ruby = platforms == [Gem::Platform::RUBY] @gem_version_promoter = gem_version_promoter @use_gvp = Bundler.feature_flag.use_gem_version_promoter_for_major_updates? || !@gem_version_promoter.major? @lockfile_uses_separate_rubygems_sources = Bundler.feature_flag.disable_multisource? + + @variant_specific_names = [] + @generic_names = [] end def start(requirements) @@ -102,14 +107,24 @@ module Bundler include Molinillo::SpecificationProvider def dependencies_for(specification) - specification.dependencies_for_activated_platforms + all_dependencies = specification.dependencies_for_activated_platforms + + if @variant_specific_names.include?(specification.name) + @variant_specific_names |= all_dependencies.map(&:name) - @generic_names + else + generic_names, variant_specific_names = specification.partitioned_dependency_names_for_activated_platforms + @variant_specific_names |= variant_specific_names - @generic_names + @generic_names |= generic_names + end + + all_dependencies end def search_for(dependency_proxy) platform = dependency_proxy.__platform dependency = dependency_proxy.dep - @search_for[dependency_proxy] ||= begin - name = dependency.name + name = dependency.name + search_result = @search_for[dependency_proxy] ||= begin index = index_for(dependency) results = index.search(dependency, @base[name]) @@ -136,37 +151,48 @@ module Bundler end nested.reduce([]) do |groups, (version, specs)| next groups if locked_requirement && !locked_requirement.satisfied_by?(version) - spec_group = SpecGroup.new(specs) - groups << spec_group + + specs_by_platform = Hash.new do |current_specs, current_platform| + current_specs[current_platform] = select_best_platform_match(specs, current_platform) + end + + spec_group_ruby = SpecGroup.create_for(specs_by_platform, [Gem::Platform::RUBY], Gem::Platform::RUBY) + groups << spec_group_ruby if spec_group_ruby + + next groups if @resolving_only_for_ruby + + spec_group = SpecGroup.create_for(specs_by_platform, @platforms, platform) + groups << spec_group if spec_group + + groups end else [] end # GVP handles major itself, but it's still a bit risky to trust it with it # until we get it settled with new behavior. For 2.x it can take over all cases. - search = if !@use_gvp + if !@use_gvp spec_groups else @gem_version_promoter.sort_versions(dependency, spec_groups) end - selected_sgs = [] - search.each do |sg| - next unless sg.for?(platform) - sg_all_platforms = sg.copy_for(self.class.sort_platforms(@platforms).reverse) - next unless sg_all_platforms - - selected_sgs << sg_all_platforms + end - next if sg_all_platforms.activated_platforms == [Gem::Platform::RUBY] - # Add a spec group for "non platform specific spec" as the fallback - # spec group. - sg_ruby = sg.copy_for([Gem::Platform::RUBY]) - next unless sg_ruby + unless search_result.empty? + specific_dependency = @variant_specific_names.include?(name) + return search_result unless specific_dependency - selected_sgs.insert(-2, sg_ruby) + search_result.each do |sg| + if @generic_names.include?(name) + @variant_specific_names -= [name] + sg.activate_all_platforms! + else + sg.activate_platform!(platform) + end end - selected_sgs end + + search_result end def index_for(dependency) @@ -237,13 +263,6 @@ module Bundler end end - # Sort platforms from most general to most specific - def self.sort_platforms(platforms) - platforms.sort_by do |platform| - platform_sort_key(platform) - end - end - def self.platform_sort_key(platform) # Prefer specific platform to not specific platform return ["99-LAST", "", "", ""] if Gem::Platform::RUBY == platform diff --git a/lib/bundler/resolver/spec_group.rb b/lib/bundler/resolver/spec_group.rb index 7fba5043a7..73ffec5838 100644 --- a/lib/bundler/resolver/spec_group.rb +++ b/lib/bundler/resolver/spec_group.rb @@ -3,27 +3,37 @@ module Bundler class Resolver class SpecGroup - include GemHelpers - attr_accessor :name, :version, :source attr_accessor :activated_platforms - def initialize(all_specs) - @all_specs = all_specs - raise ArgumentError, "cannot initialize with an empty value" unless exemplary_spec = all_specs.first + def self.create_for(specs, all_platforms, specific_platform) + specific_platform_specs = specs[specific_platform] + return unless specific_platform_specs.any? + + platforms = all_platforms.select {|p| specs[p].any? } + + new(specific_platform_specs.first, specs, platforms) + end + + def initialize(exemplary_spec, specs, relevant_platforms) + @exemplary_spec = exemplary_spec @name = exemplary_spec.name @version = exemplary_spec.version @source = exemplary_spec.source - @activated_platforms = [] - @dependencies = nil - @specs = Hash.new do |specs, platform| - specs[platform] = select_best_platform_match(all_specs, platform) + @all_platforms = relevant_platforms + @activated_platforms = relevant_platforms + @dependencies = Hash.new do |dependencies, platforms| + dependencies[platforms] = dependencies_for(platforms) end + @partitioned_dependency_names = Hash.new do |partitioned_dependency_names, platforms| + partitioned_dependency_names[platforms] = partitioned_dependency_names_for(platforms) + end + @specs = specs end def to_specs - @activated_platforms.map do |p| + activated_platforms.map do |p| specs = @specs[p] next unless specs.any? @@ -35,17 +45,12 @@ module Bundler end.flatten.compact.uniq end - def copy_for(platforms) - platforms.select! {|p| for?(p) } - return unless platforms.any? - - copied_sg = self.class.new(@all_specs) - copied_sg.activated_platforms = platforms - copied_sg + def activate_platform!(platform) + self.activated_platforms = [platform] end - def for?(platform) - @specs[platform].any? + def activate_all_platforms! + self.activated_platforms = @all_platforms end def to_s @@ -54,11 +59,11 @@ module Bundler end def dependencies_for_activated_platforms - dependencies = @activated_platforms.map {|p| __dependencies[p] } - metadata_dependencies = @activated_platforms.map do |platform| - metadata_dependencies(@specs[platform].first, platform) - end - dependencies.concat(metadata_dependencies).flatten + @dependencies[activated_platforms] + end + + def partitioned_dependency_names_for_activated_platforms + @partitioned_dependency_names[activated_platforms] end def ==(other) @@ -84,27 +89,37 @@ module Bundler protected def sorted_activated_platforms - @activated_platforms.sort_by(&:to_s) + activated_platforms.sort_by(&:to_s) end private - def __dependencies - @dependencies = Hash.new do |dependencies, platform| - dependencies[platform] = [] - specs = @specs[platform] - if spec = specs.first - spec.dependencies.each do |dep| - next if dep.type == :development - dependencies[platform] << DepProxy.get_proxy(dep, platform) - end - end - dependencies[platform] + def dependencies_for(platforms) + platforms.map do |platform| + __dependencies(platform) + metadata_dependencies(platform) + end.flatten + end + + def partitioned_dependency_names_for(platforms) + return @dependencies[platforms].map(&:name), [] if platforms.size == 1 + + @dependencies[platforms].partition do |dep_proxy| + @dependencies[platforms].count {|dp| dp.dep == dep_proxy.dep } == platforms.size + end.map {|deps| deps.map(&:name) } + end + + def __dependencies(platform) + dependencies = [] + @specs[platform].first.dependencies.each do |dep| + next if dep.type == :development + dependencies << DepProxy.get_proxy(dep, platform) end + dependencies end - def metadata_dependencies(spec, platform) - return [] unless spec && spec.is_a?(Gem::Specification) + def metadata_dependencies(platform) + spec = @specs[platform].first + return [] unless spec.is_a?(Gem::Specification) dependencies = [] if !spec.required_ruby_version.nil? && !spec.required_ruby_version.none? dependencies << DepProxy.get_proxy(Gem::Dependency.new("Ruby\0", spec.required_ruby_version), platform) diff --git a/lib/bundler/shared_helpers.rb b/lib/bundler/shared_helpers.rb index ca0ab67fb8..09b79acbf9 100644 --- a/lib/bundler/shared_helpers.rb +++ b/lib/bundler/shared_helpers.rb @@ -194,11 +194,11 @@ module Bundler return @md5_available if defined?(@md5_available) @md5_available = begin require "openssl" - OpenSSL::Digest.digest("MD5", "") + ::OpenSSL::Digest.digest("MD5", "") true rescue LoadError true - rescue OpenSSL::Digest::DigestError + rescue ::OpenSSL::Digest::DigestError false end end diff --git a/lib/bundler/source_list.rb b/lib/bundler/source_list.rb index 731a791531..436891256d 100644 --- a/lib/bundler/source_list.rb +++ b/lib/bundler/source_list.rb @@ -1,7 +1,5 @@ # frozen_string_literal: true -require "set" - module Bundler class SourceList attr_reader :path_sources, @@ -99,7 +97,7 @@ module Bundler @rubygems_aggregate = replacement_rubygems if replacement_rubygems return true if !equal_sources?(lock_sources, replacement_sources) && !equivalent_sources?(lock_sources, replacement_sources) - return true if replacement_rubygems && rubygems_remotes.to_set != replacement_rubygems.remotes.to_set + return true if replacement_rubygems && rubygems_remotes.sort_by(&:to_s) != replacement_rubygems.remotes.sort_by(&:to_s) false end @@ -153,7 +151,7 @@ module Bundler end def equal_sources?(lock_sources, replacement_sources) - lock_sources.to_set == replacement_sources.to_set + lock_sources.sort_by(&:to_s) == replacement_sources.sort_by(&:to_s) end def equal_source?(source, other_source) diff --git a/lib/bundler/spec_set.rb b/lib/bundler/spec_set.rb index 951e80231e..399c91fea5 100644 --- a/lib/bundler/spec_set.rb +++ b/lib/bundler/spec_set.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require "tsort" -require "set" module Bundler class SpecSet @@ -13,14 +12,16 @@ module Bundler end def for(dependencies, skip = [], check = false, match_current_platform = false, raise_on_missing = true) - handled = Set.new + handled = [] deps = dependencies.dup specs = [] skip += ["bundler"] loop do break unless dep = deps.shift - next if !handled.add?(dep) || skip.include?(dep.name) + next if handled.include?(dep) || skip.include?(dep.name) + + handled << dep specs_for_dep = spec_for_dependency(dep, match_current_platform) if specs_for_dep.any? diff --git a/lib/bundler/templates/newgem/CHANGELOG.md.tt b/lib/bundler/templates/newgem/CHANGELOG.md.tt new file mode 100644 index 0000000000..c9ea96d453 --- /dev/null +++ b/lib/bundler/templates/newgem/CHANGELOG.md.tt @@ -0,0 +1,5 @@ +## [Unreleased] + +## [0.1.0] - <%= Time.now.strftime('%F') %> + +- Initial release diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb index d1d7045daf..936399ed2f 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'set' require 'tsort' require_relative 'dependency_graph/log' diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb index 41bc013143..1185a8ab05 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/dependency_graph/vertex.rb @@ -59,7 +59,7 @@ module Bundler::Molinillo # @param [Set<Vertex>] vertices the set to add the predecessors to # @return [Set<Vertex>] the vertices of {#graph} where `self` is a # {#descendent?} - def _recursive_predecessors(vertices = Set.new) + def _recursive_predecessors(vertices = new_vertex_set) incoming_edges.each do |edge| vertex = edge.origin next unless vertices.add?(vertex) @@ -85,7 +85,7 @@ module Bundler::Molinillo # @param [Set<Vertex>] vertices the set to add the successors to # @return [Set<Vertex>] the vertices of {#graph} where `self` is an # {#ancestor?} - def _recursive_successors(vertices = Set.new) + def _recursive_successors(vertices = new_vertex_set) outgoing_edges.each do |edge| vertex = edge.destination next unless vertices.add?(vertex) @@ -128,7 +128,7 @@ module Bundler::Molinillo # Is there a path from `self` to `other` following edges in the # dependency graph? - # @return true iff there is a path following edges within this {#graph} + # @return whether there is a path following edges within this {#graph} def path_to?(other) _path_to?(other) end @@ -138,7 +138,7 @@ module Bundler::Molinillo # @param [Vertex] other the vertex to check if there's a path to # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited # @return [Boolean] whether there is a path to `other` from `self` - def _path_to?(other, visited = Set.new) + def _path_to?(other, visited = new_vertex_set) return false unless visited.add?(self) return true if equal?(other) successors.any? { |v| v._path_to?(other, visited) } @@ -147,12 +147,18 @@ module Bundler::Molinillo # Is there a path from `other` to `self` following edges in the # dependency graph? - # @return true iff there is a path following edges within this {#graph} + # @return whether there is a path following edges within this {#graph} def ancestor?(other) other.path_to?(self) end alias is_reachable_from? ancestor? + + def new_vertex_set + require 'set' + Set.new + end + private :new_vertex_set end end end diff --git a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb index 14ac26b39e..e210202b69 100644 --- a/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb +++ b/lib/bundler/vendor/molinillo/lib/molinillo/errors.rb @@ -34,7 +34,7 @@ module Bundler::Molinillo # An error caused by attempting to fulfil a dependency that was circular # - # @note This exception will be thrown iff a {Vertex} is added to a + # @note This exception will be thrown if and only if a {Vertex} is added to a # {DependencyGraph} that has a {DependencyGraph::Vertex#path_to?} an # existing {DependencyGraph::Vertex} class CircularDependencyError < ResolverError diff --git a/lib/bundler/vendor/thor/lib/thor.rb b/lib/bundler/vendor/thor/lib/thor.rb index f2a03388cc..0794dbb522 100644 --- a/lib/bundler/vendor/thor/lib/thor.rb +++ b/lib/bundler/vendor/thor/lib/thor.rb @@ -1,7 +1,7 @@ -require "set" require_relative "thor/base" class Bundler::Thor + $thor_runner ||= false class << self # Allows for custom "Command" package naming. # @@ -323,7 +323,7 @@ class Bundler::Thor # ==== Parameters # Symbol ...:: A list of commands that should be affected. def stop_on_unknown_option!(*command_names) - stop_on_unknown_option.merge(command_names) + @stop_on_unknown_option = stop_on_unknown_option | command_names end def stop_on_unknown_option?(command) #:nodoc: @@ -337,7 +337,7 @@ class Bundler::Thor # ==== Parameters # Symbol ...:: A list of commands that should be affected. def disable_required_check!(*command_names) - disable_required_check.merge(command_names) + @disable_required_check = disable_required_check | command_names end def disable_required_check?(command) #:nodoc: @@ -347,12 +347,12 @@ class Bundler::Thor protected def stop_on_unknown_option #:nodoc: - @stop_on_unknown_option ||= Set.new + @stop_on_unknown_option ||= [] end # help command has the required check disabled by default. def disable_required_check #:nodoc: - @disable_required_check ||= Set.new([:help]) + @disable_required_check ||= [:help] end # The method responsible for dispatching given the args. @@ -398,7 +398,6 @@ class Bundler::Thor # the namespace should be displayed as arguments. # def banner(command, namespace = nil, subcommand = false) - $thor_runner ||= false command.formatted_usage(self, $thor_runner, subcommand).split("\n").map do |formatted_usage| "#{basename} #{formatted_usage}" end.join("\n") diff --git a/lib/bundler/vendor/thor/lib/thor/actions.rb b/lib/bundler/vendor/thor/lib/thor/actions.rb index a5368d07f3..de9323b2db 100644 --- a/lib/bundler/vendor/thor/lib/thor/actions.rb +++ b/lib/bundler/vendor/thor/lib/thor/actions.rb @@ -219,7 +219,7 @@ class Bundler::Thor contents = if is_uri require "open-uri" - open(path, "Accept" => "application/x-thor-template", &:read) + URI.open(path, "Accept" => "application/x-thor-template", &:read) else open(path, &:read) end diff --git a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb index afdbd53dd0..62c82b3dba 100644 --- a/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb +++ b/lib/bundler/vendor/thor/lib/thor/actions/file_manipulation.rb @@ -251,7 +251,8 @@ class Bundler::Thor # path<String>:: path of the file to be changed # flag<Regexp|String>:: the regexp or string to be replaced # replacement<String>:: the replacement, can be also given as a block - # config<Hash>:: give :verbose => false to not log the status. + # config<Hash>:: give :verbose => false to not log the status, and + # :force => true, to force the replacement regardles of runner behavior. # # ==== Example # @@ -262,9 +263,10 @@ class Bundler::Thor # end # def gsub_file(path, flag, *args, &block) - return unless behavior == :invoke config = args.last.is_a?(Hash) ? args.pop : {} + return unless behavior == :invoke || config.fetch(:force, false) + path = File.expand_path(path, destination_root) say_status :gsub, relative_to_original_destination_root(path), config.fetch(:verbose, true) diff --git a/lib/bundler/vendor/thor/lib/thor/error.rb b/lib/bundler/vendor/thor/lib/thor/error.rb index 1553afd201..7d57129b83 100644 --- a/lib/bundler/vendor/thor/lib/thor/error.rb +++ b/lib/bundler/vendor/thor/lib/thor/error.rb @@ -1,5 +1,5 @@ class Bundler::Thor - Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) + Correctable = if defined?(DidYouMean::SpellChecker) && defined?(DidYouMean::Correctable) # rubocop:disable Naming/ConstantName # In order to support versions of Ruby that don't have keyword # arguments, we need our own spell checker class that doesn't take key # words. Even though this code wouldn't be hit because of the check diff --git a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb index d0f43e2d97..3a5d82cf29 100644 --- a/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb +++ b/lib/bundler/vendor/thor/lib/thor/parser/arguments.rb @@ -30,7 +30,11 @@ class Bundler::Thor arguments.each do |argument| if !argument.default.nil? - @assigns[argument.human_name] = argument.default + begin + @assigns[argument.human_name] = argument.default.dup + rescue TypeError # Compatibility shim for un-dup-able Fixnum in Ruby < 2.4 + @assigns[argument.human_name] = argument.default + end elsif argument.required? @non_assigned_required << argument end diff --git a/lib/bundler/vendor/thor/lib/thor/parser/options.rb b/lib/bundler/vendor/thor/lib/thor/parser/options.rb index 6d1342ee3c..3a8927d09c 100644 --- a/lib/bundler/vendor/thor/lib/thor/parser/options.rb +++ b/lib/bundler/vendor/thor/lib/thor/parser/options.rb @@ -133,15 +133,16 @@ class Bundler::Thor protected - def assign_result!(option, result) - if option.repeatable && option.type == :hash - (@assigns[option.human_name] ||= {}).merge!(result) - elsif option.repeatable - (@assigns[option.human_name] ||= []) << result - else - @assigns[option.human_name] = result + def assign_result!(option, result) + if option.repeatable && option.type == :hash + (@assigns[option.human_name] ||= {}).merge!(result) + elsif option.repeatable + (@assigns[option.human_name] ||= []) << result + else + @assigns[option.human_name] = result + end end - end + # Check if the current value in peek is a registered switch. # # Two booleans are returned. The first is true if the current value diff --git a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb index be48358cb1..2dddd4a53a 100644 --- a/lib/bundler/vendor/thor/lib/thor/shell/basic.rb +++ b/lib/bundler/vendor/thor/lib/thor/shell/basic.rb @@ -94,6 +94,8 @@ class Bundler::Thor # say("I know you knew that.") # def say(message = "", color = nil, force_new_line = (message.to_s !~ /( |\t)\Z/)) + return if quiet? + buffer = prepare_message(message, *color) buffer << "\n" if force_new_line && !message.to_s.end_with?("\n") @@ -230,8 +232,9 @@ class Bundler::Thor paras = message.split("\n\n") paras.map! do |unwrapped| - counter = 0 - unwrapped.split(" ").inject do |memo, word| + words = unwrapped.split(" ") + counter = words.first.length + words.inject do |memo, word| word = word.gsub(/\n\005/, "\n").gsub(/\005/, "\n") counter = 0 if word.include? "\n" if (counter + word.length + 1) < width diff --git a/lib/bundler/vendor/thor/lib/thor/shell/color.rb b/lib/bundler/vendor/thor/lib/thor/shell/color.rb index 29f280202d..dc167ed3cc 100644 --- a/lib/bundler/vendor/thor/lib/thor/shell/color.rb +++ b/lib/bundler/vendor/thor/lib/thor/shell/color.rb @@ -97,7 +97,11 @@ class Bundler::Thor protected def can_display_colors? - stdout.tty? && !are_colors_disabled? + are_colors_supported? && !are_colors_disabled? + end + + def are_colors_supported? + stdout.tty? && ENV["TERM"] != "dumb" end def are_colors_disabled? diff --git a/lib/bundler/vendor/thor/lib/thor/version.rb b/lib/bundler/vendor/thor/lib/thor/version.rb index 1b222da995..a3efa9f762 100644 --- a/lib/bundler/vendor/thor/lib/thor/version.rb +++ b/lib/bundler/vendor/thor/lib/thor/version.rb @@ -1,3 +1,3 @@ class Bundler::Thor - VERSION = "1.0.1" + VERSION = "1.1.0" end diff --git a/lib/bundler/version.rb b/lib/bundler/version.rb index 35007186b5..f9569c8f78 100644 --- a/lib/bundler/version.rb +++ b/lib/bundler/version.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false module Bundler - VERSION = "2.2.7".freeze + VERSION = "2.2.9".freeze def self.bundler_major_version @bundler_major_version ||= VERSION.split(".").first.to_i diff --git a/lib/rubygems.rb b/lib/rubygems.rb index f90e6c5c85..41b1353e1f 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = "3.2.7".freeze + VERSION = "3.2.9".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -275,7 +275,7 @@ module Gem unless spec = specs.first msg = "can't find gem #{dep} with executable #{exec_name}" - if name == "bundler" && bundler_message = Gem::BundlerVersionFinder.missing_version_message + if dep.filters_bundler? && bundler_message = Gem::BundlerVersionFinder.missing_version_message msg = bundler_message end raise Gem::GemNotFoundException, msg diff --git a/lib/rubygems/dependency.rb b/lib/rubygems/dependency.rb index 68f3e3d991..3721204ab2 100644 --- a/lib/rubygems/dependency.rb +++ b/lib/rubygems/dependency.rb @@ -277,7 +277,7 @@ class Gem::Dependency requirement.satisfied_by?(spec.version) && env_req.satisfied_by?(spec.version) end.map(&:to_spec) - Gem::BundlerVersionFinder.filter!(matches) if name == "bundler".freeze && !requirement.specific? + Gem::BundlerVersionFinder.filter!(matches) if filters_bundler? if platform_only matches.reject! do |spec| @@ -295,6 +295,10 @@ class Gem::Dependency @requirement.specific? end + def filters_bundler? + name == "bundler".freeze && !specific? + end + def to_specs matches = matching_specs true diff --git a/lib/rubygems/resolver/index_specification.rb b/lib/rubygems/resolver/index_specification.rb index 2aa6b419ba..9ea76f40ba 100644 --- a/lib/rubygems/resolver/index_specification.rb +++ b/lib/rubygems/resolver/index_specification.rb @@ -35,9 +35,12 @@ class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification ## # The required_ruby_version constraint for this specification + # + # A fallback is included because when generated, some marshalled specs have it + # set to +nil+. def required_ruby_version - spec.required_ruby_version + spec.required_ruby_version || Gem::Requirement.default end ## diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb index 2ddb0ac426..b765226fb0 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/delegates/specification_provider.rb @@ -26,6 +26,13 @@ module Gem::Resolver::Molinillo end end + # (see Gem::Resolver::Molinillo::SpecificationProvider#dependencies_equal?) + def dependencies_equal?(dependencies, other_dependencies) + with_no_such_dependency_error_handling do + specification_provider.dependencies_equal?(dependencies, other_dependencies) + end + end + # (see Gem::Resolver::Molinillo::SpecificationProvider#name_for) def name_for(dependency) with_no_such_dependency_error_handling do diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb index 773bb3417f..16430a79f5 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true -require 'set' require 'tsort' require_relative 'dependency_graph/log' diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb index f4cc333dd1..77114951b2 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/dependency_graph/vertex.rb @@ -59,7 +59,7 @@ module Gem::Resolver::Molinillo # @param [Set<Vertex>] vertices the set to add the predecessors to # @return [Set<Vertex>] the vertices of {#graph} where `self` is a # {#descendent?} - def _recursive_predecessors(vertices = Set.new) + def _recursive_predecessors(vertices = new_vertex_set) incoming_edges.each do |edge| vertex = edge.origin next unless vertices.add?(vertex) @@ -85,7 +85,7 @@ module Gem::Resolver::Molinillo # @param [Set<Vertex>] vertices the set to add the successors to # @return [Set<Vertex>] the vertices of {#graph} where `self` is an # {#ancestor?} - def _recursive_successors(vertices = Set.new) + def _recursive_successors(vertices = new_vertex_set) outgoing_edges.each do |edge| vertex = edge.destination next unless vertices.add?(vertex) @@ -138,7 +138,7 @@ module Gem::Resolver::Molinillo # @param [Vertex] other the vertex to check if there's a path to # @param [Set<Vertex>] visited the vertices of {#graph} that have been visited # @return [Boolean] whether there is a path to `other` from `self` - def _path_to?(other, visited = Set.new) + def _path_to?(other, visited = new_vertex_set) return false unless visited.add?(self) return true if equal?(other) successors.any? { |v| v._path_to?(other, visited) } @@ -147,12 +147,18 @@ module Gem::Resolver::Molinillo # Is there a path from `other` to `self` following edges in the # dependency graph? - # @return true iff there is a path following edges within this {#graph} + # @return whether there is a path following edges within this {#graph} def ancestor?(other) other.path_to?(self) end alias is_reachable_from? ancestor? + + def new_vertex_set + require 'set' + Set.new + end + private :new_vertex_set end end end diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb index a6e182e84d..ada03a901c 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/errors.rb @@ -121,7 +121,7 @@ module Gem::Resolver::Molinillo t = ''.dup depth = 2 tree.each do |req| - t << ' ' * depth << req.to_s + t << ' ' * depth << printable_requirement.call(req) unless tree.last == req if spec = conflict.activated_by_name[name_for(req)] t << %( was resolved to #{version_for_spec.call(spec)}, which) diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb index a44b9c0d5d..9448dc7bf3 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/modules/specification_provider.rb @@ -45,6 +45,17 @@ module Gem::Resolver::Molinillo true end + # Determines whether two arrays of dependencies are equal, and thus can be + # grouped. + # + # @param [Array<Object>] dependencies + # @param [Array<Object>] other_dependencies + # @return [Boolean] whether `dependencies` and `other_dependencies` should + # be considered equal. + def dependencies_equal?(dependencies, other_dependencies) + dependencies == other_dependencies + end + # Returns the name for the given `dependency`. # @note This method should be 'pure', i.e. the return value should depend # only on the `dependency` parameter. diff --git a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb index f1c60ec544..8b40e59e42 100644 --- a/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb +++ b/lib/rubygems/resolver/molinillo/lib/molinillo/resolution.rb @@ -329,11 +329,11 @@ module Gem::Resolver::Molinillo # Look for past conflicts that could be unwound to affect the # requirement tree for the current conflict + all_reqs = last_detail_for_current_unwind.all_requirements + all_reqs_size = all_reqs.size relevant_unused_unwinds = unused_unwind_options.select do |alternative| - intersecting_requirements = - last_detail_for_current_unwind.all_requirements & - alternative.requirements_unwound_to_instead - next if intersecting_requirements.empty? + diff_reqs = all_reqs - alternative.requirements_unwound_to_instead + next if diff_reqs.size == all_reqs_size # Find the highest index unwind whilst looping through current_detail = alternative if alternative > current_detail alternative @@ -344,8 +344,12 @@ module Gem::Resolver::Molinillo state.unused_unwind_options += unwind_details.reject { |detail| detail.state_index == -1 } # Update the requirements_unwound_to_instead on any relevant unused unwinds - relevant_unused_unwinds.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } - unwind_details.each { |d| d.requirements_unwound_to_instead << current_detail.state_requirement } + relevant_unused_unwinds.each do |d| + (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! + end + unwind_details.each do |d| + (d.requirements_unwound_to_instead << current_detail.state_requirement).uniq! + end current_detail end @@ -803,7 +807,7 @@ module Gem::Resolver::Molinillo possibilities.reverse_each do |possibility| dependencies = dependencies_for(possibility) - if current_possibility_set && current_possibility_set.dependencies == dependencies + if current_possibility_set && dependencies_equal?(current_possibility_set.dependencies, dependencies) current_possibility_set.possibilities.unshift(possibility) else possibility_sets.unshift(PossibilitySet.new(dependencies, [possibility])) diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 4e1a3a3801..73062afe53 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -827,7 +827,9 @@ class Gem::Specification < Gem::BasicSpecification if @@stubs @@stubs_by_name[name] || [] else - @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec") + @@stubs_by_name[name] ||= stubs_for_pattern("#{name}-*.gemspec").select do |s| + s.name == name + end end end @@ -848,7 +850,9 @@ class Gem::Specification < Gem::BasicSpecification specs.sort! do |a, b| names = a.name <=> b.name next names if names.nonzero? - b.version <=> a.version + versions = b.version <=> a.version + next versions if versions.nonzero? + b.platform == Gem::Platform::RUBY ? -1 : 1 end end @@ -1084,20 +1088,15 @@ class Gem::Specification < Gem::BasicSpecification end def self._latest_specs(specs, prerelease = false) # :nodoc: - result = Hash.new {|h,k| h[k] = {} } - native = {} + result = {} specs.reverse_each do |spec| next if spec.version.prerelease? unless prerelease - native[spec.name] = spec.version if spec.platform == Gem::Platform::RUBY - result[spec.name][spec.platform] = spec + result[spec.name] = spec end - result.map(&:last).map(&:values).flatten.reject do |spec| - minimum = native[spec.name] - minimum && spec.version < minimum - end.sort_by{|tup| tup.name } + result.map(&:last).flatten.sort_by{|tup| tup.name } end ## @@ -2552,7 +2551,7 @@ class Gem::Specification < Gem::BasicSpecification begin dependencies.each do |dep| next unless dep.runtime? - dep.to_specs.each do |dep_spec| + dep.matching_specs(true).each do |dep_spec| next if visited.has_key?(dep_spec) visited[dep_spec] = true trail.push(dep_spec) diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 0f3791f03d..e2763561c6 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -311,7 +311,7 @@ class Gem::TestCase < Minitest::Test ENV['XDG_CONFIG_HOME'] = nil ENV['XDG_DATA_HOME'] = nil ENV['SOURCE_DATE_EPOCH'] = nil - ENV["TMPDIR"] = @tmp + ENV['BUNDLER_VERSION'] = nil @current_dir = Dir.pwd @fetcher = nil @@ -322,13 +322,10 @@ class Gem::TestCase < Minitest::Test # capture output Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new - tmpdir = File.realpath Dir.tmpdir - tmpdir.tap(&Gem::UNTAINT) - - @tempdir = File.join(tmpdir, "test_rubygems_#{$$}") + @tempdir = Dir.mktmpdir("test_rubygems_", @tmp) @tempdir.tap(&Gem::UNTAINT) - FileUtils.mkdir_p @tempdir + ENV["TMPDIR"] = @tempdir @orig_SYSTEM_WIDE_CONFIG_FILE = Gem::ConfigFile::SYSTEM_WIDE_CONFIG_FILE Gem::ConfigFile.send :remove_const, :SYSTEM_WIDE_CONFIG_FILE @@ -367,7 +364,9 @@ class Gem::TestCase < Minitest::Test Dir.chdir @tempdir ENV['HOME'] = @userhome + Gem.instance_variable_set :@config_file, nil Gem.instance_variable_set :@user_home, nil + Gem.instance_variable_set :@config_home, nil Gem.instance_variable_set :@data_home, nil Gem.instance_variable_set :@gemdeps, nil Gem.instance_variable_set :@env_requirements_by_name, nil diff --git a/spec/bundler/bundler/gem_helper_spec.rb b/spec/bundler/bundler/gem_helper_spec.rb index 7eb334356d..d718615ad2 100644 --- a/spec/bundler/bundler/gem_helper_spec.rb +++ b/spec/bundler/bundler/gem_helper_spec.rb @@ -9,7 +9,8 @@ RSpec.describe Bundler::GemHelper do let(:app_gemspec_path) { app_path.join("#{app_name}.gemspec") } before(:each) do - global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false", "BUNDLE_GEM__CI" => "false" + global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__COC" => "false", "BUNDLE_GEM__RUBOCOP" => "false", + "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__CHANGELOG" => "false" bundle "gem #{app_name}" prepare_gemspec(app_gemspec_path) end @@ -97,6 +98,7 @@ RSpec.describe Bundler::GemHelper do context "before installation" do it "raises an error with appropriate message" do task_names.each do |name| + skip "Rake::FileTask '#{name}' exists" if File.exist?(name) expect { Rake.application[name] }. to raise_error(/^Don't know how to build task '#{name}'/) end diff --git a/spec/bundler/bundler/gem_version_promoter_spec.rb b/spec/bundler/bundler/gem_version_promoter_spec.rb index af51a270b6..43a3630bbb 100644 --- a/spec/bundler/bundler/gem_version_promoter_spec.rb +++ b/spec/bundler/bundler/gem_version_promoter_spec.rb @@ -28,7 +28,7 @@ RSpec.describe Bundler::GemVersionPromoter do def build_spec_groups(name, versions) versions.map do |v| - Bundler::Resolver::SpecGroup.new(build_spec(name, v)) + Bundler::Resolver::SpecGroup.create_for({ Gem::Platform::RUBY => build_spec(name, v) }, [Gem::Platform::RUBY], Gem::Platform::RUBY) end end diff --git a/spec/bundler/commands/info_spec.rb b/spec/bundler/commands/info_spec.rb index 6bc07ea399..7702959306 100644 --- a/spec/bundler/commands/info_spec.rb +++ b/spec/bundler/commands/info_spec.rb @@ -165,7 +165,7 @@ RSpec.describe "bundle info" do G bundle "info rac" - expect(out).to eq "1 : rack\n2 : rack-obama\n0 : - exit -\n>" + expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/) end end diff --git a/spec/bundler/commands/lock_spec.rb b/spec/bundler/commands/lock_spec.rb index afc3b03a53..44bde4a9b8 100644 --- a/spec/bundler/commands/lock_spec.rb +++ b/spec/bundler/commands/lock_spec.rb @@ -220,6 +220,30 @@ RSpec.describe "bundle lock" do expect(lockfile.platforms).to match_array(local_platforms.unshift(java, mingw).uniq) end + it "supports adding new platforms with force_ruby_platform = true" do + lockfile <<-L + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + platform_specific (1.0) + platform_specific (1.0-x86-linux) + + PLATFORMS + ruby + x86-linux + + DEPENDENCIES + platform_specific + L + + bundle "config set force_ruby_platform true" + bundle "lock --add-platform java x86-mingw32" + + allow(Bundler::SharedHelpers).to receive(:find_gemfile).and_return(bundled_app_gemfile) + lockfile = Bundler::LockfileParser.new(read_lockfile) + expect(lockfile.platforms).to contain_exactly(rb, linux, java, mingw) + end + it "supports adding the `ruby` platform" do bundle "lock --add-platform ruby" diff --git a/spec/bundler/commands/newgem_spec.rb b/spec/bundler/commands/newgem_spec.rb index 265268a1fe..c5294a6b4d 100644 --- a/spec/bundler/commands/newgem_spec.rb +++ b/spec/bundler/commands/newgem_spec.rb @@ -158,6 +158,26 @@ RSpec.describe "bundle gem" do end end + shared_examples_for "--changelog flag" do + before do + bundle "gem #{gem_name} --changelog" + end + it "generates a gem skeleton with a CHANGELOG", :readline do + gem_skeleton_assertions + expect(bundled_app("#{gem_name}/CHANGELOG.md")).to exist + end + end + + shared_examples_for "--no-changelog flag" do + before do + bundle "gem #{gem_name} --no-changelog" + end + it "generates a gem skeleton without a CHANGELOG", :readline do + gem_skeleton_assertions + expect(bundled_app("#{gem_name}/CHANGELOG.md")).to_not exist + end + end + shared_examples_for "--rubocop flag" do before do bundle "gem #{gem_name} --rubocop" @@ -902,6 +922,22 @@ RSpec.describe "bundle gem" do it_behaves_like "--rubocop flag" it_behaves_like "--no-rubocop flag" end + + context "with changelog option in bundle config settings set to true" do + before do + global_config "BUNDLE_GEM__CHANGELOG" => "true" + end + it_behaves_like "--changelog flag" + it_behaves_like "--no-changelog flag" + end + + context "with changelog option in bundle config settings set to false" do + before do + global_config "BUNDLE_GEM__CHANGELOG" => "false" + end + it_behaves_like "--changelog flag" + it_behaves_like "--no-changelog flag" + end end context "gem naming with underscore", :readline do @@ -1087,6 +1123,17 @@ Usage: "bundle gem NAME [OPTIONS]" expect(bundled_app("foobar/CODE_OF_CONDUCT.md")).to exist end + + it "asks about CHANGELOG" do + global_config "BUNDLE_GEM__MIT" => "false", "BUNDLE_GEM__TEST" => "false", "BUNDLE_GEM__CI" => "false", "BUNDLE_GEM__RUBOCOP" => "false", + "BUNDLE_GEM__COC" => "false" + + bundle "gem foobar" do |input, _, _| + input.puts "yes" + end + + expect(bundled_app("foobar/CHANGELOG.md")).to exist + end end context "on conflicts with a previously created file", :readline do diff --git a/spec/bundler/commands/show_spec.rb b/spec/bundler/commands/show_spec.rb index 30e9de9686..2adb121616 100644 --- a/spec/bundler/commands/show_spec.rb +++ b/spec/bundler/commands/show_spec.rb @@ -173,7 +173,7 @@ RSpec.describe "bundle show", :bundler => "< 3" do G bundle "show rac" - expect(out).to eq "1 : rack\n2 : rack-obama\n0 : - exit -\n>" + expect(out).to match(/\A1 : rack\n2 : rack-obama\n0 : - exit -(\n>)?\z/) end end diff --git a/spec/bundler/install/gemfile/platform_spec.rb b/spec/bundler/install/gemfile/platform_spec.rb index 46fc393fe9..8ab59abeeb 100644 --- a/spec/bundler/install/gemfile/platform_spec.rb +++ b/spec/bundler/install/gemfile/platform_spec.rb @@ -299,6 +299,48 @@ RSpec.describe "bundle install across platforms" do bundle :install expect(vendored_gems("gems/rack-1.0.0")).to exist end + + it "keeps existing platforms when installing with force_ruby_platform" do + lockfile <<-G + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + platform_specific (1.0-java) + + PLATFORMS + java + + DEPENDENCIES + platform_specific + G + + bundle "config set --local force_ruby_platform true" + + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "platform_specific" + G + + expect(the_bundle).to include_gem "platform_specific 1.0 RUBY" + + lockfile_should_be <<-G + GEM + remote: #{file_uri_for(gem_repo1)}/ + specs: + platform_specific (1.0) + platform_specific (1.0-java) + + PLATFORMS + java + ruby + + DEPENDENCIES + platform_specific + + BUNDLED WITH + #{Bundler::VERSION} + G + end end RSpec.describe "bundle install with platform conditionals" do diff --git a/spec/bundler/install/gemfile/specific_platform_spec.rb b/spec/bundler/install/gemfile/specific_platform_spec.rb index b58726064f..9e30fc4fd4 100644 --- a/spec/bundler/install/gemfile/specific_platform_spec.rb +++ b/spec/bundler/install/gemfile/specific_platform_spec.rb @@ -211,37 +211,17 @@ RSpec.describe "bundle install with specific platforms" do build_repo2 do build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86_64-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x86-linux" } build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "x64-mingw32" } build_gem("google-protobuf", "3.0.0.alpha.5.0.5.1") {|s| s.platform = "universal-darwin" } build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86_64-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-linux" } build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x64-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.5") {|s| s.platform = "x86-mingw32" } build_gem("google-protobuf", "3.0.0.alpha.5.0.5") build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "universal-darwin" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86_64-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x86-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.4") {|s| s.platform = "x64-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.4") - - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86_64-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x86-linux" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "x64-mingw32" } - build_gem("google-protobuf", "3.0.0.alpha.5.0.3") {|s| s.platform = "universal-darwin" } build_gem("google-protobuf", "3.0.0.alpha.4.0") build_gem("google-protobuf", "3.0.0.alpha.3.1.pre") - build_gem("google-protobuf", "3.0.0.alpha.3") - build_gem("google-protobuf", "3.0.0.alpha.2.0") - build_gem("google-protobuf", "3.0.0.alpha.1.1") - build_gem("google-protobuf", "3.0.0.alpha.1.0") end end diff --git a/spec/bundler/install/gems/standalone_spec.rb b/spec/bundler/install/gems/standalone_spec.rb index 90134865e1..0a0f992704 100644 --- a/spec/bundler/install/gems/standalone_spec.rb +++ b/spec/bundler/install/gems/standalone_spec.rb @@ -32,6 +32,21 @@ RSpec.shared_examples "bundle install --standalone" do expect(out).to eq(expected_gems.values.join("\n")) end + it "makes the gems available without bundler via Kernel.require" do + testrb = String.new <<-RUBY + $:.unshift File.expand_path("bundle") + require "bundler/setup" + + RUBY + expected_gems.each do |k, _| + testrb << "\nKernel.require \"#{k}\"" + testrb << "\nputs #{k.upcase}" + end + ruby testrb + + expect(out).to eq(expected_gems.values.join("\n")) + end + it "makes system gems unavailable without bundler" do system_gems "rack-1.0.0" diff --git a/spec/bundler/quality_spec.rb b/spec/bundler/quality_spec.rb index 405c786842..2b1e28fa30 100644 --- a/spec/bundler/quality_spec.rb +++ b/spec/bundler/quality_spec.rb @@ -220,7 +220,7 @@ RSpec.describe "The library itself" do gem_list = loaded_gemspec.files - expect(git_list.to_set).to eq(gem_list.to_set) + expect(git_list.sort).to eq(gem_list.sort) end it "does not contain any warnings" do diff --git a/spec/bundler/resolver/platform_spec.rb b/spec/bundler/resolver/platform_spec.rb index 415c5458df..7169ba4b95 100644 --- a/spec/bundler/resolver/platform_spec.rb +++ b/spec/bundler/resolver/platform_spec.rb @@ -120,6 +120,157 @@ RSpec.describe "Resolving platform craziness" do should_resolve_as %w[foo-1.1.0] end + it "doesn't include gems not needed for none of the platforms" do + @index = build_index do + gem "empyrean", "0.1.0" + gem "coderay", "1.1.2" + gem "method_source", "0.9.0" + + gem "spoon", "0.0.6" do + dep "ffi", ">= 0" + end + + gem "pry", "0.11.3", "java" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + dep "spoon", "~> 0.0" + end + + gem "pry", "0.11.3" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + end + + gem "ffi", "1.9.23", "java" + gem "ffi", "1.9.23" + end + + dep "empyrean", "0.1.0" + dep "pry" + + platforms "ruby", "java" + + should_resolve_as %w[coderay-1.1.2 empyrean-0.1.0 ffi-1.9.23-java method_source-0.9.0 pry-0.11.3 pry-0.11.3-java spoon-0.0.6] + end + + it "includes gems needed for at least one platform" do + @index = build_index do + gem "empyrean", "0.1.0" + gem "coderay", "1.1.2" + gem "method_source", "0.9.0" + + gem "spoon", "0.0.6" do + dep "ffi", ">= 0" + end + + gem "pry", "0.11.3", "java" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + dep "spoon", "~> 0.0" + end + + gem "pry", "0.11.3" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + end + + gem "ffi", "1.9.23", "java" + gem "ffi", "1.9.23" + + gem "extra", "1.0.0" do + dep "ffi", ">= 0" + end + end + + dep "empyrean", "0.1.0" + dep "pry" + dep "extra" + + platforms "ruby", "java" + + should_resolve_as %w[coderay-1.1.2 empyrean-0.1.0 extra-1.0.0 ffi-1.9.23 ffi-1.9.23-java method_source-0.9.0 pry-0.11.3 pry-0.11.3-java spoon-0.0.6] + end + + it "includes gems needed for at least one platform even when the platform specific requirement is processed earlier than the generic requirement" do + @index = build_index do + gem "empyrean", "0.1.0" + gem "coderay", "1.1.2" + gem "method_source", "0.9.0" + + gem "spoon", "0.0.6" do + dep "ffi", ">= 0" + end + + gem "pry", "0.11.3", "java" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + dep "spoon", "~> 0.0" + end + + gem "pry", "0.11.3" do + dep "coderay", "~> 1.1.0" + dep "method_source", "~> 0.9.0" + end + + gem "ffi", "1.9.23", "java" + gem "ffi", "1.9.23" + + gem "extra", "1.0.0" do + dep "extra2", ">= 0" + end + + gem "extra2", "1.0.0" do + dep "extra3", ">= 0" + end + + gem "extra3", "1.0.0" do + dep "ffi", ">= 0" + end + end + + dep "empyrean", "0.1.0" + dep "pry" + dep "extra" + + platforms "ruby", "java" + + should_resolve_as %w[coderay-1.1.2 empyrean-0.1.0 extra-1.0.0 extra2-1.0.0 extra3-1.0.0 ffi-1.9.23 ffi-1.9.23-java method_source-0.9.0 pry-0.11.3 pry-0.11.3-java spoon-0.0.6] + end + + it "properly adds platforms when platform requirements come from different dependencies" do + @index = build_index do + gem "ffi", "1.9.14" + gem "ffi", "1.9.14", "universal-mingw32" + + gem "gssapi", "0.1" + gem "gssapi", "0.2" + gem "gssapi", "0.3" + gem "gssapi", "1.2.0" do + dep "ffi", ">= 1.0.1" + end + + gem "mixlib-shellout", "2.2.6" + gem "mixlib-shellout", "2.2.6", "universal-mingw32" do + dep "win32-process", "~> 0.8.2" + end + + # we need all these versions to get the sorting the same as it would be + # pulling from rubygems.org + %w[0.8.3 0.8.2 0.8.1 0.8.0].each do |v| + gem "win32-process", v do + dep "ffi", ">= 1.0.0" + end + end + end + + dep "mixlib-shellout" + dep "gssapi" + + platforms "universal-mingw32", "ruby" + + should_resolve_as %w[ffi-1.9.14 ffi-1.9.14-universal-mingw32 gssapi-1.2.0 mixlib-shellout-2.2.6 mixlib-shellout-2.2.6-universal-mingw32 win32-process-0.8.3] + end + describe "with mingw32" do before :each do @index = build_index do diff --git a/spec/bundler/runtime/platform_spec.rb b/spec/bundler/runtime/platform_spec.rb index 79ca69a810..f28b5ea16b 100644 --- a/spec/bundler/runtime/platform_spec.rb +++ b/spec/bundler/runtime/platform_spec.rb @@ -112,6 +112,15 @@ RSpec.describe "Bundler.setup with multi platform stuff" do expect(the_bundle).to include_gems "nokogiri 1.4.2", "platform_specific 1.0 RUBY" end + it "doesn't pull platform specific gems on truffleruby", :truffleruby do + install_gemfile <<-G + source "#{file_uri_for(gem_repo1)}" + gem "platform_specific" + G + + expect(the_bundle).to include_gems "platform_specific 1.0 RUBY" + end + it "allows specifying only-ruby-platform on windows with dependency platforms" do simulate_windows do install_gemfile <<-G diff --git a/spec/bundler/runtime/setup_spec.rb b/spec/bundler/runtime/setup_spec.rb index 7b15a9b644..7af1cd9801 100644 --- a/spec/bundler/runtime/setup_spec.rb +++ b/spec/bundler/runtime/setup_spec.rb @@ -1252,7 +1252,7 @@ end exempts << "fiddle" if Gem.win_platform? && Gem::Version.new(Gem::VERSION) >= Gem::Version.new("2.7") exempts << "uri" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("2.7") exempts << "pathname" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") - exempts << "set" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") + exempts << "set" unless Gem::Version.new(Gem::VERSION) >= Gem::Version.new("3.2.6") exempts << "tsort" if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.0") exempts end @@ -1334,31 +1334,8 @@ end expect(out).to eq("The Gemfile's dependencies are satisfied") end - # bundler respects paths specified directly in RUBYLIB or RUBYOPT, and - # that happens when running ruby from the ruby-core setup. To - # workaround, we manually remove those for these tests when they would - # override the default gem. - def load_path_exclusions_hack_for(name) - if ruby_core? - ext_folder = source_root.join(".ext/common") - require_name = name.tr("-", "/") - if File.exist?(ext_folder.join("#{require_name}.rb")) - { :exclude_from_load_path => ext_folder.to_s } - else - lib_folder = source_lib_dir - if File.exist?(lib_folder.join("#{require_name}.rb")) - { :exclude_from_load_path => lib_folder.to_s } - else - {} - end - end - else - {} - end - end - Gem::Specification.select(&:default_gem?).map(&:name).each do |g| - it "activates newer versions of #{g}" do + it "activates newer versions of #{g}", :ruby_repo do skip if exemptions.include?(g) build_repo4 do @@ -1370,11 +1347,10 @@ end gem "#{g}", "999999" G - opts = { :env => { "RUBYOPT" => activation_warning_hack_rubyopt } } - expect(the_bundle).to include_gem("#{g} 999999", opts.merge(load_path_exclusions_hack_for(g))) + expect(the_bundle).to include_gem("#{g} 999999", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }) end - it "activates older versions of #{g}" do + it "activates older versions of #{g}", :ruby_repo do skip if exemptions.include?(g) build_repo4 do @@ -1386,8 +1362,7 @@ end gem "#{g}", "0.0.0.a" G - opts = { :env => { "RUBYOPT" => activation_warning_hack_rubyopt } } - expect(the_bundle).to include_gem("#{g} 0.0.0.a", opts.merge(load_path_exclusions_hack_for(g))) + expect(the_bundle).to include_gem("#{g} 0.0.0.a", :env => { "RUBYOPT" => activation_warning_hack_rubyopt }) end end end diff --git a/spec/bundler/support/filters.rb b/spec/bundler/support/filters.rb index b1978e44e6..0c1f27e470 100644 --- a/spec/bundler/support/filters.rb +++ b/spec/bundler/support/filters.rb @@ -32,7 +32,8 @@ RSpec.configure do |config| config.filter_run_excluding :no_color_tty => Gem.win_platform? || !ENV["GITHUB_ACTION"].nil? config.filter_run_excluding :permissions => Gem.win_platform? config.filter_run_excluding :readline => Gem.win_platform? - config.filter_run_excluding :jruby => RUBY_PLATFORM != "java" + config.filter_run_excluding :jruby => RUBY_ENGINE != "jruby" + config.filter_run_excluding :truffleruby => RUBY_ENGINE != "truffleruby" config.filter_run_when_matching :focus unless ENV["CI"] end diff --git a/spec/bundler/support/matchers.rb b/spec/bundler/support/matchers.rb index 01e11eb94d..a6944495ff 100644 --- a/spec/bundler/support/matchers.rb +++ b/spec/bundler/support/matchers.rb @@ -115,7 +115,6 @@ module Spec opts = names.last.is_a?(Hash) ? names.pop : {} source = opts.delete(:source) groups = Array(opts[:groups]) - exclude_from_load_path = opts.delete(:exclude_from_load_path) opts[:raise_on_error] = false groups << opts @errors = names.map do |name| @@ -123,7 +122,6 @@ module Spec require_path = name == "bundler" ? "#{lib_dir}/bundler" : name.tr("-", "/") version_const = name == "bundler" ? "Bundler::VERSION" : Spec::Builders.constantize(name) code = [] - code << "$LOAD_PATH.delete '#{exclude_from_load_path}'" if exclude_from_load_path code << "require '#{require_path}.rb'" code << "puts #{version_const}" run code.join("; "), *groups diff --git a/spec/bundler/support/rubygems_version_manager.rb b/spec/bundler/support/rubygems_version_manager.rb index ac02021cff..c2e5a5f484 100644 --- a/spec/bundler/support/rubygems_version_manager.rb +++ b/spec/bundler/support/rubygems_version_manager.rb @@ -78,6 +78,7 @@ class RubygemsVersionManager end def rubygems_unrequire_needed? + require "rubygems" !$LOADED_FEATURES.include?(local_copy_path.join("lib/rubygems.rb").to_s) end diff --git a/test/rubygems/data/null-required-ruby-version.gemspec.rz b/test/rubygems/data/null-required-ruby-version.gemspec.rz Binary files differnew file mode 100644 index 0000000000..f4ec1a9620 --- /dev/null +++ b/test/rubygems/data/null-required-ruby-version.gemspec.rz diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 68e3eccdaf..1c6d790b25 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -297,6 +297,58 @@ class TestGem < Gem::TestCase assert_equal %w[a-1 b-2 c-1], loaded_spec_names end + def test_activate_bin_path_does_not_error_if_a_gem_thats_not_finally_activated_has_orphaned_dependencies + a1 = util_spec 'a', '1' do |s| + s.executables = ['exec'] + s.add_dependency 'b' + end + + b1 = util_spec 'b', '1' do |s| + s.add_dependency 'c', '1' + end + + b2 = util_spec 'b', '2' do |s| + s.add_dependency 'c', '2' + end + + c2 = util_spec 'c', '2' + + install_specs c2, b1, b2, a1 + + # c1 is missing, but not needed for activation, so we should not get any errors here + + Gem.activate_bin_path("a", "exec", ">= 0") + + assert_equal %w[a-1 b-2 c-2], loaded_spec_names + end + + def test_activate_bin_path_raises_a_meaningful_error_if_a_gem_thats_finally_activated_has_orphaned_dependencies + a1 = util_spec 'a', '1' do |s| + s.executables = ['exec'] + s.add_dependency 'b' + end + + b1 = util_spec 'b', '1' do |s| + s.add_dependency 'c', '1' + end + + b2 = util_spec 'b', '2' do |s| + s.add_dependency 'c', '2' + end + + c1 = util_spec 'c', '1' + + install_specs c1, b1, b2, a1 + + # c2 is missing, and b2 which has it as a dependency will be activated, so we should get an error about the orphaned dependency + + e = assert_raises Gem::UnsatisfiableDependencyError do + load Gem.activate_bin_path("a", "exec", ">= 0") + end + + assert_equal "Unable to resolve dependency: 'b (>= 0)' requires 'c (= 2)'", e.message + end + def test_activate_bin_path_in_debug_mode a1 = util_spec 'a', '1' do |s| s.executables = ['exec'] @@ -416,6 +468,32 @@ class TestGem < Gem::TestCase assert_equal %w[bundler-1.17.3], loaded_spec_names end + def test_activate_bin_path_gives_proper_error_for_bundler_when_underscore_selection_given + File.open("Gemfile.lock", "w") do |f| + f.write <<-L.gsub(/ {8}/, "") + GEM + remote: https://rubygems.org/ + specs: + + PLATFORMS + ruby + + DEPENDENCIES + + BUNDLED WITH + 2.1.4 + L + end + + File.open("Gemfile", "w") {|f| f.puts('source "https://rubygems.org"') } + + e = assert_raises Gem::GemNotFoundException do + load Gem.activate_bin_path("bundler", "bundle", "= 2.2.8") + end + + assert_equal "can't find gem bundler (= 2.2.8) with executable bundle", e.message + end + def test_self_bin_path_no_exec_name e = assert_raises ArgumentError do Gem.bin_path 'a' diff --git a/test/rubygems/test_gem_commands_outdated_command.rb b/test/rubygems/test_gem_commands_outdated_command.rb index 57939b8088..c4af421f5d 100644 --- a/test/rubygems/test_gem_commands_outdated_command.rb +++ b/test/rubygems/test_gem_commands_outdated_command.rb @@ -28,4 +28,22 @@ class TestGemCommandsOutdatedCommand < Gem::TestCase assert_equal "foo (0.2 < 2.0)\n", @ui.output assert_equal "", @ui.error end + + def test_execute_with_up_to_date_platform_specific_gem + spec_fetcher do |fetcher| + fetcher.download 'foo', '2.0' + + fetcher.gem 'foo', '1.0' + fetcher.gem 'foo', '2.0' do |s| + s.platform = Gem::Platform.local + end + end + + use_ui @ui do + @cmd.execute + end + + assert_equal "", @ui.output + assert_equal "", @ui.error + end end diff --git a/test/rubygems/test_gem_dependency_installer.rb b/test/rubygems/test_gem_dependency_installer.rb index 85dba54675..c62a3f355a 100644 --- a/test/rubygems/test_gem_dependency_installer.rb +++ b/test/rubygems/test_gem_dependency_installer.rb @@ -44,7 +44,7 @@ class TestGemDependencyInstaller < Gem::TestCase s.add_development_dependency 'c' end - util_reset_gems + util_setup_spec_fetcher(@a1, @a1_pre, @b1, @d1) end def test_install @@ -287,8 +287,6 @@ class TestGemDependencyInstaller < Gem::TestCase @aa1, @aa1_gem = util_gem 'aa', '1' - util_reset_gems - FileUtils.mv @a1_gem, @tempdir FileUtils.mv @aa1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -307,8 +305,6 @@ class TestGemDependencyInstaller < Gem::TestCase @aa1, @aa1_gem = util_gem 'aa', '1' - util_reset_gems - FileUtils.mv @a1_gem, @tempdir FileUtils.mv @aa1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -329,8 +325,6 @@ class TestGemDependencyInstaller < Gem::TestCase @aa1, @aa1_gem = util_gem 'aa', '1' - util_reset_gems - FileUtils.mv @a1_gem, @tempdir FileUtils.mv @aa1_gem, @tempdir FileUtils.mv @b1_gem, @tempdir @@ -946,6 +940,31 @@ class TestGemDependencyInstaller < Gem::TestCase assert_equal %w[d-2], inst.installed_gems.map {|s| s.full_name } end + def test_install_legacy_spec_with_nil_required_ruby_version + path = File.expand_path "../data/null-required-ruby-version.gemspec.rz", __FILE__ + spec = Marshal.load Gem.read_binary(path) + def spec.validate(*args); end + + util_build_gem spec + + cache_file = File.join @tempdir, 'gems', "#{spec.original_name}.gem" + FileUtils.mkdir_p File.dirname cache_file + FileUtils.mv spec.cache_file, cache_file + + util_setup_spec_fetcher spec + + data = Gem.read_binary(cache_file) + + @fetcher.data['http://gems.example.com/gems/activesupport-1.0.0.gem'] = data + + dep = Gem::Dependency.new 'activesupport' + + inst = Gem::DependencyInstaller.new + inst.install dep + + assert_equal %w[activesupport-1.0.0], Gem::Specification.map(&:full_name) + end + def test_install_legacy_spec_with_nil_required_rubygems_version path = File.expand_path "../data/null-required-rubygems-version.gemspec.rz", __FILE__ spec = Marshal.load Gem.read_binary(path) @@ -1131,16 +1150,6 @@ class TestGemDependencyInstaller < Gem::TestCase @d1, @d1_gem = util_gem 'd', '1' @d2, @d2_gem = util_gem 'd', '2' - util_reset_gems - end - - def util_reset_gems - @a1 ||= nil - @b1 ||= nil - @a1_pre ||= nil - @d1 ||= nil - @d2 ||= nil - - util_setup_spec_fetcher(*[@a1, @a1_pre, @b1, @d1, @d2].compact) + util_setup_spec_fetcher(@d1, @d2) end end diff --git a/test/rubygems/test_gem_requirement.rb b/test/rubygems/test_gem_requirement.rb index 837f60fbb2..aa4c57ac27 100644 --- a/test/rubygems/test_gem_requirement.rb +++ b/test/rubygems/test_gem_requirement.rb @@ -83,7 +83,7 @@ class TestGemRequirement < Gem::TestCase Gem::Requirement.parse(Gem::Version.new('2')) end - if RUBY_VERSION >= '2.5' + if RUBY_VERSION >= '2.5' && !(Gem.java_platform? && ENV["JRUBY_OPTS"] =~ /--debug/) def test_parse_deduplication assert_same '~>', Gem::Requirement.parse('~> 1').first end diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 763b62c22b..29a3e74bfc 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -1208,6 +1208,16 @@ dependencies: [] Gem.platforms = orig_platform end + def test_self_stubs_returns_only_specified_named_specs + dir_standard_specs = File.join Gem.dir, 'specifications' + + save_gemspec('a-1', '1', dir_standard_specs){|s| s.name = 'a' } + save_gemspec('a-2', '2', dir_standard_specs){|s| s.name = 'a' } + save_gemspec('a-a', '3', dir_standard_specs){|s| s.name = 'a-a' } + + assert_equal ['a-1', 'a-2'], Gem::Specification.stubs_for('a').map(&:full_name).sort + end + def test_handles_private_null_type path = File.expand_path "../data/null-type.gemspec.rz", __FILE__ @@ -3530,19 +3540,6 @@ Did you mean 'Ruby'? specfile.delete end - ## - # KEEP p-1-x86-darwin-8 - # KEEP p-1 - # KEEP c-1.2 - # KEEP a_evil-9 - # a-1 - # a-1-x86-my_platform-1 - # KEEP a-2 - # a-2-x86-other_platform-1 - # KEEP a-2-x86-my_platform-1 - # a-3.a - # KEEP a-3-x86-other_platform-1 - def test_latest_specs spec_fetcher do |fetcher| fetcher.spec 'a', 1 do |s| @@ -3565,8 +3562,6 @@ Did you mean 'Ruby'? end expected = %W[ - a-2 - a-2-x86-my_platform-1 a-3-x86-other_platform-1 ] diff --git a/test/rubygems/test_gem_util.rb b/test/rubygems/test_gem_util.rb index acf7ac8962..7197f664e2 100644 --- a/test/rubygems/test_gem_util.rb +++ b/test/rubygems/test_gem_util.rb @@ -46,8 +46,8 @@ class TestGemUtil < Gem::TestCase assert_equal File.join(@tempdir, 'd'), paths[0] assert_equal @tempdir, paths[1] - assert_equal File.realpath(Dir.tmpdir), paths[2] - assert_equal File.realpath("..", Dir.tmpdir), paths[3] + assert_equal File.realpath("..", @tempdir), paths[2] + assert_equal File.realpath("../..", @tempdir), paths[3] ensure # restore default permissions, allow the directory to be removed FileUtils.chmod(0775, 'd/e') unless win_platform? || java_platform? @@ -72,10 +72,10 @@ class TestGemUtil < Gem::TestCase ] files_with_absolute_base = Gem::Util.glob_files_in_dir('*.rb', File.join(@tempdir, 'g')) - assert_equal expected_paths.to_set, files_with_absolute_base.to_set + assert_equal expected_paths.sort, files_with_absolute_base.sort files_with_relative_base = Gem::Util.glob_files_in_dir('*.rb', 'g') - assert_equal expected_paths.to_set, files_with_relative_base.to_set + assert_equal expected_paths.sort, files_with_relative_base.sort end def test_correct_for_windows_path |