[Rubygems-developers] Dependency Resolution

Trans transfire at gmail.com
Mon Aug 2 13:01:16 EDT 2010


Hi--

I wrote up some code for doing dependency resolution. Right now I am
using my own Version class to do the constraint comparisons, but it
shouldn't too hard to adapt to RubyGems'.

    def rubygems_resolve
      requests = []
      matches  = []
      missing  = []
      gems.each do |name, constraint|
        gem_dep  = Gem::Dependency.new(name, [constraint])
        rubygems_resolve_gem(gem_dep, requests, matches, missing)
      end
      libs = matches.group_by{ |spec| spec.name }
      requests.each do |name, constraint|
        next unless libs[name]
        libs[name].reject! do |spec|
          !Gemdo::VersionNumber.new(spec.version.to_s).match?
(constraint.to_s)
        end
      end
      libs.each do |name, specs|
        print "#{name} ("
        print specs.sort.reverse.map{ |spec|
"#{spec.version}" }.join(', ')
        print ")"
        puts
      end
      missing.each do |gem_dep|
        puts "#{gem_dep.name} ()"
      end
    end

    # recursive resolution of dependencies
    def rubygems_resolve_gem(gem_dep, requests=[], matches=[],
missing=[])
      requests << [gem_dep.name, gem_dep.requirement]
      list = Gem.source_index.find_name(gem_dep.name,
gem_dep.requirement)
      missing << gem_dep if list.empty?
      matches.concat(list)
      list.each do |spec|
        next if matches.include?(spec)
        spec.runtime_dependencies.each do |dep_gem|
          next if missing.include?(gem_dep)
          rubygems_resolve_gem(dep_gem, matches, missing)
        end
        spec.development_dependencies.each do |dep_gem|
          next if missing.include?(gem_dep)
          rubygems_resolve_gem(dep_gem, matches, missing)
        end
      end
    end

The `gems` method used on the fifth line just returns a list of the
current project requirements in an assoc list of [foo, '>= 1.0']
format.

Currently this code only works against installed gems. To work really
well it would need to support remote lookup too. I haven't endeavored
into that b/c of the bug I ran into that I mentioned in my last post.
Any advice on adding that would be appreciated though.

With a bit of tweaking perhaps this can get into the RubyGems?

While I am on the subject, the Gemdo::Version class I'm using can
handle version constraints in these formats:

  1.0+   (same as >= 1.0)
  1.0-    (same as < 1.0)
  1.0~   (same as ~> 1.0)

It would very nice if RubyGems could handle constraints like that at
well.



More information about the Rubygems-developers mailing list