Runs commands connected with pipes, as cmd1 | cmd2 in a shell. The
standard output of each command is the standard input of the next one.
The data flows between the processes through operating system pipes, not
through R. R gets the standard output of the last command and the
standard error of every command.
Describe each command with run_step(), which takes the same command,
arguments and env_name as run(). Each command can run in a
different Conda environment. Commands that do not set an environment
use the env_name of run_pipeline().
Usage
run_pipeline(
...,
env_name = "condathis-env",
method = "auto",
verbose = c("output", "silent", "cmd", "spinner", "full"),
error = c("cancel", "continue"),
stdout = "|",
stderr = "|",
stdin = NULL,
input = NULL,
binary = FALSE,
supervise = TRUE,
cleanup_tree = TRUE,
linux_pdeathsig = FALSE,
activate = TRUE,
timeout = Inf
)Arguments
- ...
Two or more pipeline steps, built with
run_step(), in pipeline order. Splice in a list of steps, built withlist()orc(), with!!!, as inrun_pipeline(!!!steps).c()on steps gives a list of steps that laterc()calls extend, as inc(c(step_1, step_2), step_3). To add a step to a plain list or toNULL, wrap it inlist(), as inc(steps, list(step)).c()with a plain list orNULLfirst splits a step into its fields. Any other value aborts with classcondathis_run_pipeline_invalid_step, so name every option below in full. Fewer than two steps abort with classcondathis_run_pipeline_too_few_commands.- env_name
Character string with the default environment of the steps that do not set their own, or an environment given by
env_path(). Defaults to"condathis-env", whichrun_pipeline()creates (empty, with the backend thatmethodselects) when it does not exist.run_pipeline()never creates any other missing environment and fails pererror. A name must follow the rules of theenv_nameargument ofrun(). Invalid values abort with classcondathis_invalid_env_name.- method
Character string naming the default backend of the steps that do not set their own
method(seerun_step())."auto"(the default) uses the backend that owns each environment, and otherwise the first available backend ingetOption("condathis.backend_priority")order (see condathis-options). Any name fromlist_registered_backend_names()selects that backend."micromamba"is built in. The name of a backend whose package condathis knows also selects it, such as"rattler"of therattlerthispackage. condathis loads that package, and aborts with classcondathis_backend_not_installedwhen it is not installed."native"is a deprecated alias for"micromamba"(it warns once per session). If you name a backend other than the owner of an environment, condathis warns (condathis_backend_mismatch_warning) and uses the owner. An environment found under several backends aborts with classcondathis_backend_ambiguous_env, unlessmethodnames one of them. Witherror = "continue", its steps get status 127. Steps that share an environment must agree on the backend. Otherwiserun_pipeline()aborts with classcondathis_run_pipeline_conflicting_method. Invalid values abort with classcondathis_invalid_method.- verbose
Character string that controls the console output. One of
"output","silent","cmd","spinner"and"full". Usage shows the default."output"prints, while the pipeline runs, what it captures: the last command's standard output and every command's standard error, when their target is"|"."cmd"prints the whole pipeline first."full"does both."spinner"shows only a spinner, and"silent"shows nothing.TRUEmeans"output"andFALSEmeans"silent". Every level except"silent"shows a spinner in interactive sessions. Invalid values abort with classcondathis_invalid_verbose.- error
Character string that controls what happens when a command fails. With
"cancel"(the default),run_pipeline()aborts:a command that exits with a non-zero status: class
condathis_run_pipeline_status_error(alsocondathis_status_error). A broken pipe can end a command that is not the last one: that does not count (see Broken pipes).a timeout: class
condathis_run_pipeline_timeout_error(alsocondathis_timeout_error).a step environment that does not exist: class
condathis_run_pipeline_env_not_found(alsocondathis_env_not_found). For anenv_path(), the error also hascondathis_env_path_not_foundorcondathis_env_path_not_conda_env.a step environment found under several backends: class
condathis_backend_ambiguous_env(seemethod).a command that the backend fails to resolve, for example because an
activate.dscript of the environment fails: classcondathis_run_pipeline_resolve_failed(alsocondathis_backend_error). The error keeps the condathis classes of the backend's error, for examplecondathis_micromamba_status_error, and has that error as its parent.an invalid command description from a backend package (a bug in that package): class
condathis_backend_resolve_run_invalid.
The status and timeout errors carry the fields
status,stdout,stderrandtimeout, as the errors ofrun()do. They also carryresult(thecondathis_pipelineobject thaterror = "continue"returns) andstatuses. With"continue",run_pipeline()returns the result instead. Every step in an environment that does not exist or is found under several backends gets status 127, with the reason in itsstderr. So does every command that cannot be resolved or started. The other steps still run. A timeout gives status -9. Invalid values abort with classcondathis_invalid_error. See condathis-conditions for all classes.- stdout
Standard output target of the last command:
"|"(the default) captures it in the result, a file path writes it to that file, andNULLdiscards it. The standard output of every other command goes to the next command.- stderr
Standard error target for all processes.
"|"(the default) captures each command's standard error in its result. A file path writes them all to that file, in command order once the pipeline finishes.NULLdiscards them. Thestderrargument ofrun_step()replaces it for one command.- stdin
Standard input source of the first command:
NULL(the default) for no input, the path of an existing file to read, or"|"to writeinputto it.- input
Character or raw vector written to the standard input of the first command, as in
run(). Must beNULL(the default) unlessstdin = "|". Other values abort with classcondathis_invalid_input.- binary
Logical. Whether to return raw vectors, not UTF-8 text, for the standard error of every command and the standard output of the last one. Defaults to
FALSE. It applies to the whole pipeline. There is no per-command setting.- supervise
Logical. Whether the
processxsupervisor watches each process: when the R session ends, even by a crash, the supervisor kills it. Defaults toTRUE, unlike inrun()andrun_bin(), since a pipeline starts several connected processes. Ignored on Windows, where supervised pipelines hang.- cleanup_tree
Logical. Whether to kill the process tree of each command, processes that it started in the background included. R kills the tree when it frees the process object of the command, at a garbage collection after the pipeline finishes. Defaults to
TRUE, so that no command outlives the pipeline, unlike inrun()andrun_bin(), where a daemon that a command starts keeps running.- linux_pdeathsig
Logical. On Linux, whether each command gets
SIGTERMwhen the R session ends, even by a crash. Ignored on other platforms. Defaults toFALSE.- activate
Logical.
TRUE(the default) runs each command with the activation of its environment, asrun()does.FALSEsets a fixed set of variables instead, withoutactivate.dscripts (see condathis-options). Each command runs in the working directory of the R session, unless the activation of a backend gives another one.- timeout
Number of seconds the whole pipeline may take, the activations of the environments included: one deadline for all commands, not one per command. Defaults to
Inf(no limit).run_pipeline()lowers a finite value above 2147483 (about 24.8 days) to that value. When the time is up,run_pipeline()kills every command still running (status -9 andtimeout = TRUEin its result). It does not start a command whose activation took the rest of the time, and counts it as killed.error = "cancel"then aborts with classcondathis_run_pipeline_timeout_error, anderror = "continue"returns the result, withtimeout = TRUE. Values that are not a single, non-negative number abort with classcondathis_invalid_timeout.
Value
A condathis_pipeline object, invisibly, which prints as a
short summary and which parse_output() reads. It is a classed list
with:
- status
Integer. The status of the pipeline: -9 when it timed out, otherwise the status of the first command that failed, or 0. A broken pipe can end a command that is not the last one: that does not count (see Broken pipes).
- statuses
Integer vector, the exit status of each command. A command that a signal ends has the negative signal number, such as -13 for
SIGPIPE.- processes
List of
condathis_resultobjects, one per command, with the fields of arun()result:stdoutisNAfor every command but the last,env_nameis the environment name or the directory of anenv_path(), andtimeoutisTRUEfor the commands that the timeout killed.- timeout
Logical. Whether the pipeline timed out.
- cmd
Character string. The command lines of the commands, each part quoted, joined with
" | ".
Broken pipes
A command that is not the last one ends as it would in a shell when it
writes again after the next command has exited. On Linux and macOS,
SIGPIPE kills it. Windows has no such signal. There, run_pipeline()
reads the pipe in place of the command that exited. It kills the writer
when more output comes after the pipe was empty for about one second in
total. It also kills the writer when more than 64 KiB comes, which is
what a Linux pipe holds. Output that was already in the pipe does not
count. Either way, the status of the writer is -13, and that is not a
failure. It does not make error = "cancel" abort, and it is not the
status of the result. So seq 1 1000000 | head -n 1 has status 0.
Programs that handle SIGPIPE themselves, such as R and Python, exit
with their own status (R with 1, Python usually with 120), which counts
as a failure. A command that writes nothing more keeps running, on every
platform, and keeps its own status. On Windows, the reader that takes the
place of the exited command is a small Rscript process. When it cannot
start, the writer gets one second to exit on its own, and
run_pipeline() then kills it.
See also
env_path() for an environment created outside condathis,
and condathis-conditions for the condition classes.
Other commands:
parse_output(),
run(),
run_bin(),
run_step()
Examples
if (FALSE) { # \dontrun{
condathis::with_sandbox_dir({
# `pigz` and `ripgrep` (the `rg` binary) come from conda-forge, which
# builds both for Linux, macOS and Windows. `rg` is used here instead
# of GNU `grep`, which conda-forge has for Windows only as an MSYS2
# package (with the "m2-" prefix).
create_env("conda-forge::pigz", env_name = "pigz-env")
create_env("conda-forge::ripgrep", env_name = "ripgrep-env")
# Pipeline with per-command environments: count the reads of a FASTQ
# file shipped with condathis. In this file, the header line of each
# read starts with "@read".
fastq_file <- fs::path_package(
"condathis", "extdata", "sample1_L001_R1_001.fastq.gz"
)
res <- run_pipeline(
run_step(
"pigz", "--decompress", "--stdout", fastq_file,
env_name = "pigz-env"
),
run_step("rg", "--count", "^@read", env_name = "ripgrep-env"),
verbose = "silent"
)
print(parse_output(res))
#> [1] "1086"
# Steps are values: build a list of them, then splice it in with `!!!`
steps <- list(
run_step("rg", "--version", env_name = "ripgrep-env"),
run_step("rg", "ripgrep", env_name = "ripgrep-env")
)
print(parse_output(run_pipeline(!!!steps, verbose = "silent")))
#> [1] "ripgrep 15.2.0 (rev 78115297cd)"
})
} # }