-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bundler should not try to force install StubSpecifications #4088
Comments
I have opened a matching issue with Nixpkgs with a fix on that side NixOS/nixpkgs#104977 however I feel there is an opportunity here anyways for bundler to be better. For instance, should bundler anyways be more tolerant to a cache miss? Thanks for looking at this when you get the change 🙏 |
The way in which Nixpks builds Ruby gems means that certain operations by bundler *will not work*, namely `bundle install --redownload`. According to the source the _cache/_ directory should have been kept, however it seems through revisions to the file it has been purged. Here was the comment from the original commit that introduced buildRubyGem: ``` # Note: # We really do need to keep the $out/${ruby.gemPath}/cache. # This is very important in order for many parts of RubyGems/Bundler to not blow up. # See rubygems/bundler#3327 ``` Why is the _cache_ directory needed? Bundler and RubyGems uses the cache as a source of truth. When bundler executes `bundler install --redownload`, any gems it discovers in the _GEM_PATH_ it assums must have their _.gem_ file present in the cache (unaware it was installed from Nix). Rather than downloading the gem from RubyGems the bundler code forcibly re-installs the gem from the cache directory instead and **fails** if it does not exist. I've opened rubygems/rubygems#4088 to see if this failure should be soft and not so explicit; or fallback to fetching the gem from scratch. Without this change the following is the error: ```bash > [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ bundle install --force [DEPRECATED] The `--force` option has been renamed to `--redownload` WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/nix/store/fis6nzrpw9pmcivr84qh5byfgm07qn10-jruby-9.2.13.0/lib/ruby/stdlib/jopenssl.jar) to field java.security.MessageDigest.provider WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Fetching gem metadata from https://rubygems.org/. Using bundler 2.1.4 Installing hello-world 1.2.0 Bundler::GemNotFound: Could not find hello-world-1.2.0.gem for installation An error occurred while installing hello-world (1.2.0), and Bundler cannot continue. Make sure that `gem install hello-world -v '1.2.0' --source 'https://rubygems.org/'` succeeds before bundling. ``` Wth the fix the following no woccurs: ```bash [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ bundle install --redownload WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/nix/store/69wjlj4yirp48rv1q03zxgd4xvf0150d-jruby-9.2.13.0/lib/ruby/stdlib/jopenssl.jar) to field java.security.MessageDigest.provider WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Fetching gem metadata from https://rubygems.org/. Using bundler 2.1.4 Installing hello-world 1.2.0 Bundle complete! 1 Gemfile dependency, 2 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. ``` ``` [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ ls -l /nix/store/cwl9n5073hqgpfhnw4wic13nrrgg9dn8-gem-env/lib/jruby/gems/2.5.0/cache/ total 8 lrwxrwxrwx 1 fmzakari primarygroup 102 Dec 31 1969 bundler-2.1.4.gem -> /nix/store/ifc8a0gsfkrhkv953rd4rz8bcspahi8y-bundler-2.1.4/lib/jruby/gems/2.5.0/cache/bundler-2.1.4.gem lrwxrwxrwx 1 fmzakari primarygroup 110 Dec 31 1969 hello-world-1.2.0.gem -> /nix/store/xi9ln6n1mz2is5ppykjxqhhkpjq9zm6i-hello-world-1.2.0/lib/jruby/gems/2.5.0/cache/hello-world-1.2.0.gem ``` I have a minimal project that demonstrates this issue at https://github.com/fzakaria/jruby-bundler-nix-failure
The way in which Nixpks builds Ruby gems means that certain operations by bundler *will not work*, namely `bundle install --redownload`. According to the source the _cache/_ directory should have been kept, however it seems through revisions to the file it has been purged. Here was the comment from the original commit that introduced buildRubyGem: ``` # Note: # We really do need to keep the $out/${ruby.gemPath}/cache. # This is very important in order for many parts of RubyGems/Bundler to not blow up. # See rubygems/bundler#3327 ``` Why is the _cache_ directory needed? Bundler and RubyGems uses the cache as a source of truth. When bundler executes `bundler install --redownload`, any gems it discovers in the _GEM_PATH_ it assums must have their _.gem_ file present in the cache (unaware it was installed from Nix). Rather than downloading the gem from RubyGems the bundler code forcibly re-installs the gem from the cache directory instead and **fails** if it does not exist. I've opened rubygems/rubygems#4088 to see if this failure should be soft and not so explicit; or fallback to fetching the gem from scratch. Without this change the following is the error: ```bash > [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ bundle install --force [DEPRECATED] The `--force` option has been renamed to `--redownload` WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/nix/store/fis6nzrpw9pmcivr84qh5byfgm07qn10-jruby-9.2.13.0/lib/ruby/stdlib/jopenssl.jar) to field java.security.MessageDigest.provider WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Fetching gem metadata from https://rubygems.org/. Using bundler 2.1.4 Installing hello-world 1.2.0 Bundler::GemNotFound: Could not find hello-world-1.2.0.gem for installation An error occurred while installing hello-world (1.2.0), and Bundler cannot continue. Make sure that `gem install hello-world -v '1.2.0' --source 'https://rubygems.org/'` succeeds before bundling. ``` Wth the fix the following no woccurs: ```bash [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ bundle install --redownload WARNING: An illegal reflective access operation has occurred WARNING: Illegal reflective access by org.jruby.ext.openssl.SecurityHelper (file:/nix/store/69wjlj4yirp48rv1q03zxgd4xvf0150d-jruby-9.2.13.0/lib/ruby/stdlib/jopenssl.jar) to field java.security.MessageDigest.provider WARNING: Please consider reporting this to the maintainers of org.jruby.ext.openssl.SecurityHelper WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations WARNING: All illegal access operations will be denied in a future release Fetching gem metadata from https://rubygems.org/. Using bundler 2.1.4 Installing hello-world 1.2.0 Bundle complete! 1 Gemfile dependency, 2 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. ``` ``` [nix-shell:~/code/nix/playground/jruby-bundler-rake]$ ls -l /nix/store/cwl9n5073hqgpfhnw4wic13nrrgg9dn8-gem-env/lib/jruby/gems/2.5.0/cache/ total 8 lrwxrwxrwx 1 fmzakari primarygroup 102 Dec 31 1969 bundler-2.1.4.gem -> /nix/store/ifc8a0gsfkrhkv953rd4rz8bcspahi8y-bundler-2.1.4/lib/jruby/gems/2.5.0/cache/bundler-2.1.4.gem lrwxrwxrwx 1 fmzakari primarygroup 110 Dec 31 1969 hello-world-1.2.0.gem -> /nix/store/xi9ln6n1mz2is5ppykjxqhhkpjq9zm6i-hello-world-1.2.0/lib/jruby/gems/2.5.0/cache/hello-world-1.2.0.gem ``` I have a minimal project that demonstrates this issue at https://github.com/fzakaria/jruby-bundler-nix-failure
Hi @fzakaria! I'll try to find some time to install nix and repro this, but in the mean time these are my thoughts. I think the problem in this case is not that the specification at hand is a In my opinion, we should treat this case the same as we treat default gems. If you specify a default gem in your Gemfile, it's no longer treated as a default gem, and it starts being locked in the lockfile and installed from the remote sources and cached normally. If on the other hand you don't specify a default gem in the Gemfile, you can still require it but it will be picked up from the standard location, and you want be able to choose its version, it will be the version that comes with ruby. For these gems, I think the same strategy could work. |
Sorry for the late response; I was battling COVID :( I was able to offset the issue with NixOS/nixpkgs#104977 being accepted; I hope it's idiomatic. I however ran into a interesting case where I wanted to provide my users a default gemset (i.e. rake) but they still used Bundler for their application development. The reality of not having the cache file present caused the problem. It was easily remedied in Nix by keeping the cache file however I find the lack of fallback to download it again via bundler the ultimate bug report here. The cache file should be a short-circuit to download but not cause it to fail if missing? |
Hope feel better now 💪.
No, not at all. I understood the issue, yeah. My preferred fix as I tried to explain would be to treat this "default gemset" locations the same way as we treat default gems: they're not cached, they are not reinstalled, they are only "used" when needed. Changing that would essentially involve adding a similar trick to this: rubygems/bundler/lib/bundler/rubygems_integration.rb Lines 422 to 440 in cf06c72
but with the gems in these "alternative gem locations". |
I see -- they become a no-op for the redownload operation then ? How would Bundler distinguish it as a "default gemset" though? It's only specified via the GEM_PATH argument so it just looks like any gem installation? (curious) Seems like you have a good handle on the "issue" opened by me. |
It would always exit early from the method you pointed out earlier as being already installed with a "Using hello-world" message: rubygems/bundler/lib/bundler/source/rubygems.rb Lines 107 to 112 in cf06c72
If on the other hand, if you do specify it in the |
I am using bundler with Nixpkgs/NixOS where I pre-install some gems but also rely on bundler to install the remaining gems.
When I try to use the
--force / --redownload
option, bundler fails.I have done some investigation into this @deivid-rodriguez and I would like your feedback.
Nix has the ability to setup GEM_PATHS that are prebaked with some gems.
For instance
The above is an example of a gem environment setup by Nix where I've pre-installed bundler & the hellow-world gem.
I add this environment variable $GEM_NIX_ENV to my $GEM_PATH.
When I execute bundle install, bundler works correctly; and determines that the gem is already installed.
When I execute bundle install --redownload, bundler fails; since it tries to check if the gem is present on the cache.
Bundler enters the following codeblock https://github.com/rubygems/rubygems/blob/master/bundler/lib/bundler/source/rubygems.rb#L137 however the specification for the hello-gem is a StubSpecification since bundler has found that the gem already exists.
StubSpecification specs do not have a remote, so the gem itself is not downloaded.
Unfortunately, the way Nix creates the environment, the gem itself is not in the cache directory.
Suggestion: should bundler skip that code block if it's of type StubSpecification & the cache entry does not exist rather than failing ?
I can look into also fixing the nixpkgs code as well with how it creates the environment however this was a pretty thorny issue to try and diagnose.
Post steps to reproduce the problem
I have included a reproducing minimal example you can find: https://github.com/fzakaria/jruby-bundler-nix-failure
It will require that you have Nix installed (https://nixos.org/download.html) which can be done on Darwin or any Linux distribution.
Environment
Bundler Build Metadata
Bundler settings
Gemfile
Gemfile
Gemfile.lock
The text was updated successfully, but these errors were encountered: