[前][次][番号順一覧][スレッド一覧]

ruby-changes:18584

From: ryan <ko1@a...>
Date: Thu, 20 Jan 2011 06:24:38 +0900 (JST)
Subject: [ruby-changes:18584] Ruby:r30608 (trunk): Importing rubygems @ c2d4131: Deal with platforms that have DLEXT2 == nil. Fixes RF#28867

ryan	2011-01-20 06:23:04 +0900 (Thu, 20 Jan 2011)

  New Revision: 30608

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=30608

  Log:
    Importing rubygems @ c2d4131: Deal with platforms that have DLEXT2 == nil. Fixes RF#28867

  Modified files:
    trunk/lib/rubygems/builder.rb
    trunk/lib/rubygems/commands/sources_command.rb
    trunk/lib/rubygems/install_update_options.rb
    trunk/lib/rubygems/installer.rb
    trunk/lib/rubygems/package/tar_output.rb
    trunk/lib/rubygems/package.rb
    trunk/lib/rubygems.rb
    trunk/test/rubygems/gemutilities.rb
    trunk/test/rubygems/test_gem_commands_sources_command.rb
    trunk/test/rubygems/test_gem_installer.rb

Index: lib/rubygems/install_update_options.rb
===================================================================
--- lib/rubygems/install_update_options.rb	(revision 30607)
+++ lib/rubygems/install_update_options.rb	(revision 30608)
@@ -11,8 +11,14 @@
 #++
 
 require 'rubygems'
-require 'rubygems/security'
 
+# forward-declare
+
+module Gem::Security # :nodoc:
+  class Policy # :nodoc:
+  end
+end
+
 ##
 # Mixin methods for install and update options for Gem::Commands
 
@@ -23,8 +29,12 @@
 
   def add_install_update_options
     OptionParser.accept Gem::Security::Policy do |value|
+      require 'rubygems/security'
+
       value = Gem::Security::Policies[value]
-      raise OptionParser::InvalidArgument, value if value.nil?
+      valid = Gem::Security::Policies.keys.sort
+      message = "#{value} (#{valid.join ', '} are valid)"
+      raise OptionParser::InvalidArgument, message if value.nil?
       value
     end
 
Index: lib/rubygems/builder.rb
===================================================================
--- lib/rubygems/builder.rb	(revision 30607)
+++ lib/rubygems/builder.rb	(revision 30608)
@@ -20,7 +20,6 @@
 Gem.load_yaml
 
 require 'rubygems/package'
-require 'rubygems/security'
 
 ##
 # The Builder class processes RubyGem specification files
@@ -73,6 +72,8 @@
     signer = nil
 
     if @spec.respond_to?(:signing_key) and @spec.signing_key then
+      require 'rubygems/security'
+
       signer = Gem::Security::Signer.new @spec.signing_key, @spec.cert_chain
       @spec.signing_key = nil
       @spec.cert_chain = signer.cert_chain.map { |cert| cert.to_s }
Index: lib/rubygems/package/tar_output.rb
===================================================================
--- lib/rubygems/package/tar_output.rb	(revision 30607)
+++ lib/rubygems/package/tar_output.rb	(revision 30608)
@@ -85,6 +85,7 @@
       # if we have a signing key, then sign the data
       # digest and return the signature
       if @signer then
+        require 'rubygems/security'
         digest = Gem::Security::OPT[:dgst_algo].digest sio.string
         @data_signature = @signer.sign digest
         inner.write sio.string
@@ -113,6 +114,7 @@
         # if we have a signing key, then sign the metadata digest and return
         # the signature
         if @signer then
+          require 'rubygems/security'
           digest = Gem::Security::OPT[:dgst_algo].digest sio.string
           @meta_signature = @signer.sign digest
           io.write sio.string
Index: lib/rubygems/package.rb
===================================================================
--- lib/rubygems/package.rb	(revision 30607)
+++ lib/rubygems/package.rb	(revision 30608)
@@ -10,7 +10,6 @@
 # See LICENSE.txt for additional licensing information.
 #++
 
-require 'rubygems/security'
 require 'rubygems/specification'
 
 ##
Index: lib/rubygems/installer.rb
===================================================================
--- lib/rubygems/installer.rb	(revision 30607)
+++ lib/rubygems/installer.rb	(revision 30608)
@@ -24,7 +24,7 @@
 # gemspec in the specifications dir, storing the cached gem in the cache dir,
 # and installing either wrappers or symlinks for executables.
 #
