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