# install.packages("pak")
pak::pak("luciorq/rattlerthis")What a Backend Does
Every condathis function that touches an environment hands the work to a backend. The backend solves the package specs, downloads and links the packages, and activates the environment before a command runs. condathis keeps everything else: the arguments, the checks, the messages, the results and the condition classes.
Two backends exist today:
-
"micromamba"is built in.condathisdownloads themicromambabinary the first time it needs it, and runs it as a separate process. Every environment uses it unless you ask for another backend. -
"rattler"comes from therattlerthispackage. It usesrattler, the Rust library behindpixi, inside the R process. There is no package manager binary to download.
Your code stays the same with either backend. The method argument of the environment functions, and of run(), run_bin() and run_pipeline(), picks the backend. Its default, "auto", picks it for you.
Installing rattlerthis
rattlerthis is not on CRAN yet. It builds from source, so it needs a Rust toolchain (rustc >= 1.88.0 and cargo, from https://rustup.rs). Linux also needs pkg-config and the OpenSSL headers, and Windows needs Rtools. The rattlerthis README lists the requirements of each platform.
You never call library(rattlerthis). The package exports no functions: condathis loads it when method names "rattler", and when rattler environments already exist.
Choosing the Backend of a New Environment
Without method, a new environment uses micromamba:
create_env("jq", env_name = "jq-env", verbose = "silent")Pass method = "rattler" to create one with rattler instead:
create_env(
"ripgrep",
env_name = "rg-env",
method = "rattler",
verbose = "silent"
)list_envs() covers every backend. The backend column tells you which one owns each environment:
Running Commands
Commands need no method. "auto" finds the backend that owns the environment, and that backend activates it:
res <- run("rg", "--version", env_name = "rg-env", verbose = "silent")
parse_output(res)[1]
#> [1] "ripgrep 15.2.0 (rev 78115297cd)"Environments of different backends work together. In this pipeline, ripgrep from the rattler environment searches a file and prints its matches as JSON. jq from the micromamba environment turns the JSON into one line per match:
notes_path <- fs::file_temp(pattern = "notes-", ext = "txt")
writeLines(
con = notes_path,
text = c(
"micromamba is the built-in backend.",
"Environments live in the condathis data directory.",
"rattler is the backend of rattlerthis."
)
)
res <- run_pipeline(
run_step("rg", "--json", "backend", notes_path, env_name = "rg-env"),
run_step(
"jq", "-r",
paste(
'select(.type == "match")',
'"\\(.data.line_number): \\(.data.lines.text | rtrimstr("\\n") | rtrimstr("\\r"))"',
sep = " | "
),
env_name = "jq-env"
),
verbose = "silent"
)
parse_output(res)
#> [1] "1: micromamba is the built-in backend."
#> [2] "3: rattler is the backend of rattlerthis."One Environment, One Backend
The backend that creates an environment owns it for its whole life. A call that names another backend for it does not move it:
- Functions that change the environment, such as
install_packages()andremove_env(), abort with classcondathis_backend_mismatch. - Functions that only read it, such as
run()andlist_packages(), warn with classcondathis_backend_mismatch_warningand use the owner.
install_packages("jq", env_name = "rg-env", method = "micromamba")
#> Error in `install_packages()`:
#> ✖ Environment rg-env is owned by backend rattler, not micromamba.
#> ℹ Remove it first, or use `method = "rattler"`.create_env() refuses the name under another backend too, so a name belongs to one backend at a time. To move an environment to another backend, remove it, then create it again with that backend. Each backend keeps its environments in its own directory. If the same name still ends up under both, for example in a directory copied by hand, "auto" cannot choose, and the call aborts with class condathis_backend_ambiguous_env until method names one of them.
Making rattler the Default
The option condathis.backend_priority sets the order that "auto" tries for a new environment. Its default is "micromamba", so installing rattlerthis alone changes nothing. To create new environments with rattler, and keep micromamba as the fallback, put this in your .Rprofile:
With the option set, create_env() uses rattler without method:
old_options <- options(condathis.backend_priority = c("rattler", "micromamba"))
create_env("jq", env_name = "jq-rattler-env", verbose = "silent")
options(old_options)
list_envs()[, c("backend", "env_name")]
#> # A tibble: 3 × 2
#> backend env_name
#> <chr> <chr>
#> 1 micromamba jq-env
#> 2 rattler jq-rattler-env
#> 3 rattler rg-envExisting environments keep their owner: jq-env stays a micromamba environment.
Which Backend to Use
Both backends behave the same wherever they can. They activate environments the same way, cache the activation, install the pip: sections of environment files, and let one R session at a time change an environment. The differences you are most likely to notice:
-
Link scripts.
rattlernever runs thepre-link,post-linkandpre-unlinkscripts of packages.condathiswarns with classcondathis_link_scripts_skipped, and names the packages.micromambaruns them. Both run theactivate.dscripts. -
No binary, no command line.
rattlerneeds no download of a package manager, and nothing runs as a separate process to create an environment. For the same reason,verbose = "cmd"prints a one-line description, and the results ofcreate_env()andinstall_packages()haveNAincmdandpid. -
Errors. The classes are
condathis’s with both backends. Under arattlerfailure, the parent condition has the classesrattlerthis_rattler_<kind>, such asrattlerthis_rattler_solve, instead ofmicromamba’s status classes. - Disk. The package caches are separate, so a package that both backends use is downloaded twice.
The rattlerthis README and ?rattlerthis list every difference. A simple rule: keep micromamba for packages whose link scripts matter. Try rattler when you want no extra binary, or a solver inside R.
Where the Files Live
get_install_dir() reports the data directory of each backend:
get_install_dir()
#> # A tibble: 2 × 2
#> backend path
#> <chr> <chr>
#> 1 micromamba /home/runner/.local/share/R/condathis
#> 2 rattler /home/runner/.local/share/R/condathis/rattlerThe rattler backend keeps its environments, its package cache and its channel metadata in backend_root_dir("rattler"), the rattler directory inside the data directory of condathis. The functions that manage files cover every backend:
-
clean_cache()deletes the package caches ofmicromambaand ofrattler. -
with_sandbox_dir()redirects the directories of every backend, so code in it leaves nothing behind.
Writing a Backend
The backend system is open: another package can add its own backend with register_backend(), and users then select it with method. The API is experimental, and it may still change between 0.x releases. ?register_backend describes the functions a backend provides, and how to register them when the package loads. rattlerthis is a complete example.
Cleaning Up
remove_env(env_name = "jq-env", verbose = "silent")
if (isTRUE(has_rattler)) {
remove_env(env_name = "rg-env", verbose = "silent")
remove_env(env_name = "jq-rattler-env", verbose = "silent")
}