* lib/rubygems/ext/builder.rb: Fix incompatibilities when installing

extensions.  Patch by Nobu.
  [ruby-trunk - Bug #7968] [ruby-trunk - Bug #7971]
* lib/rubygems/ext/ext_conf_builder.rb:  ditto.
* lib/rubygems/installer.rb:  ditto.
* test/rubygems/test_gem_ext_ext_conf_builder.rb:  Test for the above.
* test/rubygems/test_gem_installer.rb:  ditto.

* lib/rubygems/commands/sources_command.rb:  Prefer HTTPS over HTTP.
* lib/rubygems/defaults.rb:  ditto
* lib/rubygems/dependency_resolver.rb:  Ditto.
* lib/rubygems/source.rb:  ditto.
* lib/rubygems/spec_fetcher.rb:  ditto.
* lib/rubygems/specification.rb:  ditto.
* lib/rubygems/test_utilities.rb:  ditto.
* test/rubygems/test_gem.rb:  Test for the above.
* test/rubygems/test_gem_commands_sources_command.rb:  ditto.
* test/rubygems/test_gem_dependency_resolver_api_set.rb:  ditto.
* test/rubygems/test_gem_remote_fetcher.rb:  ditto.
* test/rubygems/test_gem_source.rb:  ditto.
* test/rubygems/test_gem_spec_fetcher.rb:  ditto.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39542 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
drbrain 2013-02-28 22:25:55 +00:00
Родитель 3fc7731297
Коммит a5dfaca00a
19 изменённых файлов: 298 добавлений и 40 удалений

Просмотреть файл

@ -1,3 +1,27 @@
Fri Mar 1 07:21:41 2013 Eric Hodel <drbrain@segment7.net>
* lib/rubygems/ext/builder.rb: Fix incompatibilities when installing
extensions. Patch by Nobu.
[ruby-trunk - Bug #7968] [ruby-trunk - Bug #7971]
* lib/rubygems/ext/ext_conf_builder.rb: ditto.
* lib/rubygems/installer.rb: ditto.
* test/rubygems/test_gem_ext_ext_conf_builder.rb: Test for the above.
* test/rubygems/test_gem_installer.rb: ditto.
* lib/rubygems/commands/sources_command.rb: Prefer HTTPS over HTTP.
* lib/rubygems/defaults.rb: ditto
* lib/rubygems/dependency_resolver.rb: Ditto.
* lib/rubygems/source.rb: ditto.
* lib/rubygems/spec_fetcher.rb: ditto.
* lib/rubygems/specification.rb: ditto.
* lib/rubygems/test_utilities.rb: ditto.
* test/rubygems/test_gem.rb: Test for the above.
* test/rubygems/test_gem_commands_sources_command.rb: ditto.
* test/rubygems/test_gem_dependency_resolver_api_set.rb: ditto.
* test/rubygems/test_gem_remote_fetcher.rb: ditto.
* test/rubygems/test_gem_source.rb: ditto.
* test/rubygems/test_gem_spec_fetcher.rb: ditto.
Fri Mar 1 03:25:00 2013 Zachary Scott <zachary@zacharyscott.net>
* ext/psych/lib/psych.rb: rdoc for Psych overview by Adam Stankiewicz

Просмотреть файл

@ -65,6 +65,19 @@ class Gem::Commands::SourcesCommand < Gem::Command
end
if source_uri = options[:add] then
uri = URI source_uri
if uri.scheme and uri.scheme.downcase == 'http' and
uri.host.downcase == 'rubygems.org' then
question = <<-QUESTION.chomp
https://rubygems.org is recommended for security over #{uri}
Do you want to add this insecure source?
QUESTION
terminate_interaction 1 unless ask_yes_no question
end
source = Gem::Source.new source_uri
begin

Просмотреть файл

@ -11,7 +11,7 @@ module Gem
# An Array of the default sources that come with RubyGems
def self.default_sources
%w[http://rubygems.org/]
%w[https://rubygems.org/]
end
##

Просмотреть файл

@ -69,6 +69,8 @@ module Gem
# and dependencies.
#
class APISpecification
attr_reader :set # :nodoc:
def initialize(set, api_data)
@set = set
@name = api_data[:name]
@ -80,6 +82,14 @@ module Gem
attr_reader :name, :version, :dependencies
def == other # :nodoc:
self.class === other and
@set == other.set and
@name == other.name and
@version == other.version and
@dependencies == other.dependencies
end
def full_name
"#{@name}-#{@version}"
end
@ -91,6 +101,7 @@ module Gem
class APISet
def initialize
@data = Hash.new { |h,k| h[k] = [] }
@dep_uri = URI 'https://rubygems.org/api/v1/dependencies'
end
# Return data for all versions of the gem +name+.
@ -100,8 +111,8 @@ module Gem
return @data[name]
end
u = URI.parse "http://rubygems.org/api/v1/dependencies?gems=#{name}"
str = Net::HTTP.get(u)
uri = @dep_uri + "?gems=#{name}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver
@ -134,8 +145,8 @@ module Gem
return if needed.empty?
u = URI.parse "http://rubygems.org/api/v1/dependencies?gems=#{needed.join ','}"
str = Net::HTTP.get(u)
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
Marshal.load(str).each do |ver|
@data[ver[:name]] << ver

Просмотреть файл

@ -16,13 +16,6 @@ class Gem::Ext::Builder
raise Gem::InstallError, "Makefile not found:\n\n#{results.join "\n"}"
end
mf = Gem.read_binary 'Makefile'
mf = mf.gsub(/^RUBYARCHDIR\s*=\s*\$[^$]*/, "RUBYARCHDIR = #{dest_path}")
mf = mf.gsub(/^RUBYLIBDIR\s*=\s*\$[^$]*/, "RUBYLIBDIR = #{dest_path}")
mf = mf.gsub(/\s*\S+\.time$/, "")
File.open('Makefile', 'wb') {|f| f.print mf}
# try to find make program from Ruby configure arguments first
RbConfig::CONFIG['configure_args'] =~ /with-make-prog\=(\w+)/
make_program = $1 || ENV['MAKE'] || ENV['make']

Просмотреть файл

@ -6,16 +6,36 @@
require 'rubygems/ext/builder'
require 'rubygems/command'
require 'fileutils'
require 'tmpdir'
class Gem::Ext::ExtConfBuilder < Gem::Ext::Builder
def self.build(extension, directory, dest_path, results, args=[])
cmd = "#{Gem.ruby} #{File.basename extension}"
pwd = Dir.pwd
cmd = "#{Gem.ruby} -r./siteconf #{File.join pwd, File.basename(extension)}"
cmd << " #{args.join ' '}" unless args.empty?
Dir.mktmpdir("gem-install.") do |tmpdir|
Dir.chdir(tmpdir) do
open("siteconf.rb", "w") do |f|
f.puts "require 'rbconfig'"
f.puts "dest_path = #{dest_path.dump}"
%w[sitearchdir sitelibdir].each do |dir|
f.puts "RbConfig::MAKEFILE_CONFIG['#{dir}'] = dest_path"
f.puts "RbConfig::CONFIG['#{dir}'] = dest_path"
end
end
begin
run cmd, results
make dest_path, results
ensure
FileUtils.mv("mkmf.log", pwd) if $! and File.exist?("mkmf.log")
end
end
end
results
end

Просмотреть файл

@ -681,7 +681,7 @@ TEXT
say results.join("\n") if Gem.configuration.really_verbose
end
rescue
extension_build_error(extension_dir, results.join("\n"))
extension_build_error(extension_dir, results.join("\n"), $@)
end
end
end
@ -689,7 +689,7 @@ TEXT
##
# Logs the build +output+ in +build_dir+, then raises ExtensionBuildError.
def extension_build_error(build_dir, output)
def extension_build_error(build_dir, output, backtrace = nil)
gem_make_out = File.join build_dir, 'gem_make.out'
open gem_make_out, 'wb' do |io| io.puts output end
@ -703,7 +703,7 @@ Gem files will remain installed in #{gem_dir} for inspection.
Results logged to #{gem_make_out}
EOF
raise ExtensionBuildError, message
raise ExtensionBuildError, message, backtrace
end
##

Просмотреть файл

@ -141,4 +141,14 @@ class Gem::Source
fetcher = Gem::RemoteFetcher.fetcher
fetcher.download spec, @uri.to_s, dir
end
##
# Replaces the URI for this source with +uri+. Used for upgrading this
# source to HTTPS
def uri= uri # :nodoc:
@api_uri = nil
@uri = uri
end
end

Просмотреть файл

@ -188,6 +188,8 @@ class Gem::SpecFetcher
list = {}
Gem.sources.each_source do |source|
source = upgrade_http_source source
begin
names = case type
when :latest
@ -225,5 +227,31 @@ class Gem::SpecFetcher
cache[source.uri] ||= source.load_specs(type)
end
end
def upgrade_http_source source
uri = source.uri
return source unless uri.scheme.downcase == 'http'
https_uri = uri.dup
https_uri.scheme = 'https'
https_uri += '/'
Gem::RemoteFetcher.fetcher.fetch_path https_uri, nil, true
say "Upgraded #{uri} to HTTPS"
https_uri += uri.request_uri
source.uri = URI https_uri.to_s # cast to URI::HTTPS
source
rescue Gem::RemoteFetcher::FetchError
say "Upgrading #{uri} to HTTPS failed, continuing" if
Gem.configuration.really_verbose
source
end
end

Просмотреть файл

@ -17,7 +17,7 @@
# s.authors = ["Ruby Coder"]
# s.email = 'rubycoder@example.com'
# s.files = ["lib/example.rb"]
# s.homepage = 'http://rubygems.org/gems/example'
# s.homepage = 'https://rubygems.org/gems/example'
# end
#
# Starting in RubyGems 1.9.0, a Specification can hold arbitrary

Просмотреть файл

@ -49,7 +49,7 @@ class Gem::FakeFetcher
@data[path]
end
def fetch_path path, mtime = nil
def fetch_path path, mtime = nil, head = false
data = find_data(path)
if data.respond_to?(:call) then

Просмотреть файл

@ -665,7 +665,7 @@ class TestGem < Gem::TestCase
end
def test_self_default_sources
assert_equal %w[http://rubygems.org/], Gem.default_sources
assert_equal %w[https://rubygems.org/], Gem.default_sources
end
def test_self_detect_gemdeps

Просмотреть файл

@ -118,6 +118,45 @@ source #{@gem_repo} already present in the cache
assert_equal '', @ui.error
end
def test_execute_add_http_rubygems_org
http_rubygems_org = 'http://rubygems.org'
util_setup_fake_fetcher
install_specs @a1
specs = Gem::Specification.map { |spec|
[spec.name, spec.version, spec.original_platform]
}
specs_dump_gz = StringIO.new
Zlib::GzipWriter.wrap specs_dump_gz do |io|
Marshal.dump specs, io
end
@fetcher.data["#{http_rubygems_org}/specs.#{@marshal_version}.gz"] =
specs_dump_gz.string
@cmd.handle_options %W[--add #{http_rubygems_org}]
util_setup_spec_fetcher
ui = Gem::MockGemUi.new "n"
use_ui ui do
assert_raises Gem::MockGemUi::TermError do
@cmd.execute
end
end
assert_equal [@gem_repo], Gem.sources
expected = <<-EXPECTED
EXPECTED
assert_equal expected, @ui.output
assert_empty @ui.error
end
def test_execute_add_bad_uri
@cmd.handle_options %w[--add beta-gems.example.com]

Просмотреть файл

@ -0,0 +1,80 @@
require 'rubygems/test_case'
require 'rubygems/dependency_resolver'
class TestGemDependencyResolverAPISet < Gem::TestCase
def setup
super
@DR = Gem::DependencyResolver
@api_set = @DR::APISet.new
@uri = 'https://rubygems.org/api/v1/dependencies'
@fetcher = Gem::FakeFetcher.new
Gem::RemoteFetcher.fetcher = @fetcher
end
def test_find_all
b_entry = {
:name => 'b',
:number => '2',
:platform => 'ruby',
:dependencies => [['a', '>= 0']],
}
@fetcher.data["#{@uri}?gems=b"] = Marshal.dump [b_entry]
b_req = @DR::DependencyRequest.new dep('b', '>= 0'), nil
expected = [
@DR::APISpecification.new(@api_set, b_entry)
]
assert_equal expected, @api_set.find_all(b_req)
end
def test_prefetch
b_entry = {
:name => 'b',
:number => '2',
:platform => 'ruby',
:dependencies => [['a', '>= 0']],
}
a_entry = {
:name => 'a',
:number => '2',
:platform => 'ruby',
:dependencies => [],
}
@fetcher.data["#{@uri}?gems=a,b"] = Marshal.dump [a_entry, b_entry]
a_req = @DR::DependencyRequest.new dep('a', '>= 0'), nil
b_req = @DR::DependencyRequest.new dep('b', '>= 0'), nil
@api_set.prefetch([b_req, a_req])
assert_equal [a_entry], @api_set.versions('a')
assert_equal [b_entry], @api_set.versions('b')
end
def test_versions_cache
entry = {
:name => 'b',
:number => '2',
:platform => 'ruby',
:dependencies => [['a', '>= 0']],
}
@fetcher.data["#{@uri}?gems=b"] = Marshal.dump [entry]
assert_equal [entry], @api_set.versions('b')
@fetcher.data["#{@uri}?gems=b"] = 'garbage'
assert_equal [entry], @api_set.versions('b'), 'version data must be cached'
end
end

Просмотреть файл

@ -30,7 +30,7 @@ class TestGemExtExtConfBuilder < Gem::TestCase
Gem::Ext::ExtConfBuilder.build 'extconf.rb', nil, @dest_path, output
end
assert_match(/^#{Gem.ruby} extconf.rb/, output[0])
assert_match(/^#{Gem.ruby} .*extconf.rb/, output[0])
assert_equal "creating Makefile\n", output[1]
case RUBY_PLATFORM
when /mswin/ then
@ -107,10 +107,10 @@ class TestGemExtExtConfBuilder < Gem::TestCase
assert_match(/\Aextconf failed:
#{Gem.ruby} extconf.rb.*
#{Gem.ruby} .*extconf.rb.*
checking for main\(\) in .*?nonexistent/m, error.message)
assert_match(/^#{Gem.ruby} extconf.rb/, output[0])
assert_match(/^#{Gem.ruby} .*extconf.rb/, output[0])
end
def test_class_make
@ -134,12 +134,6 @@ checking for main\(\) in .*?nonexistent/m, error.message)
assert_equal make_command, output[0]
assert_equal "#{make_command} install", output[2]
edited_makefile = Gem.read_binary makefile_path
edited_makefile.gsub!(/\r/, '') if Gem.win_platform?
assert_match "\nRUBYARCHDIR = #{@ext}$(target_prefix)\n", edited_makefile
assert_match "\nRUBYLIBDIR = #{@ext}$(target_prefix)\n", edited_makefile
end
def test_class_make_no_Makefile

Просмотреть файл

@ -81,7 +81,7 @@ load Gem.bin_path('a', 'executable', version)
gem_make_out = File.join @gemhome, 'gems', @spec.full_name, 'gem_make.out'
assert_match %r%#{Regexp.escape Gem.ruby} extconf\.rb%,
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)
@ -119,7 +119,8 @@ load Gem.bin_path('a', 'executable', version)
File.open File.join(@spec.gem_dir, "extconf.rb"), "w" do |f|
f.write <<-'RUBY'
puts "IN EXTCONF"
File.open 'extconf_args', 'w' do |f|
extconf_args = File.join File.dirname(__FILE__), 'extconf_args'
File.open extconf_args, 'w' do |f|
f.puts ARGV.inspect
end

Просмотреть файл

@ -399,6 +399,9 @@ gems:
@fetcher.instance_variable_set :@a1, @a1
@fetcher.instance_variable_set :@a2, @a2
def @fetcher.fetch_path uri, mtime = nil, head = false
raise Gem::RemoteFetcher::FetchError.new 'no http upgrade', uri if
uri.scheme != 'http'
case uri.request_uri
when /#{@a1.spec_name}/ then
Gem.deflate Marshal.dump @a1

Просмотреть файл

@ -184,5 +184,16 @@ class TestGemSource < Gem::TestCase
end
end
def test_uri_equals
@source.api_uri # cached
refute_equal URI('https://secure.example'), @source.api_uri
@source.uri = URI 'https://secure.example'
assert_equal URI('https://secure.example'), @source.uri
assert_equal URI('https://secure.example'), @source.api_uri
end
end

Просмотреть файл

@ -32,13 +32,14 @@ class TestGemSpecFetcher < Gem::TestCase
Gem::NameTuple.new(spec.name, spec.version, spec.original_platform)
}
v = Gem.marshal_version
s_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@specs)))
l_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@latest_specs)))
p_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@prerelease_specs)))
@fetcher.data["#{@gem_repo}specs.#{v}.gz"] = s_zip
@fetcher.data["#{@gem_repo}latest_specs.#{v}.gz"] = l_zip
@fetcher.data["#{@gem_repo}prerelease_specs.#{v}.gz"] = p_zip
@v = Gem.marshal_version
@s_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@specs)))
@l_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@latest_specs)))
@p_zip = util_gzip(Marshal.dump(Gem::NameTuple.to_basic(@prerelease_specs)))
@fetcher.data["#{@gem_repo}specs.#{@v}.gz"] = @s_zip
@fetcher.data["#{@gem_repo}latest_specs.#{@v}.gz"] = @l_zip
@fetcher.data["#{@gem_repo}prerelease_specs.#{@v}.gz"] = @p_zip
@sf = Gem::SpecFetcher.new
@ -200,7 +201,6 @@ class TestGemSpecFetcher < Gem::TestCase
assert_equal comp.sort, specs[@source].sort
end
def test_available_specs_cache
specs, _ = @sf.available_specs(:latest)
@ -240,5 +240,36 @@ class TestGemSpecFetcher < Gem::TestCase
assert_kind_of Gem::SourceFetchProblem, errors.first
end
def test_upgrade_http_source
Gem.configuration.verbose = :really
source = Gem::Source.new URI 'http://example'
same_source = nil
https_source = nil
use_ui @ui do
same_source = @sf.upgrade_http_source source
end
assert_equal URI('http://example'), same_source.uri
@fetcher.data['https://example/'] = 'hello'
use_ui @ui do
https_source = @sf.upgrade_http_source source
end
assert_equal URI('https://example'), https_source.uri
assert_empty @ui.error
expected = <<-EXPECTED
Upgrading http://example to HTTPS failed, continuing
Upgraded http://example to HTTPS
EXPECTED
assert_equal expected, @ui.output
end
end