bundler/inline: perform installation from a forked child - #7941
Conversation
754c404 to
e715b14
Compare
72db816 to
c9c77d2
Compare
| # If the install succeeded, we need to refresh gem info | ||
| Bundler.reset! | ||
|
|
||
| builder = Bundler::Dsl.new | ||
| builder.instance_eval(&gemfile) | ||
| builder.check_primary_source_safety | ||
|
|
||
| definition = builder.to_definition(nil, true) | ||
| def definition.lock(*); end | ||
| definition.validate_runtime! |
There was a problem hiding this comment.
Of course it's harder than I expected, because since the install is done in a subprocess the parent need to refresh the gem info. I'm super un-familiar with rubygems/bundler do I don't know what the clean way of doing this, but it seems to work except for native gems :/
There is 3 failing specs left I don't know how to fix:
rspec ./spec/runtime/inline_spec.rb:193 # bundler/inline#gemfile installs subdependencies quietly if necessary when the install option is not set, and multiple sources used
rspec ./spec/runtime/inline_spec.rb:218 # bundler/inline#gemfile installs quietly from git if necessary when the install option is not set
rspec ./spec/runtime/inline_spec.rb:323 # bundler/inline#gemfile installs gems with native extensions in later gemfile calls
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
| else | ||
| do_install.call | ||
| end | ||
| end |
This comment was marked as spam.
This comment was marked as spam.
Sorry, something went wrong.
413e8d3 to
11962a7
Compare
Unless of course fork isn't available. Alternate: ruby#7930, ruby#7933 Fix: ruby#7930, ruby#7933 When bundler inline has to install gems, it loads more dependencies than when it goes through the fast path of all gems being installed. One of them is `securerandom` so if trying to use bundler/inline with a gem that have a dependency on securerandom that don't match the default version, the script fails with `Gem::LoadError`. This can be preproduced on Ruby 3.2.x, after making sure to `gem uninstall securerandom` so only the default gem remains, and then running the following script: ```ruby require 'bundler/inline' gemfile do source 'https://rubygems.org' gem 'activesupport', '7.2.0' # depends on securerandom >= 0.3 end require 'securerandom' ```
bf83056 to
21586e7
Compare
|
@casperisfine @byroot Sorry to noisy notification. I finally resolved the CI failure and rebased with the current master branch. Maybe Ruby 3.2 will also reach EOL and this issue will no longer be an issue. However, the default gems will continue to remain in rubygems and bundler, so I will merge this. |
|
No worries, I'm not notified on pushes. Thanks for the merge! |
`script/run_snippets.sh` runs the snippets through `bundler/inline`, which
installs the gems and sets up the runtime in one process. Since bundler
4.0.15 that produces a `$LOAD_PATH` built from specs that never learned their
real `require_paths`, so every gem is assumed to use the default `lib`.
`concurrent-ruby`, an ActiveSupport dependency, uses `lib/concurrent-ruby`,
and the first snippet dies before running a single example:
Running avoid_fixture_name_collision.rb
There was an error while trying to load the gem 'rails'.
Gem Load Error is: cannot load such file -- concurrent/map
CI hits this on every run because its gem home starts out empty, so the
snippets are always the ones installing those gems. Bisecting the released
gems against a fresh gem home puts the break at exactly 4.0.15, which shipped
on 2026-06-24 -- the day after the last green build on `main`.
The cause is ruby/rubygems#9618: `Installer#install` now calls
`release_resolution_memory!`, discarding the memoized remote index before
installing. `Source::Rubygems#install` annotates the resolved
`EndpointSpecification` in place rather than swapping it, and
`EndpointSpecification#load_paths` only reports the gemspec's real
`require_paths` while that annotation is present. Any re-resolution after the
install therefore rebuilds pristine specs that report `<gem>/lib`. It is still
present in 4.0.18; `master` avoids it only incidentally, by installing in a
forked child (ruby/rubygems#7941, never backported to 4.0).
Pin until there is a release we can move to.
`script/run_snippets.sh` runs the snippets through `bundler/inline`, which
installs the gems and sets up the runtime in one process. Since bundler
4.0.15 that produces a `$LOAD_PATH` built from specs that never learned their
real `require_paths`, so every gem is assumed to use the default `lib`.
`concurrent-ruby`, an ActiveSupport dependency, uses `lib/concurrent-ruby`,
and the first snippet dies before running a single example:
Running avoid_fixture_name_collision.rb
There was an error while trying to load the gem 'rails'.
Gem Load Error is: cannot load such file -- concurrent/map
CI hits this on every run because its gem home starts out empty, so the
snippets are always the ones installing those gems. Bisecting the released
gems against a fresh gem home puts the break at exactly 4.0.15, which shipped
on 2026-06-24 -- the day after the last green build on `main`.
The cause is ruby/rubygems#9618: `Installer#install` now calls
`release_resolution_memory!`, discarding the memoized remote index before
installing. `Source::Rubygems#install` annotates the resolved
`EndpointSpecification` in place rather than swapping it, and
`EndpointSpecification#load_paths` only reports the gemspec's real
`require_paths` while that annotation is present. Any re-resolution after the
install therefore rebuilds pristine specs that report `<gem>/lib`. It is still
present in 4.0.18; `master` avoids it only incidentally, by installing in a
forked child (ruby/rubygems#7941, never backported to 4.0).
Reported upstream as ruby/rubygems#9781. Pin until there is a release we
can move to.
Unless of course fork isn't available.
Alternate: #7930, #7933
Fix: #7930, #7933
When bundler inline has to install gems, it loads more dependencies than when it goes through the fast path of all gems being installed.
One of them is
securerandomso if trying to use bundler/inline with a gem that have a dependency on securerandom that don't match the default version, the script fails withGem::LoadError.This can be preproduced on Ruby 3.2.x, after making sure to
gem uninstall securerandomso only the default gem remains, and then running the following script: