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