Skip to contents

Scripts in a repository usually depend on each other: a preparation script writes a file a later analysis script reads, or one source()s another. Running them in the wrong order fails for reasons that have nothing to do with reproducibility, so a run must order them first. This derives an order from three signals, in decreasing strength:

Usage

repro_run_order(files, extra_edges = NULL)

Arguments

files

a data frame with one row per code file, columns file_name, and reads / writes / sources list-columns of basenames (as produced by repro_file_io()). When reads/writes/sources are absent they are derived from a code_text list-column if present. An optional file_path column holds each file's path, and an optional source_refs list-column each source() reference as written, in the order of sources: when several files share the name a source() call gives, these decide which one it means, and if they cannot, no edge is added.

extra_edges

a list of c(from_file_name, to_file_name) pairs, or NULL (default). Each pair adds the rule that the file from_file_name runs before the file to_file_name, such as when an error about an undefined variable shows that the file defining it must run first.

Value

a data frame with columns file_name, order (1-based run position, NA when unplaceable), depends_on (comma-joined file_names that must run earlier), and order_basis (dependency, numeric, or none). Attribute "cycle" is a character vector of file_names in a dependency cycle (empty when acyclic); attribute "ambiguous" is TRUE when no ordering signal placed a multi-file set (they share order = NA, basis none). Attribute "fuzzy_sources" is a data frame (from, to) of source() edges that only resolved after normalising both basenames (a renumbered/ reworded script reference — see .repro_normalize_basename()), empty when every source() reference matched an exact basename. Attribute "source_edges" is a data frame (from, to) of every resolved source() edge, exact or fuzzy: from is the sourced file, to the file that sources it.

Details

  1. read-after-write — if file A's code writes x.csv and file B's code reads x.csv, A must precede B (hard data dependency);

  2. source() edges — if A source()s B, B must precede A;

  3. numeric filename prefixes — 0_prep.R before 1_analysis.R (a weak tie-breaker, not a dependency).

The read/write and source references come from the shared static analysis (code_file_refs() and a source scan); matching is by basename (as elsewhere). The dependency graph is topologically sorted; a cycle (A reads a file B writes and vice versa) cannot be ordered and is reported.

Examples

files <- data.frame(file_name = c("1_analysis.R", "0_prep.R"))
files$reads   <- list("clean.csv", character(0))
files$writes  <- list(character(0), "clean.csv")
files$sources <- list(character(0), character(0))
repro_run_order(files)
#>      file_name order depends_on order_basis
#> 1 1_analysis.R     2   0_prep.R  dependency
#> 2     0_prep.R     1                numeric