-# The installer fires pre and post install hooks.  Hooks can be added either
+# 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.
@@ -61,6 +61,11 @@
 
   attr_reader :spec
 
+  ##
+  # The options passed when the Gem::Installer was instantiated.
+
+  attr_reader :options
+
   @path_warning = false
 
   class << self
@@ -98,49 +103,16 @@
     require 'fileutils'
 
     @gem = gem
+    @options = options
+    process_options
+    load_gem_file
 
-    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]
-
-    begin
-      @format = Gem::Format.from_file_by_path @gem, @security_policy
-    rescue Gem::Package::FormatError
-      raise Gem::InstallError, "invalid gem format for #{@gem}"
-    end
-
     if options[:user_install] and not options[:unpack] then
       @gem_home = Gem.user_dir
-
-      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
+      check_that_user_bin_dir_is_in_path
     end
 
-    FileUtils.mkdir_p @gem_home
-    raise Gem::FilePermissionError, @gem_home unless
-      options[:unpack] or File.writable? @gem_home
+    verify_gem_home(options[:unpack])
 
     @spec = @format.spec
 
@@ -160,48 +132,48 @@
 
   def install
     # If we're forcing the install then disable security unless the security
-    # policy says that we only install singed gems.
+    # policy says that we only install signed gems.
     @security_policy = nil if @force and @security_policy and
                               not @security_policy.only_signed
 
-    unless @force then
-      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
+    unless @force
+      ensure_required_ruby_version_met
+      ensure_required_rubygems_version_met
+      ensure_dependencies_met unless @ignore_dependencies
+    end
 
-      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
+    Gem.pre_install_hooks.each do |hook|
+      result = hook.call self
 
-      unless @ignore_dependencies then
-        deps = @spec.runtime_dependencies
-        deps |= @spec.development_dependencies if @development
+      if result == false then
+        location = " at #{$1}" if hook.inspect =~ /@(.*:\d+)/
 
-        deps.each do |dep_gem|
-          ensure_dependency @spec, dep_gem
-        end
+        message = "pre-install hook#{location} failed for #{@spec.full_name}"
+        raise Gem::InstallError, message
       end
     end
 
-    Gem.pre_install_hooks.each do |hook|
-      hook.call self
-    end
-
-    FileUtils.mkdir_p @gem_home unless File.directory? @gem_home
-
     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
-    build_extensions
     write_spec
 
     write_require_paths_file_if_needed if QUICKLOADER_SUCKAGE
@@ -238,7 +210,6 @@
     unless installation_satisfies_dependency? dependency then
       raise Gem::InstallError, "#{spec.name} requires #{dependency}"
     end
-
     true
   end
 
@@ -388,6 +359,80 @@
     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.
 
Index: lib/rubygems/commands/sources_command.rb
===================================================================
--- lib/rubygems/commands/sources_command.rb	(revision 30607)
+++ lib/rubygems/commands/sources_command.rb	(revision 30608)
@@ -57,12 +57,16 @@
       path = Gem::SpecFetcher.fetcher.dir
       FileUtils.rm_rf path
 
-      if not File.exist?(path) then
+      unless File.exist? path then
         say "*** Removed specs cache ***"
-      elsif not File.writable?(path) then
-        say "*** Unable to remove source cache (write protected) ***"
       else
-        say "*** Unable to remove source cache ***"
+        unless File.writable? path then
+          say "*** Unable to remove source cache (write protected) ***"
+        else
+          say "*** Unable to remove source cache ***"
+        end
+
+        terminate_interaction 1
       end
     end
 
@@ -78,8 +82,10 @@
         say "#{source_uri} added to sources"
       rescue URI::Error, ArgumentError
         say "#{source_uri} is not a URI"
+        terminate_interaction 1
       rescue Gem::RemoteFetcher::FetchError => e
         say "Error fetching #{source_uri}:\n\t#{e.message}"
+        terminate_interaction 1
       end
     end
 
Index: lib/rubygems.rb
===================================================================
--- lib/rubygems.rb	(revision 30607)
+++ lib/rubygems.rb	(revision 30608)
@@ -193,6 +193,7 @@
   @ruby = nil
   @sources = []
 
