From fcbf63e62c627deae76c1b8cb8c0876c536ed811 Mon Sep 17 00:00:00 2001
From: Jari Vetoniemi <jari.vetoniemi@indooratlas.com>
Date: Mon, 16 Mar 2020 18:49:26 +0900
Subject: Fresh start

---
 .../lib/rubygems/resolver/activation_request.rb    | 172 ++++++++++++++++
 jni/ruby/lib/rubygems/resolver/api_set.rb          | 125 ++++++++++++
 .../lib/rubygems/resolver/api_specification.rb     |  85 ++++++++
 jni/ruby/lib/rubygems/resolver/best_set.rb         |  78 +++++++
 jni/ruby/lib/rubygems/resolver/composed_set.rb     |  66 ++++++
 jni/ruby/lib/rubygems/resolver/conflict.rb         | 160 +++++++++++++++
 jni/ruby/lib/rubygems/resolver/current_set.rb      |  13 ++
 .../lib/rubygems/resolver/dependency_request.rb    | 116 +++++++++++
 jni/ruby/lib/rubygems/resolver/git_set.rb          | 122 +++++++++++
 .../lib/rubygems/resolver/git_specification.rb     |  59 ++++++
 jni/ruby/lib/rubygems/resolver/index_set.rb        |  80 ++++++++
 .../lib/rubygems/resolver/index_specification.rb   |  69 +++++++
 .../rubygems/resolver/installed_specification.rb   |  58 ++++++
 jni/ruby/lib/rubygems/resolver/installer_set.rb    | 224 +++++++++++++++++++++
 .../lib/rubygems/resolver/local_specification.rb   |  41 ++++
 jni/ruby/lib/rubygems/resolver/lock_set.rb         |  84 ++++++++
 .../lib/rubygems/resolver/lock_specification.rb    |  84 ++++++++
 jni/ruby/lib/rubygems/resolver/requirement_list.rb |  81 ++++++++
 jni/ruby/lib/rubygems/resolver/set.rb              |  56 ++++++
 .../lib/rubygems/resolver/spec_specification.rb    |  56 ++++++
 jni/ruby/lib/rubygems/resolver/specification.rb    | 110 ++++++++++
 jni/ruby/lib/rubygems/resolver/stats.rb            |  44 ++++
 jni/ruby/lib/rubygems/resolver/vendor_set.rb       |  87 ++++++++
 .../lib/rubygems/resolver/vendor_specification.rb  |  24 +++
 24 files changed, 2094 insertions(+)
 create mode 100644 jni/ruby/lib/rubygems/resolver/activation_request.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/api_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/api_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/best_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/composed_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/conflict.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/current_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/dependency_request.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/git_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/git_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/index_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/index_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/installed_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/installer_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/local_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/lock_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/lock_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/requirement_list.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/spec_specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/specification.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/stats.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/vendor_set.rb
 create mode 100644 jni/ruby/lib/rubygems/resolver/vendor_specification.rb

(limited to 'jni/ruby/lib/rubygems/resolver')

