class GitHooks::SystemUtils::Command

Constants

ENV_WHITELIST

Attributes

bin_path[R]
name[R]
run_path[R]

Public Class Methods

new(name, options = {}) click to toggle source
# File lib/githooks/system_utils.rb, line 108
def initialize(name, options = {})
  @bin_path = options.delete(:bin_path) || SystemUtils.which(name) || name
  @run_path = options.delete(:chdir)
  @name     = name.to_s.gsub(/([\W-]+)/, '_')
end

Public Instance Methods

build_command(args, options) click to toggle source
# File lib/githooks/system_utils.rb, line 118
def build_command(args, options)
  Array(args).unshift(command_path(options))
end
call(*args, &_block)
Alias for: execute
command_path(options = {}) click to toggle source
# File lib/githooks/system_utils.rb, line 122
def command_path(options = {})
  options.delete(:use_name) ? name : bin_path.to_s
end
execute(*args) { |result| ... } click to toggle source
# File lib/githooks/system_utils.rb, line 155
def execute(*args, &_block) # rubocop:disable MethodLength, CyclomaticComplexity, AbcSize, PerceivedComplexity
  options = args.extract_options!

  command = build_command(args, options)
  command.unshift("cd #{run_path} ;") if run_path
  command.unshift('sudo') if options.delete(:use_sudo)
  command = Array(command.flatten.join(' '))

  command.unshift options.delete(:pre_pipe)  if options[:pre_pipe]
  command.push options.delete(:post_pipe) if options[:post_pipe]
  command = Array(command.flatten.join('|'))

  command.unshift options.delete(:pre_run)  if options[:pre_run]
  command.push options.delete(:post_run) if options[:post_run]
  command = shellwords(command.flatten.join(';'))

  error_file = Tempfile.new('ghstderr')

  script_file = Tempfile.new('ghscript')
  script_file.puts "exec 2>#{error_file.path}"
  script_file.puts command.join(' ')

  script_file.rewind

  begin
    real_command = "/usr/bin/env bash #{script_file.path}"

    output = with_sanitized_env(options.delete(:env)) do
      %x{ #{real_command} }
    end

    result = Result.new(output, error_file.read, $?)

    if GitHooks.verbose?
      if result.failure?
        STDERR.puts "---\nCommand failed with exit code [#{result.status.exitstatus}]",
                    "COMMAND: #{command.join(' ')}\n",
                    result.output.strip.empty? ? '' : "OUTPUT:\n#{result.output}\n---\n",
                    result.error.strip.empty? ? '' : "ERROR:\n#{result.error}\n---\n"
      else
        STDERR.puts "---\nCommand succeeded with exit code [#{result.status.exitstatus}]",
                    "COMMAND: #{command.join(' ')}\n",
                    result.output.strip.empty? ? '' : "OUTPUT:\n#{result.output}\n---\n",
                    result.error.strip.empty? ? '' : "ERROR:\n#{result.error}\n---\n"
      end
    end

    sanitize = [ :strip, :non_printable ]
    sanitize << :colors unless options.delete(:color)
    sanitize << :empty_lines if options.delete(:strip_empty_lines)
    result.sanitize!(*sanitize)

    result.tap { yield(result) if block_given? }
  ensure
    script_file.close
    script_file.unlink

    error_file.close
    error_file.unlink
  end
end
Also aliased as: call
method() click to toggle source
# File lib/githooks/system_utils.rb, line 114
def method
  @name.to_sym
end
sanitize_env(env = ENV.to_h, options = {}) click to toggle source
# File lib/githooks/system_utils.rb, line 126
def sanitize_env(env = ENV.to_h, options = {})
  include_keys = options.delete(:include) || ENV_WHITELIST
  exclude_keys = options.delete(:exclude) || []

  unless exclude_keys.empty? ^ include_keys.empty?
    fail ArgumentError, 'include and exclude are mutually exclusive'
  end

  env.to_h.reject do |key, _|
    exclude_keys.include?(key) || !include_keys.include?(key)
  end
end
with_sanitized_env(env = {}) { || ... } click to toggle source
# File lib/githooks/system_utils.rb, line 139
def with_sanitized_env(env = {})
  env ||= {}
  old_env = ENV.to_h
  new_env = sanitize_env(
    ENV.to_h.merge(env),
    include: ENV_WHITELIST | env.keys
  )

  begin
    ENV.replace(new_env)
    yield
  ensure
    ENV.replace(old_env)
  end
end