Skip to contents

Runs each script with callr::r() from run_dir, with lib_dir prepended to the subprocess .libPaths() so the throwaway library is seen. Each run is bounded by timeout seconds; its exit, error, stdout and stderr are captured. A script whose inputs are known-missing (in skip) is not run — it is recorded skipped_missing_inputs, since it cannot succeed and would only produce a confusing error. callr isolates a crash to the subprocess; it does not sandbox the filesystem or network, so this only runs on explicit opt-in.

Usage

repro_run_scripts(
  run_tbl,
  order,
  lib_dir = NULL,
  timeout = 600,
  skip = character(0),
  parses = NULL,
  failed_deps = character(0),
  deadline = NULL
)

Arguments

run_tbl

repro_write_scripts() output (file_name, script_path, run_dir)

order

a vector of file_names in the order to run (unplaceable files are appended at the end in input order)

lib_dir

throwaway library to expose to each subprocess (or NULL)

timeout

per-script timeout in seconds

skip

character vector of file_names to record as skipped_missing_inputs instead of running

parses

named logical (by file_name); a file that will not parse is recorded not_parsed and not run

failed_deps

character vector of package names that repro_install_deps() could not install (CRAN Archive retry included) — used only to tell apart a script that failed because ITS OWN dependency is genuinely unavailable (dependency_unavailable) from a script that failed for any other reason (errored), so an unavailable package does not read as a bug in the paper's code

deadline

the time (Sys.time() plus the time for all scripts together) after which no script is started, recorded as skipped_time_limit; a running script is stopped then. NULL (the default) sets no such limit.

Value

a data frame with file_name, outcome (one of ran_ok, errored, timed_out, not_parsed, skipped_missing_inputs, dependency_unavailable), error (message or ""), error_type (undefined_variable, timeout, dependency_unavailable, runtime, or NA), undefined_var (the missing variable name when error_type == "undefined_variable", else NA), stdout, stderr, elapsed (seconds), and script_lines (list-column: the EXECUTED script's own text, one element per source line — the exact text stdout's echoed statements were run from, so read_r_output() can match them back to a line number; empty character(0) for a script that did not run).

Examples

# \donttest{
if (requireNamespace("callr", quietly = TRUE)) {
  root <- file.path(tempdir(), "run_demo")
  plan <- data.frame(file_name = "analysis.R", target_path = "analysis/analysis.R")
  code <- list(analysis.R = c("x <- c(1, 2, 3)", "print(mean(x))"))
  run_tbl <- repro_write_scripts(code, list(), plan, root)
  res <- repro_run_scripts(run_tbl, order = "analysis.R")
  res[, c("file_name", "outcome")]
}
#> [repro]   rewriting 'analysis.R' (29 bytes) ...
#> [repro]   -> running 'analysis.R' (timeout 600s) ...
#> [repro]   <- 'analysis.R' done in 0.5s (ok; stdout 40 chars, stderr 0 chars)
#>    file_name outcome
#> 1 analysis.R  ran_ok
# }