diff --git a/jni/ruby/lib/rubygems/resolver/activation_request.rb b/jni/ruby/lib/rubygems/resolver/activation_request.rb
new file mode 100644
index 0000000..56c6363
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/activation_request.rb
@@ -0,0 +1,172 @@
+##
+# Specifies a Specification object that should be activated.  Also contains a
+# dependency that was used to introduce this activation.
+
+class Gem::Resolver::ActivationRequest
+
+  ##
+  # The parent request for this activation request.
+
+  attr_reader :request
+
+  ##
+  # The specification to be activated.
+
+  attr_reader :spec
+
+  ##
+  # Creates a new ActivationRequest that will activate +spec+.  The parent
+  # +request+ is used to provide diagnostics in case of conflicts.
+  #
+  # +others_possible+ indicates that other specifications may also match this
+  # activation request.
+
+  def initialize spec, request, others_possible = true
+    @spec = spec
+    @request = request
+    @others_possible = others_possible
+  end
+
+  def == other # :nodoc:
+    case other
+    when Gem::Specification
+      @spec == other
+    when Gem::Resolver::ActivationRequest
+      @spec == other.spec && @request == other.request
+    else
+      false
+    end
+  end
+
+  ##
+  # Is this activation request for a development dependency?
+
+  def development?
+    @request.development?
+  end
+
+  ##
+  # Downloads a gem at +path+ and returns the file path.
+
+  def download path
+    if @spec.respond_to? :source
+      source = @spec.source
+    else
+      source = Gem.sources.first
+    end
+
+    Gem.ensure_gem_subdirectories path
+
+    source.download full_spec, path
+  end
+
+  ##
+  # The full name of the specification to be activated.
+
+  def full_name
+    @spec.full_name
+  end
+
+  ##
+  # The Gem::Specification for this activation request.
+
+  def full_spec
+    Gem::Specification === @spec ? @spec : @spec.spec
+  end
+
+  def inspect # :nodoc:
+    others =
+      case @others_possible
+      when true then # TODO remove at RubyGems 3
+        ' (others possible)'
+      when false then # TODO remove at RubyGems 3
+        nil
+      else
+        unless @others_possible.empty? then
+          others = @others_possible.map { |s| s.full_name }
+          " (others possible: #{others.join ', '})"
+        end
+      end
+
+    '#<%s for %p from %s%s>' % [
+      self.class, @spec, @request, others
+    ]
+  end
+
+  ##
+  # True if the requested gem has already been installed.
+
+  def installed?
+    case @spec
+    when Gem::Resolver::VendorSpecification then
+      true
+    else
+      this_spec = full_spec
+
+      Gem::Specification.any? do |s|
+        s == this_spec
+      end
+    end
+  end
+
+  ##
+  # The name of this activation request's specification
+
+  def name
+    @spec.name
+  end
+
+  ##
+  # Indicate if this activation is one of a set of possible
+  # requests for the same Dependency request.
+
+  def others_possible?
+    case @others_possible
+    when true, false then
+      @others_possible
+    else
+      not @others_possible.empty?
+    end
+  end
+
+  ##
+  # Return the ActivationRequest that contained the dependency
+  # that we were activated for.
+
+  def parent
+    @request.requester
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[Activation request', ']' do
+      q.breakable
+      q.pp @spec
+
+      q.breakable
+      q.text ' for '
+      q.pp @request
+
+      case @others_possible
+      when false then
+      when true then
+        q.breakable
+        q.text 'others possible'
+      else
+        unless @others_possible.empty? then
+          q.breakable
+          q.text 'others '
+          q.pp @others_possible.map { |s| s.full_name }
+        end
+      end
+    end
+  end
+
+  ##
+  # The version of this activation request's specification
+
+  def version
+    @spec.version
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/api_set.rb b/jni/ruby/lib/rubygems/resolver/api_set.rb
new file mode 100644
index 0000000..17d602f
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/api_set.rb
@@ -0,0 +1,125 @@
+##
+# The global rubygems pool, available via the rubygems.org API.
+# Returns instances of APISpecification.
+
+class Gem::Resolver::APISet < Gem::Resolver::Set
+
+  ##
+  # The URI for the dependency API this APISet uses.
+
+  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 URL +dep_uri+ which is described at
+  # http://guides.rubygems.org/rubygems-org-api
+
+  def initialize dep_uri = 'https://rubygems.org/api/v1/dependencies'
+    super()
+
+    dep_uri = URI dep_uri unless URI === dep_uri # for ruby 1.8
+
+    @dep_uri = dep_uri
+    @uri     = dep_uri + '../..'
+
+    @data   = Hash.new { |h,k| h[k] = [] }
+    @source = Gem::Source.new @uri
+
+    @to_fetch = []
+  end
+
+  ##
+  # Return an array of APISpecification objects matching
+  # DependencyRequest +req+.
+
+  def find_all req
+    res = []
+
+    return res unless @remote
+
+    if @to_fetch.include?(req.name)
+      prefetch_now
+    end
+
+    versions(req.name).each do |ver|
+      if req.dependency.match? req.name, ver[:number]
+        res << Gem::Resolver::APISpecification.new(self, ver)
+      end
+    end
+
+    res
+  end
+
+  ##
+  # A hint run by the resolver to allow the Set to fetch
+  # data for DependencyRequests +reqs+.
+
+  def prefetch reqs
+    return unless @remote
+    names = reqs.map { |r| r.dependency.name }
+    needed = names - @data.keys - @to_fetch
+
+    @to_fetch += needed
+  end
+
+  def prefetch_now # :nodoc:
+    needed, @to_fetch = @to_fetch, []
+
+    uri = @dep_uri + "?gems=#{needed.sort.join ','}"
+    str = Gem::RemoteFetcher.fetcher.fetch_path uri
+
+    loaded = []
+
+    Marshal.load(str).each do |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
+
+  ##
+  # Return data for all versions of the gem +name+.
+
+  def versions name # :nodoc:
+    if @data.key?(name)
+      return @data[name]
+    end
+
+    uri = @dep_uri + "?gems=#{name}"
+    str = Gem::RemoteFetcher.fetcher.fetch_path uri
+
+    Marshal.load(str).each do |ver|
+      @data[ver[:name]] << ver
+    end
+
+    @data[name]
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/api_specification.rb b/jni/ruby/lib/rubygems/resolver/api_specification.rb
new file mode 100644
index 0000000..4960e66
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/api_specification.rb
@@ -0,0 +1,85 @@
+##
+# Represents a specification retrieved via the rubygems.org API.
+#
+# This is used to avoid loading the full Specification object when all we need
+# is the name, version, and dependencies.
+
+class Gem::Resolver::APISpecification < Gem::Resolver::Specification
+
+  ##
+  # Creates an APISpecification for the given +set+ from the rubygems.org
+  # +api_data+.
+  #
+  # See http://guides.rubygems.org/rubygems-org-api/#misc_methods for the
+  # format of the +api_data+.
+
+  def initialize(set, api_data)
+    super()
+
+    @set = set
+    @name = api_data[:name]
+    @version = Gem::Version.new api_data[:number]
+    @platform = Gem::Platform.new api_data[:platform]
+    @dependencies = api_data[:dependencies].map do |name, ver|
+      Gem::Dependency.new name, ver.split(/\s*,\s*/)
+    end
+  end
+
+  def == other # :nodoc:
+    self.class === other and
+      @set          == other.set and
+      @name         == other.name and
+      @version      == other.version and
+      @platform     == other.platform and
+      @dependencies == other.dependencies
+  end
+
+  def fetch_development_dependencies # :nodoc:
+    spec = source.fetch_spec Gem::NameTuple.new @name, @version, @platform
+
+    @dependencies = spec.dependencies
+  end
+
+  def installable_platform? # :nodoc:
+    Gem::Platform.match @platform
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[APISpecification', ']' do
+      q.breakable
+      q.text "name: #{name}"
+
+      q.breakable
+      q.text "version: #{version}"
+
+      q.breakable
+      q.text "platform: #{platform}"
+
+      q.breakable
+      q.text 'dependencies:'
+      q.breakable
+      q.pp @dependencies
+
+      q.breakable
+      q.text "set uri: #{@set.dep_uri}"
+    end
+  end
+
+  ##
+  # Fetches a Gem::Specification for this APISpecification.
+
+  def spec # :nodoc:
+    @spec ||=
+      begin
+        tuple = Gem::NameTuple.new @name, @version, @platform
+
+        source.fetch_spec tuple
+      end
+  end
+
+  def source # :nodoc:
+    @set.source
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/best_set.rb b/jni/ruby/lib/rubygems/resolver/best_set.rb
new file mode 100644
index 0000000..7e2d7e2
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/best_set.rb
@@ -0,0 +1,78 @@
+##
+# The BestSet chooses the best available method to query a remote index.
+#
+# It combines IndexSet and APISet
+
+class Gem::Resolver::BestSet < Gem::Resolver::ComposedSet
+
+  ##
+  # Creates a BestSet for the given +sources+ or Gem::sources if none are
+  # specified.  +sources+ must be a Gem::SourceList.
+
+  def initialize sources = Gem.sources
+    super()
+
+    @sources = sources
+  end
+
+  ##
+  # Picks which sets to use for the configured sources.
+
+  def pick_sets # :nodoc:
+    @sources.each_source do |source|
+      @sets << source.dependency_resolver_set
+    end
+  end
+
+  def find_all req # :nodoc:
+    pick_sets if @remote and @sets.empty?
+
+    super
+  rescue Gem::RemoteFetcher::FetchError => e
+    replace_failed_api_set e
+
+    retry
+  end
+
+  def prefetch reqs # :nodoc:
+    pick_sets if @remote and @sets.empty?
+
+    super
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[BestSet', ']' do
+      q.breakable
+      q.text 'sets:'
+
+      q.breakable
+      q.pp @sets
+    end
+  end
+
+  ##
+  # Replaces a failed APISet for the URI in +error+ with an IndexSet.
+  #
+  # If no matching APISet can be found the original +error+ is raised.
+  #
+  # The calling method must retry the exception to repeat the lookup.
+
+  def replace_failed_api_set error # :nodoc:
+    uri = error.uri
+    uri = URI uri unless URI === uri
+    uri.query = nil
+
+    raise error unless api_set = @sets.find { |set|
+      Gem::Resolver::APISet === set and set.dep_uri == uri
+    }
+
+    index_set = Gem::Resolver::IndexSet.new api_set.source
+
+    @sets.map! do |set|
+      next set unless set == api_set
+      index_set
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/composed_set.rb b/jni/ruby/lib/rubygems/resolver/composed_set.rb
new file mode 100644
index 0000000..5b08f12
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/composed_set.rb
@@ -0,0 +1,66 @@
+##
+# 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
+    super()
+
+    @sets = sets
+  end
+
+  ##
+  # When +allow_prerelease+ is set to +true+ prereleases gems are allowed to
+  # match dependencies.
+
+  def prerelease= allow_prerelease
+    super
+
+    sets.each do |set|
+      set.prerelease = allow_prerelease
+    end
+  end
+
+  ##
+  # Sets the remote network access for all composed sets.
+
+  def remote= remote
+    super
+
+    @sets.each { |set| set.remote = remote }
+  end
+
+  def errors
+    @errors + @sets.map { |set| set.errors }.flatten
+  end
+
+  ##
+  # Finds all specs matching +req+ in all sets.
+
+  def find_all req
+    @sets.map do |s|
+      s.find_all req
+    end.flatten
+  end
+
+  ##
+  # Prefetches +reqs+ in all sets.
+
+  def prefetch reqs
+    @sets.each { |s| s.prefetch(reqs) }
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/conflict.rb b/jni/ruby/lib/rubygems/resolver/conflict.rb
new file mode 100644
index 0000000..902c286
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/conflict.rb
@@ -0,0 +1,160 @@
+##
+# Used internally to indicate that a dependency conflicted
+# with a spec that would be activated.
+
+class Gem::Resolver::Conflict
+
+  ##
+  # The specification that was activated prior to the conflict
+
+  attr_reader :activated
+
+  ##
+  # The dependency that is in conflict with the activated gem.
+
+  attr_reader :dependency
+
+  attr_reader :failed_dep # :nodoc:
+
+  ##
+  # Creates a new resolver conflict when +dependency+ is in conflict with an
+  # already +activated+ specification.
+
+  def initialize(dependency, activated, failed_dep=dependency)
+    @dependency = dependency
+    @activated = activated
+    @failed_dep = failed_dep
+  end
+
+  def == other # :nodoc:
+    self.class === other and
+      @dependency == other.dependency and
+      @activated  == other.activated  and
+      @failed_dep == other.failed_dep
+  end
+
+  ##
+  # A string explanation of the conflict.
+
+  def explain
+    "<Conflict wanted: #{@failed_dep}, had: #{activated.spec.full_name}>"
+  end
+
+  ##
+  # Return the 2 dependency objects that conflicted
+
+  def conflicting_dependencies
+    [@failed_dep.dependency, @activated.request.dependency]
+  end
+
+  ##
+  # Explanation of the conflict used by exceptions to print useful messages
+
+  def explanation
+    activated   = @activated.spec.full_name
+    dependency  = @failed_dep.dependency
+    requirement = dependency.requirement
+    alternates  = dependency.matching_specs.map { |spec| spec.full_name }
+
+    unless alternates.empty? then
+      matching = <<-MATCHING.chomp
+
+  Gems matching %s:
+    %s
+      MATCHING
+
+      matching = matching % [
+        dependency,
+        alternates.join(', '),
+      ]
+    end
+
+    explanation = <<-EXPLANATION
+  Activated %s
+  which does not match conflicting dependency (%s)
+
+  Conflicting dependency chains:
+    %s
+
+  versus:
+    %s
+%s
+    EXPLANATION
+
+    explanation % [
+      activated, requirement,
+      request_path(@activated).reverse.join(", depends on\n    "),
+      request_path(@failed_dep).reverse.join(", depends on\n    "),
+      matching,
+    ]
+  end
+
+  ##
+  # Returns true if the conflicting dependency's name matches +spec+.
+
+  def for_spec?(spec)
+    @dependency.name == spec.name
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[Dependency conflict: ', ']' do
+      q.breakable
+
+      q.text 'activated '
+      q.pp @activated
+
+      q.breakable
+      q.text ' dependency '
+      q.pp @dependency
+
+      q.breakable
+      if @dependency == @failed_dep then
+        q.text ' failed'
+      else
+        q.text ' failed dependency '
+        q.pp @failed_dep
+      end
+    end
+  end
+
+  ##
+  # Path of activations from the +current+ list.
+
+  def request_path current
+    path = []
+
+    while current do
+      case current
+      when Gem::Resolver::ActivationRequest then
+        path <<
+          "#{current.request.dependency}, #{current.spec.version} activated"
+
+        current = current.parent
+      when Gem::Resolver::DependencyRequest then
+        path << "#{current.dependency}"
+
+        current = current.requester
+      else
+        raise Gem::Exception, "[BUG] unknown request class #{current.class}"
+      end
+    end
+
+    path = ['user request (gem command or Gemfile)'] if path.empty?
+
+    path
+  end
+
+  ##
+  # Return the Specification that listed the dependency
+
+  def requester
+    @failed_dep.requester
+  end
+
+end
+
+##
+# TODO: Remove in RubyGems 3
+
+Gem::Resolver::DependencyConflict = Gem::Resolver::Conflict # :nodoc:
+
diff --git a/jni/ruby/lib/rubygems/resolver/current_set.rb b/jni/ruby/lib/rubygems/resolver/current_set.rb
new file mode 100644
index 0000000..4e8d340
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/current_set.rb
@@ -0,0 +1,13 @@
+##
+# A set which represents the installed gems. Respects
+# all the normal settings that control where to look
+# for installed gems.
+
+class Gem::Resolver::CurrentSet < Gem::Resolver::Set
+
+  def find_all req
+    req.dependency.matching_specs
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/dependency_request.rb b/jni/ruby/lib/rubygems/resolver/dependency_request.rb
new file mode 100644
index 0000000..79690be
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/dependency_request.rb
@@ -0,0 +1,116 @@
+##
+# Used Internally. Wraps a Dependency object to also track which spec
+# contained the Dependency.
+
+class Gem::Resolver::DependencyRequest
+
+  ##
+  # The wrapped Gem::Dependency
+
+  attr_reader :dependency
+
+  ##
+  # The request for this dependency.
+
+  attr_reader :requester
+
+  ##
+  # Creates a new DependencyRequest for +dependency+ from +requester+.
+  # +requester may be nil if the request came from a user.
+
+  def initialize dependency, requester
+    @dependency = dependency
+    @requester  = requester
+  end
+
+  def == other # :nodoc:
+    case other
+    when Gem::Dependency
+      @dependency == other
+    when Gem::Resolver::DependencyRequest
+      @dependency == other.dependency && @requester == other.requester
+    else
+      false
+    end
+  end
+
+  ##
+  # Is this dependency a development dependency?
+
+  def development?
+    @dependency.type == :development
+  end
+
+  ##
+  # Does this dependency request match +spec+?
+  #
+  # NOTE:  #match? only matches prerelease versions when #dependency is a
+  # prerelease dependency.
+
+  def match? spec, allow_prerelease = false
+    @dependency.match? spec, nil, allow_prerelease
+  end
+
+  ##
+  # Does this dependency request match +spec+?
+  #
+  # NOTE:  #matches_spec? matches prerelease versions.  See also #match?
+
+  def matches_spec?(spec)
+    @dependency.matches_spec? spec
+  end
+
+  ##
+  # The name of the gem this dependency request is requesting.
+
+  def name
+    @dependency.name
+  end
+
+  ##
+  # Indicate that the request is for a gem explicitly requested by the user
+
+  def explicit?
+    @requester.nil?
+  end
+
+  ##
+  # Indicate that the request is for a gem requested as a dependency of
+  # another gem
+
+  def implicit?
+    !explicit?
+  end
+
+  ##
+  # Return a String indicating who caused this request to be added (only
+  # valid for implicit requests)
+
+  def request_context
+    @requester ? @requester.request : "(unknown)"
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[Dependency request ', ']' do
+      q.breakable
+      q.text @dependency.to_s
+
+      q.breakable
+      q.text ' requested by '
+      q.pp @requester
+    end
+  end
+
+  ##
+  # The version requirement for this dependency request
+
+  def requirement
+    @dependency.requirement
+  end
+
+  def to_s # :nodoc:
+    @dependency.to_s
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/git_set.rb b/jni/ruby/lib/rubygems/resolver/git_set.rb
new file mode 100644
index 0000000..5f1b368
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/git_set.rb
@@ -0,0 +1,122 @@
+##
+# A GitSet represents gems that are sourced from git repositories.
+#
+# This is used for gem dependency file support.
+#
+# Example:
+#
+#   set = Gem::Resolver::GitSet.new
+#   set.add_git_gem 'rake', 'git://example/rake.git', tag: 'rake-10.1.0'
+
+class Gem::Resolver::GitSet < Gem::Resolver::Set
+
+  ##
+  # The root directory for git gems in this set.  This is usually Gem.dir, the
+  # installation directory for regular gems.
+
+  attr_accessor :root_dir
+
+  ##
+  # Contains repositories needing submodules
+
+  attr_reader :need_submodules # :nodoc:
+
+  ##
+  # A Hash containing git gem names for keys and a Hash of repository and
+  # git commit reference as values.
+
+  attr_reader :repositories # :nodoc:
+
+  ##
+  # A hash of gem names to Gem::Resolver::GitSpecifications
+
+  attr_reader :specs # :nodoc:
+
+  def initialize # :nodoc:
+    super()
+
+    @git             = ENV['git'] || 'git'
+    @need_submodules = {}
+    @repositories    = {}
+    @root_dir        = Gem.dir
+    @specs           = {}
+  end
+
+  def add_git_gem name, repository, reference, submodules # :nodoc:
+    @repositories[name] = [repository, reference]
+    @need_submodules[repository] = submodules
+  end
+
+  ##
+  # Adds and returns a GitSpecification with the given +name+ and +version+
+  # which came from a +repository+ at the given +reference+.  If +submodules+
+  # is true they are checked out along with the repository.
+  #
+  # This fills in the prefetch information as enough information about the gem
+  # is present in the arguments.
+
+  def add_git_spec name, version, repository, reference, submodules # :nodoc:
+    add_git_gem name, repository, reference, submodules
+
+    source = Gem::Source::Git.new name, repository, reference
+    source.root_dir = @root_dir
+
+    spec = Gem::Specification.new do |s|
+      s.name    = name
+      s.version = version
+    end
+
+    git_spec = Gem::Resolver::GitSpecification.new self, spec, source
+
+    @specs[spec.name] = git_spec
+
+    git_spec
+  end
+
+  ##
+  # Finds all git gems matching +req+
+
+  def find_all req
+    prefetch nil
+
+    specs.values.select do |spec|
+      req.match? spec
+    end
+  end
+
+  ##
+  # Prefetches specifications from the git repositories in this set.
+
+  def prefetch reqs
+    return unless @specs.empty?
+
+    @repositories.each do |name, (repository, reference)|
+      source = Gem::Source::Git.new name, repository, reference
+      source.root_dir = @root_dir
+      source.remote = @remote
+
+      source.specs.each do |spec|
+        git_spec = Gem::Resolver::GitSpecification.new self, spec, source
+
+        @specs[spec.name] = git_spec
+      end
+    end
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[GitSet', ']' do
+      next if @repositories.empty?
+      q.breakable
+
+      repos = @repositories.map do |name, (repository, reference)|
+        "#{name}: #{repository}@#{reference}"
+      end
+
+      q.seplist repos do |repo|
+        q.text repo
+      end
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/git_specification.rb b/jni/ruby/lib/rubygems/resolver/git_specification.rb
new file mode 100644
index 0000000..55e180e
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/git_specification.rb
@@ -0,0 +1,59 @@
+##
+# A GitSpecification represents a gem that is sourced from a git repository
+# and is being loaded through a gem dependencies file through the +git:+
+# option.
+
+class Gem::Resolver::GitSpecification < Gem::Resolver::SpecSpecification
+
+  def == other # :nodoc:
+    self.class === other and
+      @set  == other.set and
+      @spec == other.spec and
+      @source == other.source
+  end
+
+  def add_dependency dependency # :nodoc:
+    spec.dependencies << dependency
+  end
+
+  ##
+  # Installing a git gem only involves building the extensions and generating
+  # the executables.
+
+  def install options = {}
+    require 'rubygems/installer'
+
+    installer = Gem::Installer.new '', options
+    installer.spec = spec
+
+    yield installer if block_given?
+
+    installer.run_pre_install_hooks
+    installer.build_extensions
+    installer.run_post_build_hooks
+    installer.generate_bin
+    installer.run_post_install_hooks
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[GitSpecification', ']' do
+      q.breakable
+      q.text "name: #{name}"
+
+      q.breakable
+      q.text "version: #{version}"
+
+      q.breakable
+      q.text 'dependencies:'
+      q.breakable
+      q.pp dependencies
+
+      q.breakable
+      q.text "source:"
+      q.breakable
+      q.pp @source
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/index_set.rb b/jni/ruby/lib/rubygems/resolver/index_set.rb
new file mode 100644
index 0000000..7c56c2b
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/index_set.rb
@@ -0,0 +1,80 @@
+##
+# The global rubygems pool represented via the traditional
+# source index.
+
+class Gem::Resolver::IndexSet < Gem::Resolver::Set
+
+  def initialize source = nil # :nodoc:
+    super()
+
+    @f =
+      if source then
+        sources = Gem::SourceList.from [source]
+
+        Gem::SpecFetcher.new sources
+      else
+        Gem::SpecFetcher.fetcher
+      end
+
+    @all = Hash.new { |h,k| h[k] = [] }
+
+    list, errors = @f.available_specs :complete
+
+    @errors.concat errors
+
+    list.each do |uri, specs|
+      specs.each do |n|
+        @all[n.name] << [uri, n]
+      end
+    end
+
+    @specs = {}
+  end
+
+  ##
+  # Return an array of IndexSpecification objects matching
+  # DependencyRequest +req+.
+
+  def find_all req
+    res = []
+
+    return res unless @remote
+
+    name = req.dependency.name
+
+    @all[name].each do |uri, n|
+      if req.match? n, @prerelease then
+        res << Gem::Resolver::IndexSpecification.new(
+          self, n.name, n.version, uri, n.platform)
+      end
+    end
+
+    res
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[IndexSet', ']' do
+      q.breakable
+      q.text 'sources:'
+      q.breakable
+      q.pp @f.sources
+
+      q.breakable
+      q.text 'specs:'
+
+      q.breakable
+
+      names = @all.values.map do |tuples|
+        tuples.map do |_, tuple|
+          tuple.full_name
+        end
+      end.flatten
+
+      q.seplist names do |name|
+        q.text name
+      end
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/index_specification.rb b/jni/ruby/lib/rubygems/resolver/index_specification.rb
new file mode 100644
index 0000000..56fecb5
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/index_specification.rb
@@ -0,0 +1,69 @@
+##
+# Represents a possible Specification object returned from IndexSet.  Used to
+# delay needed to download full Specification objects when only the +name+
+# and +version+ are needed.
+
+class Gem::Resolver::IndexSpecification < Gem::Resolver::Specification
+
+  ##
+  # An IndexSpecification is created from the index format described in `gem
+  # help generate_index`.
+  #
+  # The +set+ contains other specifications for this (URL) +source+.
+  #
+  # The +name+, +version+ and +platform+ are the name, version and platform of
+  # the gem.
+
+  def initialize set, name, version, source, platform
+    super()
+
+    @set = set
+    @name = name
+    @version = version
+    @source = source
+    @platform = platform.to_s
+
+    @spec = nil
+  end
+
+  ##
+  # The dependencies of the gem for this specification
+
+  def dependencies
+    spec.dependencies
+  end
+
+  def inspect # :nodoc:
+    '#<%s %s source %s>' % [self.class, full_name, @source]
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[Index specification', ']' do
+      q.breakable
+      q.text full_name
+
+      unless Gem::Platform::RUBY == @platform then
+        q.breakable
+        q.text @platform.to_s
+      end
+
+      q.breakable
+      q.text 'source '
+      q.pp @source
+    end
+  end
+
+  ##
+  # Fetches a Gem::Specification for this IndexSpecification from the #source.
+
+  def spec # :nodoc:
+    @spec ||=
+      begin
+        tuple = Gem::NameTuple.new @name, @version, @platform
+
+        @source.fetch_spec tuple
+      end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/installed_specification.rb b/jni/ruby/lib/rubygems/resolver/installed_specification.rb
new file mode 100644
index 0000000..2a2b89a
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/installed_specification.rb
@@ -0,0 +1,58 @@
+##
+# An InstalledSpecification represents a gem that is already installed
+# locally.
+
+class Gem::Resolver::InstalledSpecification < Gem::Resolver::SpecSpecification
+
+  def == other # :nodoc:
+    self.class === other and
+      @set  == other.set and
+      @spec == other.spec
+  end
+
+  ##
+  # This is a null install as this specification is already installed.
+  # +options+ are ignored.
+
+  def install options = {}
+    yield nil
+  end
+
+  ##
+  # Returns +true+ if this gem is installable for the current platform.
+
+  def installable_platform?
+    # BACKCOMPAT If the file is coming out of a specified file, then we
+    # ignore the platform. This code can be removed in RG 3.0.
+    return true if @source.kind_of? Gem::Source::SpecificFile
+
+    super
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[InstalledSpecification', ']' do
+      q.breakable
+      q.text "name: #{name}"
+
+      q.breakable
+      q.text "version: #{version}"
+
+      q.breakable
+      q.text "platform: #{platform}"
+
+      q.breakable
+      q.text 'dependencies:'
+      q.breakable
+      q.pp spec.dependencies
+    end
+  end
+
+  ##
+  # The source for this specification
+
+  def source
+    @source ||= Gem::Source::Installed.new
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/installer_set.rb b/jni/ruby/lib/rubygems/resolver/installer_set.rb
new file mode 100644
index 0000000..a68ff09
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/installer_set.rb
@@ -0,0 +1,224 @@
+##
+# A set of gems for installation sourced from remote sources and local .gem
+# files
+
+class Gem::Resolver::InstallerSet < Gem::Resolver::Set
+
+  ##
+  # List of Gem::Specification objects that must always be installed.
+
+  attr_reader :always_install # :nodoc:
+
+  ##
+  # Only install gems in the always_install list
+
+  attr_accessor :ignore_dependencies # :nodoc:
+
+  ##
+  # Do not look in the installed set when finding specifications.  This is
+  # used by the --install-dir option to `gem install`
+
+  attr_accessor :ignore_installed # :nodoc:
+
+  ##
+  # The remote_set looks up remote gems for installation.
+
+  attr_reader :remote_set # :nodoc:
+
+  ##
+  # Creates a new InstallerSet that will look for gems in +domain+.
+
+  def initialize domain
+    super()
+
+    @domain = domain
+    @remote = consider_remote?
+
+    @f = Gem::SpecFetcher.fetcher
+
+    @always_install      = []
+    @ignore_dependencies = false
+    @ignore_installed    = false
+    @local               = {}
+    @remote_set          = Gem::Resolver::BestSet.new
+    @specs               = {}
+  end
+
+  ##
+  # Looks up the latest specification for +dependency+ and adds it to the
+  # always_install list.
+
+  def add_always_install dependency
+    request = Gem::Resolver::DependencyRequest.new dependency, nil
+
+    found = find_all request
+
+    found.delete_if { |s|
+      s.version.prerelease? and not s.local?
+    } unless dependency.prerelease?
+
+    found = found.select do |s|
+      Gem::Source::SpecificFile === s.source or
+        Gem::Platform::RUBY == s.platform or
+        Gem::Platform.local === s.platform
+    end
+
+    if found.empty? then
+      exc = Gem::UnsatisfiableDependencyError.new request
+      exc.errors = errors
+
+      raise exc
+    end
+
+    newest = found.max_by do |s|
+      [s.version, s.platform == Gem::Platform::RUBY ? -1 : 1]
+    end
+
+    @always_install << newest.spec
+  end
+
+  ##
+  # Adds a local gem requested using +dep_name+ with the given +spec+ that can
+  # be loaded and installed using the +source+.
+
+  def add_local dep_name, spec, source
+    @local[dep_name] = [spec, source]
+  end
+
+  ##
+  # Should local gems should be considered?
+
+  def consider_local? # :nodoc:
+    @domain == :both or @domain == :local
+  end
+
+  ##
+  # Should remote gems should be considered?
+
+  def consider_remote? # :nodoc:
+    @domain == :both or @domain == :remote
+  end
+
+  ##
+  # Errors encountered while resolving gems
+
+  def errors
+    @errors + @remote_set.errors
+  end
+
+  ##
+  # Returns an array of IndexSpecification objects matching DependencyRequest
+  # +req+.
+
+  def find_all req
+    res = []
+
+    dep  = req.dependency
+
+    return res if @ignore_dependencies and
+              @always_install.none? { |spec| dep.match? spec }
+
+    name = dep.name
+
+    dep.matching_specs.each do |gemspec|
+      next if @always_install.any? { |spec| spec.name == gemspec.name }
+
+      res << Gem::Resolver::InstalledSpecification.new(self, gemspec)
+    end unless @ignore_installed
+
+    if consider_local? then
+      matching_local = @local.values.select do |spec, _|
+        req.match? spec
+      end.map do |spec, source|
+        Gem::Resolver::LocalSpecification.new self, spec, source
+      end
+
+      res.concat matching_local
+
+      local_source = Gem::Source::Local.new
+
+      if local_spec = local_source.find_gem(name, dep.requirement) then
+        res << Gem::Resolver::IndexSpecification.new(
+          self, local_spec.name, local_spec.version,
+          local_source, local_spec.platform)
+      end
+    end
+
+    res.delete_if do |spec|
+      spec.version.prerelease? and not dep.prerelease?
+    end
+
+    res.concat @remote_set.find_all req if consider_remote?
+
+    res
+  end
+
+  def prefetch(reqs)
+    @remote_set.prefetch(reqs) if consider_remote?
+  end
+
+  def prerelease= allow_prerelease
+    super
+
+    @remote_set.prerelease = allow_prerelease
+  end
+
+  def inspect # :nodoc:
+    always_install = @always_install.map { |s| s.full_name }
+
+    '#<%s domain: %s specs: %p always install: %p>' % [
+      self.class, @domain, @specs.keys, always_install,
+    ]
+  end
+
+  ##
+  # Called from IndexSpecification to get a true Specification
+  # object.
+
+  def load_spec name, ver, platform, source # :nodoc:
+    key = "#{name}-#{ver}-#{platform}"
+
+    @specs.fetch key do
+      tuple = Gem::NameTuple.new name, ver, platform
+
+      @specs[key] = source.fetch_spec tuple
+    end
+  end
+
+  ##
+  # Has a local gem for +dep_name+ been added to this set?
+
+  def local? dep_name # :nodoc:
+    spec, = @local[dep_name]
+
+    spec
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[InstallerSet', ']' do
+      q.breakable
+      q.text "domain: #{@domain}"
+
+      q.breakable
+      q.text 'specs: '
+      q.pp @specs.keys
+
+      q.breakable
+      q.text 'always install: '
+      q.pp @always_install
+    end
+  end
+
+  def remote= remote # :nodoc:
+    case @domain
+    when :local then
+      @domain = :both if remote
+    when :remote then
+      @domain = nil unless remote
+    when :both then
+      @domain = :local unless remote
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/local_specification.rb b/jni/ruby/lib/rubygems/resolver/local_specification.rb
new file mode 100644
index 0000000..20a283f
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/local_specification.rb
@@ -0,0 +1,41 @@
+##
+# A LocalSpecification comes from a .gem file on the local filesystem.
+
+class Gem::Resolver::LocalSpecification < Gem::Resolver::SpecSpecification
+
+  ##
+  # Returns +true+ if this gem is installable for the current platform.
+
+  def installable_platform?
+    return true if @source.kind_of? Gem::Source::SpecificFile
+
+    super
+  end
+
+  def local? # :nodoc:
+    true
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[LocalSpecification', ']' do
+      q.breakable
+      q.text "name: #{name}"
+
+      q.breakable
+      q.text "version: #{version}"
+
+      q.breakable
+      q.text "platform: #{platform}"
+
+      q.breakable
+      q.text 'dependencies:'
+      q.breakable
+      q.pp dependencies
+
+      q.breakable
+      q.text "source: #{@source.path}"
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/lock_set.rb b/jni/ruby/lib/rubygems/resolver/lock_set.rb
new file mode 100644
index 0000000..4ede597
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/lock_set.rb
@@ -0,0 +1,84 @@
+##
+# A set of gems from a gem dependencies lockfile.
+
+class Gem::Resolver::LockSet < Gem::Resolver::Set
+
+  attr_reader :specs # :nodoc:
+
+  ##
+  # Creates a new LockSet from the given +sources+
+
+  def initialize sources
+    super()
+
+    @sources = sources.map do |source|
+      Gem::Source::Lock.new source
+    end
+
+    @specs   = []
+  end
+
+  ##
+  # Creates a new IndexSpecification in this set using the given +name+,
+  # +version+ and +platform+.
+  #
+  # The specification's set will be the current set, and the source will be
+  # the current set's source.
+
+  def add name, version, platform # :nodoc:
+    version = Gem::Version.new version
+
+    specs = @sources.map do |source|
+      Gem::Resolver::LockSpecification.new self, name, version, source,
+                                           platform
+    end
+
+    @specs.concat specs
+
+    specs
+  end
+
+  ##
+  # Returns an Array of IndexSpecification objects matching the
+  # DependencyRequest +req+.
+
+  def find_all req
+    @specs.select do |spec|
+      req.match? spec
+    end
+  end
+
+  ##
+  # Loads a Gem::Specification with the given +name+, +version+ and
+  # +platform+.  +source+ is ignored.
+
+  def load_spec name, version, platform, source # :nodoc:
+    dep = Gem::Dependency.new name, version
+
+    found = @specs.find do |spec|
+      dep.matches_spec? spec and spec.platform == platform
+    end
+
+    tuple = Gem::NameTuple.new found.name, found.version, found.platform
+
+    found.source.fetch_spec tuple
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[LockSet', ']' do
+      q.breakable
+      q.text 'source:'
+
+      q.breakable
+      q.pp @source
+
+      q.breakable
+      q.text 'specs:'
+
+      q.breakable
+      q.pp @specs.map { |spec| spec.full_name }
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/lock_specification.rb b/jni/ruby/lib/rubygems/resolver/lock_specification.rb
new file mode 100644
index 0000000..0013171
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/lock_specification.rb
@@ -0,0 +1,84 @@
+##
+# The LockSpecification comes from a lockfile (Gem::RequestSet::Lockfile).
+#
+# A LockSpecification's dependency information is pre-filled from the
+# lockfile.
+
+class Gem::Resolver::LockSpecification < Gem::Resolver::Specification
+
+  def initialize set, name, version, source, platform
+    super()
+
+    @name     = name
+    @platform = platform
+    @set      = set
+    @source   = source
+    @version  = version
+
+    @dependencies = []
+    @spec         = nil
+  end
+
+  ##
+  # This is a null install as a locked specification is considered installed.
+  # +options+ are ignored.
+
+  def install options = {}
+    destination = options[:install_dir] || Gem.dir
+
+    if File.exist? File.join(destination, 'specifications', spec.spec_name) then
+      yield nil
+      return
+    end
+
+    super
+  end
+
+  ##
+  # Adds +dependency+ from the lockfile to this specification
+
+  def add_dependency dependency # :nodoc:
+    @dependencies << dependency
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[LockSpecification', ']' do
+      q.breakable
+      q.text "name: #{@name}"
+
+      q.breakable
+      q.text "version: #{@version}"
+
+      unless @platform == Gem::Platform::RUBY then
+        q.breakable
+        q.text "platform: #{@platform}"
+      end
+
+      unless @dependencies.empty? then
+        q.breakable
+        q.text 'dependencies:'
+        q.breakable
+        q.pp @dependencies
+      end
+    end
+  end
+
+  ##
+  # A specification constructed from the lockfile is returned
+
+  def spec
+    @spec ||= Gem::Specification.find { |spec|
+      spec.name == @name and spec.version == @version
+    }
+
+    @spec ||= Gem::Specification.new do |s|
+      s.name     = @name
+      s.version  = @version
+      s.platform = @platform
+
+      s.dependencies.concat @dependencies
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/requirement_list.rb b/jni/ruby/lib/rubygems/resolver/requirement_list.rb
new file mode 100644
index 0000000..a6bfaab
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/requirement_list.rb
@@ -0,0 +1,81 @@
+##
+# The RequirementList is used to hold the requirements being considered
+# while resolving a set of gems.
+#
+# The RequirementList acts like a queue where the oldest items are removed
+# first.
+
+class Gem::Resolver::RequirementList
+
+  include Enumerable
+
+  ##
+  # Creates a new RequirementList.
+
+  def initialize
+    @exact = []
+    @list = []
+  end
+
+  def initialize_copy other # :nodoc:
+    @exact = @exact.dup
+    @list = @list.dup
+  end
+
+  ##
+  # Adds Resolver::DependencyRequest +req+ to this requirements list.
+
+  def add(req)
+    if req.requirement.exact?
+      @exact.push req
+    else
+      @list.push req
+    end
+    req
+  end
+
+  ##
+  # Enumerates requirements in the list
+
+  def each # :nodoc:
+    return enum_for __method__ unless block_given?
+
+    @exact.each do |requirement|
+      yield requirement
+    end
+
+    @list.each do |requirement|
+      yield requirement
+    end
+  end
+
+  ##
+  # How many elements are in the list
+
+  def size
+    @exact.size + @list.size
+  end
+
+  ##
+  # Is the list empty?
+
+  def empty?
+    @exact.empty? && @list.empty?
+  end
+
+  ##
+  # Remove the oldest DependencyRequest from the list.
+
+  def remove
+    return @exact.shift unless @exact.empty?
+    @list.shift
+  end
+
+  ##
+  # Returns the oldest five entries from the list.
+
+  def next5
+    x = @exact[0,5]
+    x + @list[0,5 - x.size]
+  end
+end
diff --git a/jni/ruby/lib/rubygems/resolver/set.rb b/jni/ruby/lib/rubygems/resolver/set.rb
new file mode 100644
index 0000000..b26dc45
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/set.rb
@@ -0,0 +1,56 @@
+##
+# Resolver sets are used to look up specifications (and their
+# dependencies) used in resolution.  This set is abstract.
+
+class Gem::Resolver::Set
+
+  ##
+  # Set to true to disable network access for this set
+
+  attr_accessor :remote
+
+  ##
+  # Errors encountered when resolving gems
+
+  attr_accessor :errors
+
+  ##
+  # When true, allows matching of requests to prerelease gems.
+
+  attr_accessor :prerelease
+
+  def initialize # :nodoc:
+    @prerelease = false
+    @remote     = true
+    @errors     = []
+  end
+
+  ##
+  # The find_all method must be implemented.  It returns all Resolver
+  # Specification objects matching the given DependencyRequest +req+.
+
+  def find_all req
+    raise NotImplementedError
+  end
+
+  ##
+  # The #prefetch method may be overridden, but this is not necessary.  This
+  # default implementation does nothing, which is suitable for sets where
+  # looking up a specification is cheap (such as installed gems).
+  #
+  # When overridden, the #prefetch method should look up specifications
+  # matching +reqs+.
+
+  def prefetch reqs
+  end
+
+  ##
+  # When true, this set is allowed to access the network when looking up
+  # specifications or dependencies.
+
+  def remote? # :nodoc:
+    @remote
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/spec_specification.rb b/jni/ruby/lib/rubygems/resolver/spec_specification.rb
new file mode 100644
index 0000000..1350e8a
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/spec_specification.rb
@@ -0,0 +1,56 @@
+##
+# The Resolver::SpecSpecification contains common functionality for
+# Resolver specifications that are backed by a Gem::Specification.
+
+class Gem::Resolver::SpecSpecification < Gem::Resolver::Specification
+
+  ##
+  # A SpecSpecification is created for a +set+ for a Gem::Specification in
+  # +spec+.  The +source+ is either where the +spec+ came from, or should be
+  # loaded from.
+
+  def initialize set, spec, source = nil
+    @set    = set
+    @source = source
+    @spec   = spec
+  end
+
+  ##
+  # The dependencies of the gem for this specification
+
+  def dependencies
+    spec.dependencies
+  end
+
+  ##
+  # The name and version of the specification.
+  #
+  # Unlike Gem::Specification#full_name, the platform is not included.
+
+  def full_name
+    "#{spec.name}-#{spec.version}"
+  end
+
+  ##
+  # The name of the gem for this specification
+
+  def name
+    spec.name
+  end
+
+  ##
+  # The platform this gem works on.
+
+  def platform
+    spec.platform
+  end
+
+  ##
+  # The version of the gem for this specification.
+
+  def version
+    spec.version
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/specification.rb b/jni/ruby/lib/rubygems/resolver/specification.rb
new file mode 100644
index 0000000..4d77293
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/specification.rb
@@ -0,0 +1,110 @@
+##
+# A Resolver::Specification contains a subset of the information
+# contained in a Gem::Specification.  Only the information necessary for
+# dependency resolution in the resolver is included.
+
+class Gem::Resolver::Specification
+
+  ##
+  # The dependencies of the gem for this specification
+
+  attr_reader :dependencies
+
+  ##
+  # The name of the gem for this specification
+
+  attr_reader :name
+
+  ##
+  # The platform this gem works on.
+
+  attr_reader :platform
+
+  ##
+  # The set this specification came from.
+
+  attr_reader :set
+
+  ##
+  # The source for this specification
+
+  attr_reader :source
+
+  ##
+  # The Gem::Specification for this Resolver::Specification.
+  #
+  # Implementers, note that #install updates @spec, so be sure to cache the
+  # Gem::Specification in @spec when overriding.
+
+  attr_reader :spec
+
+  ##
+  # The version of the gem for this specification.
+
+  attr_reader :version
+
+  ##
+  # Sets default instance variables for the specification.
+
+  def initialize
+    @dependencies = nil
+    @name         = nil
+    @platform     = nil
+    @set          = nil
+    @source       = nil
+    @version      = nil
+  end
+
+  ##
+  # Fetches development dependencies if the source does not provide them by
+  # default (see APISpecification).
+
+  def fetch_development_dependencies # :nodoc:
+  end
+
+  ##
+  # The name and version of the specification.
+  #
+  # Unlike Gem::Specification#full_name, the platform is not included.
+
+  def full_name
+    "#{@name}-#{@version}"
+  end
+
+  ##
+  # Installs this specification using the Gem::Installer +options+.  The
+  # install method yields a Gem::Installer instance, which indicates the
+  # gem will be installed, or +nil+, which indicates the gem is already
+  # installed.
+  #
+  # After installation #spec is updated to point to the just-installed
+  # specification.
+
+  def install options = {}
+    require 'rubygems/installer'
+
+    destination = options[:install_dir] || Gem.dir
+
+    Gem.ensure_gem_subdirectories destination
+
+    gem = source.download spec, destination
+
+    installer = Gem::Installer.new gem, options
+
+    yield installer if block_given?
+
+    @spec = installer.install
+  end
+
+  ##
+  # Returns true if this specification is installable on this platform.
+
+  def installable_platform?
+    Gem::Platform.match spec.platform
+  end
+
+  def local? # :nodoc:
+    false
+  end
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/stats.rb b/jni/ruby/lib/rubygems/resolver/stats.rb
new file mode 100644
index 0000000..c31e5be
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/stats.rb
@@ -0,0 +1,44 @@
+class Gem::Resolver::Stats
+  def initialize
+    @max_depth = 0
+    @max_requirements = 0
+    @requirements = 0
+    @backtracking = 0
+    @iterations = 0
+  end
+
+  def record_depth(stack)
+    if stack.size > @max_depth
+      @max_depth = stack.size
+    end
+  end
+
+  def record_requirements(reqs)
+    if reqs.size > @max_requirements
+      @max_requirements = reqs.size
+    end
+  end
+
+  def requirement!
+    @requirements += 1
+  end
+
+  def backtracking!
+    @backtracking += 1
+  end
+
+  def iteration!
+    @iterations += 1
+  end
+
+  PATTERN = "%20s: %d\n"
+
+  def display
+    $stdout.puts "=== Resolver Statistics ==="
+    $stdout.printf PATTERN, "Max Depth", @max_depth
+    $stdout.printf PATTERN, "Total Requirements", @requirements
+    $stdout.printf PATTERN, "Max Requirements", @max_requirements
+    $stdout.printf PATTERN, "Backtracking #", @backtracking
+    $stdout.printf PATTERN, "Iteration #", @iterations
+  end
+end
diff --git a/jni/ruby/lib/rubygems/resolver/vendor_set.rb b/jni/ruby/lib/rubygems/resolver/vendor_set.rb
new file mode 100644
index 0000000..614bd05
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/vendor_set.rb
@@ -0,0 +1,87 @@
+##
+# A VendorSet represents gems that have been unpacked into a specific
+# directory that contains a gemspec.
+#
+# This is used for gem dependency file support.
+#
+# Example:
+#
+#   set = Gem::Resolver::VendorSet.new
+#
+#   set.add_vendor_gem 'rake', 'vendor/rake'
+#
+# The directory vendor/rake must contain an unpacked rake gem along with a
+# rake.gemspec (watching the given name).
+
+class Gem::Resolver::VendorSet < Gem::Resolver::Set
+
+  ##
+  # The specifications for this set.
+
+  attr_reader :specs # :nodoc:
+
+  def initialize # :nodoc:
+    super()
+
+    @directories = {}
+    @specs       = {}
+  end
+
+  ##
+  # Adds a specification to the set with the given +name+ which has been
+  # unpacked into the given +directory+.
+
+  def add_vendor_gem name, directory # :nodoc:
+    gemspec = File.join directory, "#{name}.gemspec"
+
+    spec = Gem::Specification.load gemspec
+
+    raise Gem::GemNotFoundException,
+          "unable to find #{gemspec} for gem #{name}" unless spec
+
+    spec.full_gem_path = File.expand_path directory
+
+    @specs[spec.name]  = spec
+    @directories[spec] = directory
+
+    spec
+  end
+
+  ##
+  # Returns an Array of VendorSpecification objects matching the
+  # DependencyRequest +req+.
+
+  def find_all req
+    @specs.values.select do |spec|
+      req.match? spec
+    end.map do |spec|
+      source = Gem::Source::Vendor.new @directories[spec]
+      Gem::Resolver::VendorSpecification.new self, spec, source
+    end
+  end
+
+  ##
+  # Loads a spec with the given +name+. +version+, +platform+ and +source+ are
+  # ignored.
+
+  def load_spec name, version, platform, source # :nodoc:
+    @specs.fetch name
+  end
+
+  def pretty_print q # :nodoc:
+    q.group 2, '[VendorSet', ']' do
+      next if @directories.empty?
+      q.breakable
+
+      dirs = @directories.map do |spec, directory|
+        "#{spec.full_name}: #{directory}"
+      end
+
+      q.seplist dirs do |dir|
+        q.text dir
+      end
+    end
+  end
+
+end
+
diff --git a/jni/ruby/lib/rubygems/resolver/vendor_specification.rb b/jni/ruby/lib/rubygems/resolver/vendor_specification.rb
new file mode 100644
index 0000000..a99b5f3
--- /dev/null
+++ b/jni/ruby/lib/rubygems/resolver/vendor_specification.rb
@@ -0,0 +1,24 @@
+##
+# A VendorSpecification represents a gem that has been unpacked into a project
+# and is being loaded through a gem dependencies file through the +path:+
+# option.
+
+class Gem::Resolver::VendorSpecification < Gem::Resolver::SpecSpecification
+
+  def == other # :nodoc:
+    self.class === other and
+      @set  == other.set and
+      @spec == other.spec and
+      @source == other.source
+  end
+
+  ##
+  # This is a null install as this gem was unpacked into a directory.
+  # +options+ are ignored.
+
+  def install options = {}
+    yield nil
+  end
+
+end
+
-- 
cgit v1.2.3-70-g09d2