From 3e047420d69240af98add002e7a3025004094379 Mon Sep 17 00:00:00 2001 From: hsbt Date: Wed, 31 Oct 2018 03:23:30 +0000 Subject: [PATCH] Merge upstream from rubygems/rubygems master branch. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@65470 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- lib/rubygems/core_ext/kernel_warn.rb | 47 ++++++++++++++------- lib/rubygems/ext/builder.rb | 8 ++-- lib/rubygems/ext/ext_conf_builder.rb | 5 ++- lib/rubygems/ext/rake_builder.rb | 21 ++++----- lib/rubygems/installer.rb | 21 +++++---- lib/rubygems/test_case.rb | 21 ++++++++- test/rubygems/test_config.rb | 9 +++- test/rubygems/test_gem_ext_cmake_builder.rb | 2 +- 8 files changed, 92 insertions(+), 42 deletions(-) diff --git a/lib/rubygems/core_ext/kernel_warn.rb b/lib/rubygems/core_ext/kernel_warn.rb index 319fdfe606..3e531441ed 100755 --- a/lib/rubygems/core_ext/kernel_warn.rb +++ b/lib/rubygems/core_ext/kernel_warn.rb @@ -1,28 +1,45 @@ # frozen_string_literal: true +# `uplevel` keyword argument of Kernel#warn is available since ruby 2.5. if RUBY_VERSION >= "2.5" + module Kernel - path = "#{__dir__}/" + path = "#{__dir__}/" # Frames to be skipped start with this path. + + # Suppress "method redefined" warning original_warn = instance_method(:warn) Module.new {define_method(:warn, original_warn)} + original_warn = method(:warn) module_function define_method(:warn) {|*messages, uplevel: nil| - if uplevel - uplevel, = [uplevel].pack("l!").unpack("l!") - if uplevel >= 0 - start = 0 - begin - loc, = caller_locations(start, 1) - break start += uplevel unless loc - start += 1 - end while (loc.path.start_with?(path) or (uplevel -= 1) >= 0) - uplevel = start - end - original_warn.call(*messages, uplevel: uplevel) - else - original_warn.call(*messages) + unless uplevel + return original_warn.call(*messages) end + + # Ensure `uplevel` fits a `long` + uplevel, = [uplevel].pack("l!").unpack("l!") + + if uplevel >= 0 + start = 0 + while uplevel >= 0 + loc, = caller_locations(start, 1) + unless loc + # No more backtrace + start += uplevel + break + end + + start += 1 + + unless loc.path.start_with?(path) + # Non-rubygems frames + uplevel -= 1 + end + end + uplevel = start + end + original_warn.call(*messages, uplevel: uplevel) } end end diff --git a/lib/rubygems/ext/builder.rb b/lib/rubygems/ext/builder.rb index b3b9033962..93be458cd8 100644 --- a/lib/rubygems/ext/builder.rb +++ b/lib/rubygems/ext/builder.rb @@ -56,6 +56,7 @@ class Gem::Ext::Builder end def self.redirector + warn "#{caller[0]}: Use IO.popen(..., err: [:child, :out])" '2>&1' end @@ -63,7 +64,6 @@ class Gem::Ext::Builder verbose = Gem.configuration.really_verbose begin - # TODO use Process.spawn when ruby 1.8 support is dropped. rubygems_gemdeps, ENV['RUBYGEMS_GEMDEPS'] = ENV['RUBYGEMS_GEMDEPS'], nil if verbose puts("current directory: #{Dir.pwd}") @@ -71,9 +71,11 @@ class Gem::Ext::Builder system(command) else results << "current directory: #{Dir.pwd}" - results << command - results << `#{command} #{redirector}` + results << (command.respond_to?(:shelljoin) ? command.shelljoin : command) + results << IO.popen(command, "r", err: [:child, :out], &:read) end + rescue => error + raise Gem::InstallError, "#{command_name || class_name} failed#{error.message}" ensure ENV['RUBYGEMS_GEMDEPS'] = rubygems_gemdeps end diff --git a/lib/rubygems/ext/ext_conf_builder.rb b/lib/rubygems/ext/ext_conf_builder.rb index 18e300d8c2..97bb789fb8 100644 --- a/lib/rubygems/ext/ext_conf_builder.rb +++ b/lib/rubygems/ext/ext_conf_builder.rb @@ -7,6 +7,7 @@ require 'fileutils' require 'tempfile' +require 'shellwords' class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder FileEntry = FileUtils::Entry_ # :nodoc: @@ -38,7 +39,9 @@ class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder destdir = ENV["DESTDIR"] begin - cmd = [Gem.ruby, "-I", File.expand_path("../../..", __FILE__), "-r", get_relative_path(siteconf.path), File.basename(extension), *args].join ' ' + cmd = Gem.ruby.shellsplit << "-I" << File.expand_path("../../..", __FILE__) << + "-r" << get_relative_path(siteconf.path) << File.basename(extension) + cmd.push(*args) begin run cmd, results diff --git a/lib/rubygems/ext/rake_builder.rb b/lib/rubygems/ext/rake_builder.rb index 890803aaef..f41e5618dc 100644 --- a/lib/rubygems/ext/rake_builder.rb +++ b/lib/rubygems/ext/rake_builder.rb @@ -11,22 +11,23 @@ class Gem::Ext::RakeBuilder < Gem::Ext::Builder def self.build(extension, dest_path, results, args=[], lib_dir=nil) if File.basename(extension) =~ /mkrf_conf/i then - cmd = "#{Gem.ruby} #{File.basename extension}".dup - cmd << " #{args.join " "}" unless args.empty? - run cmd, results + run([Gem.ruby, File.basename(extension), *args], results) end rake = ENV['rake'] - rake ||= begin - "#{Gem.ruby} -rrubygems #{Gem.bin_path('rake', 'rake')}" - rescue Gem::Exception - end - - rake ||= Gem.default_exec_format % 'rake' + if rake + rake = rake.shellsplit + else + begin + rake = [Gem.ruby, "-rrubygems", Gem.bin_path('rake', 'rake')] + rescue Gem::Exception + rake = [Gem.default_exec_format % 'rake'] + end + end rake_args = ["RUBYARCHDIR=#{dest_path}", "RUBYLIBDIR=#{dest_path}", *args] - run "#{rake} #{rake_args.shelljoin}", results + run(rake + rake_args, results) results end diff --git a/lib/rubygems/installer.rb b/lib/rubygems/installer.rb index 298a7053c7..7587c259dc 100644 --- a/lib/rubygems/installer.rb +++ b/lib/rubygems/installer.rb @@ -771,33 +771,38 @@ TEXT # return the stub script text used to launch the true Ruby script def windows_stub_script(bindir, bin_file_name) - rb_bindir = RbConfig::CONFIG["bindir"] - # All comparisons should be case insensitive - if bindir.downcase == rb_bindir.downcase + rb_config = RbConfig::CONFIG + rb_topdir = RbConfig::TOPDIR || File.dirname(rb_config["bindir"]) + + # get ruby executable file name from RbConfig + ruby_exe = "#{rb_config['RUBY_INSTALL_NAME']}#{rb_config['EXEEXT']}" + ruby_exe = "ruby.exe" if ruby_exe.empty? + + if File.exist?(File.join bindir, ruby_exe) # stub & ruby.exe withing same folder. Portable <<-TEXT @ECHO OFF @"%~dp0ruby.exe" "%~dpn0" %* TEXT - elsif bindir.downcase.start_with?((RbConfig::TOPDIR || File.dirname(rb_bindir)).downcase) - # stub within ruby folder, but not standard bin. Not portable + elsif bindir.downcase.start_with? rb_topdir.downcase + # stub within ruby folder, but not standard bin. Portable require 'pathname' from = Pathname.new bindir - to = Pathname.new rb_bindir + to = Pathname.new "#{rb_topdir}/bin" rel = to.relative_path_from from <<-TEXT @ECHO OFF @"%~dp0#{rel}/ruby.exe" "%~dpn0" %* TEXT else - # outside ruby folder, maybe -user-install or bundler. Portable + # outside ruby folder, maybe -user-install or bundler. Portable, but ruby + # is dependent on PATH <<-TEXT @ECHO OFF @ruby.exe "%~dpn0" %* TEXT end end - ## # Builds extensions. Valid types of extensions are extconf.rb files, # configure scripts and rakefiles or mkrf_conf files. diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 718571ea57..fc9456709f 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -1319,9 +1319,26 @@ Also, a list: end end + class << self + # :nodoc: + ## + # Return the join path, with escaping backticks, dollars, and + # double-quotes. Unlike `shellescape`, equal-sign is not escaped. + private + def escape_path(*path) + path = File.join(*path) + if %r'\A[-+:/=@,.\w]+\z' =~ path + path + else + "\"#{path.gsub(/[`$"]/, '\\&')}\"" + end + end + end + @@ruby = rubybin - @@good_rake = "#{rubybin} \"#{File.expand_path('../../../test/rubygems/good_rake.rb', __FILE__)}\"" - @@bad_rake = "#{rubybin} \"#{File.expand_path('../../../test/rubygems/bad_rake.rb', __FILE__)}\"" + gempath = File.expand_path('../../../test/rubygems', __FILE__) + @@good_rake = "#{rubybin} #{escape_path(gempath, 'good_rake.rb')}" + @@bad_rake = "#{rubybin} #{escape_path(gempath, 'bad_rake.rb')}" ## # Construct a new Gem::Dependency. diff --git a/test/rubygems/test_config.rb b/test/rubygems/test_config.rb index f8aadb4a23..70fc4e23f0 100644 --- a/test/rubygems/test_config.rb +++ b/test/rubygems/test_config.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require 'rubygems/test_case' require 'rubygems' +require 'shellwords' class TestConfig < Gem::TestCase @@ -13,12 +14,16 @@ class TestConfig < Gem::TestCase def test_good_rake_path_is_escaped path = Gem::TestCase.class_eval('@@good_rake') - assert_match(/#{Gem.ruby} "[^"]*good_rake.rb"/, path) + ruby, rake = path.shellsplit + assert_equal(Gem.ruby, ruby) + assert_match(/\/good_rake.rb\z/, rake) end def test_bad_rake_path_is_escaped path = Gem::TestCase.class_eval('@@bad_rake') - assert_match(/#{Gem.ruby} "[^"]*bad_rake.rb"/, path) + ruby, rake = path.shellsplit + assert_equal(Gem.ruby, ruby) + assert_match(/\/bad_rake.rb\z/, rake) end end diff --git a/test/rubygems/test_gem_ext_cmake_builder.rb b/test/rubygems/test_gem_ext_cmake_builder.rb index 2d449fc2fd..6e62908090 100644 --- a/test/rubygems/test_gem_ext_cmake_builder.rb +++ b/test/rubygems/test_gem_ext_cmake_builder.rb @@ -10,7 +10,7 @@ class TestGemExtCmakeBuilder < Gem::TestCase # Details: https://github.com/rubygems/rubygems/issues/1270#issuecomment-177368340 skip "CmakeBuilder doesn't work on Windows." if Gem.win_platform? - `cmake #{Gem::Ext::Builder.redirector}` + system('cmake', out: IO::NULL, err: [:child, :out]) skip 'cmake not present' unless $?.success?