aboutsummaryrefslogtreecommitdiffstats
path: root/lib/bundler/cli/exec.rb
diff options
context:
space:
mode:
authorKir Shatrov <shatrov@me.com>2014-12-09 03:14:02 +0300
committerAndre Arko <andre@arko.net>2015-01-19 13:09:18 -0800
commitfd0acaa751cc72dc0625ea8373198423967edaee (patch)
tree7f79d9020c51e6e8afe25f0b23174ff93a5297a7 /lib/bundler/cli/exec.rb
parenta2343c9eabf5403d8ffcbca4dea33d18a60fc157 (diff)
downloadbundler-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/exec.rb')
-rw-r--r--lib/bundler/cli/exec.rb67
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