1 # frozen_string_literal: true
3 require_relative "../current_ruby"
7 attr_reader :options, :args, :cmd
9 TRAPPED_SIGNALS = %w[INT].freeze
11 def initialize(options, args)
15 @args << { close_others: !options.keep_file_descriptors? } unless Bundler.current_ruby.jruby?
20 SharedHelpers.set_bundle_environment
21 if bin_path = Bundler.which(cmd)
22 if !Bundler.settings[:disable_exec_load] && ruby_shebang?(bin_path)
23 return kernel_load(bin_path, *args)
25 kernel_exec(bin_path, *args)
27 # exec using the given command
28 kernel_exec(cmd, *args)
35 return unless cmd.nil?
36 Bundler.ui.error "bundler: exec needs a command to run"
40 def kernel_exec(*args)
42 rescue Errno::EACCES, Errno::ENOEXEC
43 Bundler.ui.error "bundler: not executable: #{cmd}"
46 Bundler.ui.error "bundler: command not found: #{cmd}"
47 Bundler.ui.warn "Install missing gem executables with `bundle install`"
51 def kernel_load(file, *args)
52 args.pop if args.last.is_a?(Hash)
55 Process.setproctitle(process_title(file, args)) if Process.respond_to?(:setproctitle)
56 require_relative "../setup"
57 TRAPPED_SIGNALS.each {|s| trap(s, "DEFAULT") }
59 rescue SystemExit, SignalException
61 rescue Exception # rubocop:disable Lint/RescueException
62 Bundler.ui.error "bundler: failed to load command: #{cmd} (#{file})"
63 Bundler::FriendlyErrors.disable!
67 def process_title(file, args)
68 "#{file} #{args.join(" ")}".strip
71 def ruby_shebang?(file)
73 "#!/usr/bin/env ruby\n",
74 "#!/usr/bin/env jruby\n",
75 "#!/usr/bin/env truffleruby\n",
80 Bundler.ui.warn "#{file} is empty"
84 first_line = File.open(file, "rb") {|f| f.read(possibilities.map(&:size).max) }
85 possibilities.any? {|shebang| first_line.start_with?(shebang) }