Reads a legacy source job and copies its deterministic choices into a
supported template. Writes the migrated job and an evidence report beside
it. Review the remaining EDIT: markers before rendering the job.
Usage
migrate_job(
source,
subject,
type,
prefix = NULL,
qualifier = NULL,
lst = NULL,
log = NULL,
reference = NULL,
dir = NULL
)Arguments
- source
Path to one legacy source job, relative to the working directory or absolute.
- subject
Grouping topic for the new job's filename. It is a statistical endpoint only when the job analyses one; an endpoint-free job may use a topic such as
"cohort".- type
Analysis-type field for the new job's filename.
- prefix
Template prefix, such as
"dc", or a template's full name, such as"dc-tables", which carries its qualifier and leavesqualifierNULL. Read from the SAS filename whenNULL. When given withoutqualifier, the qualifier is still read from the filename's second field if that field names one of this prefix's templates.- qualifier
Template qualifier, such as
"tables". Read from the SAS filename whenNULL. When given withoutprefix, the prefix is read from the filename and this qualifier is used. Filename fields must match[A-Za-z0-9_]+.- lst
Optional path to a SAS listing, relative to the working directory or absolute. Defaults to the same-named file beside
sourcewhen present.- log
Optional path to a SAS log, relative to the working directory or absolute. Defaults to the same-named file beside
sourcewhen present.- reference
Optional vector of paths to output references, such as RTF or DOCX files, relative to the working directory or absolute. They record comparison targets, not analysis choices.
- dir
Any directory in the study, used only to locate the study root. Defaults to the directory of
source.
Details
A converter is available for dc-tables, dc-gfup,
dc-trends, and dc-eda, each interpreting its own source
choices; choices the interpreter does not recognize remain for review.
Legacy EDA reports migrate into dc-eda with
SECTIONS <- c("continuous", "percent", "count"), the pages they
drew. Naming a deprecated template warns and writes the job from its
replacement. Naming a template by its name before a rename, such as
dp-trends, warns and writes the job from the renamed template,
dc-trends; a legacy source whose own file name carries the old name,
such as dp.trends.sas, migrates into the renamed template without
a warning, since that name is not the caller's to change. A
template with no converter yet still migrates: it is scaffolded with every
EDIT: marker kept, the evidence travels with it, and the report
says the migration adapter is not yet available.
Relative source, lst, log and reference paths
resolve against the working directory, as in any R function; dir
only locates the study root. Each file must exist, be readable and lie
beneath that root, and symbolic links are checked after resolution. The
evidence files are never modified. The report records whether the listing
and log were supplied, found beside the source, or not found.
The job uses the filename and study folder selected by add_job.
Its report replaces the .qmd extension with -migration.md and
records study-relative evidence paths, SHA-256 checksums, the package
version, translated choices, unresolved choices, and ignored material.
Source text quoted in the report is masked, whichever converter ran:
string literal contents (R raw strings included), SAS and R comment bodies,
%let values (whole, even when a macro-quoting function such as
%str() holds a semicolon), %put text, unquoted
title and footnote text, and digit runs of five or more are
replaced by placeholders such as "[string]" or [text], and
Quarto or R Markdown prose and YAML are withheld.
Statement keywords, variable names and operators remain. Absolute paths in
any remaining text are redacted. The job is not masked. SAS log errors
leave a blocking EDIT: marker in the generated job.
Listings, RTF files and log messages may contain patient observations.
Their text is withheld; locations remain available for local review.
Logs retain severity, error codes and recognized aggregate counts only.
Both outputs are prepared as temporary files beside their targets before placement. Migration refuses to overwrite an existing target, checked for each output immediately before it is placed. Outputs are placed by hard link, which cannot replace an existing file; where the filesystem refuses hard links, the prepared file is renamed into place after a fresh check, so a concurrent writer landing between that check and the rename can still be replaced. If placement fails, only the outputs this call placed are removed, along with its temporary files.
Examples
# \donttest{
root <- file.path(tempdir(), "migrate-job-example")
invisible(hvtiRutilities::study_setup(root, "Example", 1L, renv = FALSE))
# A legacy follow-up job; the template is read from its name, dc.gfup.
sas <- file.path(hvtiRutilities::study_dir("descriptive", root), "dc.gfup.sas")
writeLines(c("data followup;", " set built;", "run;",
"proc means data=followup; var iv_dead; by dead; run;"), sas)
job <- migrate_job(sas, subject = "cohort", type = "eda")
basename(job)
#> [1] "dc.gfup.cohort.eda.qmd"
# The choices it translated into the new job ...
grep("^(EVENT|FOLLOWUP) <- ", readLines(job), value = TRUE)
#> [1] "EVENT <- \"dead\"" "FOLLOWUP <- c(\"iv_dead\")"
# ... and the report beside it, saying what was translated and what is left
# to review.
report <- readLines(sub("[.]qmd$", "-migration.md", job))
headings <- grep("^## ", report)
first <- which(report[headings] == "## Translated")
# The Translated section and the one after it, Unresolved.
report[headings[first]:(headings[first + 2L] - 1L)]
#> [1] "## Translated"
#> [2] ""
#> [3] "- line=4; text=var iv_dead;; reason=Declared follow-up fields; no interval derivation reproduced."
#> [4] "- line=4; text=by dead;; reason=Leading BY field supplies event evidence; other sort fields do not filter data."
#> [5] ""
#> [6] "## Unresolved"
#> [7] ""
#> [8] "- line=2; text=set built;; reason=study_config(): [absolute path]) after the default study dataset exists."
#> [9] ""
unlink(root, recursive = TRUE)
# }