gel-rb / gel

A modern gem manager: Gel is a lightweight alternative to Bundler

Home Page:https://gel.dev

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Requiring version in gemspec from git source fails

kaspth opened this issue · comments

Using resque-pause from GitHub with gel fails with:

Fetching sources.....
Resolving dependencies...Traceback (most recent call last):
	7: from -e:1:in `<main>'
	6: from /Users/kaspth/.gem/ruby/2.6.0/gems/gel-0.3.0/lib/gel/gemspec_parser.rb:90:in `parse'
	5: from /Users/kaspth/.gem/ruby/2.6.0/gems/gel-0.3.0/lib/gel/gemspec_parser.rb:90:in `chdir'
	4: from /Users/kaspth/.gem/ruby/2.6.0/gems/gel-0.3.0/lib/gel/gemspec_parser.rb:91:in `block in parse'
	3: from /Users/kaspth/.gem/ruby/2.6.0/gems/gel-0.3.0/lib/gel/gemspec_parser.rb:91:in `eval'
	2: from /Users/kaspth/.local/gel/git/resque-pause-45d8b943d8586/resque-pause.gemspec:5:in `context'
	1: from /Users/kaspth/.gem/ruby/2.6.0/gems/gel-0.3.0/lib/gel/gemspec_parser.rb:26:in `new'
/Users/kaspth/.local/gel/git/resque-pause-45d8b943d8586/resque-pause.gemspec:7:in `block in context': uninitialized constant Gel::GemspecParser::Context::Resque (NameError)
ERROR: Gemspec parse failed

Resque isn't defined at the time because the earlier require "version" ends up resolving to another activated gem's version.rb (in my testing from base32) via

super Gel::Environment.resolve_gem_path(path)

Not sure what the right solution is here, if Gel needs to activate the gem before parsing the gemspecs.

Reproduction script

set -ex

mkdir -p holder
cd holder

cat << GEMFILE > Gemfile
source "https://rubygems.org"

git_source(:github) { |repo| "https://github.com/#{repo}.git" }

gem "resque-pause", github: "wandenberg/resque-pause"
GEMFILE

gel lock

Hmm.. this one might be tricky.

We can't activate the gem before the load the gemspec, because we're loading the gemspec in order to activate the gem: until we've done so, we don't even know the require_paths, say.

That leaves us in a situation where a gem is supplying "version", and the local load path is attempting to override that by also supplying a file by the same name... which is a designed impossibility in Gel: the load path optimisations are built around the rule that the 'application' can't override a file that's supplied by a gem.

It's unfortunate there are multiple gems polluting the top-level require namespace like that. 😕

Solutions that come to mind:

  • implement a custom resolve order for require "version", on the assumption that this pattern is going to affect more gems, but may be unique to that particular filename -- feels like a band-aid, but limits the scope of the change
  • lock the environment to disallow all gem access inside gemspec (we don't know about any legitimately declared dependencies yet, because that's one of the things we're getting from the gemspec) -- more pure, but more likely to break on differently-odd gemspecs, like this
  • declare those gemspecs to be malformed, and that we can't support them (notably this only affects a git/path reference -- the compiled .gem will contain a standard well-formed gemspec, notwithstanding the fact they're both exporting a file that's outside their respective namespaces)

Option 3 is looking pretty appealing at the moment.. how much of an adoption hurdle would that be for you? I see https://github.com/basecamp/resque-pause exists (and is presumably why you need the git reference in the first place); how do you feel about a bit of:

-$:.push File.expand_path("../lib", __FILE__)
-require "version"
+require File.expand_path("../lib/version", __FILE__)

Still not sure what to do about this one 😕