mirror of
				https://github.com/ruby/ruby.git
				synced 2022-11-09 12:17:21 -05:00 
			
		
		
		
	git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@30752 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
		
			
				
	
	
		
			598 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
			
		
		
	
	
			598 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			Ruby
		
	
	
	
	
	
######################################################################
 | 
						|
# This file is imported from the rubygems project.
 | 
						|
# DO NOT make modifications in this repo. They _will_ be reverted!
 | 
						|
# File a patch instead and assign it to Ryan Davis or Eric Hodel.
 | 
						|
######################################################################
 | 
						|
 | 
						|
#--
 | 
						|
# Copyright 2006 by Chad Fowler, Rich Kilmer, Jim Weirich and others.
 | 
						|
# All rights reserved.
 | 
						|
# See LICENSE.txt for permissions.
 | 
						|
#++
 | 
						|
 | 
						|
require 'rubygems/format'
 | 
						|
require 'rubygems/exceptions'
 | 
						|
require 'rubygems/ext'
 | 
						|
require 'rubygems/require_paths_builder'
 | 
						|
require 'rubygems/user_interaction'
 | 
						|
 | 
						|
##
 | 
						|
# The installer class processes RubyGem .gem files and installs the files
 | 
						|
# contained in the .gem into the Gem.path.
 | 
						|
#
 | 
						|
# Gem::Installer does the work of putting files in all the right places on the
 | 
						|
# filesystem including unpacking the gem into its gem dir, installing the
 | 
						|
# gemspec in the specifications dir, storing the cached gem in the cache dir,
 | 
						|
# and installing either wrappers or symlinks for executables.
 | 
						|
#
 | 
						|
# The installer invokes pre and post install hooks.  Hooks can be added either
 | 
						|
# through a rubygems_plugin.rb file in an installed gem or via a
 | 
						|
# rubygems/defaults/#{RUBY_ENGINE}.rb or rubygems/defaults/operating_system.rb
 | 
						|
# file.  See Gem.pre_install and Gem.post_install for details.
 | 
						|
 | 
						|
class Gem::Installer
 | 
						|
 | 
						|
  ##
 | 
						|
  # Paths where env(1) might live.  Some systems are broken and have it in
 | 
						|
  # /bin
 | 
						|
 | 
						|
  ENV_PATHS = %w[/usr/bin/env /bin/env]
 | 
						|
 | 
						|
  ##
 | 
						|
  # Raised when there is an error while building extensions.
 | 
						|
  #
 | 
						|
  class ExtensionBuildError < Gem::InstallError; end
 | 
						|
 | 
						|
  include Gem::UserInteraction
 | 
						|
 | 
						|
  include Gem::RequirePathsBuilder if Gem::QUICKLOADER_SUCKAGE
 | 
						|
 | 
						|
  ##
 | 
						|
  # The directory a gem's executables will be installed into
 | 
						|
 | 
						|
  attr_reader :bin_dir
 | 
						|
 | 
						|
  ##
 | 
						|
  # The gem repository the gem will be installed into
 | 
						|
 | 
						|
  attr_reader :gem_home
 | 
						|
 | 
						|
  ##
 | 
						|
  # The Gem::Specification for the gem being installed
 | 
						|
 | 
						|
  attr_reader :spec
 | 
						|
 | 
						|
  ##
 | 
						|
  # The options passed when the Gem::Installer was instantiated.
 | 
						|
 | 
						|
  attr_reader :options
 | 
						|
 | 
						|
  @path_warning = false
 | 
						|
 | 
						|
  class << self
 | 
						|
 | 
						|
    ##
 | 
						|
    # True if we've warned about PATH not including Gem.bindir
 | 
						|
 | 
						|
    attr_accessor :path_warning
 | 
						|
 | 
						|
    attr_writer :exec_format
 | 
						|
 | 
						|
    # Defaults to use Ruby's program prefix and suffix.
 | 
						|
    def exec_format
 | 
						|
      @exec_format ||= Gem.default_exec_format
 | 
						|
    end
 | 
						|
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Constructs an Installer instance that will install the gem located at
 | 
						|
  # +gem+.  +options+ is a Hash with the following keys:
 | 
						|
  #
 | 
						|
  # :env_shebang:: Use /usr/bin/env in bin wrappers.
 | 
						|
  # :force:: Overrides all version checks and security policy checks, except
 | 
						|
  #          for a signed-gems-only policy.
 | 
						|
  # :ignore_dependencies:: Don't raise if a dependency is missing.
 | 
						|
  # :install_dir:: The directory to install the gem into.
 | 
						|
  # :format_executable:: Format the executable the same as the ruby executable.
 | 
						|
  #                      If your ruby is ruby18, foo_exec will be installed as
 | 
						|
  #                      foo_exec18.
 | 
						|
  # :security_policy:: Use the specified security policy.  See Gem::Security
 | 
						|
  # :wrappers:: Install wrappers if true, symlinks if false.
 | 
						|
 | 
						|
  def initialize(gem, options={})
 | 
						|
    require 'fileutils'
 | 
						|
 | 
						|
    @gem = gem
 | 
						|
    @options = options
 | 
						|
    process_options
 | 
						|
    load_gem_file
 | 
						|
 | 
						|
    if options[:user_install] and not options[:unpack] then
 | 
						|
      @gem_home = Gem.user_dir
 | 
						|
      check_that_user_bin_dir_is_in_path
 | 
						|
    end
 | 
						|
 | 
						|
    verify_gem_home(options[:unpack])
 | 
						|
 | 
						|
    @spec = @format.spec
 | 
						|
 | 
						|
    @gem_dir = File.join(@gem_home, "gems", @spec.full_name).untaint
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Installs the gem and returns a loaded Gem::Specification for the installed
 | 
						|
  # gem.
 | 
						|
  #
 | 
						|
  # The gem will be installed with the following structure:
 | 
						|
  #
 | 
						|
  #   @gem_home/
 | 
						|
  #     cache/<gem-version>.gem #=> a cached copy of the installed gem
 | 
						|
  #     gems/<gem-version>/... #=> extracted files
 | 
						|
  #     specifications/<gem-version>.gemspec #=> the Gem::Specification
 | 
						|
 | 
						|
  def install
 | 
						|
    # If we're forcing the install then disable security unless the security
 | 
						|
    # policy says that we only install signed gems.
 | 
						|
    @security_policy = nil if @force and @security_policy and
 | 
						|
                              not @security_policy.only_signed
 | 
						|
 | 
						|
    unless @force
 | 
						|
      ensure_required_ruby_version_met
 | 
						|
      ensure_required_rubygems_version_met
 | 
						|
      ensure_dependencies_met unless @ignore_dependencies
 | 
						|
    end
 | 
						|
 | 
						|
    Gem.pre_install_hooks.each do |hook|
 | 
						|
      result = hook.call self
 | 
						|
 | 
						|
      if result == false then
 | 
						|
        location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
 | 
						|
 | 
						|
        message = "pre-install hook#{location} failed for #{@spec.full_name}"
 | 
						|
        raise Gem::InstallError, message
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    Gem.ensure_gem_subdirectories @gem_home
 | 
						|
 | 
						|
    FileUtils.mkdir_p @gem_dir
 | 
						|
 | 
						|
    extract_files
 | 
						|
    build_extensions
 | 
						|
 | 
						|
    Gem.post_build_hooks.each do |hook|
 | 
						|
      result = hook.call self
 | 
						|
 | 
						|
      if result == false then
 | 
						|
        FileUtils.rm_rf @gem_dir
 | 
						|
 | 
						|
        location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
 | 
						|
 | 
						|
        message = "post-build hook#{location} failed for #{@spec.full_name}"
 | 
						|
        raise Gem::InstallError, message
 | 
						|
      end
 | 
						|
    end
 | 
						|
 | 
						|
    generate_bin
 | 
						|
    write_spec
 | 
						|
 | 
						|
    write_require_paths_file_if_needed if Gem::QUICKLOADER_SUCKAGE
 | 
						|
 | 
						|
    # HACK remove?  Isn't this done in multiple places?
 | 
						|
    cached_gem = File.join @gem_home, "cache", @gem.split(/\//).pop
 | 
						|
    unless File.exist? cached_gem then
 | 
						|
      FileUtils.cp @gem, File.join(@gem_home, "cache")
 | 
						|
    end
 | 
						|
 | 
						|
    say @spec.post_install_message unless @spec.post_install_message.nil?
 | 
						|
 | 
						|
    @spec.loaded_from = File.join(@gem_home, 'specifications', @spec.spec_name)
 | 
						|
 | 
						|
    @source_index.add_spec @spec
 | 
						|
 | 
						|
    Gem.post_install_hooks.each do |hook|
 | 
						|
      hook.call self
 | 
						|
    end
 | 
						|
 | 
						|
    return @spec
 | 
						|
  rescue Zlib::GzipFile::Error
 | 
						|
    raise Gem::InstallError, "gzip error installing #{@gem}"
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Ensure that the dependency is satisfied by the current installation of
 | 
						|
  # gem.  If it is not an exception is raised.
 | 
						|
  #
 | 
						|
  # spec       :: Gem::Specification
 | 
						|
  # dependency :: Gem::Dependency
 | 
						|
 | 
						|
  def ensure_dependency(spec, dependency)
 | 
						|
    unless installation_satisfies_dependency? dependency then
 | 
						|
      raise Gem::InstallError, "#{spec.name} requires #{dependency}"
 | 
						|
    end
 | 
						|
    true
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # True if the gems in the source_index satisfy +dependency+.
 | 
						|
 | 
						|
  def installation_satisfies_dependency?(dependency)
 | 
						|
    @source_index.find_name(dependency.name, dependency.requirement).size > 0
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Unpacks the gem into the given directory.
 | 
						|
 | 
						|
  def unpack(directory)
 | 
						|
    @gem_dir = directory
 | 
						|
    @format = Gem::Format.from_file_by_path @gem, @security_policy
 | 
						|
    extract_files
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Writes the .gemspec specification (in Ruby) to the gem home's
 | 
						|
  # specifications directory.
 | 
						|
 | 
						|
  def write_spec
 | 
						|
    rubycode = @spec.to_ruby
 | 
						|
 | 
						|
    file_name = File.join @gem_home, 'specifications', @spec.spec_name
 | 
						|
 | 
						|
    file_name.untaint
 | 
						|
 | 
						|
    File.open(file_name, "w") do |file|
 | 
						|
      file.puts rubycode
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Creates windows .bat files for easy running of commands
 | 
						|
 | 
						|
  def generate_windows_script(filename, bindir)
 | 
						|
    if Gem.win_platform? then
 | 
						|
      script_name = filename + ".bat"
 | 
						|
      script_path = File.join bindir, File.basename(script_name)
 | 
						|
      File.open script_path, 'w' do |file|
 | 
						|
        file.puts windows_stub_script(bindir, filename)
 | 
						|
      end
 | 
						|
 | 
						|
      say script_path if Gem.configuration.really_verbose
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def generate_bin
 | 
						|
    return if @spec.executables.nil? or @spec.executables.empty?
 | 
						|
 | 
						|
    # If the user has asked for the gem to be installed in a directory that is
 | 
						|
    # the system gem directory, then use the system bin directory, else create
 | 
						|
    # (or use) a new bin dir under the gem_home.
 | 
						|
    bindir = @bin_dir ? @bin_dir : Gem.bindir(@gem_home)
 | 
						|
 | 
						|
    Dir.mkdir bindir unless File.exist? bindir
 | 
						|
    raise Gem::FilePermissionError.new(bindir) unless File.writable? bindir
 | 
						|
 | 
						|
    @spec.executables.each do |filename|
 | 
						|
      filename.untaint
 | 
						|
      bin_path = File.expand_path "#{@spec.bindir}/#{filename}", @gem_dir
 | 
						|
      mode = File.stat(bin_path).mode | 0111
 | 
						|
      File.chmod mode, bin_path
 | 
						|
 | 
						|
      if @wrappers then
 | 
						|
        generate_bin_script filename, bindir
 | 
						|
      else
 | 
						|
        generate_bin_symlink filename, bindir
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Creates the scripts to run the applications in the gem.
 | 
						|
  #--
 | 
						|
  # The Windows script is generated in addition to the regular one due to a
 | 
						|
  # bug or misfeature in the Windows shell's pipe.  See
 | 
						|
  # http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/193379
 | 
						|
 | 
						|
  def generate_bin_script(filename, bindir)
 | 
						|
    bin_script_path = File.join bindir, formatted_program_filename(filename)
 | 
						|
 | 
						|
    FileUtils.rm_f bin_script_path # prior install may have been --no-wrappers
 | 
						|
 | 
						|
    File.open bin_script_path, 'w', 0755 do |file|
 | 
						|
      file.print app_script_text(filename)
 | 
						|
    end
 | 
						|
 | 
						|
    say bin_script_path if Gem.configuration.really_verbose
 | 
						|
 | 
						|
    generate_windows_script filename, bindir
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Creates the symlinks to run the applications in the gem.  Moves
 | 
						|
  # the symlink if the gem being installed has a newer version.
 | 
						|
 | 
						|
  def generate_bin_symlink(filename, bindir)
 | 
						|
    if Gem.win_platform? then
 | 
						|
      alert_warning "Unable to use symlinks on Windows, installing wrapper"
 | 
						|
      generate_bin_script filename, bindir
 | 
						|
      return
 | 
						|
    end
 | 
						|
 | 
						|
    src = File.join @gem_dir, 'bin', filename
 | 
						|
    dst = File.join bindir, formatted_program_filename(filename)
 | 
						|
 | 
						|
    if File.exist? dst then
 | 
						|
      if File.symlink? dst then
 | 
						|
        link = File.readlink(dst).split File::SEPARATOR
 | 
						|
        cur_version = Gem::Version.create(link[-3].sub(/^.*-/, ''))
 | 
						|
        return if @spec.version < cur_version
 | 
						|
      end
 | 
						|
      File.unlink dst
 | 
						|
    end
 | 
						|
 | 
						|
    FileUtils.symlink src, dst, :verbose => Gem.configuration.really_verbose
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Generates a #! line for +bin_file_name+'s wrapper copying arguments if
 | 
						|
  # necessary.
 | 
						|
 | 
						|
  def shebang(bin_file_name)
 | 
						|
    ruby_name = Gem::ConfigMap[:ruby_install_name] if @env_shebang
 | 
						|
    path = File.join @gem_dir, @spec.bindir, bin_file_name
 | 
						|
    first_line = File.open(path, "rb") {|file| file.gets}
 | 
						|
 | 
						|
    if /\A#!/ =~ first_line then
 | 
						|
      # Preserve extra words on shebang line, like "-w".  Thanks RPA.
 | 
						|
      shebang = first_line.sub(/\A\#!.*?ruby\S*(?=(\s+\S+))/, "#!#{Gem.ruby}")
 | 
						|
      opts = $1
 | 
						|
      shebang.strip! # Avoid nasty ^M issues.
 | 
						|
    end
 | 
						|
 | 
						|
    if not ruby_name then
 | 
						|
      "#!#{Gem.ruby}#{opts}"
 | 
						|
    elsif opts then
 | 
						|
      "#!/bin/sh\n'exec' #{ruby_name.dump} '-x' \"$0\" \"$@\"\n#{shebang}"
 | 
						|
    else
 | 
						|
      # Create a plain shebang line.
 | 
						|
      @env_path ||= ENV_PATHS.find {|env_path| File.executable? env_path }
 | 
						|
      "#!#{@env_path} #{ruby_name}"
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def ensure_required_ruby_version_met
 | 
						|
    if rrv = @spec.required_ruby_version then
 | 
						|
      unless rrv.satisfied_by? Gem.ruby_version then
 | 
						|
        raise Gem::InstallError, "#{@spec.name} requires Ruby version #{rrv}."
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def ensure_required_rubygems_version_met
 | 
						|
    if rrgv = @spec.required_rubygems_version then
 | 
						|
      unless rrgv.satisfied_by? Gem::Version.new(Gem::VERSION) then
 | 
						|
        raise Gem::InstallError,
 | 
						|
          "#{@spec.name} requires RubyGems version #{rrgv}. " +
 | 
						|
          "Try 'gem update --system' to update RubyGems itself."
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def ensure_dependencies_met
 | 
						|
    deps = @spec.runtime_dependencies
 | 
						|
    deps |= @spec.development_dependencies if @development
 | 
						|
 | 
						|
    deps.each do |dep_gem|
 | 
						|
      ensure_dependency @spec, dep_gem
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def process_options
 | 
						|
    @options = {
 | 
						|
      :bin_dir      => nil,
 | 
						|
      :env_shebang  => false,
 | 
						|
      :exec_format  => false,
 | 
						|
      :force        => false,
 | 
						|
      :install_dir  => Gem.dir,
 | 
						|
      :source_index => Gem.source_index,
 | 
						|
    }.merge options
 | 
						|
 | 
						|
    @env_shebang         = options[:env_shebang]
 | 
						|
    @force               = options[:force]
 | 
						|
    gem_home             = options[:install_dir]
 | 
						|
    @gem_home            = File.expand_path(gem_home)
 | 
						|
    @ignore_dependencies = options[:ignore_dependencies]
 | 
						|
    @format_executable   = options[:format_executable]
 | 
						|
    @security_policy     = options[:security_policy]
 | 
						|
    @wrappers            = options[:wrappers]
 | 
						|
    @bin_dir             = options[:bin_dir]
 | 
						|
    @development         = options[:development]
 | 
						|
    @source_index        = options[:source_index]
 | 
						|
  end
 | 
						|
 | 
						|
  def load_gem_file
 | 
						|
    begin
 | 
						|
      @format = Gem::Format.from_file_by_path @gem, @security_policy
 | 
						|
    rescue Gem::Package::FormatError
 | 
						|
      raise Gem::InstallError, "invalid gem format for #{@gem}"
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def check_that_user_bin_dir_is_in_path
 | 
						|
    user_bin_dir = File.join(@gem_home, 'bin')
 | 
						|
    unless ENV['PATH'].split(File::PATH_SEPARATOR).include? user_bin_dir then
 | 
						|
      unless self.class.path_warning then
 | 
						|
        alert_warning "You don't have #{user_bin_dir} in your PATH,\n\t  gem executables will not run."
 | 
						|
        self.class.path_warning = true
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  def verify_gem_home(unpack = false)
 | 
						|
    FileUtils.mkdir_p @gem_home
 | 
						|
    raise Gem::FilePermissionError, @gem_home unless
 | 
						|
      unpack or File.writable? @gem_home
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Return the text for an application file.
 | 
						|
 | 
						|
  def app_script_text(bin_file_name)
 | 
						|
    <<-TEXT
 | 
						|
#{shebang bin_file_name}
 | 
						|
#
 | 
						|
# This file was generated by RubyGems.
 | 
						|
#
 | 
						|
# The application '#{@spec.name}' is installed as part of a gem, and
 | 
						|
# this file is here to facilitate running it.
 | 
						|
#
 | 
						|
 | 
						|
require 'rubygems'
 | 
						|
 | 
						|
version = "#{Gem::Requirement.default}"
 | 
						|
 | 
						|
if ARGV.first =~ /^_(.*)_$/ and Gem::Version.correct? $1 then
 | 
						|
  version = $1
 | 
						|
  ARGV.shift
 | 
						|
end
 | 
						|
 | 
						|
gem '#{@spec.name}', version
 | 
						|
load Gem.bin_path('#{@spec.name}', '#{bin_file_name}', version)
 | 
						|
TEXT
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # return the stub script text used to launch the true ruby script
 | 
						|
 | 
						|
  def windows_stub_script(bindir, bin_file_name)
 | 
						|
    <<-TEXT
 | 
						|
@ECHO OFF
 | 
						|
IF NOT "%~f0" == "~f0" GOTO :WinNT
 | 
						|
@"#{File.basename(Gem.ruby).chomp('"')}" "#{File.join(bindir, bin_file_name)}" %1 %2 %3 %4 %5 %6 %7 %8 %9
 | 
						|
GOTO :EOF
 | 
						|
:WinNT
 | 
						|
@"#{File.basename(Gem.ruby).chomp('"')}" "%~dpn0" %*
 | 
						|
TEXT
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Builds extensions.  Valid types of extensions are extconf.rb files,
 | 
						|
  # configure scripts and rakefiles or mkrf_conf files.
 | 
						|
 | 
						|
  def build_extensions
 | 
						|
    return if @spec.extensions.empty?
 | 
						|
    say "Building native extensions.  This could take a while..."
 | 
						|
    dest_path = File.join @gem_dir, @spec.require_paths.first
 | 
						|
    ran_rake = false # only run rake once
 | 
						|
 | 
						|
    @spec.extensions.each do |extension|
 | 
						|
      break if ran_rake
 | 
						|
      results = []
 | 
						|
 | 
						|
      builder = case extension
 | 
						|
                when /extconf/ then
 | 
						|
                  Gem::Ext::ExtConfBuilder
 | 
						|
                when /configure/ then
 | 
						|
                  Gem::Ext::ConfigureBuilder
 | 
						|
                when /rakefile/i, /mkrf_conf/i then
 | 
						|
                  ran_rake = true
 | 
						|
                  Gem::Ext::RakeBuilder
 | 
						|
                else
 | 
						|
                  results = ["No builder for extension '#{extension}'"]
 | 
						|
                  nil
 | 
						|
                end
 | 
						|
 | 
						|
 | 
						|
      extension_dir = begin
 | 
						|
                        File.join @gem_dir, File.dirname(extension)
 | 
						|
                      rescue TypeError # extension == nil
 | 
						|
                        @gem_dir
 | 
						|
                      end
 | 
						|
 | 
						|
 | 
						|
      begin
 | 
						|
        Dir.chdir extension_dir do
 | 
						|
          results = builder.build(extension, @gem_dir, dest_path, results)
 | 
						|
 | 
						|
          say results.join("\n") if Gem.configuration.really_verbose
 | 
						|
        end
 | 
						|
      rescue
 | 
						|
        results = results.join "\n"
 | 
						|
 | 
						|
        gem_make_out = File.join extension_dir, 'gem_make.out'
 | 
						|
 | 
						|
        open gem_make_out, 'wb' do |io| io.puts results end
 | 
						|
 | 
						|
        message = <<-EOF
 | 
						|
ERROR: Failed to build gem native extension.
 | 
						|
 | 
						|
        #{results}
 | 
						|
 | 
						|
Gem files will remain installed in #{@gem_dir} for inspection.
 | 
						|
Results logged to #{gem_make_out}
 | 
						|
EOF
 | 
						|
 | 
						|
        raise ExtensionBuildError, message
 | 
						|
      end
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Reads the file index and extracts each file into the gem directory.
 | 
						|
  #
 | 
						|
  # Ensures that files can't be installed outside the gem directory.
 | 
						|
 | 
						|
  def extract_files
 | 
						|
    @gem_dir = File.expand_path @gem_dir
 | 
						|
 | 
						|
    raise ArgumentError, "format required to extract from" if @format.nil?
 | 
						|
 | 
						|
    dirs = []
 | 
						|
 | 
						|
    @format.file_entries.each do |entry, file_data|
 | 
						|
      path = entry['path'].untaint
 | 
						|
 | 
						|
      if path =~ /\A\// then # for extra sanity
 | 
						|
        raise Gem::InstallError,
 | 
						|
              "attempt to install file into #{entry['path'].inspect}"
 | 
						|
      end
 | 
						|
 | 
						|
      path = File.expand_path File.join(@gem_dir, path)
 | 
						|
 | 
						|
      if path !~ /\A#{Regexp.escape @gem_dir}/ then
 | 
						|
        msg = "attempt to install file into %p under %p" %
 | 
						|
                [entry['path'], @gem_dir]
 | 
						|
        raise Gem::InstallError, msg
 | 
						|
      end
 | 
						|
 | 
						|
      FileUtils.rm_rf(path) if File.exists?(path)
 | 
						|
 | 
						|
      dir = File.dirname(path)
 | 
						|
      if !dirs.include?(dir)
 | 
						|
        dirs << dir
 | 
						|
        FileUtils.mkdir_p dir
 | 
						|
      end
 | 
						|
 | 
						|
      File.open(path, "wb") do |out|
 | 
						|
        out.write file_data
 | 
						|
      end
 | 
						|
 | 
						|
      FileUtils.chmod entry['mode'], path
 | 
						|
 | 
						|
      say path if Gem.configuration.really_verbose
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
  ##
 | 
						|
  # Prefix and suffix the program filename the same as ruby.
 | 
						|
 | 
						|
  def formatted_program_filename(filename)
 | 
						|
    if @format_executable then
 | 
						|
      self.class.exec_format % File.basename(filename)
 | 
						|
    else
 | 
						|
      filename
 | 
						|
    end
 | 
						|
  end
 | 
						|
 | 
						|
end
 | 
						|
 |