A package developed in a Pixi project has its R, its dependencies and its development tools in pixi.lock: the same on every contributor’s computer, and in CI. This guide goes through the workflow. Several environments has more on checking across versions of R.
Setting up
In the package’s folder, set up Pixi, then add what DESCRIPTION asks for:
library(rpix)
use_pixi(ide = "positron") # or "rstudio", or "vscode"
pixi_import_description()-
use_pixi()adds Pixi’s files (.pixi,pixi.tomlandpixi.lock) to.Rbuildignore, and setting up an IDE adds.vscode, so they stay out of the package’s builds. -
pixi_import_description()addsDepends,ImportsandLinkingToto the project, andSuggeststo atestenvironment, which uses the same versions as the default one. Packages that aren’t on conda-forge or bioconda are listed and left out: add them withpixi_add(), which offers to build them from source (see Finding packages).
Then add the development tools, to a dev feature that the default environment includes, so they’re there when you work but stay apart from what the package needs:
pixi_add(c("devtools", "roxygen2", "testthat"), feature = "dev")
pixi_add_environment("default", features = "dev", overwrite = TRUE)The daily loop
Work in the environment’s R, as your IDE starts it once use_pixi() has set it up (from a terminal, pixi run R). devtools works as usual there:
Install packages with pixi_add(), not with devtools::install_dev_deps(), pak or remotes: those install into the environment without recording it in pixi.toml, so a collaborator doesn’t get them, and Pixi may remove them the next time it installs the environment. In the environment’s R, install.packages() goes through rpix.
For a dependency of the package, type adds it to DESCRIPTION too, as usethis::use_package() does, so the two files stay in step:
pixi_add("rlang>=1.1", type = "Imports") # rlang (>= 1.1) in Imports
pixi_add("github::hadley/emo", type = "Imports") # also hadley/emo in Remotes
pixi_add("conda::gdal>=3.6", type = "SystemRequirements") # gdal (>= 3.6)
pixi_remove("rlang", type = "Imports")SystemRequirements gets conda-forge’s names, such as gdal or pkg-config, after what it says already. Those are the names tools that map SystemRequirements to packages look for, conda-forge’s recipe tools among them.
Pixi tasks make the common commands one word, in a terminal and in CI:
pixi_add_task("test", "Rscript -e 'devtools::test()'", description = "Run the tests")
pixi_add_task("check", "Rscript -e 'devtools::check()'", description = "Run R CMD check")Then pixi_run("test"), or pixi run test in a terminal, and pixi_tasks() lists them.
Keeping DESCRIPTION and pixi.toml in step
DESCRIPTION and pixi.toml drift apart easily: usethis::use_package() only changes DESCRIPTION, and pixi_add() only pixi.toml.
In the environment’s R, rpix notices when DESCRIPTION changes, and offers to add what it now needs:
usethis::use_package("rlang")
#> ✔ Adding rlang to Imports field in DESCRIPTION.
#> ℹ 'DESCRIPTION' now needs rlang, which isn't in 'pixi.toml'.
#> ? Would you like to add it?
#> 1: Yes
#> 2: NoIt says when DESCRIPTION no longer lists a package too, but leaves removing it to you, as pixi.toml can need it for other reasons. options(rpix.watch_description = FALSE) turns this off.
pixi_sitrep() also compares them, in a “Package” section:
pixi_sitrep()
#> ── Package ──
#> ! 'DESCRIPTION' needs rlang, which isn't in the default environment in 'pixi.toml'.
#> Add them with `pixi_import_description()`.It also says when an installed package is older than DESCRIPTION asks for. Run pixi_import_description() again to add what’s missing.
Compiled code
conda-forge’s R comes with its C, C++ and Fortran compilers, and on Linux and macOS with make, so packages with compiled code build without Rtools or a separately installed compiler.
-
Windows: R’s build tools also need MSYS2’s
make,sedandcoreutils, which conda-forge’s R doesn’t bring there. Without them, devtools asks for Rtools. Add them for Windows only: macOS: the compilers use Apple’s SDK, from Xcode’s Command Line Tools. If a build can’t find system headers such as
stdio.h, install them withxcode-select --installin a terminal.Rust: add conda-forge’s
rust, and on Windows also its GNU target:pixi_add("conda::rust", feature = "dev"), andpixi_add("conda::rust-std-x86_64-pc-windows-gnu", feature = "dev", platform = "win-64").
Checking across versions
-
Several versions of R:
use_pixi_check_matrix(c("4.3", "4.4", "4.5"))adds an environment for each, andpixi_check_matrix()runs the tests in all of them. -
The minimum versions in
DESCRIPTION:use_pixi_check_matrix(minimum = TRUE)adds an environment with R and each dependency at the lowest versionDESCRIPTIONallows,Suggestsincluded. -
Packages as of a date:
pixi_set_date()uses packages as they were on a date, e.g. to see whether a bug came with a dependency’s release.
See Several environments for each of these.
Continuous integration
use_pixi_github_action() writes a GitHub Actions workflow that installs the environments from pixi.lock, so CI runs with exactly what you ran:
use_pixi_check_matrix(c("4.4", "4.5"), minimum = TRUE)
use_pixi_github_action("check")"check" runs R CMD check on Linux, macOS and Windows (those of the project’s platforms), in each environment that has rcmdcheck and the package’s Suggests, as the check matrix’s r44, r45 and minimum do: the default environment has neither. Or name the environments with environments =. "test-coverage" and "pkgdown" write the other two workflows a package usually has. Commit pixi.lock: the run fails when it’s out of date with pixi.toml.
What Pixi doesn’t cover
- R-devel isn’t on conda-forge, so checking against it, as CRAN does, still needs r-lib’s actions with an R from outside Pixi.
-
CRAN’s own checks (
--as-cran, win-builder, R-hub) run outside your environment, as they always have.