rubygems / bundler

Manage your Ruby application's gem dependencies
https://bundler.io
MIT License
4.88k stars 1.99k forks source link

Bundler 2.1.4 errors with different prefix for path source gems #7598

Closed fzakaria closed 4 years ago

fzakaria commented 4 years ago

When running my Ruby code via JRuby -- I've encountered an interesting failure specifically on 2.1.4 whereas 2.0.2 does not have the issue.

The failure at startup is:

eval_gemfile at uri:classloader:/gems/bundler-2.1.4/lib/bundler/dsl.rb:53
          evaluate at uri:classloader:/gems/bundler-2.1.4/lib/bundler/dsl.rb:12
             build at uri:classloader:/gems/bundler-2.1.4/lib/bundler/definition.rb:34
        definition at uri:classloader:/gems/bundler-2.1.4/lib/bundler.rb:195
             setup at uri:classloader:/gems/bundler-2.1.4/lib/bundler.rb:143
   block in (root) at uri:classloader:/gems/bundler-2.1.4/lib/bundler/setup.rb:20
        with_level at uri:classloader:/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:136
           silence at uri:classloader:/gems/bundler-2.1.4/lib/bundler/ui/shell.rb:88
            <main> at uri:classloader:/gems/bundler-2.1.4/lib/bundler/setup.rb:20

[!] There was an error parsing `Gemfile`: different prefix: "uri:classloader://" and
"uri:classloader:/my-application". Bundler cannot continue.

The Gemfile looks like:

gem 'some-gem', :path => "ruby-gems/some-gem"

I have not git-bisected yet but auditing the code; I have strong intuition to believe the issue is caused by https://github.com/rubygems/bundler/commit/c7532ced89bbc8ddc7296c56391c1c3cc981c54a as it introduces relative_path_from for path Gems.

Environment

jruby 9.1.17.0 (2.3.3) 2018-04-20 d8b1ff9 OpenJDK 64-Bit Server VM 25.232-b09 on 1.8.0_232-b09 +jit [darwin-x86_64]

Darwin MacBook-Pro.localdomain 18.7.0 Darwin Kernel Version 18.7.0: Tue Aug 20 16:57:14 PDT 2019; root:xnu-4903.271.2~2/RELEASE_X86_64 x86_64
fzakaria commented 4 years ago

Tracking this in JRuby issue also https://github.com/jruby/jruby/issues/6045

deivid-rodriguez commented 4 years ago

Hello @fzakaria! Could you post exact repro instructions? I tried bundling a Gemfile including something like gem 'some-gem', :path => "ruby-gems/some-gem" and it worked, so there must be something else going on in your application.

fzakaria commented 4 years ago

@deivid-rodriguez I'll craft a repro project. It needs to be done with JRuby and then packaged as a JAR.

I'll set up a repro project today.

fzakaria commented 4 years ago

@deivid-rodriguez I have produced a minimal example at https://github.com/fzakaria/warbler-bundler-jruby-failure

In order to reproduce it, please make sure you are using jruby (I used rvm to install)

If you run the example script with simply ruby, it works.

bundle exec ruby bin/warbler-example.rb
>> Starting the JAR!
>> hello world

however, if you build the JAR & run it you get the error from above.

bundle exec warble
java -jar warbler-example.jar

[!] There was an error parsing `Gemfile`: different prefix: "uri:classloader://" and "uri:classloader:/warbler-example". Bundler cannot continue.

 #  from uri:classloader:/warbler-example/Gemfile:4
 #  -------------------------------------------
 #  gem 'warbler', '2.0.5'
 >  gem 'jruby-jars', '9.1.17.0' #  ruby '2.3.3', engine: 'jruby', engine_version: '9.1.17.0'
 #  -------------------------------------------
deivid-rodriguez commented 4 years ago

I could reproduce the issue, thanks! I'll try to investigate it.

fzakaria commented 4 years ago

Great ! Let me know if you need anything else for help in the investigation.

deivid-rodriguez commented 4 years ago

Ok, so this seems like due to a weird inconsistency in jruby that should probably be fixed, where Pathname#expand_path with an argument always returns uri:classloader:// (double slash) as the canonical version of "uri:classloader" paths, while Pathname#expand_path without an argument always returns uri:classloader/ (single slash) as the canonical version of "uri:classloader" paths.

Pathname.new("uri:classloader://foo/bar").expand_path
#  => <Pathname:uri:classloader:/foo/bar>

Pathname.new("uri:classloader:/foo/bar").expand_path
# => <Pathname:uri:classloader:/foo/bar>

Pathname.new("foo/bar").expand_path("uri:classloader://")
# => <Pathname:uri:classloader://foo/bar>

Pathname.new("foo/bar").expand_path("uri:classloader:/")
# => <Pathname:uri:classloader://foo/bar>

That makes Pathname#relative_path_from explode because we end up passing to different "uri:classloader" kind of paths to it.

So, I see two things that can be fixed/changed in jruby:

As a workaround, I believe we can apply the following patch to bundler:

diff --git a/lib/bundler/source/path.rb b/lib/bundler/source/path.rb
index f98f5155fb..1aea7ece0d 100644
--- a/lib/bundler/source/path.rb
+++ b/lib/bundler/source/path.rb
@@ -132,7 +132,7 @@ module Bundler
       end

       def expand(somepath)
-        somepath.expand_path(root_path)
+        somepath.expand_path(root_path).expand_path
       rescue ArgumentError => e
         Bundler.ui.debug(e)
         raise PathError, "There was an error while trying to use the path " \
fzakaria commented 4 years ago

Since it's way less onerous to update Bundler gem vs updating our JRuby installation I would very much appreciate the patch to bundler to accommodate the bug.

I'll also add your latest investigation to https://github.com/jruby/jruby/issues/6045 for them

deivid-rodriguez commented 4 years ago

Yes, we'll provide a workaround in bundler. I want to make sure I add a basic test for this in order to catch basic errors with warbler like this one in the future.

fzakaria commented 4 years ago

🙏 thanks. Please feel free to tag me on the PR.