Feature #16744
closedFlag to load current bundle without using bundle exec
Description
The bundle exec
command is used by Ruby users primarily to start up a Ruby command or application with only its specific locked dependencies wired up. Unfortunately to do this it currently double-launches, executing a second Ruby command and doubling the base startup time for these use cases. With Bundler becoming part of the standard library, it seems a good time to add support for doing what bundle exec
does without requiring a relaunch.
For many years, JRuby has implemented the -G
/--gemfile
flag which requires in bundler/setup
before user code starts, eliminating the need to bundle exec in these situations.
https://github.com/jruby/jruby/commit/ea0eed02b4eb57c2198afa9fd47f94bc46cfc69f
This is based on the same flags in Rubinius:
https://github.com/rubinius/rubinius/commit/edc94f2e3a61d8c94031a942b2024c6c5aa3ea94
There's at least one more commit later on in Rubinius that fixes some interations between -G
and -S
.
Obviously this does not eliminate bundle exec
use cases where the target command is not a Ruby command, but that is a very specific (and rather strange to me) feature. The majority of use cases are booting up a Ruby command, for which this implementation of -G
would be sufficient (I think).
There may be different or additional ways that bundle exec
attempts to isolate the subcommand's environment and dependencies, but I believe requiring bundler/setup
at boot comes pretty close.
See also this bug report where I suggest using JRuby's embedding APIs to do bundle exec
. We very much want to help eliminate this double-launching, one way or another.
Updated by headius (Charles Nutter) about 5 years ago
- Description updated (diff)
Updated by ioquatix (Samuel Williams) about 5 years ago
Just so I understand this more clearly, could bin stubs use this in a shim to avoid needing to use bundle exec
?
koyoko% cat /home/samuel/.rbenv/versions/2.7.0/bin/bake
#!/usr/bin/env ruby
#
# This file was generated by RubyGems.
#
# The application 'bake' is installed as part of a gem, and
# this file is here to facilitate running it.
#
require 'rubygems'
version = ">= 0.a"
str = ARGV.first
if str
str = str.b[/\A_(.*)_\z/, 1]
if str and Gem::Version.correct?(str)
version = str
ARGV.shift
end
end
if Gem.respond_to?(:activate_bin_path)
load Gem.activate_bin_path('bake', 'bake', version)
else
gem "bake", version
load Gem.bin_path("bake", "bake", version)
end
Can we change the hashbang line to have -G and then get bundle exec
like behaviour for all shims?
Updated by Eregon (Benoit Daloze) about 5 years ago
ioquatix (Samuel Williams) wrote in #note-2:
Can we change the hashbang line to have -G and then get
bundle exec
like behaviour for all shims?
Extra arguments in the shebang line are not respected on all OS IIRC.
And require 'bundler/setup'
inside the shim seems much clearer anyway for that purpose.
But, I don't think we want to force using a Gemfile on every gem command.
At least I can think of a few use-cases where I either don't have a Gemfile or want to use a gem executable that's not part of them Gemfile (e.g. irb or pry).
FWIW RVM achieves something similar with gem-wrappers and a few other RVM gems/functionality without double-launching, but it sounds rather hacky (it changes the shebang of all gem executables to not be the Ruby exectuable anyway but some wrapper).
I think it's something we should solve either in RubyGems/Bundler or in Ruby implementations.
Updated by headius (Charles Nutter) about 5 years ago
- Description updated (diff)
Updated by Eregon (Benoit Daloze) about 5 years ago
I think supporting -G
would be valuable, because then it could be used interchangeably on multiple Ruby implementations.
I think so far very few people know about -G
, mostly because MRI doesn't have it.
Solving it directly in RubyGems/Bundler would be even nicer, but I'm not sure how feasible that is (it's been like that for years).
Updated by headius (Charles Nutter) about 5 years ago
Added missing link to the RubyGems/Bundler issue I mentioned.
But, I don't think we want to force using a Gemfile on every gem command.
This must be opt-in. There are many cases where you will not want to automatically pull in the Gemfile:
- No Gemfile exists
- Gemfile does not include a dependency for the command you want to run
- Gemfile contains a different version of the dependency than the version you want to run
- Gemfile is broken
Updated by Eregon (Benoit Daloze) about 5 years ago
Given that latest Bundler no longer creates a subprocess for bundle exec
, I think we don't need this anymore.
Or did I miss something?
https://github.com/rubygems/rubygems/issues/3246#issuecomment-606764738
Updated by headius (Charles Nutter) about 5 years ago
I think so far very few people know about -G, mostly because MRI doesn't have it.
Sadly I don't believe the Rubinius folks ever submitted a feature request. It might have been discussed briefly on the ruby-core list.
Updated by headius (Charles Nutter) about 5 years ago
Given that latest Bundler no longer creates a subprocess for bundle exec
Your example is incorrect. exec
reuses process ID.
$ jruby -e 'puts $$; exec %{jruby -e "puts $$"}'
85727
85727
Updated by headius (Charles Nutter) about 5 years ago
I understand your comment on my issue better now that we discussed it...
It does appear that Bundler added in the past few years the ability to detect that the bundle exec
target is a Ruby script with an appropriate shebang, where appropriate is one of:
-
env
with "ruby", "jruby", or "truffleruby" - Exact match to
RbConfig.ruby
output
If the target script has a matching shebang, it will be executed in-process.
So you are correct, in the cases where the target script has a matching shebang, it will not double-launch. This may be the large majority of cases. However it still double-launches in any case where there's no shebang or it doesn't match.
Perhaps we need a way to force this behavior, like bundle ruby mycommand
?
I suppose the other remaining benefit of -G
is that it's shorter than -rbundle/setup
if you want to put it in the RUBYOPT
environment variable.
Updated by nobu (Nobuyoshi Nakada) almost 5 years ago
- Status changed from Open to Third Party's Issue
If this is possible by -rbundle/setup
, bundler could try the benefit without changing ruby implementations.
And then, if it is significant but the option is too long, let's add the new option.
Updated by naruse (Yui NARUSE) almost 5 years ago
I rarely run bundle exec ruby
.
Usually I run something like bundle exec rake
, bundle exec rails
, bundle exec rspec
, bundle exec script/foo
and so on.
I think ruby -G
sounds nonsense.