Project

General

Profile

Feature #16744

Flag to load current bundle without using bundle exec

Added by headius (Charles Nutter) 4 months ago. Updated 3 months ago.

Status:
Third Party's Issue
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:97629]

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.

https://github.com/rubygems/rubygems/issues/3246

#1

Updated by headius (Charles Nutter) 4 months ago

  • Description updated (diff)

Updated by ioquatix (Samuel Williams) 4 months 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) 4 months 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.

#4

Updated by headius (Charles Nutter) 4 months ago

  • Description updated (diff)

Updated by Eregon (Benoit Daloze) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 4 months 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) 3 months 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.

Also available in: Atom PDF