class Terrapin::CommandLine

def best_runner

def best_runner
  [ProcessRunner, BackticksRunner].detect do |runner|
    runner.supported?
  end.new
end

def bit_bucket

def bit_bucket
  OS.unix? ? "2>/dev/null" : "2>NUL"
end

def colored(text, ansi_color = "\e[32m")

def colored(text, ansi_color = "\e[32m")
  if @logger && @logger.respond_to?(:tty?) && @logger.tty?
    "#{ansi_color}#{text}\e[0m"
  else
    text
  end
end

def command(interpolations = {})

def command(interpolations = {})
  cmd = [path_prefix, @binary, interpolate(@params, interpolations)]
  cmd << bit_bucket if @swallow_stderr
  cmd.join(" ").strip
end

def command_error_output

def command_error_output
  output.error_output
end

def command_output

def command_output
  output.output
end

def environment

def environment
  @supplemental_environment ||= {}
end

def environment

def environment
  self.class.environment.merge(@environment)
end

def execute(command)

def execute(command)
  runner.call(command, environment, runner_options)
end

def fake!

def fake!
  @runner = FakeRunner.new
end

def initialize(binary, params = "", options = {})

def initialize(binary, params = "", options = {})
  if options.nil?
    raise ArgumentError, "3rd argument to CommandLine.new should be a" \
      "hash of values that will be interpolated into the command line"
  end
  @options = options.dup
  @binary = binary.dup
  @params = params.to_s.dup
  @runner = @options.delete(:runner) || self.class.runner
  @logger = @options.delete(:logger) || self.class.logger
  @swallow_stderr = @options.delete(:swallow_stderr)
  @expected_outcodes = @options.delete(:expected_outcodes) || [0]
  @environment = @options.delete(:environment) || {}
  @runner_options = @options.delete(:runner_options) || {}
end

def interpolate(pattern, interpolations)

def interpolate(pattern, interpolations)
  interpolations = stringify_keys(interpolations)
  pattern.gsub(/:\{?(\w+)\b\}?/) do |match|
    key = match.tr(":{}", "")
    if interpolations.key?(key)
      shell_quote_all_values(interpolations[key])
    else
      match
    end
  end
end

def log(text)

def log(text)
  if @logger
    @logger.info(text)
  end
end

def os_path_prefix

def os_path_prefix
  if OS.unix?
    unix_path_prefix
  else
    windows_path_prefix
  end
end

def output

def output
  @output || Output.new
end

def path

def path
  @supplemental_path
end

def path=(supplemental_path)

def path=(supplemental_path)
  @supplemental_path = Array(supplemental_path).
    flatten.
    join(OS.path_separator)
end

def path_prefix

def path_prefix
  if !self.class.path.nil? && !self.class.path.empty?
    os_path_prefix
  end
end

def run(interpolations = {})

def run(interpolations = {})
  @exit_status = nil
  begin
    full_command = command(interpolations)
    log("#{colored("Command")} :: #{full_command}")
    @output = execute(full_command)
  rescue Errno::ENOENT => e
    raise Terrapin::CommandNotFoundError, e.message
  ensure
    @exit_status = $?.respond_to?(:exitstatus) ? $?.exitstatus : 0
  end
  if @exit_status == 127
    raise Terrapin::CommandNotFoundError
  end
  unless @expected_outcodes.include?(@exit_status)
    message = [
      "Command '#{full_command}' returned #{@exit_status.inspect}. Expected #{@expected_outcodes.join(", ")}",
      "Here is the command output: STDOUT:\n", command_output,
      "\nSTDERR:\n", command_error_output
    ].join("\n")
    raise Terrapin::ExitStatusError, message
  end
  command_output
end

def runner

def runner
  @runner || best_runner
end

def runner_options

def runner_options
  @default_runner_options ||= {}
end

def runner_options

def runner_options
  self.class.runner_options.merge(@runner_options)
end

def shell_quote(string)

def shell_quote(string)
  return "" if string.nil?
  string = string.to_s if string.respond_to? :to_s
  if OS.unix?
    if string.empty?
      "''"
    else
      string.split("'", -1).map{|m| "'#{m}'" }.join("\\'")
    end
  else
    %{"#{string}"}
  end
end

def shell_quote_all_values(values)

def shell_quote_all_values(values)
  Array(values).map(&method(:shell_quote)).join(" ")
end

def stringify_keys(hash)

def stringify_keys(hash)
  Hash[hash.map{ |k, v| [k.to_s, v] }]
end

def unfake!

def unfake!
  @runner = nil
end

def unix_path_prefix

def unix_path_prefix
  "PATH=#{self.class.path}#{OS.path_separator}$PATH;"
end

def windows_path_prefix

def windows_path_prefix
  "SET PATH=#{self.class.path}#{OS.path_separator}%PATH% &"
end