diff options
author | Kir Shatrov <shatrov@me.com> | 2014-12-09 03:14:02 +0300 |
---|---|---|
committer | Andre Arko <andre@arko.net> | 2015-01-19 13:09:18 -0800 |
commit | fd0acaa751cc72dc0625ea8373198423967edaee (patch) | |
tree | 7f79d9020c51e6e8afe25f0b23174ff93a5297a7 /lib/bundler/cli | |
parent | a2343c9eabf5403d8ffcbca4dea33d18a60fc157 (diff) | |
download | bundler-fd0acaa751cc72dc0625ea8373198423967edaee.tar.gz |
Optimized bundle-exec
(from https://trello.com/c/bf90QcsN/66-exec-as-soon-as-possible)
Right now the exec command loads the entire Gemfile, the entire lockfile, resolves the gemfile against the lockfile, and then execs. Instead, let's check $PATH for the exec command and exec instantly if it's there.
Diffstat (limited to 'lib/bundler/cli')
-rw-r--r-- | lib/bundler/cli/exec.rb | 67 |
1 files changed, 55 insertions, 12 deletions
diff --git a/lib/bundler/cli/exec.rb b/lib/bundler/cli/exec.rb index 1739ab6f..d8836659 100644 --- a/lib/bundler/cli/exec.rb +++ b/lib/bundler/cli/exec.rb @@ -1,30 +1,31 @@ module Bundler class CLI::Exec - attr_reader :options, :args + attr_reader :options, :args, :cmd def initialize(options, args) @options = options + @cmd = args.shift @args = args + + if RUBY_VERSION >= "2.0" + @args << { :close_others => !options.keep_file_descriptors? } + elsif options.keep_file_descriptors? + Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." + end end def run - Bundler.definition.validate_ruby! - Bundler.load.setup_environment - begin - if RUBY_VERSION >= "2.0" - @args << { :close_others => !options.keep_file_descriptors? } - elsif options.keep_file_descriptors? - Bundler.ui.warn "Ruby version #{RUBY_VERSION} defaults to keeping non-standard file descriptors on Kernel#exec." + if cmd.nil? + raise ArgumentError.new end - # Run - Kernel.exec(*args) + execute_within_path rescue Errno::EACCES - Bundler.ui.error "bundler: not executable: #{args.first}" + Bundler.ui.error "bundler: not executable: #{cmd}" exit 126 rescue Errno::ENOENT - Bundler.ui.error "bundler: command not found: #{args.first}" + Bundler.ui.error "bundler: command not found: #{cmd}" Bundler.ui.warn "Install missing gem executables with `bundle install`" exit 127 rescue ArgumentError @@ -33,5 +34,47 @@ module Bundler end end + private + + def execute_within_path + if RUBY_VERSION >= "1.9" + path.each do |path| + bin_path = File.join(path, @cmd) + if bin_path == Bundler.which(@cmd) + Kernel.exec(build_env, bin_path, *args) + end + end + end + + # fallback + Bundler.definition.validate_ruby! + Bundler.load.setup_environment + Kernel.exec(@cmd, *args) + end + + def path + ENV['PATH'].split(":").map { |p| File.expand_path(p) } + end + + def build_env + rubyopt = [ENV["RUBYOPT"]].compact + if rubyopt.empty? || rubyopt.first !~ /-rbundler\/setup/ + rubyopt << %|-rbundler/setup| + end + + rubylib = (ENV["RUBYLIB"] || "").split(File::PATH_SEPARATOR) + rubylib.unshift File.expand_path('../../..', __FILE__) + + { + 'RUBYOPT' => rubyopt.join(' '), + 'RUBYLIB' => rubylib.uniq.join(File::PATH_SEPARATOR), + 'FORCE_TTY' => 'true' + } + end + + def env_string + build_env.to_a.map { |k| "#{k[0]}=#{k[1]}"}.join(" ") + end + end end |