def run(commandline, echo = false, stdin = nil)
      log.debug "running `#{commandline}`"

      out_recorder = echo ? RecordingIO.new(STDOUT) : RecordingIO.new
      err_recorder = echo ? RecordingIO.new(STDERR) : RecordingIO.new

      status = Open4.spawn(commandline, stdin: stdin, stdout: out_recorder,
                                        stderr: err_recorder, quiet: true).exitstatus

      log.debug "`#{commandline}` exited with status #{status}"

      if status != 0
        log.warn("`#{commandline}` failed with status #{status}")
        out = out_recorder.record
        err = err_recorder.record
        if out != "" || err != ""
          log.warn("Output follows:")
          log.warn(out) unless out == ""
          log.warn(err) unless err == ""
        end
        fail ExecutionFailed.new(commandline, status, out, err)
      end

      out_recorder.record
    end
def run(commandline, echo = false, stdin = nil)
      log.debug "running `#{commandline}`"

      out_recorder = echo ? RecordingIO.new(STDOUT) : RecordingIO.new
      err_recorder = echo ? RecordingIO.new(STDERR) : RecordingIO.new

      status = Open4.spawn(commandline, stdin: stdin, stdout: out_recorder,
                                        stderr: err_recorder, quiet: true).exitstatus

      log.debug "`#{commandline}` exited with status #{status}"

      if status != 0
        log.warn("`#{commandline}` failed with status #{status}")
        out = out_recorder.record
        err = err_recorder.record
        if out != "" || err != ""
          log.warn("Output follows:")
          log.warn(out) unless out == ""
          log.warn(err) unless err == ""
        end
        fail ExecutionFailed.new(commandline, status, out, err)
      end

      out_recorder.record
    end
runs a noninteractive executable and returns its output as a string
 raises ExecutionFailed if the exit status is not 0
 optionally echoes the executable's output/error to standard output/error