From 7d463e360b9c4718b17378eb52783116a01b884b Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Mon, 11 Nov 2019 15:03:57 +0900 Subject: [PATCH] Merge RubyGems 3.1.0.pre3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix gem pristine not accounting for user installed gems. Pull request #2914 by Luis Sagastume. * Refactor keyword argument test for Ruby 2.7. Pull request #2947 by SHIBATA Hiroshi. * Fix errors at frozen Gem::Version. Pull request #2949 by Nobuyoshi Nakada. * Remove taint usage on Ruby 2.7+. Pull request #2951 by Jeremy Evans. * Check Manifest.txt is up to date. Pull request #2953 by David Rodríguez. * Clarify symlink conditionals in tests. Pull request #2962 by David Rodríguez. * Update command line parsing to work under ps. Pull request #2966 by David Rodríguez. * Properly test `Gem::Specifications.stub_for`. Pull request #2970 by David Rodríguez. * Fix Gem::LOADED_SPECS_MUTEX handling for recursive locking. Pull request #2985 by MSP-Greg. --- lib/rubygems.rb | 15 +++-- lib/rubygems/basic_specification.rb | 18 +++--- lib/rubygems/bundler_version_finder.rb | 4 +- lib/rubygems/commands/pristine_command.rb | 5 -- lib/rubygems/config_file.rb | 2 +- lib/rubygems/core_ext/kernel_gem.rb | 10 +++- lib/rubygems/core_ext/kernel_require.rb | 2 +- lib/rubygems/installer.rb | 8 +-- lib/rubygems/name_tuple.rb | 2 +- lib/rubygems/package.rb | 2 +- lib/rubygems/path_support.rb | 2 +- lib/rubygems/request_set.rb | 2 +- .../request_set/gem_dependency_api.rb | 2 +- lib/rubygems/request_set/lockfile.rb | 4 +- lib/rubygems/source.rb | 2 +- lib/rubygems/specification.rb | 12 ++-- lib/rubygems/stub_specification.rb | 2 +- lib/rubygems/test_case.rb | 12 ++-- lib/rubygems/version.rb | 36 +++++++----- test/rubygems/test_gem.rb | 20 +++---- test/rubygems/test_gem_command_manager.rb | 2 +- .../test_gem_commands_pristine_command.rb | 49 ++++++++++++++++ .../rubygems/test_gem_ext_ext_conf_builder.rb | 6 +- test/rubygems/test_gem_installer.rb | 13 +++-- test/rubygems/test_gem_package.rb | 8 +-- test/rubygems/test_gem_specification.rb | 39 +++++++------ test/rubygems/test_gem_version.rb | 7 +++ test/rubygems/test_project_sanity.rb | 58 +++++++++++++++++++ test/rubygems/test_rake_package.rb | 26 --------- 29 files changed, 237 insertions(+), 133 deletions(-) create mode 100644 test/rubygems/test_project_sanity.rb delete mode 100644 test/rubygems/test_rake_package.rb diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 44b9a2e6b3..88839363e6 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -9,7 +9,7 @@ require 'rbconfig' module Gem - VERSION = "3.1.0.pre2".freeze + VERSION = "3.1.0.pre3".freeze end # Must be first since it unloads the prelude from 1.9.2 @@ -116,6 +116,11 @@ require 'rubygems/path_support' module Gem RUBYGEMS_DIR = File.dirname File.expand_path(__FILE__) + # Taint support is deprecated in Ruby 2.7. + # This allows switching ".untaint" to ".tap(&Gem::UNTAINT)", + # to avoid deprecation warnings in Ruby 2.7. + UNTAINT = RUBY_VERSION < '2.7' ? :untaint.to_sym : proc{} + ## # An Array of Regexps that match windows Ruby platforms. @@ -521,7 +526,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} glob_with_suffixes = "#{glob}#{Gem.suffix_pattern}" $LOAD_PATH.map do |load_path| Gem::Util.glob_files_in_dir(glob_with_suffixes, load_path) - end.flatten.select { |file| File.file? file.untaint } + end.flatten.select { |file| File.file? file.tap(&Gem::UNTAINT) } end ## @@ -1083,7 +1088,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} # The home directory for the user. def self.user_home - @user_home ||= find_home.untaint + @user_home ||= find_home.tap(&Gem::UNTAINT) end ## @@ -1150,7 +1155,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} globbed = Gem::Util.glob_files_in_dir(glob, load_path) globbed.each do |load_path_file| - files << load_path_file if File.file?(load_path_file.untaint) + files << load_path_file if File.file?(load_path_file.tap(&Gem::UNTAINT)) end end @@ -1196,7 +1201,7 @@ An Array (#{env.inspect}) was passed in from #{caller[3]} end end - path.untaint + path.tap(&Gem::UNTAINT) unless File.file? path return unless raise_exception diff --git a/lib/rubygems/basic_specification.rb b/lib/rubygems/basic_specification.rb index 347f8c3318..c6d63ac473 100644 --- a/lib/rubygems/basic_specification.rb +++ b/lib/rubygems/basic_specification.rb @@ -98,7 +98,7 @@ class Gem::BasicSpecification # Returns full path to the directory where gem's extensions are installed. def extension_dir - @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name)).untaint + @extension_dir ||= File.expand_path(File.join(extensions_dir, full_name)).tap(&Gem::UNTAINT) end ## @@ -113,7 +113,7 @@ class Gem::BasicSpecification def find_full_gem_path # :nodoc: # TODO: also, shouldn't it default to full_name if it hasn't been written? path = File.expand_path File.join(gems_dir, full_name) - path.untaint + path.tap(&Gem::UNTAINT) path end @@ -135,9 +135,9 @@ class Gem::BasicSpecification def full_name if platform == Gem::Platform::RUBY or platform.nil? - "#{name}-#{version}".dup.untaint + "#{name}-#{version}".dup.tap(&Gem::UNTAINT) else - "#{name}-#{version}-#{platform}".dup.untaint + "#{name}-#{version}-#{platform}".dup.tap(&Gem::UNTAINT) end end @@ -149,7 +149,7 @@ class Gem::BasicSpecification @full_require_paths ||= begin full_paths = raw_require_paths.map do |path| - File.join full_gem_path, path.untaint + File.join full_gem_path, path.tap(&Gem::UNTAINT) end full_paths << extension_dir if have_extensions? @@ -163,7 +163,7 @@ class Gem::BasicSpecification def datadir # TODO: drop the extra ", gem_name" which is uselessly redundant - File.expand_path(File.join(gems_dir, full_name, "data", name)).untaint + File.expand_path(File.join(gems_dir, full_name, "data", name)).tap(&Gem::UNTAINT) end ## @@ -277,7 +277,7 @@ class Gem::BasicSpecification # TODO: do we need these?? Kill it glob = File.join(self.lib_dirs_glob, glob) - Dir[glob].map { |f| f.untaint } # FIX our tests are broken, run w/ SAFE=1 + Dir[glob].map { |f| f.tap(&Gem::UNTAINT) } # FIX our tests are broken, run w/ SAFE=1 end ## @@ -295,7 +295,7 @@ class Gem::BasicSpecification "lib" # default value for require_paths for bundler/inline end - "#{self.full_gem_path}/#{dirs}".dup.untaint + "#{self.full_gem_path}/#{dirs}".dup.tap(&Gem::UNTAINT) end ## @@ -328,7 +328,7 @@ class Gem::BasicSpecification def have_file?(file, suffixes) return true if raw_require_paths.any? do |path| - base = File.join(gems_dir, full_name, path.untaint, file).untaint + base = File.join(gems_dir, full_name, path.tap(&Gem::UNTAINT), file).tap(&Gem::UNTAINT) suffixes.any? { |suf| File.file? base + suf } end diff --git a/lib/rubygems/bundler_version_finder.rb b/lib/rubygems/bundler_version_finder.rb index 7f420e6fea..38da7738a8 100644 --- a/lib/rubygems/bundler_version_finder.rb +++ b/lib/rubygems/bundler_version_finder.rb @@ -83,7 +83,7 @@ To install the missing version, run `gem install bundler:#{vr.first}` gemfile = ENV["BUNDLE_GEMFILE"] gemfile = nil if gemfile && gemfile.empty? Gem::Util.traverse_parents Dir.pwd do |directory| - next unless gemfile = Gem::GEM_DEP_FILES.find { |f| File.file?(f.untaint) } + next unless gemfile = Gem::GEM_DEP_FILES.find { |f| File.file?(f.tap(&Gem::UNTAINT)) } gemfile = File.join directory, gemfile break @@ -94,7 +94,7 @@ To install the missing version, run `gem install bundler:#{vr.first}` lockfile = case gemfile when "gems.rb" then "gems.locked" else "#{gemfile}.lock" - end.dup.untaint + end.dup.tap(&Gem::UNTAINT) return unless File.file?(lockfile) diff --git a/lib/rubygems/commands/pristine_command.rb b/lib/rubygems/commands/pristine_command.rb index e4628bdd40..2248a821c8 100644 --- a/lib/rubygems/commands/pristine_command.rb +++ b/lib/rubygems/commands/pristine_command.rb @@ -111,11 +111,6 @@ extensions will be restored. "Failed to find gems #{options[:args]} #{options[:version]}" end - install_dir = Gem.dir # TODO use installer option - - raise Gem::FilePermissionError.new(install_dir) unless - File.writable?(install_dir) - say "Restoring gems to pristine condition..." specs.each do |spec| diff --git a/lib/rubygems/config_file.rb b/lib/rubygems/config_file.rb index 26e80afe24..54d8a9c152 100644 --- a/lib/rubygems/config_file.rb +++ b/lib/rubygems/config_file.rb @@ -180,7 +180,7 @@ class Gem::ConfigFile operating_system_config = Marshal.load Marshal.dump(OPERATING_SYSTEM_DEFAULTS) platform_config = Marshal.load Marshal.dump(PLATFORM_DEFAULTS) system_config = load_file SYSTEM_WIDE_CONFIG_FILE - user_config = load_file config_file_name.dup.untaint + user_config = load_file config_file_name.dup.tap(&Gem::UNTAINT) environment_config = (ENV['GEMRC'] || '') .split(File::PATH_SEPARATOR).inject({}) do |result, file| diff --git a/lib/rubygems/core_ext/kernel_gem.rb b/lib/rubygems/core_ext/kernel_gem.rb index fb3053fd83..e722225739 100644 --- a/lib/rubygems/core_ext/kernel_gem.rb +++ b/lib/rubygems/core_ext/kernel_gem.rb @@ -61,9 +61,13 @@ module Kernel spec = dep.to_spec - Gem::LOADED_SPECS_MUTEX.synchronize do - spec.activate - end if spec + if spec + if Gem::LOADED_SPECS_MUTEX.owned? + spec.activate + else + Gem::LOADED_SPECS_MUTEX.synchronize { spec.activate } + end + end end private :gem diff --git a/lib/rubygems/core_ext/kernel_require.rb b/lib/rubygems/core_ext/kernel_require.rb index 858f0998a0..f0409d6068 100644 --- a/lib/rubygems/core_ext/kernel_require.rb +++ b/lib/rubygems/core_ext/kernel_require.rb @@ -41,7 +41,7 @@ module Kernel resolved_path = begin rp = nil $LOAD_PATH[0...Gem.load_path_insert_index || -1].each do |lp| - safe_lp = lp.dup.untaint + safe_lp = lp.dup.tap(&Gem::UNTAINT) next if File.symlink? safe_lp # for backword compatibility Gem.suffixes.each do |s| full_path = File.expand_path(File.join(safe_lp, "#{path}#{s}")) diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 0ffddc52fc..ad39ec81bf 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -196,8 +196,6 @@ class Gem::Installer @package.prog_mode = options[:prog_mode] @package.data_mode = options[:data_mode] - @bin_dir = options[:bin_dir] if options[:bin_dir] - if options[:user_install] @gem_home = Gem.user_dir @bin_dir = Gem.bindir gem_home unless options[:bin_dir] @@ -394,7 +392,7 @@ class Gem::Installer specs = [] Gem::Util.glob_files_in_dir("*.gemspec", File.join(gem_home, "specifications")).each do |path| - spec = Gem::Specification.load path.untaint + spec = Gem::Specification.load path.tap(&Gem::UNTAINT) specs << spec if spec end @@ -502,7 +500,7 @@ class Gem::Installer raise Gem::FilePermissionError.new(@bin_dir) unless File.writable? @bin_dir spec.executables.each do |filename| - filename.untaint + filename.tap(&Gem::UNTAINT) bin_path = File.join gem_dir, spec.bindir, filename unless File.exist? bin_path @@ -633,7 +631,7 @@ class Gem::Installer def ensure_loadable_spec ruby = spec.to_ruby_for_cache - ruby.untaint + ruby.tap(&Gem::UNTAINT) begin eval ruby diff --git a/lib/rubygems/name_tuple.rb b/lib/rubygems/name_tuple.rb index 7cb38233eb..dc1a1bbaa0 100644 --- a/lib/rubygems/name_tuple.rb +++ b/lib/rubygems/name_tuple.rb @@ -55,7 +55,7 @@ class Gem::NameTuple "#{@name}-#{@version}" else "#{@name}-#{@version}-#{@platform}" - end.dup.untaint + end.dup.tap(&Gem::UNTAINT) end ## diff --git a/lib/rubygems/package.rb b/lib/rubygems/package.rb index dadbf6a481..813ab9da33 100644 --- a/lib/rubygems/package.rb +++ b/lib/rubygems/package.rb @@ -498,7 +498,7 @@ EOM real_destination.start_with? destination_dir + '/' end - destination.untaint + destination.tap(&Gem::UNTAINT) destination end diff --git a/lib/rubygems/path_support.rb b/lib/rubygems/path_support.rb index 2187766c41..6a5d180a02 100644 --- a/lib/rubygems/path_support.rb +++ b/lib/rubygems/path_support.rb @@ -36,7 +36,7 @@ class Gem::PathSupport @spec_cache_dir = env["GEM_SPEC_CACHE"] || Gem.default_spec_cache_dir - @spec_cache_dir = @spec_cache_dir.dup.untaint + @spec_cache_dir = @spec_cache_dir.dup.tap(&Gem::UNTAINT) end private diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 4ac6ce0293..d6fb41f514 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -334,7 +334,7 @@ class Gem::RequestSet @git_set.root_dir = @install_dir - lock_file = "#{File.expand_path(path)}.lock".dup.untaint + lock_file = "#{File.expand_path(path)}.lock".dup.tap(&Gem::UNTAINT) begin tokenizer = Gem::RequestSet::Lockfile::Tokenizer.from_file lock_file parser = tokenizer.make_parser self, [] diff --git a/lib/rubygems/request_set/gem_dependency_api.rb b/lib/rubygems/request_set/gem_dependency_api.rb index cb36a62e10..b7a8ee6f4f 100644 --- a/lib/rubygems/request_set/gem_dependency_api.rb +++ b/lib/rubygems/request_set/gem_dependency_api.rb @@ -280,7 +280,7 @@ class Gem::RequestSet::GemDependencyAPI # Loads the gem dependency file and returns self. def load - instance_eval File.read(@path).untaint, @path, 1 + instance_eval File.read(@path).tap(&Gem::UNTAINT), @path, 1 self end diff --git a/lib/rubygems/request_set/lockfile.rb b/lib/rubygems/request_set/lockfile.rb index 0776cf82e3..5423f2c14f 100644 --- a/lib/rubygems/request_set/lockfile.rb +++ b/lib/rubygems/request_set/lockfile.rb @@ -79,7 +79,9 @@ class Gem::RequestSet::Lockfile @gem_deps_file = File.expand_path(gem_deps_file) @gem_deps_dir = File.dirname(@gem_deps_file) - @gem_deps_file.untaint unless gem_deps_file.tainted? + if RUBY_VERSION < '2.7' + @gem_deps_file.untaint unless gem_deps_file.tainted? + end @platforms = [] end diff --git a/lib/rubygems/source.rb b/lib/rubygems/source.rb index faed7bd350..b0cce5bea5 100644 --- a/lib/rubygems/source.rb +++ b/lib/rubygems/source.rb @@ -106,7 +106,7 @@ class Gem::Source def cache_dir(uri) # Correct for windows paths escaped_path = uri.path.sub(/^\/([a-z]):\//i, '/\\1-/') - escaped_path.untaint + escaped_path.tap(&Gem::UNTAINT) File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) end diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 4fd556f193..5321edfcc3 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -763,7 +763,7 @@ class Gem::Specification < Gem::BasicSpecification def self.each_gemspec(dirs) # :nodoc: dirs.each do |dir| Gem::Util.glob_files_in_dir("*.gemspec", dir).each do |path| - yield path.untaint + yield path.tap(&Gem::UNTAINT) end end end @@ -930,7 +930,7 @@ class Gem::Specification < Gem::BasicSpecification def self.dirs @@dirs ||= Gem.path.collect do |dir| - File.join dir.dup.untaint, "specifications" + File.join dir.dup.tap(&Gem::UNTAINT), "specifications" end end @@ -1112,12 +1112,12 @@ class Gem::Specification < Gem::BasicSpecification _spec = LOAD_CACHE_MUTEX.synchronize { LOAD_CACHE[file] } return _spec if _spec - file = file.dup.untaint + file = file.dup.tap(&Gem::UNTAINT) return unless File.file?(file) code = File.read file, :mode => 'r:UTF-8:-' - code.untaint + code.tap(&Gem::UNTAINT) begin _spec = eval code, binding, file @@ -2642,9 +2642,9 @@ class Gem::Specification < Gem::BasicSpecification case ivar when "date" # Force Date to go through the extra coerce logic in date= - self.date = val.untaint + self.date = val.tap(&Gem::UNTAINT) else - instance_variable_set "@#{ivar}", val.untaint + instance_variable_set "@#{ivar}", val.tap(&Gem::UNTAINT) end end diff --git a/lib/rubygems/stub_specification.rb b/lib/rubygems/stub_specification.rb index 2f3245f5d0..959030fd54 100644 --- a/lib/rubygems/stub_specification.rb +++ b/lib/rubygems/stub_specification.rb @@ -71,7 +71,7 @@ class Gem::StubSpecification < Gem::BasicSpecification def initialize(filename, base_dir, gems_dir, default_gem) super() - filename.untaint + filename.tap(&Gem::UNTAINT) self.loaded_from = filename @data = nil diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 14212b9213..5ecf2ab1d8 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -259,10 +259,10 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni Gem::DefaultUserInteraction.ui = Gem::MockGemUi.new tmpdir = File.realpath Dir.tmpdir - tmpdir.untaint + tmpdir.tap(&Gem::UNTAINT) @tempdir = File.join(tmpdir, "test_rubygems_#{$$}") - @tempdir.untaint + @tempdir.tap(&Gem::UNTAINT) FileUtils.mkdir_p @tempdir @@ -274,7 +274,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni # Short and long path name is specific to Windows filesystem. if win_platform? @tempdir = Dir[@tempdir][0] - @tempdir.untaint + @tempdir.tap(&Gem::UNTAINT) end @gemhome = File.join @tempdir, 'gemhome' @@ -295,7 +295,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni $LOAD_PATH.map! do |s| expand_path = File.realpath(s) rescue File.expand_path(s) if expand_path != s - expand_path.untaint + expand_path.tap(&Gem::UNTAINT) if s.instance_variable_defined?(:@gem_prelude_index) expand_path.instance_variable_set(:@gem_prelude_index, expand_path) end @@ -527,7 +527,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni end end - gem = File.join(@tempdir, File.basename(spec.cache_file)).untaint + gem = File.join(@tempdir, File.basename(spec.cache_file)).tap(&Gem::UNTAINT) end Gem::Installer.at(gem, options.merge({:wrappers => true})).install @@ -566,7 +566,7 @@ class Gem::TestCase < (defined?(Minitest::Test) ? Minitest::Test : MiniTest::Uni # Reads a Marshal file at +path+ def read_cache(path) - File.open path.dup.untaint, 'rb' do |io| + File.open path.dup.tap(&Gem::UNTAINT), 'rb' do |io| Marshal.load io.read end end diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index 619f327968..6524faf5c8 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -197,6 +197,8 @@ class Gem::Version end @@all = {} + @@bump = {} + @@release = {} def self.new(version) # :nodoc: return super unless Gem::Version == self @@ -227,14 +229,14 @@ class Gem::Version # Pre-release (alpha) parts, e.g, 5.3.1.b.2 => 5.4, are ignored. def bump - @bump ||= begin - segments = self.segments - segments.pop while segments.any? { |s| String === s } - segments.pop if segments.size > 1 + @@bump[self] ||= begin + segments = self.segments + segments.pop while segments.any? { |s| String === s } + segments.pop if segments.size > 1 - segments[-1] = segments[-1].succ - self.class.new segments.join(".") - end + segments[-1] = segments[-1].succ + self.class.new segments.join(".") + end end ## @@ -306,13 +308,13 @@ class Gem::Version # Non-prerelease versions return themselves. def release - @release ||= if prerelease? - segments = self.segments - segments.pop while segments.any? { |s| String === s } - self.class.new segments.join('.') - else - self - end + @@release[self] ||= if prerelease? + segments = self.segments + segments.pop while segments.any? { |s| String === s } + self.class.new segments.join('.') + else + self + end end def segments # :nodoc: @@ -374,6 +376,12 @@ class Gem::Version end.reduce(&:concat) end + def freeze + prerelease? + canonical_segments + super + end + protected def _version diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 23f8249e34..859aba6588 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -14,14 +14,14 @@ end # TODO: push this up to test_case.rb once battle tested $LOAD_PATH.map! do |path| - path.dup.untaint + path.dup.tap(&Gem::UNTAINT) end class TestGem < Gem::TestCase PLUGINS_LOADED = [] # rubocop:disable Style/MutableConstant - PROJECT_DIR = File.expand_path('../../..', __FILE__).untaint + PROJECT_DIR = File.expand_path('../../..', __FILE__).tap(&Gem::UNTAINT) def setup super @@ -220,7 +220,7 @@ class TestGem < Gem::TestCase end assert_equal(expected, result) ensure - File.chmod(0755, *Dir.glob(@gemhome + '/gems/**/').map {|path| path.untaint}) + File.chmod(0755, *Dir.glob(@gemhome + '/gems/**/').map {|path| path.tap(&Gem::UNTAINT)}) end def test_require_missing @@ -1617,8 +1617,8 @@ class TestGem < Gem::TestCase assert_equal expected_specs, Gem.use_gemdeps.sort_by { |s| s.name } end - LIB_PATH = File.expand_path "../../../lib".dup.untaint, __FILE__.dup.untaint - BUNDLER_LIB_PATH = File.expand_path $LOAD_PATH.find {|lp| File.file?(File.join(lp, "bundler.rb")) }.dup.untaint + LIB_PATH = File.expand_path "../../../lib".dup.tap(&Gem::UNTAINT), __FILE__.dup.tap(&Gem::UNTAINT) + BUNDLER_LIB_PATH = File.expand_path $LOAD_PATH.find {|lp| File.file?(File.join(lp, "bundler.rb")) }.dup.tap(&Gem::UNTAINT) BUNDLER_FULL_NAME = "bundler-#{Bundler::VERSION}".freeze def add_bundler_full_name(names) @@ -1645,8 +1645,8 @@ class TestGem < Gem::TestCase ENV['RUBYGEMS_GEMDEPS'] = "-" path = File.join @tempdir, "gem.deps.rb" - cmd = [Gem.ruby.dup.untaint, "-I#{LIB_PATH.untaint}", - "-I#{BUNDLER_LIB_PATH.untaint}", "-rrubygems"] + cmd = [Gem.ruby.dup.tap(&Gem::UNTAINT), "-I#{LIB_PATH.tap(&Gem::UNTAINT)}", + "-I#{BUNDLER_LIB_PATH.tap(&Gem::UNTAINT)}", "-rrubygems"] cmd << "-eputs Gem.loaded_specs.values.map(&:full_name).sort" File.open path, "w" do |f| @@ -1683,8 +1683,8 @@ class TestGem < Gem::TestCase Dir.mkdir "sub1" path = File.join @tempdir, "gem.deps.rb" - cmd = [Gem.ruby.dup.untaint, "-Csub1", "-I#{LIB_PATH.untaint}", - "-I#{BUNDLER_LIB_PATH.untaint}", "-rrubygems"] + cmd = [Gem.ruby.dup.tap(&Gem::UNTAINT), "-Csub1", "-I#{LIB_PATH.tap(&Gem::UNTAINT)}", + "-I#{BUNDLER_LIB_PATH.tap(&Gem::UNTAINT)}", "-rrubygems"] cmd << "-eputs Gem.loaded_specs.values.map(&:full_name).sort" File.open path, "w" do |f| @@ -1732,7 +1732,7 @@ class TestGem < Gem::TestCase end def test_use_gemdeps - gem_deps_file = 'gem.deps.rb'.untaint + gem_deps_file = 'gem.deps.rb'.tap(&Gem::UNTAINT) spec = util_spec 'a', 1 install_specs spec diff --git a/test/rubygems/test_gem_command_manager.rb b/test/rubygems/test_gem_command_manager.rb index 6f00fe634c..45be9f01be 100644 --- a/test/rubygems/test_gem_command_manager.rb +++ b/test/rubygems/test_gem_command_manager.rb @@ -4,7 +4,7 @@ require 'rubygems/command_manager' class TestGemCommandManager < Gem::TestCase - PROJECT_DIR = File.expand_path('../../..', __FILE__).untaint + PROJECT_DIR = File.expand_path('../../..', __FILE__).tap(&Gem::UNTAINT) def setup super diff --git a/test/rubygems/test_gem_commands_pristine_command.rb b/test/rubygems/test_gem_commands_pristine_command.rb index 962ea96a2a..e872a80957 100644 --- a/test/rubygems/test_gem_commands_pristine_command.rb +++ b/test/rubygems/test_gem_commands_pristine_command.rb @@ -53,6 +53,55 @@ class TestGemCommandsPristineCommand < Gem::TestCase assert_empty out, out.inspect end + def test_execute_user_install + FileUtils.chmod 0555, @gemhome + + a = util_spec "a" do |s| + s.executables = %w[foo] + s.files = %w[bin/foo lib/a.rb] + end + + write_file File.join(@tempdir, "lib", "a.rb") do |fp| + fp.puts "puts __FILE__" + end + + write_file File.join(@tempdir, "bin", "foo") do |fp| + fp.puts "#!/usr/bin/ruby" + end + + install_gem_user(a) + + Gem::Specification.dirs = [Gem.dir, Gem.user_dir] + + foo_path = File.join(Gem.user_dir, "gems", a.full_name, "bin", "foo") + a_rb_path = File.join(Gem.user_dir, "gems", a.full_name, "lib", "a.rb") + + write_file foo_path do |io| + io.puts("I changed it!") + end + + write_file a_rb_path do |io| + io.puts("I changed it!") + end + + @cmd.options[:args] = %w[a] + + use_ui @ui do + @cmd.execute + end + + assert_equal "#!/usr/bin/ruby\n", File.read(foo_path), foo_path + assert_equal "puts __FILE__\n", File.read(a_rb_path), a_rb_path + + out = @ui.output.split("\n") + + assert_equal "Restoring gems to pristine condition...", out.shift + assert_equal "Restored #{a.full_name}", out.shift + assert_empty out, out.inspect + ensure + FileUtils.chmod(0755, @gemhome) + end + def test_execute_all a = util_spec 'a' do |s| s.executables = %w[foo] diff --git a/test/rubygems/test_gem_ext_ext_conf_builder.rb b/test/rubygems/test_gem_ext_ext_conf_builder.rb index d92da46f92..556761c979 100644 --- a/test/rubygems/test_gem_ext_ext_conf_builder.rb +++ b/test/rubygems/test_gem_ext_ext_conf_builder.rb @@ -17,7 +17,7 @@ class TestGemExtExtConfBuilder < Gem::TestCase end def test_class_build - if java_platform? && ENV["CI"] + if java_platform? skip("failing on jruby") end @@ -49,7 +49,7 @@ class TestGemExtExtConfBuilder < Gem::TestCase end def test_class_build_rbconfig_make_prog - if java_platform? && ENV["CI"] + if java_platform? skip("failing on jruby") end @@ -76,7 +76,7 @@ class TestGemExtExtConfBuilder < Gem::TestCase env_make = ENV.delete 'MAKE' ENV['MAKE'] = 'anothermake' - if java_platform? && ENV["CI"] + if java_platform? skip("failing on jruby") end diff --git a/test/rubygems/test_gem_installer.rb b/test/rubygems/test_gem_installer.rb index 52eea77b46..7a5fb972a4 100644 --- a/test/rubygems/test_gem_installer.rb +++ b/test/rubygems/test_gem_installer.rb @@ -5,6 +5,9 @@ class TestGemInstaller < Gem::InstallerTestCase @@symlink_supported = nil + # Our CI does not currently hit the "symlink not supported" case, but this is + # needed for Windows developers without symlink support enabled (the default + # for non admin) to be able to run the tests successfully def symlink_supported? if @@symlink_supported.nil? begin @@ -544,7 +547,7 @@ gem 'other', version end def test_generate_bin_symlink - return if win_platform? #Windows FS do not support symlinks + skip "Symlinks not supported or not enabled" unless symlink_supported? installer = setup_base_installer @@ -596,7 +599,7 @@ gem 'other', version end def test_generate_bin_symlink_update_newer - return if win_platform? #Windows FS do not support symlinks + skip "Symlinks not supported or not enabled" unless symlink_supported? installer = setup_base_installer @@ -628,7 +631,7 @@ gem 'other', version end def test_generate_bin_symlink_update_older - return if !symlink_supported? + skip "Symlinks not supported or not enabled" unless symlink_supported? installer = setup_base_installer @@ -666,7 +669,7 @@ gem 'other', version end def test_generate_bin_symlink_update_remove_wrapper - return if !symlink_supported? + skip "Symlinks not supported or not enabled" unless symlink_supported? installer = setup_base_installer @@ -739,7 +742,7 @@ gem 'other', version end def test_generate_bin_uses_default_shebang - return if !symlink_supported? + skip "Symlinks not supported or not enabled" unless symlink_supported? installer = setup_base_installer diff --git a/test/rubygems/test_gem_package.rb b/test/rubygems/test_gem_package.rb index 0604a2cfc7..5da247e141 100644 --- a/test/rubygems/test_gem_package.rb +++ b/test/rubygems/test_gem_package.rb @@ -703,12 +703,12 @@ class TestGemPackage < Gem::Package::TarTestCase package = Gem::Package.new @gem file = 'file.rb'.dup - file.taint + file.taint if RUBY_VERSION < '2.7' destination = package.install_location file, @destination assert_equal File.join(@destination, 'file.rb'), destination - refute destination.tainted? + refute destination.tainted? if RUBY_VERSION < '2.7' end def test_install_location_absolute @@ -742,14 +742,14 @@ class TestGemPackage < Gem::Package::TarTestCase package = Gem::Package.new @gem file = 'foo//file.rb'.dup - file.taint + file.taint if RUBY_VERSION < '2.7' destination = @destination.sub '/', '//' destination = package.install_location file, destination assert_equal File.join(@destination, 'foo', 'file.rb'), destination - refute destination.tainted? + refute destination.tainted? if RUBY_VERSION < '2.7' end def test_install_location_relative diff --git a/test/rubygems/test_gem_specification.rb b/test/rubygems/test_gem_specification.rb index 3d166910c0..8f345f87a2 100644 --- a/test/rubygems/test_gem_specification.rb +++ b/test/rubygems/test_gem_specification.rb @@ -939,22 +939,24 @@ dependencies: [] assert_equal File.join(@tempdir, 'a-2.gemspec'), spec.loaded_from end - def test_self_load_tainted - full_path = @a2.spec_file - write_file full_path do |io| - io.write @a2.to_ruby_for_cache + if RUBY_VERSION < '2.7' + def test_self_load_tainted + full_path = @a2.spec_file + write_file full_path do |io| + io.write @a2.to_ruby_for_cache + end + + full_path.taint + loader = Thread.new { $SAFE = 1; Gem::Specification.load full_path } + spec = loader.value + + @a2.files.clear + + assert_equal @a2, spec + + ensure + $SAFE = 0 end - - full_path.taint - loader = Thread.new { $SAFE = 1; Gem::Specification.load full_path } - spec = loader.value - - @a2.files.clear - - assert_equal @a2, spec - - ensure - $SAFE = 0 end def test_self_load_escape_curly @@ -1160,12 +1162,11 @@ dependencies: [] # Create gemspecs in three locations used in stubs loaded_spec = Gem::Specification.new 'a', '3' Gem.loaded_specs['a'] = loaded_spec - save_gemspec 'a', '2', dir_default_specs - save_gemspec 'a', '1', dir_standard_specs + save_gemspec('a-2', '2', dir_default_specs) { |s| s.name = 'a' } + save_gemspec('a-1', '1', dir_standard_specs) { |s| s.name = 'a' } full_names = ['a-3', 'a-2', 'a-1'] - full_names = Gem::Specification.stubs_for('a').map { |s| s.full_name } assert_equal full_names, Gem::Specification.stubs_for('a').map { |s| s.full_name } assert_equal 1, Gem::Specification.class_variable_get(:@@stubs_by_name).length @@ -2472,7 +2473,7 @@ Gem::Specification.new do |s| s.email = "example@example.com".freeze s.files = ["lib/code.rb".freeze] s.homepage = "http://example.com".freeze - s.rubygems_version = "3.1.0.pre2".freeze + s.rubygems_version = "#{Gem::VERSION}".freeze s.summary = "this is a summary".freeze end SPEC diff --git a/test/rubygems/test_gem_version.rb b/test/rubygems/test_gem_version.rb index c90648f562..1deecc0eed 100644 --- a/test/rubygems/test_gem_version.rb +++ b/test/rubygems/test_gem_version.rb @@ -217,6 +217,13 @@ class TestGemVersion < Gem::TestCase assert_equal [1, 2, 3, "pre", 1], v("1.2.3-1").canonical_segments end + def test_frozen_version + v = v('1.freeze.test').freeze + assert_less_than v, v('1') + assert_version_equal v('1'), v.release + assert_version_equal v('2'), v.bump + end + # Asserts that +version+ is a prerelease. def assert_prerelease(version) diff --git a/test/rubygems/test_project_sanity.rb b/test/rubygems/test_project_sanity.rb new file mode 100644 index 0000000000..72f5e3b36e --- /dev/null +++ b/test/rubygems/test_project_sanity.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require "rubygems/test_case" +require "open3" + +class TestProjectSanity < Minitest::Test + + def test_rake_package_builds_ok + skip unless File.exist?(File.expand_path("../../../Rakefile", __FILE__)) + + with_empty_pkg_folder do + output, status = Open3.capture2e("rake package") + + assert_equal true, status.success?, <<~MSG.chomp + Expected `rake package` to work, but got errors: + + ``` + #{output} + ``` + + If you have added or removed files, make sure you run `rake update_manifest` to update the `Manifest.txt` accordingly + MSG + end + end + + def test_manifest_is_up_to_date + skip unless File.exist?(File.expand_path("../../../Rakefile", __FILE__)) + + _, status = Open3.capture2e("rake check_manifest") + + assert status.success?, "Expected Manifest.txt to be up to date, but it's not. Run `rake update_manifest` to sync it." + end + + private + + def with_empty_pkg_folder + if File.exist?("pkg") + FileUtils.cp_r("pkg", "tmp") + + begin + FileUtils.rm_rf("pkg") + yield + ensure + FileUtils.rm_rf("pkg") + FileUtils.cp_r("tmp/pkg", ".") + end + else + Dir.mkdir("pkg") + + begin + yield + ensure + FileUtils.rm_rf("pkg") + end + end + end + +end diff --git a/test/rubygems/test_rake_package.rb b/test/rubygems/test_rake_package.rb deleted file mode 100644 index 165da798f5..0000000000 --- a/test/rubygems/test_rake_package.rb +++ /dev/null @@ -1,26 +0,0 @@ -# frozen_string_literal: true - -require "rubygems/test_case" -require "open3" - -class TestRakePackage < Minitest::Test - - def test_builds_ok - skip unless File.exist?(File.expand_path("../../../Rakefile", __FILE__)) - - output, status = Open3.capture2e("rake package") - - assert_equal true, status.success?, <<~MSG.chomp - Expected `rake package` to work, but got errors: - - ``` - #{output} - ``` - - If you have added or removed files, make sure you run `rake update_manifest` to update the `Manifest.txt` accordingly - MSG - - FileUtils.rm_f "pkg" - end - -end