ruby-changes:31689
From: drbrain <ko1@a...>
Date: Fri, 22 Nov 2013 08:27:42 +0900 (JST)
Subject: [ruby-changes:31689] drbrain:r43767 (trunk): * lib/rubygems: Update to RubyGems master 50a8210. Important changes
drbrain 2013-11-22 08:27:30 +0900 (Fri, 22 Nov 2013) New Revision: 43767 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=43767 Log: * lib/rubygems: Update to RubyGems master 50a8210. Important changes in this commit: RubyGems now automatically checks for gem.deps.rb or Gemfile when running ruby executables. This behavior is similar to `bundle exec rake`. This change may be reverted before Ruby 2.1.0 if too many bugs are found. * test/rubygems: ditto. Modified files: trunk/ChangeLog trunk/lib/rubygems/doctor.rb trunk/lib/rubygems/exceptions.rb trunk/lib/rubygems/request_set/gem_dependency_api.rb trunk/lib/rubygems/request_set.rb trunk/lib/rubygems/resolver/api_set.rb trunk/lib/rubygems/resolver/api_specification.rb trunk/lib/rubygems/resolver/composed_set.rb trunk/lib/rubygems/resolver/conflict.rb trunk/lib/rubygems/resolver/git_set.rb trunk/lib/rubygems/resolver/requirement_list.rb trunk/lib/rubygems/resolver.rb trunk/lib/rubygems/source/git.rb trunk/lib/rubygems/source.rb trunk/lib/rubygems/specification.rb trunk/lib/rubygems/test_case.rb trunk/lib/rubygems/util.rb trunk/lib/rubygems.rb trunk/test/rubygems/test_gem.rb trunk/test/rubygems/test_gem_impossible_dependencies_error.rb trunk/test/rubygems/test_gem_request_set.rb trunk/test/rubygems/test_gem_request_set_gem_dependency_api.rb trunk/test/rubygems/test_gem_resolver.rb trunk/test/rubygems/test_gem_resolver_api_set.rb trunk/test/rubygems/test_gem_resolver_api_specification.rb trunk/test/rubygems/test_gem_resolver_conflict.rb trunk/test/rubygems/test_gem_resolver_git_set.rb trunk/test/rubygems/test_gem_source_git.rb trunk/test/rubygems/test_gem_specification.rb trunk/test/rubygems/test_gem_util.rb Index: ChangeLog =================================================================== --- ChangeLog (revision 43766) +++ ChangeLog (revision 43767) @@ -1,3 +1,15 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Nov 22 08:27:13 2013 Eric Hodel <drbrain@s...> + + * lib/rubygems: Update to RubyGems master 50a8210. Important changes + in this commit: + + RubyGems now automatically checks for gem.deps.rb or Gemfile when + running ruby executables. This behavior is similar to `bundle exec + rake`. This change may be reverted before Ruby 2.1.0 if too many bugs + are found. + + * test/rubygems: ditto. + Thu Nov 21 22:33:59 2013 Koichi Sasada <ko1@a...> * gc.c: RGENGC_CHECK_MODE should be 0. Index: lib/rubygems/request_set.rb =================================================================== --- lib/rubygems/request_set.rb (revision 43766) +++ lib/rubygems/request_set.rb (revision 43767) @@ -2,6 +2,7 @@ require 'rubygems' https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L2 require 'rubygems/dependency' require 'rubygems/dependency_list' require 'rubygems/installer' +require 'rubygems/resolver' require 'tsort' ## @@ -146,7 +147,15 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L147 resolve - install options, &block + if options[:explain] + puts "Gems to install:" + + specs.map { |s| s.full_name }.sort.each do |s| + puts " #{s}" + end + else + install options, &block + end end def install_into dir, force = true, options = {} @@ -201,7 +210,7 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L210 # Resolve the requested dependencies and return an Array of Specification # objects to be activated. - def resolve set = Gem::Resolver::IndexSet.new + def resolve set = Gem::Resolver::BestSet.new @sets << set @sets << @git_set @sets << @vendor_set @@ -253,7 +262,7 @@ class Gem::RequestSet https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set.rb#L262 end else unless @soft_missing - raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}" + raise Gem::DependencyError, "Unresolved dependency found during sorting - #{dep} (requested by #{node.spec.full_name})" end end end Index: lib/rubygems/specification.rb =================================================================== --- lib/rubygems/specification.rb (revision 43766) +++ lib/rubygems/specification.rb (revision 43767) @@ -27,6 +27,7 @@ class Date; end https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L27 # Gem::Specification.new do |s| # s.name = 'example' # s.version = '0.1.0' +# s.licenses = ['MIT'] # s.summary = "This is an example!" # s.description = "Much longer explanation of the example!" # s.authors = ["Ruby Coder"] @@ -530,6 +531,7 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L531 end ## + # :category: Recommended gemspec attributes # The license for this gem. # # The license must be a short name, no more than 64 characters. @@ -538,7 +540,12 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L540 # text of the license should be inside of the gem when you build it. # # See http://opensource.org/licenses/alphabetical for a list of licenses and - # their abbreviations (or short names). + # their abbreviations (or short names). GitHub also provides a + # license picker at http://choosealicense.com/ + # + # According to copyright law, not having an OSI-approved open source license + # means you have no rights to use the code for any purpose-- in other words, + # "all rights reserved". # # You can set multiple licenses with #licenses= # @@ -550,6 +557,7 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L557 end ## + # :category: Recommended gemspec attributes # The license(s) for the library. # # Each license must be a short name, no more than 64 characters. @@ -2526,8 +2534,8 @@ class Gem::Specification < Gem::BasicSpe https://github.com/ruby/ruby/blob/trunk/lib/rubygems/specification.rb#L2534 } warning <<-warning if licenses.empty? -licenses is empty. Use a license abbreviation from: - http://opensource.org/licenses/alphabetical +licenses is empty, but is recommended. Use a license abbreviation from: +http://opensource.org/licenses/alphabetical warning validate_permissions Index: lib/rubygems/exceptions.rb =================================================================== --- lib/rubygems/exceptions.rb (revision 43766) +++ lib/rubygems/exceptions.rb (revision 43767) @@ -223,7 +223,7 @@ class Gem::UnsatisfiableDependencyError https://github.com/ruby/ruby/blob/trunk/lib/rubygems/exceptions.rb#L223 attr_reader :dependency ## - # Creates a new UnsatisfiableDepedencyError for the unsatisfiable + # Creates a new UnsatisfiableDependencyError for the unsatisfiable # Gem::Resolver::DependencyRequest +dep+ def initialize dep, platform_mismatch=nil Index: lib/rubygems/source/git.rb =================================================================== --- lib/rubygems/source/git.rb (revision 43766) +++ lib/rubygems/source/git.rb (revision 43767) @@ -36,9 +36,11 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L36 attr_reader :need_submodules ## - # Creates a new git gem source for a gem with the given +name+ that will be - # loaded from +reference+ in +repository+. If +submodules+ is true, - # submodules will be checked out when the gem is installed. + # Creates a new git gem source for a gems from loaded from +repository+ at + # the given +reference+. The +name+ is only used to track the repository + # back to a gem dependencies file, it has no real significance as a git + # repository may contain multiple gems. If +submodules+ is true, submodules + # will be checked out when the gem is installed. def initialize name, repository, reference, submodules = false super(nil) @@ -126,34 +128,6 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L128 end ## - # Loads a Gem::Specification for +name+ from this git repository. - - def load_spec name - cache - - gemspec_reference = "#{@reference}:#{name}.gemspec" - - Dir.chdir repo_cache_dir do - source = Gem::Util.popen @git, 'show', gemspec_reference - - source.force_encoding Encoding::UTF_8 if Object.const_defined? :Encoding - source.untaint - - begin - spec = eval source, binding, gemspec_reference - - return spec if Gem::Specification === spec - - warn "git gem specification for #{@repository} #{gemspec_reference} is not a Gem::Specification (#{spec.class} instead)." - rescue SignalException, SystemExit - raise - rescue SyntaxError, Exception - warn "invalid git gem specification for #{@repository} #{gemspec_reference}" - end - end - end - - ## # The directory where the git gem's repository will be cached. def repo_cache_dir # :nodoc: @@ -164,12 +138,29 @@ class Gem::Source::Git < Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source/git.rb#L138 # Converts the git reference for the repository into a commit hash. def rev_parse # :nodoc: - # HACK no safe equivalent of ` exists on 1.8.7 Dir.chdir repo_cache_dir do Gem::Util.popen(@git, 'rev-parse', @reference).strip end end + ## + # Loads all gemspecs in the repository + + def specs + checkout + + Dir.chdir install_dir do + Dir['{,*,*/*}.gemspec'].map do |spec_file| + directory = File.dirname spec_file + file = File.basename spec_file + + Dir.chdir directory do + Gem::Specification.load file + end + end.compact + end + end + ## # A hash for the git gem based on the git repository URI. Index: lib/rubygems/util.rb =================================================================== --- lib/rubygems/util.rb (revision 43766) +++ lib/rubygems/util.rb (revision 43767) @@ -40,27 +40,24 @@ module Gem::Util https://github.com/ruby/ruby/blob/trunk/lib/rubygems/util.rb#L40 # for a command. def self.popen *command - begin - r, = IO.popen command, &:read - rescue TypeError # ruby 1.8 only supports string command - r, w = IO.pipe - - pid = fork do - STDIN.close - STDOUT.reopen w - - exec(*command) - end - - w.close - - begin - return r.read - ensure - Process.wait pid - end + IO.popen command, &:read + rescue TypeError # ruby 1.8 only supports string command + r, w = IO.pipe + + pid = fork do + STDIN.close + STDOUT.reopen w + + exec(*command) end + w.close + + begin + return r.read + ensure + Process.wait pid + end end end Index: lib/rubygems/source.rb =================================================================== --- lib/rubygems/source.rb (revision 43766) +++ lib/rubygems/source.rb (revision 43767) @@ -1,13 +1,30 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L1 require 'uri' require 'fileutils' +## +# A Source knows how to list and fetch gems from a RubyGems marshal index. +# +# There are other Source subclasses for installed gems, local gems, the +# bundler dependency API and so-forth. + class Gem::Source - FILES = { + + include Comparable + + FILES = { # :nodoc: :released => 'specs', :latest => 'latest_specs', :prerelease => 'prerelease_specs', } + ## + # The URI this source will fetch gems from. + + attr_reader :uri + + ## + # Creates a new Source which will use the index located at +uri+. + def initialize(uri) unless uri.kind_of? URI uri = URI.parse(uri.to_s) @@ -17,13 +34,17 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L34 @api_uri = nil end - attr_reader :uri + ## + # Use an SRV record on the host to look up the true endpoint for the index. - def api_uri + def api_uri # :nodoc: require 'rubygems/remote_fetcher' @api_uri ||= Gem::RemoteFetcher.fetcher.api_endpoint uri end + ## + # Sources are ordered by installation preference. + def <=>(other) case other when Gem::Source::Installed, @@ -46,13 +67,11 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L67 end end - include Comparable - - def ==(other) + def == other # :nodoc: self.class === other and @uri == other.uri end - alias_method :eql?, :== + alias_method :eql?, :== # :nodoc: ## # Returns a Set that can fetch specifications from this source. @@ -70,7 +89,7 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L89 end end - def hash + def hash # :nodoc: @uri.hash end @@ -83,6 +102,9 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L102 File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path) end + ## + # Returns true when it is possible and safe to update the cache directory. + def update_cache? @update_cache ||= begin @@ -166,6 +188,10 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L188 end end + ## + # Downloads +spec+ and writes it to +dir+. See also + # Gem::RemoteFetcher#download. + def download(spec, dir=Dir.pwd) fetcher = Gem::RemoteFetcher.fetcher fetcher.download spec, api_uri.to_s, dir @@ -176,7 +202,7 @@ class Gem::Source https://github.com/ruby/ruby/blob/trunk/lib/rubygems/source.rb#L202 q.breakable q.text @uri.to_s if api = api_uri - g.text api + q.text api.to_s end end end Index: lib/rubygems/request_set/gem_dependency_api.rb =================================================================== --- lib/rubygems/request_set/gem_dependency_api.rb (revision 43766) +++ lib/rubygems/request_set/gem_dependency_api.rb (revision 43767) @@ -115,7 +115,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L115 ## # A Hash containing gem names and files to require from those gems. - attr_reader :requires + attr_reader :requires # :nodoc: ## # A set of gems that are loaded via the +:path+ option to #gem @@ -125,7 +125,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L125 ## # The groups of gems to exclude from installation - attr_accessor :without_groups + attr_accessor :without_groups # :nodoc: ## # Creates a new GemDependencyAPI that will add dependencies to the @@ -282,6 +282,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L282 true end + private :gem_github + ## # Handles the :group and :groups +options+ for the gem with the given # +name+. @@ -361,7 +363,7 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L363 def gem_requires name, options # :nodoc: if options.include? :require then if requires = options.delete(:require) then - @requires[name].concat requires + @requires[name].concat Array requires end else @requires[name] << name @@ -370,6 +372,11 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L372 private :gem_requires + ## + # :category: Gem Dependencies DSL + # + # Block form for specifying gems from a git +repository+. + def git repository @current_repository = repository @@ -424,6 +431,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L431 ## # :category: Gem Dependencies DSL + # + # Block form for restricting gems to a particular platform. def platform what @current_platform = what @@ -436,6 +445,8 @@ class Gem::RequestSet::GemDependencyAPI https://github.com/ruby/ruby/blob/trunk/lib/rubygems/request_set/gem_dependency_api.rb#L445 ## # :category: Gem Dependencies DSL + # + # Block form for restricting gems to a particular platform. alias :platforms :platform Index: lib/rubygems/doctor.rb =================================================================== --- lib/rubygems/doctor.rb (revision 43766) +++ lib/rubygems/doctor.rb (revision 43767) @@ -27,10 +27,13 @@ class Gem::Doctor https://github.com/ruby/ruby/blob/trunk/lib/rubygems/doctor.rb#L27 ['gems', ''], ] - raise 'Update REPOSITORY_EXTENSION_MAP' unless - Gem::REPOSITORY_SUBDIRECTORIES.sort == + missing = + Gem::REPOSITORY_SUBDIRECTORIES.sort - REPOSITORY_EXTENSION_MAP.map { |(k,_)| k }.sort + raise "Update REPOSITORY_EXTENSION_MAP, missing: #{missing.join ', '}" unless + missing.empty? + ## # Creates a new Gem::Doctor that will clean up +gem_repository+. Only one # gem repository may be cleaned at a time. Index: lib/rubygems/resolver/api_set.rb =================================================================== --- lib/rubygems/resolver/api_set.rb (revision 43766) +++ lib/rubygems/resolver/api_set.rb (revision 43767) @@ -10,13 +10,28 @@ class Gem::Resolver::APISet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/api_set.rb#L10 attr_reader :dep_uri # :nodoc: ## + # The Gem::Source that gems are fetched from + + attr_reader :source + + ## + # The corresponding place to fetch gems. + + attr_reader :uri + + ## # Creates a new APISet that will retrieve gems from +uri+ using the RubyGems - # API described at http://guides.rubygems.org/rubygems-org-api + # API URL +dep_uri+ which is described at + # http://guides.rubygems.org/rubygems-org-api + + def initialize dep_uri = 'https://rubygems.org/api/v1/dependencies' + dep_uri = URI dep_uri unless URI === dep_uri # for ruby 1.8 + + @dep_uri = dep_uri + @uri = dep_uri + '../../..' - def initialize uri = 'https://rubygems.org/api/v1/dependencies' - uri = URI uri unless URI === uri # for ruby 1.8 - @data = Hash.new { |h,k| h[k] = [] } - @dep_uri = uri + @data = Hash.new { |h,k| h[k] = [] } + @source = Gem::Source.new @uri end ## @@ -41,15 +56,35 @@ class Gem::Resolver::APISet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/api_set.rb#L56 def prefetch reqs names = reqs.map { |r| r.dependency.name } - needed = names.find_all { |d| !@data.key?(d) } + needed = names - @data.keys return if needed.empty? uri = @dep_uri + "?gems=#{needed.sort.join ','}" str = Gem::RemoteFetcher.fetcher.fetch_path uri + loaded = [] + Marshal.load(str).each do |ver| - @data[ver[:name]] << ver + name = ver[:name] + + @data[name] << ver + loaded << name + end + + (needed - loaded).each do |missing| + @data[missing] = [] + end + end + + def pretty_print q # :nodoc: + q.group 2, '[APISet', ']' do + q.breakable + q.text "URI: #{@dep_uri}" + + q.breakable + q.text 'gem names:' + q.pp @data.keys end end Index: lib/rubygems/resolver/composed_set.rb =================================================================== --- lib/rubygems/resolver/composed_set.rb (revision 43766) +++ lib/rubygems/resolver/composed_set.rb (revision 43767) @@ -1,17 +1,36 @@ https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/composed_set.rb#L1 +## +# A ComposedSet allows multiple sets to be queried like a single set. +# +# To create a composed set with any number of sets use: +# +# Gem::Resolver.compose_sets set1, set2 +# +# This method will eliminate nesting of composed sets. + class Gem::Resolver::ComposedSet < Gem::Resolver::Set attr_reader :sets # :nodoc: + ## + # Creates a new ComposedSet containing +sets+. Use + # Gem::Resolver::compose_sets instead. + def initialize *sets @sets = sets end + ## + # Finds all specs matching +req+ in all sets. + def find_all req res = [] @sets.each { |s| res += s.find_all(req) } res end + ## + # Prefetches +reqs+ in all sets. + def prefetch reqs @sets.each { |s| s.prefetch(reqs) } end Index: lib/rubygems/resolver/requirement_list.rb =================================================================== --- lib/rubygems/resolver/requirement_list.rb (revision 43766) +++ lib/rubygems/resolver/requirement_list.rb (revision 43767) @@ -37,4 +37,8 @@ class Gem::Resolver::RequirementList https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/requirement_list.rb#L37 def remove @list.shift end + + def next5 + @list[0,5] + end end Index: lib/rubygems/resolver/git_set.rb =================================================================== --- lib/rubygems/resolver/git_set.rb (revision 43766) +++ lib/rubygems/resolver/git_set.rb (revision 43767) @@ -42,38 +42,27 @@ class Gem::Resolver::GitSet < Gem::Resol https://github.com/ruby/ruby/blob/trunk/lib/rubygems/resolver/git_set.rb#L42 # Finds all git gems matching +req+ def find_all req - @repositories.keys.select do |name| - name == req.name - end.map do |name| - @specs[name] || load_spec(name) - e (... truncated) -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/