class U3dCore::CommandExecutor
Executes commands and takes care of error handling and more
Public Class Methods
@param command [String] The command to be executed @param print_all [Boolean] Do we want to print out the command output while running? @param print_command [Boolean] Should we print the command that's being executed @param error [Block] A block that's called if an error occurs @param prefix [Array] An array containg a prefix + block which might get applied to the output @param admin [Boolean] Do we need admin privilege for this command? @return [String] All the output as string @deprecated
# File lib/u3d_core/command_executor.rb, line 59 def execute(command: nil, print_all: false, print_command: true, error: nil, prefix: nil, admin: false) print_all = true if U3dCore::Globals.verbose? prefix ||= {} output_callback = nil if print_all output_callback = proc do |line| # Prefix the current line with a string prefix.each do |element| line = element[:prefix] + line if element[:block] && element[:block].call(line) end UI.command_output(line) end end execute_command(command: command, output_callback: output_callback, print_command: print_command, error_callback: error, admin: admin) end
@param command [String] The command to be executed @param output_callback [Block] the command to pass to print output @param print_command [Boolean] Should we print the command that's being executed @param error_callback [Block] A block that's called if an error occurs @param admin [Boolean] Do we need admin privilege for this command? @return [String] All the output as string
# File lib/u3d_core/command_executor.rb, line 83 def execute_command(command: nil, output_callback: nil, print_command: true, error_callback: nil, admin: false) command = command.join(' ') if command.is_a?(Array) UI.command(command) if print_command command = grant_admin_privileges(command) if admin execute_command_low(command: command, output_callback: output_callback, error_callback: error_callback) end
# File lib/u3d_core/command_executor.rb, line 147 def grant_admin_privileges(command) if Helper.windows? raise CredentialsError, "The command \'#{command}\' must be run in administrative shell" unless has_admin_privileges? else env_username = ENV['USER'] unless env_username == "root" cred = U3dCore::Credentials.new(user: env_username) raise CredentialsError, "The command \'#{command}\' must be run with admin privileges" unless has_admin_privileges? command = "sudo -k && echo #{cred.password.shellescape} | sudo -S bash -c \"#{command}\"" end end UI.verbose 'Admin privileges granted for command execution' command end
rubocop:disable PredicateName,PerceivedComplexity
# File lib/u3d_core/command_executor.rb, line 119 def has_admin_privileges?(retry_count: 2) # rubocop:enable PredicateName,PerceivedComplexity if Helper.windows? begin result = system_no_output('reg query HKU\\S-1-5-19') rescue StandardError result = false end else env_username = ENV['USER'] if env_username == "root" result = true else credentials = U3dCore::Credentials.new(user: env_username) begin result = system_no_output("sudo -k && echo #{credentials.password.shellescape} | sudo -S /usr/bin/whoami") rescue StandardError result = false end credentials.forget_credentials unless result # FIXME: why? end end # returns false if result is nil (command execution fail) result = result ? true : false result = has_admin_privileges?(retry_count: retry_count - 1) unless retry_count <= 0 || result result end
Cross-platform way of finding an executable in the $PATH. Respects the $PATHEXT, which lists valid file extensions for executables on Windows.
which('ruby') #=> /usr/bin/ruby
Derived from stackoverflow.com/a/5471032/3005
# File lib/u3d_core/command_executor.rb, line 36 def which(cmd) # PATHEXT contains the list of file extensions that Windows considers executable, semicolon separated. # e.g. ".COM;.EXE;.BAT;.CMD" exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : [''] ENV['PATH'].split(File::PATH_SEPARATOR).each do |path| exts.each do |ext| cmd_path = File.expand_path("#{cmd}#{ext}", path) return cmd_path if File.executable?(cmd_path) && !File.directory?(cmd_path) end end return nil end
Private Class Methods
# File lib/u3d_core/command_executor.rb, line 92 def execute_command_low(command: nil, output_callback: nil, error_callback: nil) output = [] begin status = U3dCore::Runner.run(command) do |stdin, _stdout, _pid| stdin.each do |l| line = l.strip # strip so that \n gets removed output << line output_callback.call(l) if output_callback end end raise "Exit status: #{status}".red if !status.nil? && status.nonzero? rescue StandardError => ex # This could happen # * if the status is failed # * when the environment is wrong: # > invalid byte sequence in US-ASCII (ArgumentError) output << ex.to_s o = output.join("\n") UI.verbose o raise ex unless error_callback error_callback.call(o, nil) end return output.join("\n") end
# File lib/u3d_core/command_executor.rb, line 162 def system_no_output(command) system(command, out: File::NULL, err: File::NULL) end