R/call.R

Defines functions communicate_captured_call call_precommit call_and_capture

Documented in call_and_capture call_precommit

#' Make a call with [system2()] and capture the effects.
#' @param command The command to issue. A character string of length one.
#' @param args The command line arguments.
#' @param ... Arguments passed to [system2()].
#' @return
#' A list with:
#' * content of stderr
#' * content of stdout
#' * exit status
#' @keywords internal
call_and_capture <- function(command, args, ...) {
  if (length(command) != 1 | !inherits(command, "character")) {
    rlang::abort("The command must be a character string of length 1.")
  }
  stdout <- tempfile()
  writeLines("", stdout)
  stderr <- tempfile()
  writeLines("", stderr)
  if (!is.character(args)) {
    rlang::abort(paste0(
      "command line arguments must be a character vector, not of class `",
      class(args)[1], "`."
    ))
  }
  exit_status <- suppressWarnings(
    system2(command, args, ..., stdout = stdout, stderr = stderr)
  )
  stderr <- readLines(stderr)
  if (isTRUE(any(grepl("error", stderr, ignore.case = TRUE)))) {
    # conda run has exit status 0 but stderr with ERROR, we need to set exit
    # code in that case.
    exit_status <- -999
  }

  if (exit_status != 0) {
    if (length(stderr) < 1) {
      stderr <- paste0(
        "Could not recover stderr. Run the following command to get the error",
        paste(...)
      )
    }
  }
  list(
    stdout = readLines(stdout),
    stderr = stderr,
    exit_status = exit_status
  )
}

#' Call pre-commit
#'
#' Either via `conda run` (because conda env needs to be activated in general to
#' ensure an executable to runs successfully) or, if the installation method was
#' not conda, as a plain bash command.
#' @param ... Arguments passed to the command line call `pre-commit`.
#' @keywords internal
call_precommit <- function(...) {
  if (is_conda_installation()) {
    call_and_capture(
      reticulate::conda_binary(),
      c("run", "-n", "r-precommit", path_precommit_exec(), ...)
    )
  } else {
    call_and_capture(path_precommit_exec(), c(...))
  }
}

#' @param x The output of [call_and_capture()].
communicate_captured_call <- function(x, preamble = "") {
  if (x$exit_status != 0) {
    trans <- rlang::abort
  } else {
    trans <- rlang::warn
  }
  trans(paste0(preamble,
    "\nstderr: ",
    paste0(x$stderr, collapse = "\n"), "\n\nstdout: ",
    paste0(x$stdout, collapse = "\n"),
    collapse = "\n"
  ))
  x$exit_status
}

Try the precommit package in your browser

Any scripts or data that you put into this service are public.

precommit documentation built on Oct. 23, 2020, 6:18 p.m.