+  @post_build_hooks     ||= []
   @post_install_hooks   ||= []
   @post_uninstall_hooks ||= []
   @pre_uninstall_hooks  ||= []
@@ -729,6 +730,17 @@
   end
 
   ##
+  # Adds a post-build hook that will be passed an Gem::Installer instance
+  # when Gem::Installer#install is called.  The hook is called after the gem
+  # has been extracted and extensions have been built but before the
+  # executables or gemspec has been written.  If the hook returns +false+ then
+  # the gem's files will be removed and the install will be aborted.
+
+  def self.post_build(&hook)
+    @post_build_hooks << hook
+  end
+
+  ##
   # Adds a post-install hook that will be passed an Gem::Installer instance
   # when Gem::Installer#install is called
 
@@ -747,7 +759,8 @@
 
   ##
   # Adds a pre-install hook that will be passed an Gem::Installer instance
-  # when Gem::Installer#install is called
+  # when Gem::Installer#install is called.  If the hook returns +false+ then
+  # the install will be aborted.
 
   def self.pre_install(&hook)
     @pre_install_hooks << hook
@@ -986,7 +999,8 @@
                    '.rb',
                    *%w(DLEXT DLEXT2).map { |key|
                      val = RbConfig::CONFIG[key]
-                     ".#{val}" unless val.empty?
+                     next unless val and not val.empty?
+                     ".#{val}"
                    }
                   ].compact.uniq
   end
@@ -1097,6 +1111,12 @@
     attr_reader :loaded_specs
 
     ##
+    # The list of hooks to be run before Gem::Install#install finishes
+    # installation
+
+    attr_reader :post_build_hooks
+
+    ##
     # The list of hooks to be run before Gem::Install#install does any work
 
     attr_reader :post_install_hooks
@@ -1219,9 +1239,6 @@
 
 ##
 # Enables the require hook for RubyGems.
-#
-# Ruby 1.9 allows --disable-gems, so we require it when we didn't detect a Gem
-# constant at rubygems.rb load time.
 
 require 'rubygems/custom_require'
 
Index: test/rubygems/test_gem_commands_sources_command.rb
===================================================================
--- test/rubygems/test_gem_commands_sources_command.rb	(revision 30607)
+++ test/rubygems/test_gem_commands_sources_command.rb	(revision 30608)
@@ -90,7 +90,9 @@
     util_setup_spec_fetcher
 
     use_ui @ui do
-      @cmd.execute
+      assert_raises MockGemUi::TermError do
+        @cmd.execute
+      end
     end
 
     expected = <<-EOF
@@ -108,7 +110,9 @@
     util_setup_spec_fetcher
 
     use_ui @ui do
-      @cmd.execute
+      assert_raises MockGemUi::TermError do
+        @cmd.execute
+      end
     end
 
     assert_equal [@gem_repo], Gem.sources
Index: test/rubygems/test_gem_installer.rb
===================================================================
--- test/rubygems/test_gem_installer.rb	(revision 30607)
+++ test/rubygems/test_gem_installer.rb	(revision 30608)
@@ -521,15 +521,27 @@
   def test_install
     Dir.mkdir util_inst_bindir
     util_setup_gem
+    util_clear_gems
 
+    gemdir     = File.join @gemhome, 'gems', @spec.full_name
     cache_file = File.join @gemhome, 'cache', @spec.file_name
+    stub_exe   = File.join @gemhome, 'bin', 'executable'
+    rakefile   = File.join gemdir, 'ext', 'a', 'Rakefile'
 
     Gem.pre_install do |installer|
-      refute File.exist?(cache_file), 'cache file should not exist yet'
+      refute File.exist?(cache_file), 'cache file must not exist yet'
+      true
     end
 
+    Gem.post_build do |installer|
+      assert File.exist?(gemdir), 'gem install dir must exist'
+      assert File.exist?(rakefile), 'gem executable must exist'
+      refute File.exist?(stub_exe), 'gem executable must not exist'
+      true
+    end
+
     Gem.post_install do |installer|
-      assert File.exist?(cache_file), 'cache file should exist'
+      assert File.exist?(cache_file), 'cache file must exist'
     end
 
     build_rake_in do
@@ -538,25 +550,27 @@
       end
     end
 
