# frozen_string_literal: true require 'rubygems/installer_test_case' class TestGemInstaller < Gem::InstallerTestCase @@symlink_supported = nil def symlink_supported? if @@symlink_supported.nil? begin File.symlink("", "") rescue Errno::ENOENT, Errno::EEXIST @@symlink_supported = true rescue NotImplementedError, SystemCallError @@symlink_supported = false end end @@symlink_supported end def setup super common_installer_setup if (self.class.method_defined?(:__name__) ? __name__ : name) =~ /\Atest_install(_|\Z)/ FileUtils.rm_r @spec.gem_dir FileUtils.rm_r @user_spec.gem_dir end @config = Gem.configuration end def teardown common_installer_teardown super Gem.configuration = instance_variable_defined?(:@config) ? @config : nil end def test_app_script_text util_make_exec @spec, '' expected = <<-EOF #!#{Gem.ruby} # # This file was generated by RubyGems. # # The application 'a' is installed as part of a gem, and # this file is here to facilitate running it. # require 'rubygems' version = \">= 0.a\" str = ARGV.first if str str = str.b[/\\A_(.*)_\\z/, 1] if str and Gem::Version.correct?(str) version = str ARGV.shift end end if Gem.respond_to?(:activate_bin_path) load Gem.activate_bin_path('a', 'executable', version) else gem "a", version load Gem.bin_path("a", "executable", version) end EOF wrapper = @installer.app_script_text 'executable' assert_equal expected, wrapper end def test_check_executable_overwrite @installer.generate_bin @spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] s.name = "a" s.version = "3" s.summary = "summary" s.description = "desc" s.require_path = 'lib' end util_make_exec @installer.gem_dir = @spec.gem_dir @installer.wrappers = true @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end def test_check_executable_overwrite_default_bin_dir if defined?(RUBY_FRAMEWORK_VERSION) orig_RUBY_FRAMEWORK_VERSION = RUBY_FRAMEWORK_VERSION Object.send :remove_const, :RUBY_FRAMEWORK_VERSION end orig_bindir = RbConfig::CONFIG['bindir'] RbConfig::CONFIG['bindir'] = Gem.bindir util_conflict_executable false ui = Gem::MockGemUi.new "n\n" use_ui ui do e = assert_raises Gem::InstallError do @installer.generate_bin end conflicted = File.join @gemhome, 'bin', 'executable' assert_match %r%\A"executable" from a conflicts with (?:#{Regexp.quote(conflicted)}|installed executable from conflict)\z%, e.message end ensure Object.const_set :RUBY_FRAMEWORK_VERSION, orig_RUBY_FRAMEWORK_VERSION if orig_RUBY_FRAMEWORK_VERSION if orig_bindir RbConfig::CONFIG['bindir'] = orig_bindir else RbConfig::CONFIG.delete 'bindir' end end def test_check_executable_overwrite_format_executable @installer.generate_bin @spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] s.name = "a" s.version = "3" s.summary = "summary" s.description = "desc" s.require_path = 'lib' end File.open File.join(util_inst_bindir, 'executable'), 'w' do |io| io.write <<-EXEC #!/usr/local/bin/ruby # # This file was generated by RubyGems gem 'other', version EXEC end util_make_exec Gem::Installer.exec_format = 'foo-%s-bar' @installer.gem_dir = @spec.gem_dir @installer.wrappers = true @installer.format_executable = true @installer.generate_bin # should not raise installed_exec = File.join util_inst_bindir, 'foo-executable-bar' assert_path_exists installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper ensure Gem::Installer.exec_format = nil end def test_check_executable_overwrite_other_gem util_conflict_executable true ui = Gem::MockGemUi.new "n\n" use_ui ui do e = assert_raises Gem::InstallError do @installer.generate_bin end assert_equal '"executable" from a conflicts with installed executable from conflict', e.message end end def test_check_executable_overwrite_other_gem_force util_conflict_executable true @installer.wrappers = true @installer.force = true @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end def test_check_executable_overwrite_other_non_gem util_conflict_executable false @installer.wrappers = true @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end unless Gem.win_platform? def test_check_that_user_bin_dir_is_in_path bin_dir = @installer.bin_dir if Gem.win_platform? bin_dir = bin_dir.downcase.gsub(File::SEPARATOR, File::ALT_SEPARATOR) end orig_PATH, ENV['PATH'] = ENV['PATH'], [ENV['PATH'], bin_dir].join(File::PATH_SEPARATOR) use_ui @ui do @installer.check_that_user_bin_dir_is_in_path end assert_empty @ui.error ensure ENV['PATH'] = orig_PATH end def test_check_that_user_bin_dir_is_in_path_tilde skip "Tilde is PATH is not supported under MS Windows" if win_platform? orig_PATH, ENV['PATH'] = ENV['PATH'], [ENV['PATH'], '~/bin'].join(File::PATH_SEPARATOR) @installer.bin_dir.replace File.join @userhome, 'bin' use_ui @ui do @installer.check_that_user_bin_dir_is_in_path end assert_empty @ui.error ensure ENV['PATH'] = orig_PATH unless win_platform? end def test_check_that_user_bin_dir_is_in_path_not_in_path use_ui @ui do @installer.check_that_user_bin_dir_is_in_path end expected = @installer.bin_dir if Gem.win_platform? expected = expected.downcase.gsub(File::SEPARATOR, File::ALT_SEPARATOR) end assert_match expected, @ui.error end def test_ensure_dependency util_spec 'a' dep = Gem::Dependency.new 'a', '>= 2' assert @installer.ensure_dependency(@spec, dep) dep = Gem::Dependency.new 'b', '> 2' e = assert_raises Gem::InstallError do @installer.ensure_dependency @spec, dep end assert_equal 'a requires b (> 2)', e.message end def test_ensure_loadable_spec a, a_gem = util_gem 'a', 2 do |s| s.add_dependency 'garbage ~> 5' end installer = Gem::Installer.at a_gem e = assert_raises Gem::InstallError do installer.ensure_loadable_spec end assert_equal "The specification for #{a.full_name} is corrupt " + "(SyntaxError)", e.message end def test_ensure_loadable_spec_security_policy skip 'openssl is missing' unless defined?(OpenSSL::SSL) _, a_gem = util_gem 'a', 2 do |s| s.add_dependency 'garbage ~> 5' end policy = Gem::Security::HighSecurity installer = Gem::Installer.at a_gem, :security_policy => policy assert_raises Gem::Security::Exception do installer.ensure_loadable_spec end end def test_extract_files @installer.extract_files assert_path_exists File.join @spec.gem_dir, 'bin/executable' end def test_generate_bin_bindir @installer.wrappers = true @spec.executables = %w[executable] @spec.bindir = 'bin' exec_file = @installer.formatted_program_filename 'executable' exec_path = File.join @spec.gem_dir, exec_file File.open exec_path, 'w' do |f| f.puts '#!/usr/bin/ruby' end @installer.gem_dir = @spec.gem_dir @installer.generate_bin assert_directory_exists (util_inst_bindir) installed_exec = File.join(util_inst_bindir, 'executable') assert_path_exists installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end def test_generate_bin_bindir_with_user_install_warning bin_dir = Gem.win_platform? ? File.expand_path(ENV["WINDIR"]).upcase : "/usr/bin" old_path = ENV["PATH"] ENV["PATH"] = [ENV["PATH"], bin_dir].compact.join(File::PATH_SEPARATOR) options = { :bin_dir => bin_dir, :install_dir => "/non/existent" } inst = Gem::Installer.at '', options Gem::Installer.path_warning = false use_ui @ui do inst.check_that_user_bin_dir_is_in_path end assert_equal "", @ui.error ensure ENV["PATH"] = old_path end def test_generate_bin_script @installer.wrappers = true util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin assert_directory_exists util_inst_bindir installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end def test_generate_bin_script_format @installer.format_executable = true @installer.wrappers = true util_make_exec @installer.gem_dir = @spec.gem_dir Gem::Installer.exec_format = 'foo-%s-bar' @installer.generate_bin assert_directory_exists util_inst_bindir installed_exec = File.join util_inst_bindir, 'foo-executable-bar' assert_path_exists installed_exec ensure Gem::Installer.exec_format = nil end def test_generate_bin_script_format_disabled @installer.wrappers = true util_make_exec @installer.gem_dir = @spec.gem_dir Gem::Installer.exec_format = 'foo-%s-bar' @installer.generate_bin assert_directory_exists util_inst_bindir installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec ensure Gem::Installer.exec_format = nil end def test_generate_bin_script_install_dir @installer.wrappers = true gem_dir = File.join("#{@gemhome}2", "gems", @spec.full_name) gem_bindir = File.join gem_dir, 'bin' FileUtils.mkdir_p gem_bindir File.open File.join(gem_bindir, 'executable'), 'w' do |f| f.puts "#!/bin/ruby" end @installer.gem_home = "#{@gemhome}2" @installer.gem_dir = gem_dir @installer.bin_dir = File.join "#{@gemhome}2", 'bin' @installer.generate_bin installed_exec = File.join("#{@gemhome}2", "bin", 'executable') assert_path_exists installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper end def test_generate_bin_script_no_execs util_execless @installer.wrappers = true @installer.generate_bin refute_path_exists util_inst_bindir, 'bin dir was created when not needed' end def test_generate_bin_script_no_perms @installer.wrappers = true util_make_exec Dir.mkdir util_inst_bindir if win_platform? skip('test_generate_bin_script_no_perms skipped on MS Windows') elsif Process.uid.zero? skip('test_generate_bin_script_no_perms skipped in root privilege') else FileUtils.chmod 0000, util_inst_bindir assert_raises Gem::FilePermissionError do @installer.generate_bin end end ensure FileUtils.chmod 0755, util_inst_bindir unless ($DEBUG or win_platform?) end def test_generate_bin_script_no_shebang @installer.wrappers = true @spec.executables = %w[executable] gem_dir = File.join @gemhome, 'gems', @spec.full_name gem_bindir = File.join gem_dir, 'bin' FileUtils.mkdir_p gem_bindir File.open File.join(gem_bindir, 'executable'), 'w' do |f| f.puts "blah blah blah" end @installer.generate_bin installed_exec = File.join @gemhome, 'bin', 'executable' assert_path_exists installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? wrapper = File.read installed_exec assert_match %r|generated by RubyGems|, wrapper # HACK some gems don't have #! in their executables, restore 2008/06 #assert_no_match %r|generated by RubyGems|, wrapper end def test_generate_bin_script_wrappers @installer.wrappers = true util_make_exec @installer.gem_dir = @spec.gem_dir installed_exec = File.join(util_inst_bindir, 'executable') real_exec = File.join @spec.gem_dir, 'bin', 'executable' # fake --no-wrappers for previous install unless Gem.win_platform? FileUtils.mkdir_p File.dirname(installed_exec) FileUtils.ln_s real_exec, installed_exec end @installer.generate_bin assert_directory_exists util_inst_bindir assert_path_exists installed_exec assert_equal mask, File.stat(installed_exec).mode unless win_platform? assert_match %r|generated by RubyGems|, File.read(installed_exec) refute_match %r|generated by RubyGems|, File.read(real_exec), 'real executable overwritten' end def test_generate_bin_symlink return if win_platform? #Windows FS do not support symlinks @installer.wrappers = false util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin assert_directory_exists util_inst_bindir installed_exec = File.join util_inst_bindir, 'executable' assert_equal true, File.symlink?(installed_exec) assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'), File.readlink(installed_exec)) end def test_generate_bin_symlink_no_execs util_execless @installer.wrappers = false @installer.generate_bin refute_path_exists util_inst_bindir end def test_generate_bin_symlink_no_perms @installer.wrappers = false util_make_exec @installer.gem_dir = @spec.gem_dir Dir.mkdir util_inst_bindir if win_platform? skip('test_generate_bin_symlink_no_perms skipped on MS Windows') elsif Process.uid.zero? skip('test_user_install_disabled_read_only test skipped in root privilege') else FileUtils.chmod 0000, util_inst_bindir assert_raises Gem::FilePermissionError do @installer.generate_bin end end ensure FileUtils.chmod 0755, util_inst_bindir unless ($DEBUG or win_platform?) end def test_generate_bin_symlink_update_newer return if win_platform? #Windows FS do not support symlinks @installer.wrappers = false util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin installed_exec = File.join(util_inst_bindir, 'executable') assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'), File.readlink(installed_exec)) @spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] s.name = "a" s.version = "3" s.summary = "summary" s.description = "desc" s.require_path = 'lib' end util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin installed_exec = File.join(util_inst_bindir, 'executable') assert_equal(@spec.bin_file('executable'), File.readlink(installed_exec), "Ensure symlink moved to latest version") end def test_generate_bin_symlink_update_older return if !symlink_supported? @installer.wrappers = false util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin installed_exec = File.join(util_inst_bindir, 'executable') assert_equal(File.join(@spec.gem_dir, 'bin', 'executable'), File.readlink(installed_exec)) spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] s.name = "a" s.version = "1" s.summary = "summary" s.description = "desc" s.require_path = 'lib' end util_make_exec one = @spec.dup one.version = 1 @installer = Gem::Installer.for_spec spec @installer.gem_dir = one.gem_dir @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' expected = File.join @spec.gem_dir, 'bin', 'executable' assert_equal(expected, File.readlink(installed_exec), "Ensure symlink not moved") end def test_generate_bin_symlink_update_remove_wrapper return if !symlink_supported? @installer.wrappers = true util_make_exec @installer.gem_dir = @spec.gem_dir @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' assert_path_exists installed_exec @spec = Gem::Specification.new do |s| s.files = ['lib/code.rb'] s.name = "a" s.version = "3" s.summary = "summary" s.description = "desc" s.require_path = 'lib' end util_make_exec util_installer @spec, @gemhome @installer.wrappers = false @installer.gem_dir = @spec.gem_dir @installer.generate_bin installed_exec = File.join util_inst_bindir, 'executable' assert_equal(@spec.bin_file('executable'), File.readlink(installed_exec), "Ensure symlink moved to latest version") end def test_generate_bin_symlink_win32 old_win_platform = Gem.win_platform? Gem.win_platform = true old_alt_separator = File::ALT_SEPARATOR File.__send__(:remove_const, :ALT_SEPARATOR) File.const_set(:ALT_SEPARATOR, '\\') @installer.wrappers = false util_make_exec @installer.gem_dir = @spec.gem_dir use_ui @ui do @installer.generate_bin end assert_directory_exists util_inst_bindir installed_exec = File.join(util_inst_bindir, 'executable') assert_path_exists installed_exec if symlink_supported? assert File.symlink?(installed_exec) return end assert_match(/Unable to use symlinks, installing wrapper/i, @ui.error) wrapper = File.read installed_exec assert_match(/generated by RubyGems/, wrapper) ensure File.__send__(:remove_const, :ALT_SEPARATOR) File.const_set(:ALT_SEPARATOR, old_alt_separator) Gem.win_platform = old_win_platform end def test_generate_bin_uses_default_shebang return if !symlink_supported? @installer.wrappers = true util_make_exec @installer.generate_bin default_shebang = Gem.ruby shebang_line = open("#{@gemhome}/bin/executable") { |f| f.readlines.first } assert_match(/\A#!/, shebang_line) assert_match(/#{default_shebang}/, shebang_line) end def test_initialize spec = util_spec 'a' do |s| s.platform = Gem::Platform.new 'mswin32' end gem = File.join @tempdir, spec.file_name Dir.mkdir util_inst_bindir util_build_gem spec FileUtils.mv spec.cache_file, @tempdir installer = Gem::Installer.at gem assert_equal File.join(@gemhome, 'gems', spec.full_name), installer.gem_dir assert_equal File.join(@gemhome, 'bin'), installer.bin_dir end def test_initialize_user_install installer = Gem::Installer.at @gem, :user_install => true assert_equal File.join(Gem.user_dir, 'gems', @spec.full_name), installer.gem_dir assert_equal Gem.bindir(Gem.user_dir), installer.bin_dir end def test_initialize_user_install_bin_dir installer = Gem::Installer.at @gem, :user_install => true, :bin_dir => @tempdir assert_equal File.join(Gem.user_dir, 'gems', @spec.full_name), installer.gem_dir assert_equal @tempdir, installer.bin_dir end def test_install Dir.mkdir util_inst_bindir util_setup_gem util_clear_gems gemdir = File.join @gemhome, 'gems', @spec.full_name cache_file = File.join @gemhome, 'cache', @spec.file_name stub_exe = File.join @gemhome, 'bin', 'executable' rakefile = File.join gemdir, 'ext', 'a', 'Rakefile' spec_file = File.join @gemhome, 'specifications', @spec.spec_name Gem.pre_install do refute_path_exists cache_file, 'cache file must not exist yet' refute_path_exists spec_file, 'spec file must not exist yet' true end Gem.post_build do assert_path_exists gemdir, 'gem install dir must exist' assert_path_exists rakefile, 'gem executable must exist' refute_path_exists stub_exe, 'gem executable must not exist' refute_path_exists spec_file, 'spec file must not exist yet' true end Gem.post_install do assert_path_exists cache_file, 'cache file must exist' assert_path_exists spec_file, 'spec file must exist' end @newspec = nil build_rake_in do use_ui @ui do @newspec = @installer.install end end assert_equal @spec, @newspec assert_path_exists gemdir assert_path_exists stub_exe, 'gem executable must exist' exe = File.join gemdir, 'bin', 'executable' assert_path_exists exe exe_mode = File.stat(exe).mode & 0111 assert_equal 0111, exe_mode, "0%o" % exe_mode unless win_platform? assert_path_exists File.join gemdir, 'lib', 'code.rb' assert_path_exists rakefile spec_file = File.join(@gemhome, 'specifications', @spec.spec_name) assert_equal spec_file, @newspec.loaded_from assert_path_exists spec_file assert_same @installer, @post_build_hook_arg assert_same @installer, @post_install_hook_arg assert_same @installer, @pre_install_hook_arg end def test_install_creates_working_binstub Dir.mkdir util_inst_bindir util_setup_gem util_clear_gems @installer.wrappers = true gemdir = File.join @gemhome, 'gems', @spec.full_name @newspec = nil build_rake_in do use_ui @ui do @newspec = @installer.install end end exe = File.join gemdir, 'bin', 'executable' e = assert_raises RuntimeError do instance_eval File.read(exe) end assert_match(/ran executable/, e.message) end def test_conflicting_binstubs Dir.mkdir util_inst_bindir util_clear_gems # build old version that has a bin file util_setup_gem do |spec| File.open File.join('bin', 'executable'), 'w' do |f| f.puts "require 'code'" end File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts 'raise "I have an executable"' end end @installer.wrappers = true build_rake_in do use_ui @ui do @newspec = @installer.install end end old_bin_file = File.join @installer.bin_dir, 'executable' # build new version that doesn't have a bin file util_setup_gem do |spec| FileUtils.rm File.join('bin', 'executable') spec.files.delete File.join('bin', 'executable') spec.executables.delete 'executable' spec.version = @spec.version.bump File.open File.join('lib', 'code.rb'), 'w' do |f| f.puts 'raise "I do not have an executable"' end end build_rake_in do use_ui @ui do @newspec = @installer.install end end e = assert_raises RuntimeError do instance_eval File.read(old_bin_file) end # We expect the bin stub to activate the version that actually contains # the binstub. assert_match('I have an executable', e.message) end def test_install_creates_binstub_that_understand_version Dir.mkdir util_inst_bindir util_setup_gem util_clear_gems @installer.wrappers = true @newspec = nil build_rake_in do use_ui @ui do @newspec = @installer.install end end exe = File.join @gemhome, 'bin', 'executable' ARGV.unshift "_3.0_" begin Gem::Specification.reset e = assert_raises Gem::GemNotFoundException do instance_eval File.read(exe) end ensure ARGV.shift if ARGV.first == "_3.0_" end assert_includes(e.message, "can't find gem a (= 3.0)") end def test_install_creates_binstub_that_dont_trust_encoding Dir.mkdir util_inst_bindir util_setup_gem util_clear_gems @installer.wrappers = true @newspec = nil build_rake_in do use_ui @ui do @newspec = @installer.install end end exe = File.join @gemhome, 'bin', 'executable' extra_arg = "\xE4pfel".dup.force_encoding("UTF-8") ARGV.unshift extra_arg begin Gem::Specification.reset e = assert_raises RuntimeError do instance_eval File.read(exe) end ensure ARGV.shift if ARGV.first == extra_arg end assert_match(/ran executable/, e.message) end def test_install_with_no_prior_files Dir.mkdir util_inst_bindir util_clear_gems util_setup_gem build_rake_in do use_ui @ui do assert_equal @spec, @installer.install end end gemdir = File.join(@gemhome, 'gems', @spec.full_name) assert_path_exists File.join gemdir, 'lib', 'code.rb' util_setup_gem # Morph spec to have lib/other.rb instead of code.rb and recreate @spec.files = File.join('lib', 'other.rb') Dir.chdir @tempdir do File.open File.join('lib', 'other.rb'), 'w' do |f| f.puts '1' end use_ui ui do FileUtils.rm @gem Gem::Package.build @spec end end @installer = Gem::Installer.at @gem build_rake_in do use_ui @ui do assert_equal @spec, @installer.install end end assert_path_exists File.join gemdir, 'lib', 'other.rb' refute_path_exists File.join gemdir, 'lib', 'code.rb', "code.rb from prior install of same gem shouldn't remain here" end def test_install_force use_ui @ui do installer = Gem::Installer.at old_ruby_required('= 1.4.6'), :force => true installer.install end gem_dir = File.join(@gemhome, 'gems', 'old_ruby_required-1') assert_path_exists gem_dir end def test_install_missing_dirs FileUtils.rm_f File.join(Gem.dir, 'cache') FileUtils.rm_f File.join(Gem.dir, 'doc') FileUtils.rm_f File.join(Gem.dir, 'specifications') use_ui @ui do @installer.install end assert_directory_exists File.join(Gem.dir, 'cache') assert_directory_exists File.join(Gem.dir, 'doc') assert_directory_exists File.join(Gem.dir, 'specifications') assert_path_exists File.join @gemhome, 'cache', @spec.file_name assert_path_exists File.join @gemhome, 'specifications', @spec.spec_name end def test_install_post_build_false util_clear_gems Gem.post_build do false end use_ui @ui do e = assert_raises Gem::InstallError do @installer.install end location = "#{__FILE__}:#{__LINE__ - 9}" assert_equal "post-build hook at #{location} failed for a-2", e.message end spec_file = File.join @gemhome, 'specifications', @spec.spec_name refute_path_exists spec_file gem_dir = File.join @gemhome, 'gems', @spec.full_name refute_path_exists gem_dir end def test_install_post_build_nil util_clear_gems Gem.post_build do nil end use_ui @ui do @installer.install end spec_file = File.join @gemhome, 'specifications', @spec.spec_name assert_path_exists spec_file gem_dir = File.join @gemhome, 'gems', @spec.full_name assert_path_exists gem_dir end def test_install_pre_install_false util_clear_gems Gem.pre_install do false end use_ui @ui do e = assert_raises Gem::InstallError do @installer.install end location = "#{__FILE__}:#{__LINE__ - 9}" assert_equal "pre-install hook at #{location} failed for a-2", e.message end spec_file = File.join @gemhome, 'specifications', @spec.spec_name refute_path_exists spec_file end def test_install_pre_install_nil util_clear_gems Gem.pre_install do nil end use_ui @ui do @installer.install end spec_file = File.join @gemhome, 'specifications', @spec.spec_name assert_path_exists spec_file end def test_install_with_message @spec.post_install_message = 'I am a shiny gem!' use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.at path @installer.install end assert_match %r|I am a shiny gem!|, @ui.output end def test_install_with_skipped_message @spec.post_install_message = 'I am a shiny gem!' use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.at path, :post_install_message => false @installer.install end refute_match %r|I am a shiny gem!|, @ui.output end def test_install_extension_dir gemhome2 = "#{@gemhome}2" @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" create_makefile("#{@spec.name}") RUBY end @spec.files += %w[extconf.rb] use_ui @ui do path = Gem::Package.build @spec installer = Gem::Installer.at path, :install_dir => gemhome2 installer.install end expected_makefile = File.join gemhome2, 'gems', @spec.full_name, 'Makefile' assert_path_exists expected_makefile end def test_install_extension_dir_is_removed_on_reinstall @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" create_makefile("#{@spec.name}") RUBY end @spec.files += %w[extconf.rb] path = Gem::Package.build @spec # Install a gem with an extension use_ui @ui do installer = Gem::Installer.at path installer.install end # pretend that a binary file was created as part of the build should_be_removed = File.join(@spec.extension_dir, "#{@spec.name}.so") write_file should_be_removed do |io| io.write "DELETE ME ON REINSTALL" end assert_path_exists should_be_removed # reinstall the gem, this is also the same as pristine use_ui @ui do installer = Gem::Installer.at path installer.install end refute_path_exists should_be_removed end def test_install_user_extension_dir @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" create_makefile("#{@spec.name}") RUBY end @spec.files += %w[extconf.rb] # Create the non-user ext dir expected_extension_dir = @spec.extension_dir.dup FileUtils.mkdir_p expected_extension_dir use_ui @ui do path = Gem::Package.build @spec installer = Gem::Installer.at path, :user_install => true installer.install end expected_makefile = File.join Gem.user_dir, 'gems', @spec.full_name, 'Makefile' assert_path_exists expected_makefile assert_path_exists expected_extension_dir refute_path_exists File.join expected_extension_dir, 'gem_make.out' end def test_find_lib_file_after_install @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" CONFIG['CC'] = '$(TOUCH) $@ ||' CONFIG['LDSHARED'] = '$(TOUCH) $@ ||' $ruby = '#{Gem.ruby}' create_makefile("#{@spec.name}") RUBY end write_file File.join(@tempdir, "depend") write_file File.join(@tempdir, "a.c") do |io| io.write <<-C #include void Init_a() { } C end Dir.mkdir File.join(@tempdir, "lib") write_file File.join(@tempdir, 'lib', "b.rb") do |io| io.write "# b.rb" end @spec.files += %w[extconf.rb lib/b.rb depend a.c] use_ui @ui do path = Gem::Package.build @spec installer = Gem::Installer.at path installer.install end expected = File.join @spec.full_require_paths.find { |path| File.exist? File.join path, 'b.rb' }, 'b.rb' assert_equal expected, @spec.matches_for_glob('b.rb').first end def test_install_extension_and_script @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" create_makefile("#{@spec.name}") RUBY end rb = File.join("lib", "#{@spec.name}.rb") @spec.files += [rb] write_file File.join(@tempdir, rb) do |io| io.write <<-RUBY # #{@spec.name}.rb RUBY end Dir.mkdir(File.join("lib", @spec.name)) rb2 = File.join("lib", @spec.name, "#{@spec.name}.rb") @spec.files << rb2 write_file File.join(@tempdir, rb2) do |io| io.write <<-RUBY # #{@spec.name}/#{@spec.name}.rb RUBY end refute_path_exists File.join @spec.gem_dir, rb refute_path_exists File.join @spec.gem_dir, rb2 use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.at path @installer.install end assert_path_exists File.join @spec.gem_dir, rb assert_path_exists File.join @spec.gem_dir, rb2 end def test_install_extension_flat @spec.require_paths = ["."] @spec.extensions << "extconf.rb" write_file File.join(@tempdir, "extconf.rb") do |io| io.write <<-RUBY require "mkmf" CONFIG['CC'] = '$(TOUCH) $@ ||' CONFIG['LDSHARED'] = '$(TOUCH) $@ ||' $ruby = '#{Gem.ruby}' create_makefile("#{@spec.name}") RUBY end # empty depend file for no auto dependencies @spec.files += %W"depend #{@spec.name}.c".each {|file| write_file File.join(@tempdir, file) } so = File.join(@spec.gem_dir, "#{@spec.name}.#{RbConfig::CONFIG["DLEXT"]}") refute_path_exists so use_ui @ui do path = Gem::Package.build @spec @installer = Gem::Installer.at path @installer.install end assert_path_exists so rescue puts '-' * 78 puts File.read File.join(@gemhome, 'gems', 'a-2', 'Makefile') puts '-' * 78 path = File.join(@gemhome, 'gems', 'a-2', 'gem_make.out') if File.exist?(path) puts File.read(path) puts '-' * 78 end raise end def test_installation_satisfies_dependency_eh util_spec 'a' dep = Gem::Dependency.new 'a', '>= 2' assert @installer.installation_satisfies_dependency?(dep) dep = Gem::Dependency.new 'a', '> 2' refute @installer.installation_satisfies_dependency?(dep) end def test_installation_satisfies_dependency_eh_development @installer.options[:development] = true @installer.options[:dev_shallow] = true util_spec 'a' dep = Gem::Dependency.new 'a', :development assert @installer.installation_satisfies_dependency?(dep) end def test_pre_install_checks_dependencies @spec.add_dependency 'b', '> 5' util_setup_gem use_ui @ui do assert_raises Gem::InstallError do @installer.install end end end def test_pre_install_checks_dependencies_ignore @spec.add_dependency 'b', '> 5' @installer.ignore_dependencies = true build_rake_in do use_ui @ui do assert @installer.pre_install_checks end end end def test_pre_install_checks_dependencies_install_dir gemhome2 = "#{@gemhome}2" @spec.add_dependency 'd' quick_gem 'd', 2 gem = File.join @gemhome, @spec.file_name FileUtils.mv @gemhome, gemhome2 FileUtils.mkdir @gemhome FileUtils.mv File.join(gemhome2, 'cache', @spec.file_name), gem # Don't leak any already activated gems into the installer, require # that it work everything out on it's own. Gem::Specification.reset installer = Gem::Installer.at gem, :install_dir => gemhome2 build_rake_in do use_ui @ui do assert installer.pre_install_checks end end end def test_pre_install_checks_ruby_version use_ui @ui do installer = Gem::Installer.at old_ruby_required('= 1.4.6') e = assert_raises Gem::RuntimeRequirementNotMetError do installer.pre_install_checks end rv = Gem.ruby_version assert_equal "old_ruby_required requires Ruby version = 1.4.6. The current ruby version is #{rv}.", e.message end end def test_pre_install_checks_ruby_version_with_prereleases util_set_RUBY_VERSION '2.6.0', -1, '63539', 'ruby 2.6.0preview2 (2018-05-31 trunk 63539) [x86_64-linux]' installer = Gem::Installer.at old_ruby_required('>= 2.6.0.preview2') assert installer.pre_install_checks installer = Gem::Installer.at old_ruby_required('> 2.6.0.preview2') e = assert_raises Gem::RuntimeRequirementNotMetError do assert installer.pre_install_checks end assert_equal "old_ruby_required requires Ruby version > 2.6.0.preview2. The current ruby version is 2.6.0.preview2.", e.message ensure util_restore_RUBY_VERSION end def test_pre_install_checks_wrong_rubygems_version spec = util_spec 'old_rubygems_required', '1' do |s| s.required_rubygems_version = '< 0' end util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::RuntimeRequirementNotMetError do @installer.pre_install_checks end rgv = Gem::VERSION assert_equal "old_rubygems_required requires RubyGems version < 0. The current RubyGems version is #{rgv}. " + "Try 'gem update --system' to update RubyGems itself.", e.message end end def test_pre_install_checks_malicious_name spec = util_spec '../malicious', '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(packaging, strict); end util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal '# has an invalid name', e.message end end def test_pre_install_checks_malicious_name_before_eval spec = util_spec "malicious\n::Object.const_set(:FROM_EVAL, true)#", '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(*args); end util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal "# has an invalid name", e.message end refute defined?(::Object::FROM_EVAL) end def test_pre_install_checks_malicious_require_paths_before_eval spec = util_spec "malicious", '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(*args); end spec.require_paths = ["malicious\n``"] util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal "# has an invalid require_paths", e.message end end def test_pre_install_checks_malicious_extensions_before_eval skip "mswin environment disallow to create file contained the carriage return code." if Gem.win_platform? spec = util_spec "malicious", '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(*args); end spec.extensions = ["malicious\n``"] util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal "# has an invalid extensions", e.message end end def test_pre_install_checks_malicious_specification_version_before_eval spec = util_spec "malicious", '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(*args); end spec.specification_version = "malicious\n``" util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal "# has an invalid specification_version", e.message end end def test_pre_install_checks_malicious_dependencies_before_eval spec = util_spec "malicious", '1' def spec.full_name # so the spec is buildable "malicious-1" end def spec.validate(*args); end spec.add_dependency "b\nfoo", '> 5' util_build_gem spec gem = File.join(@gemhome, 'cache', spec.file_name) use_ui @ui do @installer = Gem::Installer.at gem @installer.ignore_dependencies = true e = assert_raises Gem::InstallError do @installer.pre_install_checks end assert_equal "# has an invalid dependencies", e.message end end def test_shebang util_make_exec @spec, "#!/usr/bin/ruby" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_process_options assert_nil @installer.build_root assert_equal File.join(@gemhome, 'bin'), @installer.bin_dir assert_equal @gemhome, @installer.gem_home end def test_process_options_build_root build_root = File.join @tempdir, 'build_root' @installer = Gem::Installer.at @gem, :build_root => build_root assert_equal Pathname(build_root), @installer.build_root assert_equal File.join(build_root, @gemhome, 'bin'), @installer.bin_dir assert_equal File.join(build_root, @gemhome), @installer.gem_home end def test_shebang_arguments util_make_exec @spec, "#!/usr/bin/ruby -ws" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby} -ws", shebang end def test_shebang_empty util_make_exec @spec, '' shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_shebang_env util_make_exec @spec, "#!/usr/bin/env ruby" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_shebang_env_arguments util_make_exec @spec, "#!/usr/bin/env ruby -ws" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby} -ws", shebang end def test_shebang_env_shebang util_make_exec @spec, '' @installer.env_shebang = true shebang = @installer.shebang 'executable' env_shebang = "/usr/bin/env" unless Gem.win_platform? assert_equal("#!#{env_shebang} #{RbConfig::CONFIG['ruby_install_name']}", shebang) end def test_shebang_nested util_make_exec @spec, "#!/opt/local/ruby/bin/ruby" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_shebang_nested_arguments util_make_exec @spec, "#!/opt/local/ruby/bin/ruby -ws" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby} -ws", shebang end def test_shebang_version util_make_exec @spec, "#!/usr/bin/ruby18" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_shebang_version_arguments util_make_exec @spec, "#!/usr/bin/ruby18 -ws" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby} -ws", shebang end def test_shebang_version_env util_make_exec @spec, "#!/usr/bin/env ruby18" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby}", shebang end def test_shebang_version_env_arguments util_make_exec @spec, "#!/usr/bin/env ruby18 -ws" shebang = @installer.shebang 'executable' assert_equal "#!#{Gem.ruby} -ws", shebang end def test_shebang_custom conf = Gem::ConfigFile.new [] conf[:custom_shebang] = 'test' Gem.configuration = conf util_make_exec @spec, "#!/usr/bin/ruby" shebang = @installer.shebang 'executable' assert_equal "#!test", shebang end def test_shebang_custom_with_expands bin_env = win_platform? ? '' : '/usr/bin/env' conf = Gem::ConfigFile.new [] conf[:custom_shebang] = '1 $env 2 $ruby 3 $exec 4 $name' Gem.configuration = conf util_make_exec @spec, "#!/usr/bin/ruby" shebang = @installer.shebang 'executable' assert_equal "#!1 #{bin_env} 2 #{Gem.ruby} 3 executable 4 a", shebang end def test_shebang_custom_with_expands_and_arguments bin_env = win_platform? ? '' : '/usr/bin/env' conf = Gem::ConfigFile.new [] conf[:custom_shebang] = '1 $env 2 $ruby 3 $exec' Gem.configuration = conf util_make_exec @spec, "#!/usr/bin/ruby -ws" shebang = @installer.shebang 'executable' assert_equal "#!1 #{bin_env} 2 #{Gem.ruby} -ws 3 executable", shebang end def test_unpack util_setup_gem dest = File.join @gemhome, 'gems', @spec.full_name @installer.unpack dest assert_path_exists File.join dest, 'lib', 'code.rb' assert_path_exists File.join dest, 'bin', 'executable' end def test_write_build_info_file refute_path_exists @spec.build_info_file @installer.build_args = %w[ --with-libyaml-dir /usr/local/Cellar/libyaml/0.1.4 ] @installer.write_build_info_file assert_path_exists @spec.build_info_file expected = "--with-libyaml-dir\n/usr/local/Cellar/libyaml/0.1.4\n" assert_equal expected, File.read(@spec.build_info_file) end def test_write_build_info_file_empty refute_path_exists @spec.build_info_file @installer.write_build_info_file refute_path_exists @spec.build_info_file end def test_write_build_info_file_install_dir installer = Gem::Installer.at @gem, :install_dir => "#{@gemhome}2" installer.build_args = %w[ --with-libyaml-dir /usr/local/Cellar/libyaml/0.1.4 ] installer.write_build_info_file refute_path_exists @spec.build_info_file assert_path_exists \ File.join("#{@gemhome}2", 'build_info', "#{@spec.full_name}.info") end def test_write_cache_file cache_file = File.join @gemhome, 'cache', @spec.file_name gem = File.join @gemhome, @spec.file_name FileUtils.mv cache_file, gem refute_path_exists cache_file installer = Gem::Installer.at gem installer.gem_home = @gemhome installer.write_cache_file assert_path_exists cache_file end def test_write_spec FileUtils.rm @spec.spec_file refute_path_exists @spec.spec_file @installer = Gem::Installer.for_spec @spec @installer.gem_home = @gemhome @installer.write_spec assert_path_exists @spec.spec_file loaded = Gem::Specification.load @spec.spec_file assert_equal @spec, loaded assert_equal Gem.rubygems_version, @spec.installed_by_version end def test_write_spec_writes_cached_spec FileUtils.rm @spec.spec_file refute_path_exists @spec.spec_file @spec.files = %w[a.rb b.rb c.rb] @installer = Gem::Installer.for_spec @spec @installer.gem_home = @gemhome @installer.write_spec # cached specs have no file manifest: @spec.files = [] assert_equal @spec, eval(File.read(@spec.spec_file)) end def test_dir assert_match %r!/gemhome/gems/a-2$!, @installer.dir end def test_default_gem_loaded_from spec = util_spec 'a' installer = Gem::Installer.for_spec spec, :install_as_default => true installer.install assert_predicate spec, :default_gem? end def test_default_gem FileUtils.rm_f File.join(Gem.dir, 'specifications') @installer.wrappers = true @installer.options[:install_as_default] = true @installer.gem_dir = @spec.gem_dir use_ui @ui do @installer.install end assert_directory_exists File.join(@spec.gem_dir, 'bin') installed_exec = File.join @spec.gem_dir, 'bin', 'executable' assert_path_exists installed_exec assert_directory_exists File.join(Gem.default_dir, 'specifications') assert_directory_exists File.join(Gem.default_dir, 'specifications', 'default') default_spec = eval File.read File.join(Gem.default_dir, 'specifications', 'default', 'a-2.gemspec') assert_equal Gem::Version.new("2"), default_spec.version assert_equal ['bin/executable'], default_spec.files end def test_default_gem_with_exe_as_bindir FileUtils.rm_f File.join(Gem.dir, 'specifications') @spec = quick_gem 'c' do |spec| util_make_exec spec, '#!/usr/bin/ruby', 'exe' end util_build_gem @spec @spec.cache_file installer = util_installer @spec, @gemhome installer.options[:install_as_default] = true installer.gem_dir = @spec.gem_dir use_ui @ui do installer.install end assert_directory_exists File.join(@spec.gem_dir, 'exe') installed_exec = File.join @spec.gem_dir, 'exe', 'executable' assert_path_exists installed_exec assert_directory_exists File.join(Gem.default_dir, 'specifications') assert_directory_exists File.join(Gem.default_dir, 'specifications', 'default') default_spec = eval File.read File.join(Gem.default_dir, 'specifications', 'default', 'c-2.gemspec') assert_equal Gem::Version.new("2"), default_spec.version assert_equal ['exe/executable'], default_spec.files end def old_ruby_required(requirement) spec = util_spec 'old_ruby_required', '1' do |s| s.required_ruby_version = requirement end util_build_gem spec spec.cache_file end def util_execless @spec = util_spec 'z' util_build_gem @spec @installer = util_installer @spec, @gemhome end def util_conflict_executable(wrappers) conflict = quick_gem 'conflict' do |spec| util_make_exec spec end util_build_gem conflict installer = util_installer conflict, @gemhome installer.wrappers = wrappers installer.generate_bin end def mask 0100755 & (~File.umask) end end