summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
-rw-r--r--lib/rubygems.rb99
-rw-r--r--lib/rubygems/doctor.rb7
-rw-r--r--lib/rubygems/exceptions.rb2
-rw-r--r--lib/rubygems/request_set.rb15
-rw-r--r--lib/rubygems/request_set/gem_dependency_api.rb17
-rw-r--r--lib/rubygems/resolver.rb51
-rw-r--r--lib/rubygems/resolver/api_set.rb49
-rw-r--r--lib/rubygems/resolver/api_specification.rb37
-rw-r--r--lib/rubygems/resolver/composed_set.rb19
-rw-r--r--lib/rubygems/resolver/conflict.rb41
-rw-r--r--lib/rubygems/resolver/git_set.rb33
-rw-r--r--lib/rubygems/resolver/requirement_list.rb4
-rw-r--r--lib/rubygems/source.rb44
-rw-r--r--lib/rubygems/source/git.rb55
-rw-r--r--lib/rubygems/specification.rb14
-rw-r--r--lib/rubygems/test_case.rb6
-rw-r--r--lib/rubygems/util.rb29
17 files changed, 356 insertions, 166 deletions
@@ -215,50 +215,6 @@ module Gem
end
end
- def self.detect_gemdeps
- if path = ENV['RUBYGEMS_GEMDEPS']
- path = path.dup.untaint
-
- if path == "-"
- here = Dir.pwd.untaint
- start = here
-
- begin
- while true
- path = GEM_DEP_FILES.find { |f| File.file?(f) }
-
- if path
- path = File.join here, path
- break
- end
-
- Dir.chdir ".."
-
- # If we're at a toplevel, stop.
- return if Dir.pwd == here
-
- here = Dir.pwd
- end
- ensure
- Dir.chdir start
- end
- end
-
- path.untaint
-
- return unless File.file? path
-
- rs = Gem::RequestSet.new
- rs.load_gemdeps path
-
- rs.resolve_current.map do |s|
- sp = s.full_spec
- sp.activate
- sp
- end
- end
- end
-
##
# Find the full path to the executable for gem +name+. If the +exec_name+
# is not given, the gem's default_executable is chosen, otherwise the
@@ -1035,6 +991,61 @@ module Gem
load_plugin_files files
end
# FIX: Almost everywhere else we use the `def self.` way of defining class
# methods, and then we switch over to `class << self` here. Pick one or the
# other.
@@ -27,10 +27,13 @@ class Gem::Doctor
['gems', ''],
]
- raise 'Update REPOSITORY_EXTENSION_MAP' unless
- Gem::REPOSITORY_SUBDIRECTORIES.sort ==
REPOSITORY_EXTENSION_MAP.map { |(k,_)| k }.sort
##
# Creates a new Gem::Doctor that will clean up +gem_repository+. Only one
# gem repository may be cleaned at a time.
@@ -223,7 +223,7 @@ class Gem::UnsatisfiableDependencyError < Gem::Exception
attr_reader :dependency
##
- # Creates a new UnsatisfiableDepedencyError for the unsatisfiable
# Gem::Resolver::DependencyRequest +dep+
def initialize dep, platform_mismatch=nil
@@ -2,6 +2,7 @@ require 'rubygems'
require 'rubygems/dependency'
require 'rubygems/dependency_list'
require 'rubygems/installer'
require 'tsort'
##
@@ -146,7 +147,15 @@ class Gem::RequestSet
resolve
- install options, &block
end
def install_into dir, force = true, options = {}
@@ -201,7 +210,7 @@ class Gem::RequestSet
# Resolve the requested dependencies and return an Array of Specification
# objects to be activated.
- def resolve set = Gem::Resolver::IndexSet.new
@sets << set
@sets << @git_set
@sets << @vendor_set
@@ -253,7 +262,7 @@ class Gem::RequestSet
end
else
unless @soft_missing
- raise Gem::DependencyError, "Unresolved depedency found during sorting - #{dep}"
end
end
end
@@ -115,7 +115,7 @@ class Gem::RequestSet::GemDependencyAPI
##
# A Hash containing gem names and files to require from those gems.
- attr_reader :requires
##
# A set of gems that are loaded via the +:path+ option to #gem
@@ -125,7 +125,7 @@ class Gem::RequestSet::GemDependencyAPI
##
# The groups of gems to exclude from installation
- attr_accessor :without_groups
##
# Creates a new GemDependencyAPI that will add dependencies to the
@@ -282,6 +282,8 @@ class Gem::RequestSet::GemDependencyAPI
true
end
##
# Handles the :group and :groups +options+ for the gem with the given
# +name+.
@@ -361,7 +363,7 @@ class Gem::RequestSet::GemDependencyAPI
def gem_requires name, options # :nodoc:
if options.include? :require then
if requires = options.delete(:require) then
- @requires[name].concat requires
end
else
@requires[name] << name
@@ -370,6 +372,11 @@ class Gem::RequestSet::GemDependencyAPI
private :gem_requires
def git repository
@current_repository = repository
@@ -424,6 +431,8 @@ class Gem::RequestSet::GemDependencyAPI
##
# :category: Gem Dependencies DSL
def platform what
@current_platform = what
@@ -436,6 +445,8 @@ class Gem::RequestSet::GemDependencyAPI
##
# :category: Gem Dependencies DSL
alias :platforms :platform
@@ -29,9 +29,23 @@ class Gem::Resolver
attr_accessor :soft_missing
def self.compose_sets *sets
sets.compact!
case sets.length
when 0 then
raise ArgumentError, 'one set in the composition must be non-nil'
@@ -77,6 +91,15 @@ class Gem::Resolver
end
end
##
# Creates an ActivationRequest for the given +dep+ and the last +possible+
# specification.
@@ -134,8 +157,6 @@ class Gem::Resolver
# If no good candidate is found, the first state is tried.
def find_conflict_state conflict, states # :nodoc:
- rejected = []
-
until states.empty? do
state = states.pop
@@ -145,14 +166,9 @@ class Gem::Resolver
state.conflicts << [state.spec, conflict]
return state
end
-
- rejected << state
end
- return rejected.shift
- ensure
- rejected = rejected.concat states
- states.replace rejected
end
##
@@ -172,14 +188,23 @@ class Gem::Resolver
# If the existing activation indicates that there are other possibles for
# it, then issue the conflict on the dependency for the activation itself.
- # Otherwise, issue it on the requester's request itself.
- if existing.others_possible? or existing.request.requester.nil? then
conflict =
Gem::Resolver::Conflict.new dep, existing
- else
depreq = dep.requester.request
conflict =
Gem::Resolver::Conflict.new depreq, existing, dep
end
@conflicts << conflict unless @conflicts.include? conflict
@@ -234,6 +259,8 @@ class Gem::Resolver
while !needed.empty?
dep = needed.remove
explain :try, [dep, dep.requester ? dep.requester.request : :toplevel]
# If there is already a spec activated for the requested name...
if specs && existing = specs.find { |s| dep.name == s.name }
@@ -284,7 +311,7 @@ class Gem::Resolver
# Retry resolution with this spec and add it's dependencies
spec, act = activation_request state.dep, state.possibles
- needed = requests spec, act, state.needed
specs = Gem::List.prepend state.specs, act
return needed, specs
@@ -10,13 +10,28 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
attr_reader :dep_uri # :nodoc:
##
# Creates a new APISet that will retrieve gems from +uri+ using the RubyGems
- # API described at http://guides.rubygems.org/rubygems-org-api
- 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
end
##
@@ -41,15 +56,35 @@ class Gem::Resolver::APISet < Gem::Resolver::Set
def prefetch reqs
names = reqs.map { |r| r.dependency.name }
- needed = names.find_all { |d| [email protected]?(d) }
return if needed.empty?
uri = @dep_uri + "?gems=#{needed.sort.join ','}"
str = Gem::RemoteFetcher.fetcher.fetch_path uri
Marshal.load(str).each do |ver|
- @data[ver[:name]] << ver
end
end
@@ -34,5 +34,42 @@ class Gem::Resolver::APISpecification < Gem::Resolver::Specification
@dependencies == other.dependencies
end
end
@@ -1,17 +1,36 @@
class Gem::Resolver::ComposedSet < Gem::Resolver::Set
attr_reader :sets # :nodoc:
def initialize *sets
@sets = sets
end
def find_all req
res = []
@sets.each { |s| res += s.find_all(req) }
res
end
def prefetch reqs
@sets.each { |s| s.prefetch(reqs) }
end
@@ -4,25 +4,38 @@
class Gem::Resolver::Conflict
attr_reader :activated
attr_reader :dependency
attr_reader :failed_dep # :nodoc:
def initialize(dependency, activated, failed_dep=dependency)
@dependency = dependency
@activated = activated
@failed_dep = failed_dep
end
- def == other
self.class === other and
@dependency == other.dependency and
@activated == other.activated and
@failed_dep == other.failed_dep
end
def explain
"<Conflict wanted: #{@failed_dep}, had: #{activated.spec.full_name}>"
end
@@ -41,11 +54,15 @@ class Gem::Resolver::Conflict
activated = @activated.spec.full_name
requirement = @failed_dep.dependency.requirement
- " Activated %s instead of (%s) via:\n %s\n" % [
- activated, requirement, request_path.join(', ')
]
end
def for_spec?(spec)
@dependency.name == spec.name
end
@@ -72,16 +89,17 @@ class Gem::Resolver::Conflict
end
##
- # Path of specifications that requested this dependency
- def request_path
- current = requester
- path = []
while current do
- path << current.spec.full_name
- current = current.request.requester
end
path = ['user request (gem command or Gemfile)'] if path.empty?
@@ -98,5 +116,8 @@ class Gem::Resolver::Conflict
end
-Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict
@@ -42,38 +42,27 @@ class Gem::Resolver::GitSet < Gem::Resolver::Set
# 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)
- end.select do |spec|
req.matches_spec? spec
end
end
- def load_spec name
- repository, reference = @repositories[name]
-
- source = Gem::Source::Git.new name, repository, reference
-
- spec = source.load_spec name
-
- git_spec =
- Gem::Resolver::GitSpecification.new self, spec, source
-
- @specs[name] = git_spec
- end
-
##
# Prefetches specifications from the git repositories in this set.
def prefetch reqs
- names = reqs.map { |req| req.name }
- @repositories.each_key do |name|
- next unless names.include? name
- load_spec name
end
end
@@ -37,4 +37,8 @@ class Gem::Resolver::RequirementList
def remove
@list.shift
end
end
@@ -1,13 +1,30 @@
require 'uri'
require 'fileutils'
class Gem::Source
- FILES = {
:released => 'specs',
:latest => 'latest_specs',
:prerelease => 'prerelease_specs',
}
def initialize(uri)
unless uri.kind_of? URI
uri = URI.parse(uri.to_s)
@@ -17,13 +34,17 @@ class Gem::Source
@api_uri = nil
end
- attr_reader :uri
- def api_uri
require 'rubygems/remote_fetcher'
@api_uri ||= Gem::RemoteFetcher.fetcher.api_endpoint uri
end
def <=>(other)
case other
when Gem::Source::Installed,
@@ -46,13 +67,11 @@ class Gem::Source
end
end
- include Comparable
-
- def ==(other)
self.class === other and @uri == other.uri
end
- alias_method :eql?, :==
##
# Returns a Set that can fetch specifications from this source.
@@ -70,7 +89,7 @@ class Gem::Source
end
end
- def hash
@uri.hash
end
@@ -83,6 +102,9 @@ class Gem::Source
File.join Gem.spec_cache_dir, "#{uri.host}%#{uri.port}", File.dirname(escaped_path)
end
def update_cache?
@update_cache ||=
begin
@@ -166,6 +188,10 @@ class Gem::Source
end
end
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
q.breakable
q.text @uri.to_s
if api = api_uri
- g.text api
end
end
end
@@ -36,9 +36,11 @@ class Gem::Source::Git < Gem::Source
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.
def initialize name, repository, reference, submodules = false
super(nil)
@@ -126,34 +128,6 @@ class Gem::Source::Git < Gem::Source
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,13 +138,30 @@ class Gem::Source::Git < Gem::Source
# 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
##
# A hash for the git gem based on the git repository URI.
def uri_hash # :nodoc:
@@ -27,6 +27,7 @@ class Date; end
# Gem::Specification.new do |s|
# s.name = 'example'
# s.version = '0.1.0'
# 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::BasicSpecification
end
##
# 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::BasicSpecification
# 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).
#
# You can set multiple licenses with #licenses=
#
@@ -550,6 +557,7 @@ class Gem::Specification < Gem::BasicSpecification
end
##
# 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::BasicSpecification
}
warning <<-warning if licenses.empty?
-licenses is empty. Use a license abbreviation from:
- http://opensource.org/licenses/alphabetical
warning
validate_permissions
@@ -1149,8 +1149,10 @@ Also, a list:
def dependency_request dep, from_name, from_version, parent = nil
remote = Gem::Source.new @uri
- parent ||= Gem::Resolver::DependencyRequest.new \
- dep, nil
spec = Gem::Resolver::IndexSpecification.new \
nil, from_name, from_version, remote, Gem::Platform::RUBY
@@ -40,27 +40,24 @@ module Gem::Util
# 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
end
-
end
end