ruby-changes:30205
From: drbrain <ko1@a...>
Date: Wed, 31 Jul 2013 07:10:37 +0900 (JST)
Subject: [ruby-changes:30205] drbrain:r42257 (trunk): * lib/rubygems: Import RubyGems from master as of commit 523551c
drbrain 2013-07-31 07:10:21 +0900 (Wed, 31 Jul 2013) New Revision: 42257 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=42257 Log: * lib/rubygems: Import RubyGems from master as of commit 523551c * test/rubygems: ditto. Modified files: trunk/ChangeLog trunk/lib/rubygems/commands/outdated_command.rb trunk/lib/rubygems/ext/builder.rb trunk/lib/rubygems/installer.rb trunk/lib/rubygems/remote_fetcher.rb trunk/lib/rubygems/security.rb trunk/lib/rubygems/specification.rb trunk/lib/rubygems.rb trunk/test/rubygems/encrypted_private_key.pem trunk/test/rubygems/test_gem_ext_builder.rb trunk/test/rubygems/test_gem_installer.rb trunk/test/rubygems/test_gem_package.rb trunk/test/rubygems/test_gem_security.rb trunk/test/rubygems/test_gem_specification.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 42256) +++ ChangeLog (revision 42257) @@ -1,3 +1,8 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Wed Jul 31 07:09:07 2013 Eric Hodel <drbrain@s...> + + * lib/rubygems: Import RubyGems from master as of commit 523551c + * test/rubygems: ditto. + Tue Jul 30 22:21:54 2013 Masaki Matsushita <glass.saga@g...> * test/ruby/test_hash.rb: add a test for enumeration order of Hash. Index: lib/rubygems/ext/builder.rb =================================================================== --- lib/rubygems/ext/builder.rb (revision 42256) +++ lib/rubygems/ext/builder.rb (revision 42257) @@ -4,8 +4,23 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/ext/builder.rb#L4 # See LICENSE.txt for permissions. #++ +require 'rubygems/user_interaction' +require 'thread' + class Gem::Ext::Builder + include Gem::UserInteraction + + ## + # The builder shells-out to run various commands after changing the + # directory. This means multiple installations cannot be allowed to build + # extensions in parallel as they may change each other's directories leading + # to broken extensions or failed installations. + + CHDIR_MUTEX = Mutex.new # :nodoc: + + attr_accessor :build_args # :nodoc: + def self.class_name name =~ /Ext::(.*)Builder/ $1.downcase @@ -63,5 +78,108 @@ class Gem::Ext::Builder https://github.com/ruby/ruby/blob/trunk/lib/rubygems/ext/builder.rb#L78 end end + ## + # Creates a new extension builder for +spec+ using the given +build_args+. + # The gem for +spec+ is unpacked in +gem_dir+. + + def initialize spec, build_args + @spec = spec + @build_args = build_args + @gem_dir = spec.gem_dir + + @ran_rake = nil + end + + ## + # Chooses the extension builder class for +extension+ + + def builder_for extension # :nodoc: + 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 + when /CMakeLists.txt/ then + Gem::Ext::CmakeBuilder + else + extension_dir = File.join @gem_dir, File.dirname(extension) + + message = "No builder for extension '#{extension}'" + build_error extension_dir, message + end + end + + ## + # Logs the build +output+ in +build_dir+, then raises ExtensionBuildError. + + def build_error build_dir, output, backtrace = nil # :nodoc: + gem_make_out = File.join build_dir, 'gem_make.out' + + open gem_make_out, 'wb' do |io| io.puts output end + + message = <<-EOF +ERROR: Failed to build gem native extension. + + #{output} + +Gem files will remain installed in #{@gem_dir} for inspection. +Results logged to #{gem_make_out} +EOF + + raise Gem::Installer::ExtensionBuildError, message, backtrace + end + + def build_extension extension, dest_path # :nodoc: + results = [] + + extension ||= '' # I wish I knew why this line existed + extension_dir = File.join @gem_dir, File.dirname(extension) + + builder = builder_for extension + + begin + FileUtils.mkdir_p dest_path + + CHDIR_MUTEX.synchronize do + Dir.chdir extension_dir do + results = builder.build(extension, @gem_dir, dest_path, + results, @build_args) + + say results.join("\n") if Gem.configuration.really_verbose + end + end + rescue + build_error extension_dir, results.join("\n"), $@ + end + 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? + + if @build_args.empty? + say "Building native extensions. This could take a while..." + else + say "Building native extensions with: '#{@build_args.join ' '}'" + say "This could take a while..." + end + + 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 + + build_extension extension, dest_path + end + end + end Index: lib/rubygems/specification.rb =================================================================== --- lib/rubygems/specification.rb (revision 42256) +++ lib/rubygems/specification.rb (revision 42257) @@ -1016,25 +1016,43 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L1016 end ## - # Return a list of all outdated specifications. This method is HEAVY + # Return a list of all outdated local gem names. This method is HEAVY # as it must go fetch specifications from the server. + # + # Use outdated_and_latest_version if you wish to retrieve the latest remote + # version as well. def self.outdated - outdateds = [] + outdated_and_latest_version.map { |local, _| local.name } + end + + ## + # Enumerates the outdated local gems yielding the local specification and + # the latest remote version. + # + # This method may take some time to return as it must check each local gem + # against the server's index. + + def self.outdated_and_latest_version + return enum_for __method__ unless block_given? # TODO: maybe we should switch to rubygems' version service? fetcher = Gem::SpecFetcher.fetcher - latest_specs(true).each do |local| - dependency = Gem::Dependency.new local.name, ">= #{local.version}" - remotes, _ = fetcher.search_for_dependency dependency - remotes = remotes.map { |n, _| n.version } - latest = remotes.sort.last + latest_specs(true).each do |local_spec| + dependency = + Gem::Dependency.new local_spec.name, ">= #{local_spec.version}" + + remotes, = fetcher.search_for_dependency dependency + remotes = remotes.map { |n, _| n.version } + + latest_remote = remotes.sort.last - outdateds << local.name if latest and local.version < latest + yield [local_spec, latest_remote] if + latest_remote and local_spec.version < latest_remote end - outdateds + nil end ## Index: lib/rubygems/commands/outdated_command.rb =================================================================== --- lib/rubygems/commands/outdated_command.rb (revision 42256) +++ lib/rubygems/commands/outdated_command.rb (revision 42257) @@ -16,18 +16,8 @@ class Gem::Commands::OutdatedCommand < G https://github.com/ruby/ruby/blob/trunk/lib/rubygems/commands/outdated_command.rb#L16 end def execute - Gem::Specification.outdated.sort.each do |name| - local = Gem::Specification.find_all_by_name(name).max - dep = Gem::Dependency.new local.name, ">= #{local.version}" - remotes, _ = Gem::SpecFetcher.fetcher.spec_for_dependency dep - - next if remotes.empty? - - remotes.sort! { |a,b| a[0].version <=> b[0].version } - - highest = remotes.last.first - - say "#{local.name} (#{local.version} < #{highest.version})" + Gem::Specification.outdated_and_latest_version.each do |spec, remote_version| + say "#{spec.name} (#{spec.version} < #{remote_version})" end end end Index: lib/rubygems/remote_fetcher.rb =================================================================== --- lib/rubygems/remote_fetcher.rb (revision 42256) +++ lib/rubygems/remote_fetcher.rb (revision 42257) @@ -325,7 +325,7 @@ class Gem::RemoteFetcher https://github.com/ruby/ruby/blob/trunk/lib/rubygems/remote_fetcher.rb#L325 def request(uri, request_class, last_modified = nil) request = Gem::Request.new uri, request_class, last_modified, @proxy - + request.fetch do |req| yield req if block_given? end Index: lib/rubygems/installer.rb =================================================================== --- lib/rubygems/installer.rb (revision 42256) +++ lib/rubygems/installer.rb (revision 42257) @@ -661,73 +661,20 @@ TEXT https://github.com/ruby/ruby/blob/trunk/lib/rubygems/installer.rb#L661 # configure scripts and rakefiles or mkrf_conf files. def build_extensions - return if spec.extensions.empty? + builder = Gem::Ext::Builder.new spec, @build_args - if @build_args.empty? - say "Building native extensions. This could take a while..." - else - say "Building native extensions with: '#{@build_args.join(' ')}'" - say "This could take a while..." - end - - 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 = [] - - extension ||= "" - extension_dir = File.join gem_dir, File.dirname(extension) - - 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 - when /CMakeLists.txt/ then - Gem::Ext::CmakeBuilder - else - message = "No builder for extension '#{extension}'" - extension_build_error extension_dir, message - end - - begin - FileUtils.mkdir_p dest_path - - Dir.chdir extension_dir do - results = builder.build(extension, gem_dir, dest_path, - results, @build_args) - - say results.join("\n") if Gem.configuration.really_verbose - end - rescue - extension_build_error(extension_dir, results.join("\n"), $@) - end - end + builder.build_extensions end ## # Logs the build +output+ in +build_dir+, then raises ExtensionBuildError. + # + # TODO: Delete this for RubyGems 3. It remains for API compatibility - def extension_build_error(build_dir, output, backtrace = nil) - gem_make_out = File.join build_dir, 'gem_make.out' + def extension_build_error(build_dir, output, backtrace = nil) # :nodoc: + builder = Gem::Ext::Builder.new spec, @build_args - open gem_make_out, 'wb' do |io| io.puts output end - - message = <<-EOF -ERROR: Failed to build gem native extension. - - #{output} - -Gem files will remain installed in #{gem_dir} for inspection. -Results logged to #{gem_make_out} -EOF - - raise ExtensionBuildError, message, backtrace + builder.build_error build_dir, output, backtrace end ## Index: lib/rubygems/security.rb =================================================================== --- lib/rubygems/security.rb (revision 42256) +++ lib/rubygems/security.rb (revision 42257) @@ -368,7 +368,7 @@ module Gem::Security https://github.com/ruby/ruby/blob/trunk/lib/rubygems/security.rb#L368 # Cipher used to encrypt the key pair used to sign gems. # Must be in the list returned by OpenSSL::Cipher.ciphers - KEY_CIPHER = OpenSSL::Cipher.new('aes256') if defined?(OpenSSL::Cipher) + KEY_CIPHER = OpenSSL::Cipher.new('AES-256-CBC') if defined?(OpenSSL::Cipher) ## # One year in seconds Index: lib/rubygems.rb =================================================================== --- lib/rubygems.rb (revision 42256) +++ lib/rubygems.rb (revision 42257) @@ -8,7 +8,7 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems.rb#L8 require 'rbconfig' module Gem - VERSION = '2.1.0' + VERSION = '2.1.0.rc.1' end # Must be first since it unloads the prelude from 1.9.2 Index: test/rubygems/test_gem_package.rb =================================================================== --- test/rubygems/test_gem_package.rb (revision 42256) +++ test/rubygems/test_gem_package.rb (revision 42257) @@ -64,13 +64,16 @@ class TestGemPackage < Gem::Package::Tar https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_package.rb#L64 reader = Gem::Package::TarReader.new gem_io checksums = nil + tar = nil reader.each_entry do |entry| case entry.full_name - when 'checksums.yaml.gz' + when 'checksums.yaml.gz' then Zlib::GzipReader.wrap entry do |io| checksums = io.read end + when 'data.tar.gz' then + tar = entry.read end end @@ -83,22 +86,17 @@ class TestGemPackage < Gem::Package::Tar https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_package.rb#L86 metadata_sha1 = Digest::SHA1.hexdigest s.string metadata_sha512 = Digest::SHA512.hexdigest s.string - data_digests = nil - util_tar do |tar| - data_digests = package.add_contents tar - end - expected = { 'SHA512' => { 'metadata.gz' => metadata_sha512, - 'data.tar.gz' => data_digests['SHA512'].hexdigest, + 'data.tar.gz' => Digest::SHA512.hexdigest(tar), } } if defined?(OpenSSL::Digest) then expected['SHA1'] = { 'metadata.gz' => metadata_sha1, - 'data.tar.gz' => data_digests['SHA1'].hexdigest, + 'data.tar.gz' => Digest::SHA1.hexdigest(tar), } end Index: test/rubygems/test_gem_specification.rb =================================================================== --- test/rubygems/test_gem_specification.rb (revision 42256) +++ test/rubygems/test_gem_specification.rb (revision 42257) @@ -828,6 +828,25 @@ dependencies: [] https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_specification.rb#L828 assert_equal %w[a], Gem::Specification.outdated end + def test_self_outdated_and_latest_remotes + util_clear_gems + util_setup_fake_fetcher true + + a4 = quick_gem @a1.name, '4' + util_build_gem a4 + b3 = quick_gem @b2.name, '3' + util_build_gem b3 + util_setup_spec_fetcher @a1, @a2, @a3a, a4, @b2, b3 + + Gem::Specification.remove_spec @a1 + Gem::Specification.remove_spec @a2 + Gem::Specification.remove_spec a4 + Gem::Specification.remove_spec b3 + + assert_equal [[@a3a, a4.version], [@b2, b3.version]], + Gem::Specification.outdated_and_latest_version.to_a + end + DATA_PATH = File.expand_path "../data", __FILE__ def test_handles_private_null_type Index: test/rubygems/test_gem_ext_builder.rb =================================================================== --- test/rubygems/test_gem_ext_builder.rb (revision 42256) +++ test/rubygems/test_gem_ext_builder.rb (revision 42257) @@ -1,5 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_ext_builder.rb#L1 require 'rubygems/test_case' require 'rubygems/ext' +require 'rubygems/installer' class TestGemExtBuilder < Gem::TestCase @@ -13,6 +14,10 @@ class TestGemExtBuilder < Gem::TestCase https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_ext_builder.rb#L14 FileUtils.mkdir_p @dest_path @orig_DESTDIR = ENV['DESTDIR'] + + @spec = quick_spec 'a' + + @builder = Gem::Ext::Builder.new @spec, '' end def teardown @@ -54,5 +59,93 @@ install: https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_ext_builder.rb#L59 assert_match %r%^install: destination$%, results end + def test_build_extensions_none + use_ui @ui do + @builder.build_extensions + end + + assert_equal '', @ui.output + assert_equal '', @ui.error + + refute File.exist?('gem_make.out') + end + + def test_build_extensions_extconf_bad + @spec.extensions << 'extconf.rb' + + e = assert_raises Gem::Installer::ExtensionBuildError do + use_ui @ui do + @builder.build_extensions + end + end + + assert_match(/\AERROR: Failed to build gem native extension.$/, e.message) + + assert_equal "Building native extensions. This could take a while...\n", + @ui.output + assert_equal '', @ui.error + + gem_make_out = File.join @gemhome, 'gems', @spec.full_name, 'gem_make.out' + + assert_match %r%#{Regexp.escape Gem.ruby} extconf\.rb%, + File.read(gem_make_out) + assert_match %r%#{Regexp.escape Gem.ruby}: No such file%, + File.read(gem_make_out) + end + + def test_build_extensions_unsupported + FileUtils.mkdir_p @spec.gem_dir + gem_make_out = File.join @spec.gem_dir, 'gem_make.out' + @spec.extensions << nil + + e = assert_raises Gem::Installer::ExtensionBuildError do + use_ui @ui do + @builder.build_extensions + end + end + + assert_match(/^\s*No builder for extension ''$/, e.message) + + assert_equal "Building native extensions. This could take a while...\n", + @ui.output + assert_equal '', @ui.error + + assert_equal "No builder for extension ''\n", File.read(gem_make_out) + ensure + FileUtils.rm_f gem_make_out + end + + def test_build_extensions_with_build_args + args = ["--aa", "--bb"] + @builder.build_args = args + @spec.extensions << 'extconf.rb' + + FileUtils.mkdir_p @spec.gem_dir + + open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f| + f.write <<-'RUBY' + puts "IN EXTCONF" + extconf_args = File.join File.dirname(__FILE__), 'extconf_args' + File.open extconf_args, 'w' do |f| + f.puts ARGV.inspect + end + + File.open 'Makefile', 'w' do |f| + f.puts "default:\n\techo built" + f.puts "install:\n\techo installed" + end + RUBY + end + + use_ui @ui do + @builder.build_extensions + end + + path = File.join @spec.gem_dir, "extconf_args" + + assert_equal args.inspect, File.read(path).strip + assert File.directory? File.join(@spec.gem_dir, 'lib') + end + end Index: test/rubygems/test_gem_installer.rb =================================================================== --- test/rubygems/test_gem_installer.rb (revision 42256) +++ test/rubygems/test_gem_installer.rb (revision 42257) @@ -55,95 +55,6 @@ load Gem.bin_path('a', 'executable', ver https://github.com/ruby/ruby/blob/trunk/test/rubygems/test_gem_installer.rb#L55 assert_equal expected, wrapper end - def test_build_extensions_none - use_ui @ui do - @installer.build_extensions - end - - assert_equal '', @ui.output - assert_equal '', @ui.error - - refute File.exist?('gem_make.out') - end - - def test_build_extensions_extconf_bad - @installer.spec = @spec - @spec.extensions << 'extconf.rb' - - e = assert_raises Gem::Installer::ExtensionBuildError do - use_ui @ui do - @installer.build_extensions - end - end - - assert_match(/\AERROR: Failed to build gem native extension.$/, e.message) - - assert_equal "Building native extensions. This could take a while...\n", - @ui.output - assert_equal '', @ui.error - - gem_make_out = File.join @gemhome, 'gems', @spec.full_name, 'gem_make.out' - - assert_match %r%#{Regexp.escape Gem.ruby} extconf\.rb%, - File.read(gem_make_out) - assert_match %r%#{Regexp.escape Gem.ruby}: No such file%, - File.read(gem_make_out) - end - - def test_build_extensions_unsupported - @installer.spec = @spec - FileUtils.mkdir_p @spec.gem_dir - gem_make_out = File.join @spec.gem_dir, 'gem_make.out' - @spec.extensions << nil - - e = assert_raises Gem::Installer::ExtensionBuildError do - use_ui @ui do - @installer.build_extensions - end - end - - assert_match(/^\s*No builder for extension ''$/, e.message) - - assert_equal "Building native extensions. This could take a while...\n", - @ui.output - assert_equal '', @ui.error - - assert_equal "No builder for extension ''\n", File.read(gem_make_out) - ensure - FileUtils.rm_f gem_make_out - end - - def test_build_extensions_with_build_args - args = ["--aa", "--bb"] - @installer.build_args = args - @installer.spec = @s (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/