1#-- 2# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others. 3# All rights reserved. 4# See LICENSE.txt for permissions. 5#++ 6 7require 'rubygems/exceptions' 8require 'rubygems/package' 9require 'rubygems/ext' 10require 'rubygems/user_interaction' 11require 'fileutils' 12require 'thread' 13 14## 15# The installer installs the files contained in the .gem into the Gem.home. 16# 17# Gem::Installer does the work of putting files in all the right places on the 18# filesystem including unpacking the gem into its gem dir, installing the 19# gemspec in the specifications dir, storing the cached gem in the cache dir, 20# and installing either wrappers or symlinks for executables. 21# 22# The installer invokes pre and post install hooks. Hooks can be added either 23# through a rubygems_plugin.rb file in an installed gem or via a 24# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb 25# file. See Gem.pre_install and Gem.post_install for details. 26 27class Gem::Installer 28 29 ## 30 # Paths where env(1) might live. Some systems are broken and have it in 31 # /bin 32 33 ENV_PATHS = %w[/usr/bin/env /bin/env] 34 35 ## 36 # The builder shells-out to run various commands after changing the 37 # directory. This means multiple installations cannot be allowed to build 38 # extensions in parallel as they may change each other's directories leading 39 # to broken extensions or failed installations. 40 41 CHDIR_MUTEX = Mutex.new # :nodoc: 42 43 ## 44 # Raised when there is an error while building extensions. 45 # 46 class ExtensionBuildError < Gem::InstallError; end 47 48 include Gem::UserInteraction 49 50 # DOC: Missing docs or :nodoc:. 51 attr_reader :gem 52 53 ## 54 # The directory a gem's executables will be installed into 55 56 attr_reader :bin_dir 57 58 ## 59 # The gem repository the gem will be installed into 60 61 attr_reader :gem_home 62 63 ## 64 # The options passed when the Gem::Installer was instantiated. 65 66 attr_reader :options 67 68 @path_warning = false 69 70 class << self 71 72 ## 73 # True if we've warned about PATH not including Gem.bindir 74 75 attr_accessor :path_warning 76 77 # DOC: Missing docs or :nodoc:. 78 attr_writer :exec_format 79 80 # Defaults to use Ruby's program prefix and suffix. 81 def exec_format 82 @exec_format ||= Gem.default_exec_format 83 end 84 85 end 86 87 ## 88 # Constructs an Installer instance that will install the gem located at 89 # +gem+. +options+ is a Hash with the following keys: 90 # 91 # :bin_dir:: Where to put a bin wrapper if needed. 92 # :development:: Whether or not development dependencies should be installed. 93 # :env_shebang:: Use /usr/bin/env in bin wrappers. 94 # :force:: Overrides all version checks and security policy checks, except 95 # for a signed-gems-only policy. 96 # :format_executable:: Format the executable the same as the ruby executable. 97 # If your ruby is ruby18, foo_exec will be installed as 98 # foo_exec18. 99 # :ignore_dependencies:: Don't raise if a dependency is missing. 100 # :install_dir:: The directory to install the gem into. 101 # :security_policy:: Use the specified security policy. See Gem::Security 102 # :user_install:: Indicate that the gem should be unpacked into the users 103 # personal gem directory. 104 # :only_install_dir:: Only validate dependencies against what is in the 105 # install_dir 106 # :wrappers:: Install wrappers if true, symlinks if false. 107 # :build_args:: An Array of arguments to pass to the extension builder 108 # process. If not set, then Gem::Command.build_args is used 109 110 def initialize(gem, options={}) 111 require 'fileutils' 112 113 @gem = gem 114 @options = options 115 @package = Gem::Package.new @gem 116 117 process_options 118 119 @package.security_policy = @security_policy 120 121 if options[:user_install] and not options[:unpack] then 122 @gem_home = Gem.user_dir 123 @bin_dir = Gem.bindir gem_home unless options[:bin_dir] 124 check_that_user_bin_dir_is_in_path 125 end 126 end 127 128 ## 129 # Checks if +filename+ exists in +@bin_dir+. 130 # 131 # If +@force+ is set +filename+ is overwritten. 132 # 133 # If +filename+ exists and is a RubyGems wrapper for different gem the user 134 # is consulted. 135 # 136 # If +filename+ exists and +@bin_dir+ is Gem.default_bindir (/usr/local) the 137 # user is consulted. 138 # 139 # Otherwise +filename+ is overwritten. 140 141 def check_executable_overwrite filename # :nodoc: 142 return if @force 143 144 generated_bin = File.join @bin_dir, formatted_program_filename(filename) 145 146 return unless File.exist? generated_bin 147 148 ruby_executable = false 149 existing = nil 150 151 open generated_bin, 'rb' do |io| 152 next unless io.gets =~ /^#!/ # shebang 153 io.gets # blankline 154 155 # TODO detect a specially formatted comment instead of trying 156 # to run a regexp against ruby code. 157 next unless io.gets =~ /This file was generated by RubyGems/ 158 159 ruby_executable = true 160 existing = io.read.slice(/^gem (['"])(.*?)(\1),/, 2) 161 end 162 163 return if spec.name == existing 164 165 # somebody has written to RubyGems' directory, overwrite, too bad 166 return if Gem.default_bindir != @bin_dir and not ruby_executable 167 168 question = "#{spec.name}'s executable \"#{filename}\" conflicts with " 169 170 if ruby_executable then 171 question << existing 172 173 return if ask_yes_no "#{question}\nOverwrite the executable?", false 174 175 conflict = "installed executable from #{existing}" 176 else 177 question << generated_bin 178 179 return if ask_yes_no "#{question}\nOverwrite the executable?", false 180 181 conflict = generated_bin 182 end 183 184 raise Gem::InstallError, 185 "\"#{filename}\" from #{spec.name} conflicts with #{conflict}" 186 end 187 188 ## 189 # Lazy accessor for the spec's gem directory. 190 191 def gem_dir 192 @gem_dir ||= File.join(gem_home, "gems", spec.full_name) 193 end 194 195 ## 196 # Lazy accessor for the installer's spec. 197 198 def spec 199 @spec ||= @package.spec 200 rescue Gem::Package::Error => e 201 raise Gem::InstallError, "invalid gem: #{e.message}" 202 end 203 204 ## 205 # Installs the gem and returns a loaded Gem::Specification for the installed 206 # gem. 207 # 208 # The gem will be installed with the following structure: 209 # 210 # @gem_home/ 211 # cache/<gem-version>.gem #=> a cached copy of the installed gem 212 # gems/<gem-version>/... #=> extracted files 213 # specifications/<gem-version>.gemspec #=> the Gem::Specification 214 215 def install 216 pre_install_checks 217 218 run_pre_install_hooks 219 220 # Completely remove any previous gem files 221 FileUtils.rm_rf gem_dir 222 223 FileUtils.mkdir_p gem_dir 224 225 extract_files 226 227 build_extensions 228 write_build_info_file 229 run_post_build_hooks 230 231 generate_bin 232 write_spec 233 write_cache_file 234 235 say spec.post_install_message unless spec.post_install_message.nil? 236 237 spec.loaded_from = spec_file 238 239 Gem::Specification.add_spec spec unless Gem::Specification.include? spec 240 241 run_post_install_hooks 242 243 spec 244 245 # TODO This rescue is in the wrong place. What is raising this exception? 246 # move this rescue to around the code that actually might raise it. 247 rescue Zlib::GzipFile::Error 248 raise Gem::InstallError, "gzip error installing #{gem}" 249 end 250 251 def run_pre_install_hooks # :nodoc: 252 Gem.pre_install_hooks.each do |hook| 253 if hook.call(self) == false then 254 location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ 255 256 message = "pre-install hook#{location} failed for #{spec.full_name}" 257 raise Gem::InstallError, message 258 end 259 end 260 end 261 262 def run_post_build_hooks # :nodoc: 263 Gem.post_build_hooks.each do |hook| 264 if hook.call(self) == false then 265 FileUtils.rm_rf gem_dir 266 267 location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/ 268 269 message = "post-build hook#{location} failed for #{spec.full_name}" 270 raise Gem::InstallError, message 271 end 272 end 273 end 274 275 def run_post_install_hooks # :nodoc: 276 Gem.post_install_hooks.each do |hook| 277 hook.call self 278 end 279 end 280 281 ## 282 # 283 # Return an Array of Specifications contained within the gem_home 284 # we'll be installing into. 285 286 def installed_specs 287 @specs ||= begin 288 specs = [] 289 290 Dir[File.join(gem_home, "specifications", "*.gemspec")].each do |path| 291 spec = Gem::Specification.load path.untaint 292 specs << spec if spec 293 end 294 295 specs 296 end 297 end 298 299 ## 300 # Ensure that the dependency is satisfied by the current installation of 301 # gem. If it is not an exception is raised. 302 # 303 # spec :: Gem::Specification 304 # dependency :: Gem::Dependency 305 306 def ensure_dependency(spec, dependency) 307 unless installation_satisfies_dependency? dependency then 308 raise Gem::InstallError, "#{spec.name} requires #{dependency}" 309 end 310 true 311 end 312 313 ## 314 # True if the gems in the system satisfy +dependency+. 315 316 def installation_satisfies_dependency?(dependency) 317 return true if installed_specs.detect { |s| dependency.matches_spec? s } 318 return false if @only_install_dir 319 not dependency.matching_specs.empty? 320 end 321 322 ## 323 # Unpacks the gem into the given directory. 324 325 def unpack(directory) 326 @gem_dir = directory 327 extract_files 328 end 329 330 ## 331 # The location of of the spec file that is installed. 332 # 333 334 def spec_file 335 File.join gem_home, "specifications", "#{spec.full_name}.gemspec" 336 end 337 338 ## 339 # Writes the .gemspec specification (in Ruby) to the gem home's 340 # specifications directory. 341 342 def write_spec 343 open spec_file, 'w' do |file| 344 file.puts spec.to_ruby_for_cache 345 file.fsync rescue nil # for filesystems without fsync(2) 346 end 347 end 348 349 ## 350 # Creates windows .bat files for easy running of commands 351 352 def generate_windows_script(filename, bindir) 353 if Gem.win_platform? then 354 script_name = filename + ".bat" 355 script_path = File.join bindir, File.basename(script_name) 356 File.open script_path, 'w' do |file| 357 file.puts windows_stub_script(bindir, filename) 358 end 359 360 say script_path if Gem.configuration.really_verbose 361 end 362 end 363 364 # DOC: Missing docs or :nodoc:. 365 def generate_bin 366 return if spec.executables.nil? or spec.executables.empty? 367 368 Dir.mkdir @bin_dir unless File.exist? @bin_dir 369 raise Gem::FilePermissionError.new(@bin_dir) unless File.writable? @bin_dir 370 371 spec.executables.each do |filename| 372 filename.untaint 373 bin_path = File.join gem_dir, spec.bindir, filename 374 375 unless File.exist? bin_path then 376 # TODO change this to a more useful warning 377 warn "#{bin_path} maybe `gem pristine #{spec.name}` will fix it?" 378 next 379 end 380 381 mode = File.stat(bin_path).mode | 0111 382 FileUtils.chmod mode, bin_path 383 384 check_executable_overwrite filename 385 386 if @wrappers then 387 generate_bin_script filename, @bin_dir 388 else 389 generate_bin_symlink filename, @bin_dir 390 end 391 392 end 393 end 394 395 ## 396 # Creates the scripts to run the applications in the gem. 397 #-- 398 # The Windows script is generated in addition to the regular one due to a 399 # bug or misfeature in the Windows shell's pipe. See 400 # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379 401 402 def generate_bin_script(filename, bindir) 403 bin_script_path = File.join bindir, formatted_program_filename(filename) 404 405 FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers 406 407 File.open bin_script_path, 'wb', 0755 do |file| 408 file.print app_script_text(filename) 409 end 410 411 say bin_script_path if Gem.configuration.really_verbose 412 413 generate_windows_script filename, bindir 414 end 415 416 ## 417 # Creates the symlinks to run the applications in the gem. Moves 418 # the symlink if the gem being installed has a newer version. 419 420 def generate_bin_symlink(filename, bindir) 421 if Gem.win_platform? then 422 alert_warning "Unable to use symlinks on Windows, installing wrapper" 423 generate_bin_script filename, bindir 424 return 425 end 426 427 src = File.join gem_dir, spec.bindir, filename 428 dst = File.join bindir, formatted_program_filename(filename) 429 430 if File.exist? dst then 431 if File.symlink? dst then 432 link = File.readlink(dst).split File::SEPARATOR 433 cur_version = Gem::Version.create(link[-3].sub(/^.*-/, '')) 434 return if spec.version < cur_version 435 end 436 File.unlink dst 437 end 438 439 FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose 440 end 441 442 ## 443 # Generates a #! line for +bin_file_name+'s wrapper copying arguments if 444 # necessary. 445 # 446 # If the :custom_shebang config is set, then it is used as a template 447 # for how to create the shebang used for to run a gem's executables. 448 # 449 # The template supports 4 expansions: 450 # 451 # $env the path to the unix env utility 452 # $ruby the path to the currently running ruby interpreter 453 # $exec the path to the gem's executable 454 # $name the name of the gem the executable is for 455 # 456 457 def shebang(bin_file_name) 458 ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang 459 path = File.join gem_dir, spec.bindir, bin_file_name 460 first_line = File.open(path, "rb") {|file| file.gets} 461 462 if /\A#!/ =~ first_line then 463 # Preserve extra words on shebang line, like "-w". Thanks RPA. 464 shebang = first_line.sub(/\A\#!.*?ruby\S*((\s+\S+)+)/, "#!#{Gem.ruby}") 465 opts = $1 466 shebang.strip! # Avoid nasty ^M issues. 467 end 468 469 if which = Gem.configuration[:custom_shebang] 470 # replace bin_file_name with "ruby" to avoid endless loops 471 which = which.gsub(/ #{bin_file_name}$/," #{Gem::ConfigMap[:ruby_install_name]}") 472 473 which = which.gsub(/\$(\w+)/) do 474 case $1 475 when "env" 476 @env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path } 477 when "ruby" 478 "#{Gem.ruby}#{opts}" 479 when "exec" 480 bin_file_name 481 when "name" 482 spec.name 483 end 484 end 485 486 "#!#{which}" 487 elsif not ruby_name then 488 "#!#{Gem.ruby}#{opts}" 489 elsif opts then 490 "#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}" 491 else 492 # Create a plain shebang line. 493 @env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path } 494 "#!#{@env_path} #{ruby_name}" 495 end 496 end 497 498 ## 499 # Ensures the Gem::Specification written out for this gem is loadable upon 500 # installation. 501 502 def ensure_loadable_spec 503 ruby = spec.to_ruby_for_cache 504 ruby.untaint 505 506 begin 507 eval ruby 508 rescue StandardError, SyntaxError => e 509 raise Gem::InstallError, 510 "The specification for #{spec.full_name} is corrupt (#{e.class})" 511 end 512 end 513 514 # DOC: Missing docs or :nodoc:. 515 def ensure_required_ruby_version_met 516 if rrv = spec.required_ruby_version then 517 unless rrv.satisfied_by? Gem.ruby_version then 518 raise Gem::InstallError, "#{spec.name} requires Ruby version #{rrv}." 519 end 520 end 521 end 522 523 # DOC: Missing docs or :nodoc:. 524 def ensure_required_rubygems_version_met 525 if rrgv = spec.required_rubygems_version then 526 unless rrgv.satisfied_by? Gem.rubygems_version then 527 raise Gem::InstallError, 528 "#{spec.name} requires RubyGems version #{rrgv}. " + 529 "Try 'gem update --system' to update RubyGems itself." 530 end 531 end 532 end 533 534 # DOC: Missing docs or :nodoc:. 535 def ensure_dependencies_met 536 deps = spec.runtime_dependencies 537 deps |= spec.development_dependencies if @development 538 539 deps.each do |dep_gem| 540 ensure_dependency spec, dep_gem 541 end 542 end 543 544 # DOC: Missing docs or :nodoc:. 545 def process_options 546 @options = { 547 :bin_dir => nil, 548 :env_shebang => false, 549 :force => false, 550 :install_dir => Gem.dir, 551 :only_install_dir => false 552 }.merge options 553 554 @env_shebang = options[:env_shebang] 555 @force = options[:force] 556 @gem_home = options[:install_dir] 557 @ignore_dependencies = options[:ignore_dependencies] 558 @format_executable = options[:format_executable] 559 @security_policy = options[:security_policy] 560 @wrappers = options[:wrappers] 561 @only_install_dir = options[:only_install_dir] 562 563 # If the user has asked for the gem to be installed in a directory that is 564 # the system gem directory, then use the system bin directory, else create 565 # (or use) a new bin dir under the gem_home. 566 @bin_dir = options[:bin_dir] || Gem.bindir(gem_home) 567 @development = options[:development] 568 569 @build_args = options[:build_args] || Gem::Command.build_args 570 end 571 572 # DOC: Missing docs or :nodoc:. 573 def check_that_user_bin_dir_is_in_path 574 user_bin_dir = @bin_dir || Gem.bindir(gem_home) 575 user_bin_dir = user_bin_dir.gsub(File::SEPARATOR, File::ALT_SEPARATOR) if 576 File::ALT_SEPARATOR 577 578 path = ENV['PATH'] 579 if Gem.win_platform? then 580 path = path.downcase 581 user_bin_dir = user_bin_dir.downcase 582 end 583 584 unless path.split(File::PATH_SEPARATOR).include? user_bin_dir then 585 unless self.class.path_warning then 586 alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t gem executables will not run." 587 self.class.path_warning = true 588 end 589 end 590 end 591 592 # DOC: Missing docs or :nodoc:. 593 def verify_gem_home(unpack = false) 594 FileUtils.mkdir_p gem_home 595 raise Gem::FilePermissionError, gem_home unless 596 unpack or File.writable?(gem_home) 597 end 598 599 ## 600 # Return the text for an application file. 601 602 def app_script_text(bin_file_name) 603 return <<-TEXT 604#{shebang bin_file_name} 605# 606# This file was generated by RubyGems. 607# 608# The application '#{spec.name}' is installed as part of a gem, and 609# this file is here to facilitate running it. 610# 611 612require 'rubygems' 613 614version = "#{Gem::Requirement.default}" 615 616if ARGV.first 617 str = ARGV.first 618 str = str.dup.force_encoding("BINARY") if str.respond_to? :force_encoding 619 if str =~ /\\A_(.*)_\\z/ 620 version = $1 621 ARGV.shift 622 end 623end 624 625gem '#{spec.name}', version 626load Gem.bin_path('#{spec.name}', '#{bin_file_name}', version) 627TEXT 628 end 629 630 ## 631 # return the stub script text used to launch the true ruby script 632 633 def windows_stub_script(bindir, bin_file_name) 634 ruby = File.basename(Gem.ruby).chomp('"') 635 return <<-TEXT 636@ECHO OFF 637IF NOT "%~f0" == "~f0" GOTO :WinNT 638@"#{ruby}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9 639GOTO :EOF 640:WinNT 641@"#{ruby}" "%~dpn0" %* 642TEXT 643 end 644 645 ## 646 # Builds extensions. Valid types of extensions are extconf.rb files, 647 # configure scripts and rakefiles or mkrf_conf files. 648 649 def build_extensions 650 return if spec.extensions.empty? 651 652 if @build_args.empty? 653 say "Building native extensions. This could take a while..." 654 else 655 say "Building native extensions with: '#{@build_args.join(' ')}'" 656 say "This could take a while..." 657 end 658 659 dest_path = File.join gem_dir, spec.require_paths.first 660 ran_rake = false # only run rake once 661 662 spec.extensions.each do |extension| 663 break if ran_rake 664 results = [] 665 666 extension ||= "" 667 extension_dir = File.join gem_dir, File.dirname(extension) 668 669 builder = case extension 670 when /extconf/ then 671 Gem::Ext::ExtConfBuilder 672 when /configure/ then 673 Gem::Ext::ConfigureBuilder 674 when /rakefile/i, /mkrf_conf/i then 675 ran_rake = true 676 Gem::Ext::RakeBuilder 677 when /CMakeLists.txt/ then 678 Gem::Ext::CmakeBuilder 679 else 680 message = "No builder for extension '#{extension}'" 681 extension_build_error extension_dir, message 682 end 683 684 begin 685 FileUtils.mkdir_p dest_path 686 687 CHDIR_MUTEX.synchronize do 688 Dir.chdir extension_dir do 689 results = builder.build(extension, gem_dir, dest_path, 690 results, @build_args) 691 692 say results.join("\n") if Gem.configuration.really_verbose 693 end 694 end 695 rescue 696 extension_build_error(extension_dir, results.join("\n"), $@) 697 end 698 end 699 end 700 701 ## 702 # Logs the build +output+ in +build_dir+, then raises ExtensionBuildError. 703 704 def extension_build_error(build_dir, output, backtrace = nil) 705 gem_make_out = File.join build_dir, 'gem_make.out' 706 707 open gem_make_out, 'wb' do |io| io.puts output end 708 709 message = <<-EOF 710ERROR: Failed to build gem native extension. 711 712 #{output} 713 714Gem files will remain installed in #{gem_dir} for inspection. 715Results logged to #{gem_make_out} 716EOF 717 718 raise ExtensionBuildError, message, backtrace 719 end 720 721 ## 722 # Reads the file index and extracts each file into the gem directory. 723 # 724 # Ensures that files can't be installed outside the gem directory. 725 726 def extract_files 727 @package.extract_files gem_dir 728 end 729 730 ## 731 # Prefix and suffix the program filename the same as ruby. 732 733 def formatted_program_filename(filename) 734 if @format_executable then 735 self.class.exec_format % File.basename(filename) 736 else 737 filename 738 end 739 end 740 741 ## 742 # 743 # Return the target directory where the gem is to be installed. This 744 # directory is not guaranteed to be populated. 745 # 746 747 def dir 748 gem_dir.to_s 749 end 750 751 ## 752 # Performs various checks before installing the gem such as the install 753 # repository is writable and its directories exist, required ruby and 754 # rubygems versions are met and that dependencies are installed. 755 # 756 # Version and dependency checks are skipped if this install is forced. 757 # 758 # The dependent check will be skipped this install is ignoring dependencies. 759 760 def pre_install_checks 761 verify_gem_home options[:unpack] 762 763 # If we're forcing the install then disable security unless the security 764 # policy says that we only install signed gems. 765 @security_policy = nil if 766 @force and @security_policy and not @security_policy.only_signed 767 768 ensure_loadable_spec 769 770 Gem.ensure_gem_subdirectories gem_home 771 772 return true if @force 773 774 ensure_required_ruby_version_met 775 ensure_required_rubygems_version_met 776 ensure_dependencies_met unless @ignore_dependencies 777 778 true 779 end 780 781 ## 782 # Writes the file containing the arguments for building this gem's 783 # extensions. 784 785 def write_build_info_file 786 return if @build_args.empty? 787 788 build_info_dir = File.join gem_home, 'build_info' 789 790 FileUtils.mkdir_p build_info_dir 791 792 build_info_file = File.join build_info_dir, "#{spec.full_name}.info" 793 794 open build_info_file, 'w' do |io| 795 @build_args.each do |arg| 796 io.puts arg 797 end 798 end 799 end 800 801 ## 802 # Writes the .gem file to the cache directory 803 804 def write_cache_file 805 cache_file = File.join gem_home, 'cache', spec.file_name 806 807 FileUtils.cp @gem, cache_file unless File.exist? cache_file 808 end 809 810end 811 812