Description
Bundler fails to evaluate a local gemspec when Ruby Box is enabled with
RUBY_BOX=1.
The failure occurs before the requested command runs:
Bundler::GemspecError:
There was an error while loading `foo.gemspec`:
uninitialized constant Gem::Specification
This reproduces with an unmodified gem project generated by bundle gem. I
also reproduced the same problem in two unrelated existing gem projects,
Caotral and Oj.
Minimal reproduction
Generate a new gem using Bundler:
bundle gem foo
cd foo
bundle install
Running a command normally succeeds:
$ bundle exec ruby -e 'puts :ok'
ok
Enable Ruby Box and run the same command:
$ RUBY_BOX=1 bundle exec ruby -e 'puts :ok'
Bundler fails while evaluating the generated, unmodified foo.gemspec:
ruby: warning: Ruby::Box is experimental, and the behavior may change in the future!
See https://docs.ruby-lang.org/en/4.0/Ruby/Box.html for known issues, etc.
[!] There was an error while loading `foo.gemspec`:
uninitialized constant Gem::Specification. Bundler cannot continue.
# from /path/to/foo/foo.gemspec:5
# -------------------------------------------
#
> Gem::Specification.new do |spec|
# spec.name = "foo"
# -------------------------------------------
Expected behavior
Bundler evaluates the gemspec and runs the requested command:
Actual behavior
Bundler raises Bundler::GemspecError because Gem::Specification is not
available while evaluating the gemspec under Ruby Box.
Subprocess reproduction
The same issue occurs in Oj when its build invokes a Ruby subprocess:
RUBY_BOX=1 bundle exec rake
The outer Rake process starts, but the Ruby subprocess spawned for
extconf.rb fails:
/path/to/ruby -I. ../../../../ext/oj/extconf.rb
[!] There was an error while loading `oj.gemspec`:
uninitialized constant Gem::Specification. Bundler cannot continue.
# from /path/to/oj/oj.gemspec:6
# -------------------------------------------
#
> Gem::Specification.new do |s|
# s.name = "oj"
# -------------------------------------------
This suggests that Ruby subprocesses inheriting both the Bundler environment
and RUBY_BOX=1 are affected as well.
Environment
The minimal bundle gem foo reproduction was confirmed with:
Ruby: 4.0.6
RubyGems: 4.0.17
Bundler: 4.0.17
OS: Linux
The same failure was also reproduced in Caotral with Bundler 4.0.12.
Attempted workarounds
Adding this to the gemspec does not fix the problem:
require "rubygems/specification"
It proceeds further but then fails because Gem::Deprecate is unavailable.
Adding this instead also does not provide a usable workaround:
It causes a circular require, after which Bundler fails to materialize the
local gemspec.
I confirmed that the application test itself works if Bundler is started
without Ruby Box and a child Ruby process is started separately with:
RUBY_BOX=1
- Bundler's resolved
$LOAD_PATH passed through RUBYLIB
- inherited
RUBYOPT cleared
--disable-gems
For example:
env = {
"RUBY_BOX" => "1",
"RUBYOPT" => nil,
"RUBYLIB" => $LOAD_PATH.join(File::PATH_SEPARATOR),
}
exec(
env,
RbConfig.ruby,
"--disable-gems",
"-Ilib",
"path/to/test.rb",
)
This avoids evaluating the gemspec inside Ruby Box, but it is not a practical
general workaround for bundle exec.
Additional context
Ruby Box must be enabled when the Ruby process starts. It cannot be enabled
after Bundler has initialized:
https://docs.ruby-lang.org/en/4.0/Ruby/Box.html
Is Bundler expected to support running under RUBY_BOX=1? If so, it appears
that the RubyGems constants required by Bundler.eval_gemspec are not
initialized in the relevant box.
Description
Bundler fails to evaluate a local gemspec when Ruby Box is enabled with
RUBY_BOX=1.The failure occurs before the requested command runs:
This reproduces with an unmodified gem project generated by
bundle gem. Ialso reproduced the same problem in two unrelated existing gem projects,
Caotral and Oj.
Minimal reproduction
Generate a new gem using Bundler:
Running a command normally succeeds:
Enable Ruby Box and run the same command:
$ RUBY_BOX=1 bundle exec ruby -e 'puts :ok'Bundler fails while evaluating the generated, unmodified
foo.gemspec:Expected behavior
Bundler evaluates the gemspec and runs the requested command:
Actual behavior
Bundler raises
Bundler::GemspecErrorbecauseGem::Specificationis notavailable while evaluating the gemspec under Ruby Box.
Subprocess reproduction
The same issue occurs in Oj when its build invokes a Ruby subprocess:
RUBY_BOX=1 bundle exec rakeThe outer Rake process starts, but the Ruby subprocess spawned for
extconf.rbfails:This suggests that Ruby subprocesses inheriting both the Bundler environment
and
RUBY_BOX=1are affected as well.Environment
The minimal
bundle gem fooreproduction was confirmed with:The same failure was also reproduced in Caotral with Bundler 4.0.12.
Attempted workarounds
Adding this to the gemspec does not fix the problem:
It proceeds further but then fails because
Gem::Deprecateis unavailable.Adding this instead also does not provide a usable workaround:
It causes a circular require, after which Bundler fails to materialize the
local gemspec.
I confirmed that the application test itself works if Bundler is started
without Ruby Box and a child Ruby process is started separately with:
RUBY_BOX=1$LOAD_PATHpassed throughRUBYLIBRUBYOPTcleared--disable-gemsFor example:
This avoids evaluating the gemspec inside Ruby Box, but it is not a practical
general workaround for
bundle exec.Additional context
Ruby Box must be enabled when the Ruby process starts. It cannot be enabled
after Bundler has initialized:
https://docs.ruby-lang.org/en/4.0/Ruby/Box.html
Is Bundler expected to support running under
RUBY_BOX=1? If so, it appearsthat the RubyGems constants required by
Bundler.eval_gemspecare notinitialized in the relevant box.