-    gemdir = File.join @gemhome, 'gems', @spec.full_name
-    assert File.exist?(gemdir)
+    assert File.exist? gemdir
+    assert File.exist?(stub_exe), 'gem executable must exist'
 
-    exe = File.join(gemdir, 'bin', 'executable')
-    assert File.exist?(exe)
+    exe = File.join gemdir, 'bin', 'executable'
+    assert File.exist? exe
+
     exe_mode = File.stat(exe).mode & 0111
     assert_equal 0111, exe_mode, "0%o" % exe_mode unless win_platform?
 
     assert File.exist?(File.join(gemdir, 'lib', 'code.rb'))
 
-    assert File.exist?(File.join(gemdir, 'ext', 'a', 'Rakefile'))
+    assert File.exist? rakefile
 
     spec_file = File.join(@gemhome, 'specifications', @spec.spec_name)
 
     assert_equal spec_file, @spec.loaded_from
     assert File.exist?(spec_file)
 
+    assert_same @installer, @post_build_hook_arg
+    assert_same @installer, @post_install_hook_arg
     assert_same @installer, @pre_install_hook_arg
-    assert_same @installer, @post_install_hook_arg
   end
 
   def test_install_bad_gem
@@ -669,6 +683,84 @@
     assert File.exist?(File.join(@gemhome, 'specifications', @spec.spec_name))
   end
 
+  def test_install_post_build_false
+    util_clear_gems
+
+    Gem.post_build do
+      false
+    end
+
+    use_ui @ui do
+      e = assert_raises Gem::InstallError do
+        @installer.install
+      end
+
+      location = "#{__FILE__}:#{__LINE__ - 9}"
+
+      assert_equal "post-build hook at #{location} failed for a-2", e.message
+    end
+
+    spec_file = File.join @gemhome, 'specifications', @spec.spec_name
+    refute File.exist? spec_file
+
+    gem_dir = File.join @gemhome, 'gems', @spec.full_name
+    refute File.exist? gem_dir
+  end
+
+  def test_install_post_build_nil
+    util_clear_gems
+
+    Gem.post_build do
+      nil
+    end
+
+    use_ui @ui do
+      @installer.install
+    end
+
+    spec_file = File.join @gemhome, 'specifications', @spec.spec_name
+    assert File.exist? spec_file
+
+    gem_dir = File.join @gemhome, 'gems', @spec.full_name
+    assert File.exist? gem_dir
+  end
+
+  def test_install_pre_install_false
+    util_clear_gems
+
+    Gem.pre_install do
+      false
+    end
+
+    use_ui @ui do
+      e = assert_raises Gem::InstallError do
+        @installer.install
+      end
+
+      location = "#{__FILE__}:#{__LINE__ - 9}"
+
+      assert_equal "pre-install hook at #{location} failed for a-2", e.message
+    end
+
+    spec_file = File.join @gemhome, 'specifications', @spec.spec_name
+    refute File.exist? spec_file
+  end
+
+  def test_install_pre_install_nil
+    util_clear_gems
+
+    Gem.pre_install do
+      nil
+    end
+
+    use_ui @ui do
+      @installer.install
+    end
+
+    spec_file = File.join @gemhome, 'specifications', @spec.spec_name
+    assert File.exist? spec_file
+  end
+
   def test_install_with_message
     @spec.post_install_message = 'I am a shiny gem!'
 
Index: test/rubygems/gemutilities.rb
===================================================================
--- test/rubygems/gemutilities.rb	(revision 30607)
+++ test/rubygems/gemutilities.rb	(revision 30608)
@@ -130,11 +130,17 @@
     @public_cert = File.expand_path File.join(File.dirname(__FILE__),
                                               'public_cert.pem')
 
+    Gem.post_build_hooks.clear
     Gem.post_install_hooks.clear
     Gem.post_uninstall_hooks.clear
     Gem.pre_install_hooks.clear
     Gem.pre_uninstall_hooks.clear
 
+    Gem.post_build do |installer|
+      @post_build_hook_arg = installer
+      true
+    end
+
     Gem.post_install do |installer|
       @post_install_hook_arg = installer
     end
@@ -145,6 +151,7 @@
 
     Gem.pre_install do |installer|
       @pre_install_hook_arg = installer
+      true
     end
 
     Gem.pre_uninstall do |uninstaller|

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]