diff options
23 files changed, 313 insertions, 39 deletions
@@ -1,3 +1,15 @@ +Tue Sep 10 09:51:22 2013 Eric Hodel <[email protected]> + + * lib/rubygems: Update to RubyGems 2.1.0. Fixes CVE-2013-4287. + + See http://rubygems.rubyforge.org/rubygems-update/CVE-2013-4287_txt.html + for CVE information. + + See http://rubygems.rubyforge.org/rubygems-update/History_txt.html#label-2.1.0+%2F+2013-09-09 + for release notes. + + * test/rubygems: Tests for the above. + Mon Sep 9 21:31:45 2013 Tanaka Akira <[email protected]> * process.c: Remove spaces between SI prefix and unit to follow diff --git a/lib/rubygems.rb b/lib/rubygems.rb index 79d9546296..51252e4773 100644 --- a/lib/rubygems.rb +++ b/lib/rubygems.rb @@ -8,7 +8,7 @@ require 'rbconfig' module Gem - VERSION = '2.1.0.rc.2' + VERSION = '2.1.0' end # Must be first since it unloads the prelude from 1.9.2 @@ -315,7 +315,7 @@ module Gem @paths = nil @user_home = nil Gem::Specification.reset - Gem::Security.reset if const_defined? :Security + Gem::Security.reset if defined?(Gem::Security) end ## diff --git a/lib/rubygems/dependency_resolver.rb b/lib/rubygems/dependency_resolver.rb index e5c05972d8..721fd43c51 100644 --- a/lib/rubygems/dependency_resolver.rb +++ b/lib/rubygems/dependency_resolver.rb @@ -79,7 +79,9 @@ class Gem::DependencyResolver needed = nil @needed.reverse_each do |n| - needed = Gem::List.new(Gem::DependencyResolver::DependencyRequest.new(n, nil), needed) + request = Gem::DependencyResolver::DependencyRequest.new n, nil + + needed = Gem::List.new request, needed end res = resolve_for needed, nil @@ -162,7 +164,9 @@ class Gem::DependencyResolver # Sort them so that we try the highest versions # first. - possible = possible.sort_by { |s| [s.source, s.version] } + possible = possible.sort_by do |s| + [s.source, s.version, s.platform == Gem::Platform::RUBY ? -1 : 1] + end # We track the conflicts seen so that we can report them # to help the user figure out how to fix the situation. diff --git a/lib/rubygems/dependency_resolver/api_specification.rb b/lib/rubygems/dependency_resolver/api_specification.rb index 5ad07396cf..ae688780dd 100644 --- a/lib/rubygems/dependency_resolver/api_specification.rb +++ b/lib/rubygems/dependency_resolver/api_specification.rb @@ -8,6 +8,7 @@ class Gem::DependencyResolver::APISpecification attr_reader :dependencies attr_reader :name + attr_reader :platform attr_reader :set # :nodoc: attr_reader :version @@ -15,6 +16,7 @@ class Gem::DependencyResolver::APISpecification @set = set @name = api_data[:name] @version = Gem::Version.new api_data[:number] + @platform = api_data[:platform] @dependencies = api_data[:dependencies].map do |name, ver| Gem::Dependency.new name, ver.split(/\s*,\s*/) end @@ -25,6 +27,7 @@ class Gem::DependencyResolver::APISpecification @set == other.set and @name == other.name and @version == other.version and + @platform == other.platform and @dependencies == other.dependencies end diff --git a/lib/rubygems/dependency_resolver/index_set.rb b/lib/rubygems/dependency_resolver/index_set.rb index fcf919d81b..d6a05e580f 100644 --- a/lib/rubygems/dependency_resolver/index_set.rb +++ b/lib/rubygems/dependency_resolver/index_set.rb @@ -43,9 +43,14 @@ class Gem::DependencyResolver::IndexSet # Called from IndexSpecification to get a true Specification # object. - def load_spec name, ver, source - key = "#{name}-#{ver}" - @specs[key] ||= source.fetch_spec(Gem::NameTuple.new(name, ver)) + def load_spec name, ver, platform, source + key = "#{name}-#{ver}-#{platform}" + + @specs.fetch key do + tuple = Gem::NameTuple.new name, ver, platform + + @specs[key] = source.fetch_spec tuple + end end ## diff --git a/lib/rubygems/dependency_resolver/index_specification.rb b/lib/rubygems/dependency_resolver/index_specification.rb index 371018ba44..d8ac69d402 100644 --- a/lib/rubygems/dependency_resolver/index_specification.rb +++ b/lib/rubygems/dependency_resolver/index_specification.rb @@ -8,6 +8,8 @@ class Gem::DependencyResolver::IndexSpecification attr_reader :name + attr_reader :platform + attr_reader :source attr_reader :version @@ -39,14 +41,19 @@ class Gem::DependencyResolver::IndexSpecification q.breakable q.text full_name + unless Gem::Platform::RUBY == @platform then + q.breakable + q.text @platform + end + q.breakable - q.text ' source ' + q.text 'source ' q.pp @source end end def spec - @spec ||= @set.load_spec(@name, @version, @source) + @spec ||= @set.load_spec(@name, @version, @platform, @source) end end diff --git a/lib/rubygems/dependency_resolver/installed_specification.rb b/lib/rubygems/dependency_resolver/installed_specification.rb index af167572bf..ca20ace61e 100644 --- a/lib/rubygems/dependency_resolver/installed_specification.rb +++ b/lib/rubygems/dependency_resolver/installed_specification.rb @@ -26,6 +26,10 @@ class Gem::DependencyResolver::InstalledSpecification @spec.name end + def platform + @spec.platform + end + def source @source ||= Gem::Source::Installed.new end diff --git a/lib/rubygems/dependency_resolver/installer_set.rb b/lib/rubygems/dependency_resolver/installer_set.rb index 7de052df77..c39f77a005 100644 --- a/lib/rubygems/dependency_resolver/installer_set.rb +++ b/lib/rubygems/dependency_resolver/installer_set.rb @@ -115,9 +115,14 @@ class Gem::DependencyResolver::InstallerSet # Called from IndexSpecification to get a true Specification # object. - def load_spec name, ver, source - key = "#{name}-#{ver}" - @specs[key] ||= source.fetch_spec Gem::NameTuple.new name, ver + def load_spec name, ver, platform, source + key = "#{name}-#{ver}-#{platform}" + + @specs.fetch key do + tuple = Gem::NameTuple.new name, ver, platform + + @specs[key] = source.fetch_spec tuple + end end ## diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb index 6446cc9799..9dbc18ba98 100644 --- a/lib/rubygems/gemcutter_utilities.rb +++ b/lib/rubygems/gemcutter_utilities.rb @@ -77,7 +77,8 @@ module Gem::GemcutterUtilities # Signs in with the RubyGems API at +sign_in_host+ and sets the rubygems API # key. - def sign_in sign_in_host = self.host + def sign_in sign_in_host = nil + sign_in_host ||= self.host return if Gem.configuration.rubygems_api_key pretty_host = if Gem::DEFAULT_HOST == sign_in_host then diff --git a/lib/rubygems/request_set.rb b/lib/rubygems/request_set.rb index 748c320c28..a45c64e0b4 100644 --- a/lib/rubygems/request_set.rb +++ b/lib/rubygems/request_set.rb @@ -28,7 +28,10 @@ class Gem::RequestSet @always_install = [] @development = false + @requests = [] @soft_missing = false + @sorted = nil + @specs = nil yield self if block_given? end diff --git a/lib/rubygems/spec_fetcher.rb b/lib/rubygems/spec_fetcher.rb index 53ff8d1f45..2ed7d4286a 100644 --- a/lib/rubygems/spec_fetcher.rb +++ b/lib/rubygems/spec_fetcher.rb @@ -200,8 +200,11 @@ class Gem::SpecFetcher when :released tuples_for source, :released when :complete - tuples_for(source, :prerelease, true) + + names = + tuples_for(source, :prerelease, true) + tuples_for(source, :released) + + names.sort when :prerelease tuples_for(source, :prerelease) else diff --git a/lib/rubygems/specification.rb b/lib/rubygems/specification.rb index 49cf25d772..12943a3e24 100644 --- a/lib/rubygems/specification.rb +++ b/lib/rubygems/specification.rb @@ -34,7 +34,7 @@ class Date; end # s.homepage = 'https://rubygems.org/gems/example' # end # -# Starting in RubyGems 1.9.0, a Specification can hold arbitrary +# Starting in RubyGems 2.0, a Specification can hold arbitrary # metadata. This metadata is accessed via Specification#metadata # and has the following restrictions: # @@ -2097,7 +2097,6 @@ class Gem::Specification < Gem::BasicSpecification # Returns an object you can use to sort specifications in #sort_by. def sort_obj - # TODO: this is horrible. Deprecate it. [@name, @version, @new_platform == Gem::Platform::RUBY ? -1 : 1] end diff --git a/lib/rubygems/test_case.rb b/lib/rubygems/test_case.rb index 5d59e35403..d6c1a36ad1 100644 --- a/lib/rubygems/test_case.rb +++ b/lib/rubygems/test_case.rb @@ -1097,7 +1097,11 @@ Also, a list: class StaticSet def initialize(specs) - @specs = specs.sort_by { |s| s.full_name } + @specs = specs + end + + def add spec + @specs << spec end def find_spec(dep) @@ -1110,6 +1114,15 @@ Also, a list: @specs.find_all { |s| dep.matches_spec? s } end + def load_spec name, ver, platform, source + dep = Gem::Dependency.new name, ver + spec = find_spec dep + + Gem::Specification.new spec.name, spec.version do |s| + s.platform = spec.platform + end + end + def prefetch(reqs) end end diff --git a/lib/rubygems/version.rb b/lib/rubygems/version.rb index fa9bbc5a9d..2e546462d4 100644 --- a/lib/rubygems/version.rb +++ b/lib/rubygems/version.rb @@ -147,7 +147,7 @@ class Gem::Version # FIX: These are only used once, in .correct?. Do they deserve to be # constants? - VERSION_PATTERN = '[0-9]+(\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc: + VERSION_PATTERN = '[0-9]+(?>\.[0-9a-zA-Z]+)*(-[0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*)?' # :nodoc: ANCHORED_VERSION_PATTERN = /\A\s*(#{VERSION_PATTERN})*\s*\z/ # :nodoc: ## diff --git a/test/rubygems/test_gem.rb b/test/rubygems/test_gem.rb index 38a63c3b2c..45db153c22 100644 --- a/test/rubygems/test_gem.rb +++ b/test/rubygems/test_gem.rb @@ -1183,23 +1183,28 @@ class TestGem < Gem::TestCase def test_default_gems_use_full_paths begin - engine = RUBY_ENGINE - Object.send :remove_const, :RUBY_ENGINE + if defined?(RUBY_ENGINE) then + engine = RUBY_ENGINE + Object.send :remove_const, :RUBY_ENGINE + end Object.const_set :RUBY_ENGINE, 'ruby' + refute Gem.default_gems_use_full_paths? ensure Object.send :remove_const, :RUBY_ENGINE - Object.const_set :RUBY_ENGINE, engine + Object.const_set :RUBY_ENGINE, engine if engine end begin - engine = RUBY_ENGINE - Object.send :remove_const, :RUBY_ENGINE + if defined?(RUBY_ENGINE) then + engine = RUBY_ENGINE + Object.send :remove_const, :RUBY_ENGINE + end Object.const_set :RUBY_ENGINE, 'jruby' assert Gem.default_gems_use_full_paths? ensure Object.send :remove_const, :RUBY_ENGINE - Object.const_set :RUBY_ENGINE, engine + Object.const_set :RUBY_ENGINE, engine if engine end end diff --git a/test/rubygems/test_gem_dependency_resolver.rb b/test/rubygems/test_gem_dependency_resolver.rb index 3f65c23aa9..38f3d868ea 100644 --- a/test/rubygems/test_gem_dependency_resolver.rb +++ b/test/rubygems/test_gem_dependency_resolver.rb @@ -66,6 +66,27 @@ class TestGemDependencyResolver < Gem::TestCase assert_set [a2], res.resolve end + def test_picks_best_platform + is = Gem::DependencyResolver::IndexSpecification + a2_p = quick_spec 'a' do |s| s.platform = Gem::Platform.local end + version = Gem::Version.new 2 + source = Gem::Source.new @gem_repo + + s = set + + a2 = is.new s, 'a', version, source, Gem::Platform::RUBY + a2_p = is.new s, 'a', version, source, Gem::Platform.local.to_s + + s.add a2_p + s.add a2 + + ad = make_dep "a" + + res = Gem::DependencyResolver.new([ad], s) + + assert_set [a2_p], res.resolve + end + def test_only_returns_spec_once a1 = util_spec "a", "1", "c" => "= 1" b1 = util_spec "b", "1", "c" => "= 1" diff --git a/test/rubygems/test_gem_dependency_resolver_api_specification.rb b/test/rubygems/test_gem_dependency_resolver_api_specification.rb new file mode 100644 index 0000000000..cdbecec822 --- /dev/null +++ b/test/rubygems/test_gem_dependency_resolver_api_specification.rb @@ -0,0 +1,33 @@ +require 'rubygems/test_case' +require 'rubygems/dependency_resolver' + +class TestGemDependencyResolverAPISpecification < Gem::TestCase + + def test_initialize + set = Gem::DependencyResolver::APISet.new + data = { + :name => 'rails', + :number => '3.0.3', + :platform => 'ruby', + :dependencies => [ + ['bundler', '~> 1.0'], + ['railties', '= 3.0.3'], + ], + } + + spec = Gem::DependencyResolver::APISpecification.new set, data + + assert_equal 'rails', spec.name + assert_equal Gem::Version.new('3.0.3'), spec.version + assert_equal Gem::Platform::RUBY, spec.platform + + expected = [ + Gem::Dependency.new('bundler', '~> 1.0'), + Gem::Dependency.new('railties', '= 3.0.3'), + ] + + assert_equal expected, spec.dependencies + end + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_index_set.rb b/test/rubygems/test_gem_dependency_resolver_index_set.rb new file mode 100644 index 0000000000..82ea486792 --- /dev/null +++ b/test/rubygems/test_gem_dependency_resolver_index_set.rb @@ -0,0 +1,53 @@ +require 'rubygems/test_case' +require 'rubygems/dependency_resolver' + +class TestGemDependencyResolverIndexSet < Gem::TestCase + + def test_load_spec + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + a_2 = quick_spec 'a', 2 + a_2_p = quick_spec 'a', 2 do |s| s.platform = Gem::Platform.local end + + Gem::Specification.add_specs a_2, a_2_p + + util_setup_spec_fetcher a_2, a_2_p + + source = Gem::Source.new @gem_repo + version = v 2 + + set = Gem::DependencyResolver::IndexSet.new + + spec = set.load_spec 'a', version, Gem::Platform.local, source + + assert_equal a_2_p.full_name, spec.full_name + end + + def test_load_spec_cached + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + a_2 = quick_spec 'a', 2 + a_2_p = quick_spec 'a', 2 do |s| s.platform = Gem::Platform.local end + + Gem::Specification.add_specs a_2, a_2_p + + util_setup_spec_fetcher a_2, a_2_p + + source = Gem::Source.new @gem_repo + version = v 2 + + set = Gem::DependencyResolver::IndexSet.new + + first = set.load_spec 'a', version, Gem::Platform.local, source + + util_setup_spec_fetcher # clear + + second = set.load_spec 'a', version, Gem::Platform.local, source + + assert_same first, second + end + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_index_specification.rb b/test/rubygems/test_gem_dependency_resolver_index_specification.rb new file mode 100644 index 0000000000..20a7e7d85b --- /dev/null +++ b/test/rubygems/test_gem_dependency_resolver_index_specification.rb @@ -0,0 +1,46 @@ +require 'rubygems/test_case' +require 'rubygems/dependency_resolver' + +class TestGemDependencyResolverIndexSpecification < Gem::TestCase + + def test_initialize + set = Gem::DependencyResolver::IndexSet.new + source = Gem::Source.new @gem_repo + version = Gem::Version.new '3.0.3' + + spec = Gem::DependencyResolver::IndexSpecification.new( + set, 'rails', version, source, Gem::Platform::RUBY) + + assert_equal 'rails', spec.name + assert_equal version, spec.version + assert_equal Gem::Platform::RUBY, spec.platform + + assert_equal source, spec.source + end + + def test_spec + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + a_2 = quick_spec 'a', 2 + a_2_p = quick_spec 'a', 2 do |s| s.platform = Gem::Platform.local end + + Gem::Specification.add_specs a_2, a_2_p + + util_setup_spec_fetcher a_2, a_2_p + + source = Gem::Source.new @gem_repo + version = v 2 + + set = Gem::DependencyResolver::IndexSet.new + i_spec = Gem::DependencyResolver::IndexSpecification.new \ + set, 'a', version, source, Gem::Platform.local + + spec = i_spec.spec + + assert_equal a_2_p.full_name, spec.full_name + end + + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_installed_specification.rb b/test/rubygems/test_gem_dependency_resolver_installed_specification.rb new file mode 100644 index 0000000000..6586ca4654 --- /dev/null +++ b/test/rubygems/test_gem_dependency_resolver_installed_specification.rb @@ -0,0 +1,19 @@ +require 'rubygems/test_case' +require 'rubygems/dependency_resolver' + +class TestGemDependencyResolverInstalledSpecification < Gem::TestCase + + def test_initialize + set = Gem::DependencyResolver::CurrentSet.new + + source_spec = quick_spec 'a' + + spec = Gem::DependencyResolver::InstalledSpecification.new set, source_spec + + assert_equal 'a', spec.name + assert_equal Gem::Version.new(2), spec.version + assert_equal Gem::Platform::RUBY, spec.platform + end + +end + diff --git a/test/rubygems/test_gem_dependency_resolver_installer_set.rb b/test/rubygems/test_gem_dependency_resolver_installer_set.rb new file mode 100644 index 0000000000..b6b50a12fe --- /dev/null +++ b/test/rubygems/test_gem_dependency_resolver_installer_set.rb @@ -0,0 +1,28 @@ +require 'rubygems/test_case' +require 'rubygems/dependency_resolver' + +class TestGemDependencyResolverInstallerSet < Gem::TestCase + + def test_load_spec + @fetcher = Gem::FakeFetcher.new + Gem::RemoteFetcher.fetcher = @fetcher + + a_2 = quick_spec 'a', 2 + a_2_p = quick_spec 'a', 2 do |s| s.platform = Gem::Platform.local end + + Gem::Specification.add_specs a_2, a_2_p + + util_setup_spec_fetcher a_2, a_2_p + + source = Gem::Source.new @gem_repo + version = v 2 + + set = Gem::DependencyResolver::InstallerSet.new :remote + + spec = set.load_spec 'a', version, Gem::Platform.local, source + + assert_equal a_2_p.full_name, spec.full_name + end + +end + diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb index 18b4518b06..d70ac35beb 100644 --- a/test/rubygems/test_gem_gemcutter_utilities.rb +++ b/test/rubygems/test_gem_gemcutter_utilities.rb @@ -101,7 +101,7 @@ class TestGemGemcutterUtilities < Gem::TestCase def test_sign_in_with_host api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' - util_sign_in [api_key, 200, 'OK'], 'http://example.com', :param + util_sign_in [api_key, 200, 'OK'], 'http://example.com', ['http://example.com'] assert_match "Enter your http://example.com credentials.", @sign_in_ui.output @@ -112,6 +112,20 @@ class TestGemGemcutterUtilities < Gem::TestCase assert_equal api_key, credentials[:rubygems_api_key] end + def test_sign_in_with_host_nil + api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' + + util_sign_in [api_key, 200, 'OK'], nil, [nil] + + assert_match "Enter your RubyGems.org credentials.", + @sign_in_ui.output + assert @fetcher.last_request["authorization"] + assert_match %r{Signed in.}, @sign_in_ui.output + + credentials = YAML.load_file Gem.configuration.credentials_path + assert_equal api_key, credentials[:rubygems_api_key] + end + def test_sign_in_with_host_ENV api_key = 'a5fdbb6ba150cbb83aad2bb2fede64cf040453903' util_sign_in [api_key, 200, 'OK'], 'http://example.com' @@ -163,14 +177,14 @@ class TestGemGemcutterUtilities < Gem::TestCase assert_match %r{Access Denied.}, @sign_in_ui.output end - def util_sign_in response, host = nil, style = :ENV + def util_sign_in response, host = nil, args = [] skip 'Always uses $stdin on windows' if Gem.win_platform? email = '[email protected]' password = 'secret' if host - ENV['RUBYGEMS_HOST'] = host if style == :ENV + ENV['RUBYGEMS_HOST'] = host else host = Gem.host end @@ -182,8 +196,8 @@ class TestGemGemcutterUtilities < Gem::TestCase @sign_in_ui = Gem::MockGemUi.new "#{email}\n#{password}\n" use_ui @sign_in_ui do - if style == :param then - @cmd.sign_in host + if args.length > 0 then + @cmd.sign_in(*args) else @cmd.sign_in end @@ -209,4 +223,3 @@ class TestGemGemcutterUtilities < Gem::TestCase end end - diff --git a/test/rubygems/test_gem_spec_fetcher.rb b/test/rubygems/test_gem_spec_fetcher.rb index a821057705..8be10a30b9 100644 --- a/test/rubygems/test_gem_spec_fetcher.rb +++ b/test/rubygems/test_gem_spec_fetcher.rb @@ -168,7 +168,7 @@ class TestGemSpecFetcher < Gem::TestCase specs, _ = @sf.available_specs(:latest) assert_equal [@source], specs.keys - assert_equal @latest_specs, specs[@source].sort + assert_equal @latest_specs, specs[@source] end def test_available_specs_released @@ -176,7 +176,7 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - assert_equal @released, specs[@source].sort + assert_equal @released, specs[@source] end def test_available_specs_complete @@ -184,9 +184,9 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - comp = @prerelease_specs + @released + expected = (@prerelease_specs + @released).sort - assert_equal comp.sort, specs[@source].sort + assert_equal expected, specs[@source] end def test_available_specs_complete_handles_no_prerelease @@ -197,12 +197,9 @@ class TestGemSpecFetcher < Gem::TestCase assert_equal [@source], specs.keys - comp = @released - - assert_equal comp.sort, specs[@source].sort + assert_equal @released, specs[@source] end - def test_available_specs_cache specs, _ = @sf.available_specs(:latest) @@ -230,7 +227,7 @@ class TestGemSpecFetcher < Gem::TestCase def test_available_specs_prerelease specs, _ = @sf.available_specs(:prerelease) - assert_equal @prerelease_specs, specs[@source].sort + assert_equal @prerelease_specs, specs[@source] end def test_available_specs_with_bad_source |