diff --git a/.gitattributes b/.gitattributes index 12ae954a..69ae23c1 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,3 +3,9 @@ # checked out on. A CRLF checkout of repositories.R broke profile marker # matching on Windows (see src/hardcoded.rs). src/data/repositories.R text eol=lf + +# Same for the shim R package source: it is byte-hashed by +# `cargo xtask gen-rvenv-shim`, so a CRLF checkout would look like a source +# change and fail the CI drift check. The built packages are binary. +src/data/rvenv-pkg/** text eol=lf +src/data/rvenv-shim/*.tar.gz binary diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index ade66205..d6faf8a1 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -79,6 +79,7 @@ jobs: cargo test cargo test -p xtask cargo xtask gen-help --check + cargo xtask gen-rvenv-shim --check - name: Build rig run: | diff --git a/Cargo.lock b/Cargo.lock index 63ecf09c..6418526d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -194,6 +194,15 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + [[package]] name = "bstr" version = "1.9.1" @@ -371,6 +380,16 @@ version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + [[package]] name = "csv" version = "1.4.0" @@ -441,6 +460,16 @@ dependencies = [ "generic-array", ] +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", +] + [[package]] name = "directories" version = "4.0.1" @@ -1839,7 +1868,7 @@ dependencies = [ "serde_derive", "serde_json", "serde_yaml", - "sha2", + "sha2 0.9.9", "shellexpand", "simple-error", "static_vcruntime", @@ -1848,6 +1877,7 @@ dependencies = [ "tar", "tempfile", "tokio", + "toml", "version-ranges", "whoami", "winreg 0.10.1", @@ -2068,6 +2098,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -2099,13 +2138,24 @@ version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer", + "block-buffer 0.9.0", "cfg-if", "cpufeatures", - "digest", + "digest 0.9.0", "opaque-debug", ] +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + [[package]] name = "shared_child" version = "1.0.0" @@ -2401,6 +2451,47 @@ dependencies = [ "tracing", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower-service" version = "0.3.2" @@ -2906,6 +2997,15 @@ version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + [[package]] name = "winreg" version = "0.10.1" @@ -3051,7 +3151,12 @@ dependencies = [ name = "xtask" version = "0.0.0" dependencies = [ + "flate2", "pulldown-cmark", + "serde", + "serde_json", + "sha2 0.10.9", + "tar", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 5ccdcd0c..9c7df70e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -97,6 +97,8 @@ serde = { version = "1.0", features = ["derive"] } serde_derive = "1.0" serde_json = "1.0" serde_yaml = "0.9" +# rproj.lock (multi-target project lockfile) +toml = "0.8" # hash url to get target path, for macOS installers sha2 = "0.9.8" # expand ~ in paths, e.g. in R_LIBS env vars, env vars for RStudio diff --git a/Makefile b/Makefile index 3ddd5cc4..9fa866d6 100644 --- a/Makefile +++ b/Makefile @@ -307,6 +307,15 @@ fonts-asset: help: cargo xtask gen-help +# Rebuild the pre-built shim R packages in src/data/rvenv-shim (one per R +# version bracket) from the package source in src/data/rvenv-pkg. `rig proj +# init` seeds one of them into a project's .rvenv/lib/rig. Needs the R +# versions listed in xtask/src/rvenv_shim.rs and installs them with `rig add` +# if they are missing, so this is a maintainer-only task; CI only runs +# `cargo xtask gen-rvenv-shim --check`, which needs no R. +rvenv-shim: + cargo xtask gen-rvenv-shim + readme: README.md # Regenerate the command-line reference (website/reference/_commands.md) from diff --git a/NEWS.md b/NEWS.md index 115b364d..af206b28 100644 --- a/NEWS.md +++ b/NEWS.md @@ -26,6 +26,12 @@ * New `rig proj tree` shows the dependency closure of a project as a tree. +* `rig run` now uses the project environment, if you call it in a project + directory: it starts `.rvenv/bin/R`, with the project's package library + and the R version the project's lock file names, and it syncs the project + first if the environment is missing or out of date. Use `--no-project` + (or `--r-version`) to run the default R version instead. + * `rig library add`, `rig library default`, `rig library list` and `rig library rm` have a new `--r-version` (`-r`) option, to operate on the libraries of an R version other than the default one. diff --git a/src/args.rs b/src/args.rs index 392041a7..98e36451 100644 --- a/src/args.rs +++ b/src/args.rs @@ -1216,6 +1216,13 @@ pub fn rig_app() -> Command { .long("r-version") .required(false), ) + .arg( + Arg::new("no-project") + .help("Ignore the project environment, use the default R version") + .long("no-project") + .action(clap::ArgAction::SetTrue) + .required(false), + ) .arg( Arg::new("app-type") .help("Explicitly specify app type to run") @@ -1316,18 +1323,46 @@ pub fn rig_app() -> Command { .required(false), ) .subcommand( - Command::new("deps") - .about(ABOUT_PROJ_DEPS) - .long_about(HELP_PROJ_DEPS) + Command::new("init") + .about(ABOUT_PROJ_INIT) + .long_about(HELP_PROJ_INIT) + .display_order(0) + .arg( + Arg::new("force") + .help("Overwrite existing project files") + .long("force") + .short('f') + .num_args(0) + .required(false), + ) + .arg( + Arg::new("r-version") + .help("R version of the project (default: the default R version, or the current R release)") + .long("r-version") + .short('r') + .num_args(1) + .required(false), + ), + ) + .subcommand( + Command::new("import") + .about(ABOUT_PROJ_IMPORT) + .long_about(HELP_PROJ_IMPORT) .display_order(0) .arg( Arg::new("input") - .help("Project file to solve (e.g. DESCRIPTION)") + .help("DESCRIPTION file to import (e.g. DESCRIPTION)") .long("input") .short('i') .num_args(1) .required(false), - ) + ), + ) + .subcommand( + Command::new("deps") + .about(ABOUT_PROJ_DEPS) + .long_about(HELP_PROJ_DEPS) + .display_order(0) .arg( Arg::new("recursive") .help("Show recursive (transitive) dependencies") @@ -1356,14 +1391,6 @@ pub fn rig_app() -> Command { .about(ABOUT_PROJ_TREE) .long_about(HELP_PROJ_TREE) .display_order(0) - .arg( - Arg::new("input") - .help("Project file to solve (e.g. DESCRIPTION)") - .long("input") - .short('i') - .num_args(1) - .required(false), - ) .arg( Arg::new("dev") .help("Include dev (development) dependencies") @@ -1396,21 +1423,13 @@ pub fn rig_app() -> Command { ), ) .subcommand( - Command::new("solve") - .about(ABOUT_PROJ_SOLVE) - .long_about(HELP_PROJ_SOLVE) + Command::new("lock") + .about(ABOUT_PROJ_LOCK) + .long_about(HELP_PROJ_LOCK) .display_order(0) - .arg( - Arg::new("input") - .help("Project file to solve (e.g. DESCRIPTION)") - .long("input") - .short('i') - .num_args(1) - .required(false), - ) .arg( Arg::new("renv") - .help("Output and renv.lock file") + .help("Output an renv.lock file") .long("renv") .num_args(0) .required(false), @@ -1458,40 +1477,53 @@ pub fn rig_app() -> Command { .required(false), ) .arg( - Arg::new("dev") - .help("Include dev (development) dependencies") - .long("dev") + Arg::new("no-dev") + .help("Leave out dev (development) dependencies") + .long("no-dev") .num_args(0) .required(false), ), ) .subcommand( - Command::new("deploy") - .about(ABOUT_PROJ_DEPLOY) - .long_about(HELP_PROJ_DEPLOY) + Command::new("sync") + .about(ABOUT_PROJ_SYNC) + .long_about(HELP_PROJ_SYNC) .display_order(0) .arg( Arg::new("library") - .help("Library path where packages should be installed") + .help( + "Library path where packages should be installed \ + (default: .rvenv/lib)", + ) .long("library") .short('l') .num_args(1) - .required(true), + .required(false), ) .arg( - Arg::new("r-binary") - .help("Path to R binary (default: R)") - .long("r-binary") - .num_args(1) + Arg::new("no-install-r") + .help( + "Fail if the R version the lockfile needs is not installed,\n\ + instead of installing it", + ) + .long("no-install-r") + .num_args(0) .required(false), ) .arg( Arg::new("max-concurrent") - .help("Maximum number of concurrent installations (default: 4)") + .help("Maximum number of concurrent installations (default: 8)") .long("max-concurrent") .num_args(1) .value_parser(clap::value_parser!(usize)) .required(false), + ) + .arg( + Arg::new("no-dev") + .help("Do not install dev (development) dependencies") + .long("no-dev") + .num_args(0) + .required(false), ), ); rig = rig.subcommand(cmd_proj); diff --git a/src/data/rvenv-pkg/DESCRIPTION b/src/data/rvenv-pkg/DESCRIPTION new file mode 100644 index 00000000..4b7ec49e --- /dev/null +++ b/src/data/rvenv-pkg/DESCRIPTION @@ -0,0 +1,13 @@ +Package: rig +Title: Project Library Activation Shim +Version: 0.1.0 +Author: Gabor Csardi +Maintainer: Gabor Csardi +Description: Loaded automatically via R_DEFAULT_PACKAGES from a project's + .Renviron file. Resolves the project's relative library path to an + absolute one, so that child R processes inherit it, and warns if the + project has not been synced yet. This package is generated and installed + by rig, the R installation manager; do not edit it. +License: MIT + file LICENSE +Encoding: UTF-8 +Depends: R (>= 3.0.0) diff --git a/src/data/rvenv-pkg/LICENSE b/src/data/rvenv-pkg/LICENSE new file mode 100644 index 00000000..86486433 --- /dev/null +++ b/src/data/rvenv-pkg/LICENSE @@ -0,0 +1,2 @@ +YEAR: 2026 +COPYRIGHT HOLDER: Gabor Csardi diff --git a/src/data/rvenv-pkg/NAMESPACE b/src/data/rvenv-pkg/NAMESPACE new file mode 100644 index 00000000..67d101bf --- /dev/null +++ b/src/data/rvenv-pkg/NAMESPACE @@ -0,0 +1,2 @@ +# This package intentionally exports nothing. All of its behavior happens in +# .onLoad(), see R/rvenv.R. diff --git a/src/data/rvenv-pkg/R/rvenv.R b/src/data/rvenv-pkg/R/rvenv.R new file mode 100644 index 00000000..c7041e2a --- /dev/null +++ b/src/data/rvenv-pkg/R/rvenv.R @@ -0,0 +1,83 @@ +# This package is loaded from a project's .Renviron, via +# +# R_DEFAULT_PACKAGES=rig,datasets,utils,grDevices,graphics,stats,methods +# +# It is the "in-session activation" leg of a rig project: it makes the +# project's `.rvenv/lib` library work in R sessions that rig did not start, +# e.g. in RStudio, Positron or VS Code. We deliberately do not use a project +# `.Rprofile` for this, because that would shadow the user's own +# `~/.Rprofile` entirely. +# +# `.Renviron` sets `R_LIBS_USER` to the *relative* path `.rvenv/lib`, because +# the file is committed to version control and has to work from any clone +# location. `.onLoad()` receives an already-resolved absolute `libname`, so +# this is where the relative path becomes an absolute one. That matters for +# child processes (callr, parallel, `R CMD`, `Rscript` from a subdirectory): +# they inherit the environment variable, not our `.libPaths()` call, so a +# child started in a subdirectory would otherwise look for +# `/.rvenv/lib`. + +.onLoad <- function(libname, pkgname) { + venv <- normalizePath(dirname(libname), mustWork = FALSE) + lib <- file.path(venv, "lib") + + # Whether a parent process activated this project already. Note that this + # does *not* mean there is nothing to do: a child process started in the + # project root reads the project .Renviron itself, which sets R_LIBS_USER + # back to the relative `.rvenv/lib`, and a grandchild started from a + # subdirectory would then look for the wrong directory. So the variables + # below are re-asserted unconditionally, and only the parts that are not + # idempotent -- re-reading the user's .Renviron and warning about an + # unsynced project -- are skipped. + activated <- identical( + normalizePath(Sys.getenv("RVENV"), mustWork = FALSE), + venv + ) + + # Re-read the user's own .Renviron first: the project .Renviron shadows it + # rather than merging with it, so without this the user's variables are + # empty in this session. Our own variables are set after it, so they win. + # Not in a child process: there the parent's environment, including + # whatever it deliberately changed, is what should survive. + home_renv <- path.expand("~/.Renviron") + if (!activated && file.exists(home_renv)) readRenviron(home_renv) + + Sys.setenv( + R_LIBS_USER = lib, + # Setting this empty does not reliably disable the site library on all R + # versions, so point it at a path that does not exist. + R_LIBS_SITE = "/nonexistent/rvenv-no-site", + RVENV = venv + ) + + # `include.site` was added in R 4.2.0. + if (getRversion() >= "4.2.0") { + .libPaths(lib, include.site = FALSE) + } else { + .libPaths(lib) + } + + Sys.unsetenv("R_DEFAULT_PACKAGES") + + # One warning per project is enough; child processes are quiet. + if (activated) return(invisible()) + + # `rig proj sync` copies the lock file it installed from to + # `.rvenv/lib/.synced`. A copy rather than a hash, so that both sides only + # need to read files: base R has no sha256, and md5 would mean one more + # dependency on the rig side. + stamp <- file.path(lib, ".synced") + lock <- file.path(dirname(venv), "rproj.lock") + synced <- FALSE + if (file.exists(stamp) && file.exists(lock)) { + synced <- identical( + readLines(stamp, warn = FALSE), + readLines(lock, warn = FALSE) + ) + } + if (!synced) { + packageStartupMessage("! Project is not synced. Run: rig proj sync") + } + + invisible() +} diff --git a/src/data/rvenv-shim/SOURCE-HASH b/src/data/rvenv-shim/SOURCE-HASH new file mode 100644 index 00000000..b10a0af3 --- /dev/null +++ b/src/data/rvenv-shim/SOURCE-HASH @@ -0,0 +1,7 @@ +# Generated by `cargo xtask gen-rvenv-shim` (run `make rvenv-shim`). +# Do not edit by hand. `cargo xtask gen-rvenv-shim --check` verifies that +# the committed shim packages still match src/data/rvenv-pkg. +source = 27876fc19c83d55b4d0bac79b5e5ae119a6e3cc5bdfd6cef95bddea575636e2c +shim-lt-3.5.tar.gz = r 3.4.4, serialize 2, sha256 cb6eabe9cb6541348025a25019dfea8dfaedcb830ae35234651321ec36685fe7 +shim-3.5.tar.gz = r 3.5.3, serialize 2, sha256 4d41a108ee53bcb960358b457d4eee515b5de2ccc3ef19bfe4586684b7d2372c +shim-4.0.tar.gz = r 4.0.5, serialize 3, sha256 3a205bb92f2fb1a8b9baacd03ea51ce6a91e9a4bb7465a5a7b8645783387770c diff --git a/src/data/rvenv-shim/shim-3.5.tar.gz b/src/data/rvenv-shim/shim-3.5.tar.gz new file mode 100644 index 00000000..d2cd5130 Binary files /dev/null and b/src/data/rvenv-shim/shim-3.5.tar.gz differ diff --git a/src/data/rvenv-shim/shim-4.0.tar.gz b/src/data/rvenv-shim/shim-4.0.tar.gz new file mode 100644 index 00000000..4f89d0b4 Binary files /dev/null and b/src/data/rvenv-shim/shim-4.0.tar.gz differ diff --git a/src/data/rvenv-shim/shim-lt-3.5.tar.gz b/src/data/rvenv-shim/shim-lt-3.5.tar.gz new file mode 100644 index 00000000..611ae7f9 Binary files /dev/null and b/src/data/rvenv-shim/shim-lt-3.5.tar.gz differ diff --git a/src/data/rvenv/Activate.ps1 b/src/data/rvenv/Activate.ps1 new file mode 100644 index 00000000..74806096 --- /dev/null +++ b/src/data/rvenv/Activate.ps1 @@ -0,0 +1,45 @@ +# Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +# +# Dot-source it from PowerShell: +# +# . .rvenv\bin\Activate.ps1 +# +# The project path below is absolute, baked in by `rig proj sync`. Re-run +# `rig proj sync` after moving the project. + +function global:deactivate([switch]$NonDestructive) { + if (Test-Path -Path Function:_old_virtual_prompt) { + Copy-Item -Path Function:_old_virtual_prompt -Destination Function:prompt + Remove-Item -Path Function:_old_virtual_prompt + } + if (Test-Path -Path env:_OLD_RVENV_PATH) { + Copy-Item -Path env:_OLD_RVENV_PATH -Destination env:PATH + Remove-Item -Path env:_OLD_RVENV_PATH + } + foreach ($name in "RVENV", "R_LIBS_USER", "R_LIBS", "R_LIBS_SITE", "R_REPOSITORIES") { + if (Test-Path -Path "env:$name") { + Remove-Item -Path "env:$name" + } + } + if (-not $NonDestructive) { + Remove-Item -Path Function:deactivate + } +} + +deactivate -NonDestructive + +$env:RVENV = "@RVENV@" +Copy-Item -Path env:PATH -Destination env:_OLD_RVENV_PATH +$env:PATH = "$env:RVENV\bin;$env:PATH" +$env:R_LIBS_USER = "$env:RVENV\lib" +$env:R_LIBS = "" +$env:R_LIBS_SITE = "/nonexistent/rvenv-no-site" +$env:R_REPOSITORIES = "$env:RVENV\etc\repositories" + +if (-not $env:RVENV_DISABLE_PROMPT) { + Copy-Item -Path Function:prompt -Destination Function:_old_virtual_prompt + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "(@RVENV_NAME@) " + _old_virtual_prompt + } +} diff --git a/src/data/rvenv/R.sh b/src/data/rvenv/R.sh new file mode 100644 index 00000000..fa95cfc9 --- /dev/null +++ b/src/data/rvenv/R.sh @@ -0,0 +1,17 @@ +#!/bin/sh +# Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +# +# A wrapper script, not a symlink: a symlink would resolve R_HOME correctly +# but would carry no environment, so putting .rvenv/bin on PATH would leak +# into the user's own package library. The exec path below is absolute, which +# also pins the R version this project was solved for. +# +# RVENV is derived from this script's own location, so the project directory +# can be moved or checked out anywhere. +RVENV=$(cd "$(dirname "$0")/.." && pwd) +export RVENV +# R_LIBS is empty, so that .libPaths()[1] stays the project library, and +# R_LIBS_SITE points at a path that cannot exist, because an empty one does +# not reliably disable the site library on every R version. +@RVENV_EXPORTS@ +exec "@R_BINARY@" "$@" diff --git a/src/data/rvenv/activate.bat b/src/data/rvenv/activate.bat new file mode 100644 index 00000000..4bd659a1 --- /dev/null +++ b/src/data/rvenv/activate.bat @@ -0,0 +1,30 @@ +@echo off +rem Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +rem +rem Run it from cmd.exe: +rem +rem .rvenv\bin\activate.bat +rem +rem The project path below is absolute, baked in by `rig proj sync`. Re-run +rem `rig proj sync` after moving the project. + +set "RVENV=@RVENV@" + +if defined _OLD_RVENV_PATH ( + set "PATH=%_OLD_RVENV_PATH%" +) else ( + set "_OLD_RVENV_PATH=%PATH%" +) +set "PATH=%RVENV%\bin;%PATH%" + +if defined _OLD_RVENV_PROMPT ( + set "PROMPT=%_OLD_RVENV_PROMPT%" +) else ( + set "_OLD_RVENV_PROMPT=%PROMPT%" +) +if not defined RVENV_DISABLE_PROMPT set "PROMPT=(@RVENV_NAME@) %PROMPT%" + +set "R_LIBS_USER=%RVENV%\lib" +set "R_LIBS=" +set "R_LIBS_SITE=/nonexistent/rvenv-no-site" +set "R_REPOSITORIES=%RVENV%\etc\repositories" diff --git a/src/data/rvenv/activate.csh b/src/data/rvenv/activate.csh new file mode 100644 index 00000000..e16e3b6d --- /dev/null +++ b/src/data/rvenv/activate.csh @@ -0,0 +1,28 @@ +# Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +# +# For csh and tcsh. Source it, do not run it: +# +# source .rvenv/bin/activate.csh +# +# The project path below is absolute, baked in by `rig proj sync`. Re-run +# `rig proj sync` after moving the project. + +alias deactivate 'test $?_OLD_RVENV_PATH != 0 && setenv PATH "$_OLD_RVENV_PATH" && unset _OLD_RVENV_PATH; test $?_OLD_RVENV_PROMPT != 0 && set prompt="$_OLD_RVENV_PROMPT" && unset _OLD_RVENV_PROMPT; unsetenv RVENV; unsetenv R_LIBS_USER; unsetenv R_LIBS; unsetenv R_LIBS_SITE; unsetenv R_REPOSITORIES; test "\!:*" != "nondestructive" && unalias deactivate; rehash' + +deactivate nondestructive + +setenv RVENV "@RVENV@" +set _OLD_RVENV_PATH="$PATH" +setenv PATH "$RVENV/bin:$PATH" +setenv R_LIBS_USER "$RVENV/lib" +setenv R_LIBS "" +setenv R_LIBS_SITE /nonexistent/rvenv-no-site +setenv R_REPOSITORIES "$RVENV/etc/repositories" + +# `prompt` is only set in an interactive shell, hence the second test. +if (! $?RVENV_DISABLE_PROMPT && $?prompt) then + set _OLD_RVENV_PROMPT="$prompt:q" + set prompt = "(@RVENV_NAME@) $prompt:q" +endif + +rehash diff --git a/src/data/rvenv/activate.fish b/src/data/rvenv/activate.fish new file mode 100644 index 00000000..42646aec --- /dev/null +++ b/src/data/rvenv/activate.fish @@ -0,0 +1,46 @@ +# Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +# +# For fish. Source it, do not run it: +# +# source .rvenv/bin/activate.fish +# +# The project path below is absolute, baked in by `rig proj sync`. Re-run +# `rig proj sync` after moving the project. + +function deactivate -d "Leave the rig project environment" + if test -n "$_OLD_RVENV_PATH" + set -gx PATH $_OLD_RVENV_PATH + set -e _OLD_RVENV_PATH + end + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + set -e RVENV + set -e R_LIBS_USER + set -e R_LIBS + set -e R_LIBS_SITE + set -e R_REPOSITORIES + if test "$argv[1]" != "nondestructive" + functions -e deactivate + end +end + +deactivate nondestructive + +set -gx RVENV "@RVENV@" +set -g _OLD_RVENV_PATH $PATH +set -gx PATH "$RVENV/bin" $PATH +set -gx R_LIBS_USER "$RVENV/lib" +set -gx R_LIBS "" +set -gx R_LIBS_SITE /nonexistent/rvenv-no-site +set -gx R_REPOSITORIES "$RVENV/etc/repositories" + +if test -z "$RVENV_DISABLE_PROMPT" + functions -c fish_prompt _old_fish_prompt + function fish_prompt + printf "%s(%s)%s " (set_color normal) "@RVENV_NAME@" (set_color normal) + _old_fish_prompt + end +end diff --git a/src/data/rvenv/activate.sh b/src/data/rvenv/activate.sh new file mode 100644 index 00000000..43891d72 --- /dev/null +++ b/src/data/rvenv/activate.sh @@ -0,0 +1,61 @@ +# Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +# +# This file must be sourced, not run: +# +# . .rvenv/bin/activate +# +# A sourced script cannot find its own path portably, so the project path +# below is absolute, baked in by `rig proj sync`. Re-run `rig proj sync` +# after moving the project. +# +# You do not need this file to use the project: `.rvenv/bin/R` and +# `.rvenv/bin/Rscript` set the same environment on their own, and R started +# by an IDE picks the project up through `.Renviron`. + +deactivate() { + if [ -n "${_OLD_RVENV_PATH:-}" ] || [ "${_OLD_RVENV_PATH-x}" != x ]; then + PATH="$_OLD_RVENV_PATH" + export PATH + unset _OLD_RVENV_PATH + fi + if [ -n "${_OLD_RVENV_PS1:-}" ] || [ "${_OLD_RVENV_PS1-x}" != x ]; then + PS1="$_OLD_RVENV_PS1" + export PS1 + unset _OLD_RVENV_PS1 + fi + unset RVENV + unset R_LIBS_USER + unset R_LIBS + unset R_LIBS_SITE + unset R_REPOSITORIES + if [ ! "${1:-}" = "nondestructive" ]; then + unset -f deactivate + fi + # Forget the hashed locations of R and Rscript. + if [ -n "${BASH:-}" ] || [ -n "${ZSH_VERSION:-}" ]; then + hash -r 2>/dev/null + fi +} + +# Start from a clean slate, in case another environment is active. +deactivate nondestructive + +RVENV="@RVENV@" +export RVENV +_OLD_RVENV_PATH="$PATH" +PATH="$RVENV/bin:$PATH" +export PATH +export R_LIBS_USER="$RVENV/lib" +export R_LIBS= +export R_LIBS_SITE=/nonexistent/rvenv-no-site +export R_REPOSITORIES="$RVENV/etc/repositories" + +if [ -z "${RVENV_DISABLE_PROMPT:-}" ]; then + _OLD_RVENV_PS1="${PS1:-}" + PS1="(@RVENV_NAME@) ${PS1:-}" + export PS1 +fi + +if [ -n "${BASH:-}" ] || [ -n "${ZSH_VERSION:-}" ]; then + hash -r 2>/dev/null +fi diff --git a/src/data/rvenv/deactivate.bat b/src/data/rvenv/deactivate.bat new file mode 100644 index 00000000..98c95317 --- /dev/null +++ b/src/data/rvenv/deactivate.bat @@ -0,0 +1,18 @@ +@echo off +rem Managed by rig (rig proj sync). Do not edit, `rig proj sync` rewrites it. +rem The cmd.exe counterpart of `activate.bat`; cmd.exe has no functions, so +rem this has to be a file of its own. + +if defined _OLD_RVENV_PATH ( + set "PATH=%_OLD_RVENV_PATH%" + set "_OLD_RVENV_PATH=" +) +if defined _OLD_RVENV_PROMPT ( + set "PROMPT=%_OLD_RVENV_PROMPT%" + set "_OLD_RVENV_PROMPT=" +) +set "RVENV=" +set "R_LIBS_USER=" +set "R_LIBS=" +set "R_LIBS_SITE=" +set "R_REPOSITORIES=" diff --git a/src/hardcoded.rs b/src/hardcoded.rs index 68e6ad87..b4b1cf8b 100644 --- a/src/hardcoded.rs +++ b/src/hardcoded.rs @@ -20,6 +20,14 @@ pub static HC_PROFILE_REPOS: Lazy = Lazy::new(|| { data.replace("\r\n", "\n") }); +// The pre-built copies of the `rig` shim R package, one per R version +// bracket, that `rig proj init` seeds into a project's `.rvenv/lib/rig`. See +// `xtask/src/rvenv_shim.rs` for what the brackets are and how these are +// built, and `src/rvenv.rs` for which one is picked when. +pub static HC_RVENV_SHIM_LT_35: &[u8] = include_bytes!("data/rvenv-shim/shim-lt-3.5.tar.gz"); +pub static HC_RVENV_SHIM_35: &[u8] = include_bytes!("data/rvenv-shim/shim-3.5.tar.gz"); +pub static HC_RVENV_SHIM_40: &[u8] = include_bytes!("data/rvenv-shim/shim-4.0.tar.gz"); + pub struct ProfileReposMarkers { pub generic_start: String, pub current_start: String, diff --git a/src/help-generated.in b/src/help-generated.in index 2e096d6a..1f189df3 100644 --- a/src/help-generated.in +++ b/src/help-generated.in @@ -37,17 +37,17 @@ const HELP_LIST: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n const ABOUT_PKG_AVAILABLE: &str = "List packages available in the R package repositories"; const HELP_PKG_AVAILABLE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n List the packages available from the configured package repositories,\n ordered by name. For each package rig shows its version and its number of\n hard dependencies (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m and \u{1b}[32mLinkingTo\u{1b}[39m, excluding R and\n the base packages). A header line reports the total number of packages and\n the R version and package type they were resolved for.\n\n By default rig uses the default R version and the current platform;\n override these with \u{1b}[32m--r-version\u{1b}[39m, \u{1b}[32m--platform\u{1b}[39m and \u{1b}[32m--pkg-type\u{1b}[39m (e.g.\n \u{1b}[32msource\u{1b}[39m or \u{1b}[32mbinary\u{1b}[39m).\n\n Use \u{1b}[32m--json\u{1b}[39m to print the full listing as JSON, including the complete\n dependency lists for every package. See\n \u{1b}[32mrig pkg info\u{1b}[39m for a detailed view of a single package,\n and \u{1b}[32mrig pkg info --versions\u{1b}[39m to list all versions of a package."; const ABOUT_PKG_DEPS: &str = "Dependencies of a package in the repositories"; -const HELP_PKG_DEPS: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show what a package needs, in a table: every package it depends on, the\n version of that package currently on CRAN, the dependency type\n (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m, \u{1b}[32mLinkingTo\u{1b}[39m) and the version requirement, if it\n has one.\n\n By default the dependencies of the latest version of the package are\n shown; use \u{1b}[32m--version\u{1b}[39m to ask about a specific one, including versions\n that CRAN has archived. Use \u{1b}[32m--json\u{1b}[39m for machine readable output.\n\n\u{1b}[1m\u{1b}[34mDependency types:\u{1b}[39m\u{1b}[22m\n By default rig lists the hard dependencies only: \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m\n and \u{1b}[32mLinkingTo\u{1b}[39m, i.e. the packages that need to be installed to use the\n package. \u{1b}[32m--dev\u{1b}[39m adds the soft dependencies, \u{1b}[32mSuggests\u{1b}[39m and \u{1b}[32mEnhances\u{1b}[39m,\n which are typically only needed to run the tests, build the vignettes or\n use some optional feature.\n\n R itself and the base packages, e.g. \u{1b}[32mutils\u{1b}[39m or \u{1b}[32mstats\u{1b}[39m, are listed if\n the package depends on them, with their version requirement, but without\n a version of their own, as they are part of R.\n\n\u{1b}[1m\u{1b}[34mRecursive dependencies:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--recursive\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) shows the whole dependency closure: not only the\n packages the package needs directly, but also the packages \u{1b}[3mthose\u{1b}[23m need,\n and so on. Each package appears once, with the \u{1b}[32mDepth\u{1b}[39m column giving its\n distance from the queried package, and the \u{1b}[32mNeeded by\u{1b}[39m column naming the\n packages that pull it in.\n\n \u{1b}[32mrig pkg tree\u{1b}[39m shows the same closure as a tree, which\n makes it easier to see how a package is pulled in, at the price of a\n longer listing.\n\n A recursive listing only ever follows hard dependencies, also below a\n soft dependency added by \u{1b}[32m--dev\u{1b}[39m, so \u{1b}[32m--dev --recursive\u{1b}[39m means the\n package's own dev dependencies plus everything they need to be\n installed.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in\n the tree, so a version requirement that would force an older version,\n with different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj solve\u{1b}[39m for a resolution that is consistent across\n versions."; +const HELP_PKG_DEPS: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show what a package needs, in a table: every package it depends on, the\n version of that package currently on CRAN, the dependency type\n (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m, \u{1b}[32mLinkingTo\u{1b}[39m) and the version requirement, if it\n has one.\n\n By default the dependencies of the latest version of the package are\n shown; use \u{1b}[32m--version\u{1b}[39m to ask about a specific one, including versions\n that CRAN has archived. Use \u{1b}[32m--json\u{1b}[39m for machine readable output.\n\n\u{1b}[1m\u{1b}[34mDependency types:\u{1b}[39m\u{1b}[22m\n By default rig lists the hard dependencies only: \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m\n and \u{1b}[32mLinkingTo\u{1b}[39m, i.e. the packages that need to be installed to use the\n package. \u{1b}[32m--dev\u{1b}[39m adds the soft dependencies, \u{1b}[32mSuggests\u{1b}[39m and \u{1b}[32mEnhances\u{1b}[39m,\n which are typically only needed to run the tests, build the vignettes or\n use some optional feature.\n\n R itself and the base packages, e.g. \u{1b}[32mutils\u{1b}[39m or \u{1b}[32mstats\u{1b}[39m, are listed if\n the package depends on them, with their version requirement, but without\n a version of their own, as they are part of R.\n\n\u{1b}[1m\u{1b}[34mRecursive dependencies:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--recursive\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) shows the whole dependency closure: not only the\n packages the package needs directly, but also the packages \u{1b}[3mthose\u{1b}[23m need,\n and so on. Each package appears once, with the \u{1b}[32mDepth\u{1b}[39m column giving its\n distance from the queried package, and the \u{1b}[32mNeeded by\u{1b}[39m column naming the\n packages that pull it in.\n\n \u{1b}[32mrig pkg tree\u{1b}[39m shows the same closure as a tree, which\n makes it easier to see how a package is pulled in, at the price of a\n longer listing.\n\n A recursive listing only ever follows hard dependencies, also below a\n soft dependency added by \u{1b}[32m--dev\u{1b}[39m, so \u{1b}[32m--dev --recursive\u{1b}[39m means the\n package's own dev dependencies plus everything they need to be\n installed.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in\n the tree, so a version requirement that would force an older version,\n with different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj lock\u{1b}[39m for a resolution that is consistent across\n versions."; const ABOUT_PKG_INFO: &str = "Information about a package in the repositories"; const HELP_PKG_INFO: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show information about a package on CRAN, from its \u{1b}[32mDESCRIPTION\u{1b}[39m file.\n\n By default the latest available version is shown; use \u{1b}[32m--version\u{1b}[39m to\n select a specific one, including versions that CRAN has archived. Use\n \u{1b}[32m--json\u{1b}[39m to print all \u{1b}[32mDESCRIPTION\u{1b}[39m fields.\n\n If CRAN has archived the package, i.e. removed it from the current\n repository, rig shows the date it was archived, next to the publication\n date of the version. \u{1b}[32m--json\u{1b}[39m reports it as an extra \u{1b}[32mArchived\u{1b}[39m field.\n\n\u{1b}[1m\u{1b}[34mREADME of a package:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--readme\u{1b}[39m prints the README of the package, instead of its metadata,\n exactly as the repository stores it, i.e. not rendered and not paged. It\n works together with \u{1b}[32m--version\u{1b}[39m, to get the README of an older version,\n but not with \u{1b}[32m--versions\u{1b}[39m.\n\n \u{1b}[32m--readme --json\u{1b}[39m prints an object with the \u{1b}[32mpackage\u{1b}[39m and \u{1b}[32mversion\u{1b}[39m the\n README belongs to, the \u{1b}[32mreadme\u{1b}[39m itself, and the \u{1b}[32mformat\u{1b}[39m it is written\n in. The format is the one the repository reports, e.g. \u{1b}[32mmd\u{1b}[39m for markdown\n or \u{1b}[32mtxt\u{1b}[39m for plain text.\n\n A package without a README is not an error. \u{1b}[32m--readme\u{1b}[39m then prints\n nothing, and \u{1b}[32m--readme --json\u{1b}[39m prints \u{1b}[32mnull\u{1b}[39m for both \u{1b}[32mreadme\u{1b}[39m and\n \u{1b}[32mformat\u{1b}[39m.\n\n\u{1b}[1m\u{1b}[34mAll versions of a package:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--versions\u{1b}[39m lists all versions of the package ever published on CRAN,\n oldest first, instead of the details of a single version. For each version\n rig shows its publication date, its R version requirement and its number\n of hard dependencies (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m and \u{1b}[32mLinkingTo\u{1b}[39m, excluding R\n and the base packages); the latest version is marked. It cannot be\n combined with \u{1b}[32m--version\u{1b}[39m.\n\n For a package CRAN has archived, i.e. removed from the current\n repository, the header also shows the date it was archived. This applies\n to the package as a whole, so all of its versions are archived.\n\n \u{1b}[32m--versions --json\u{1b}[39m prints the full \u{1b}[32mDESCRIPTION\u{1b}[39m of every version, each\n with an extra \u{1b}[32mArchived\u{1b}[39m field for an archived package."; const ABOUT_PKG_INSTALL: &str = "Install packages from the repositories"; -const HELP_PKG_INSTALL: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Install one or more R packages, and everything they need, into an R package\n library.\n\n rig pkg install cli glue\n\n ✓ Solved dependencies\n 2 of 2 packages to install (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n Package Version Type Action Reason\n cli 3.6.3 binary install not installed\n glue 1.8.0 binary install not installed\n ✓ Installed 2 packages (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n\n rig resolves the whole dependency tree first, the same way\n \u{1b}[32mrig proj solve\u{1b}[39m does for a project, so a package is only\n installed if every package it needs can be installed with it, at versions\n that work together. \u{1b}[32m--dry-run\u{1b}[39m runs the resolution and reports what it\n would install, without installing anything.\n\n Package names are case sensitive, as they are in R. Naming the same package\n twice is not an error, it is installed once.\n\n\u{1b}[1m\u{1b}[34mDev dependencies:\u{1b}[39m\u{1b}[22m\n By default rig installs the hard dependencies only: \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m\n and \u{1b}[32mLinkingTo\u{1b}[39m, i.e. the packages that need to be installed to use the\n package. \u{1b}[32m--dev\u{1b}[39m also installs the soft dependencies, \u{1b}[32mSuggests\u{1b}[39m and\n \u{1b}[32mEnhances\u{1b}[39m, which are typically only needed to run the tests, build the\n vignettes or use some optional feature.\n\n \u{1b}[32m--dev\u{1b}[39m applies to the packages named on the command line only. A dev\n dependency is installed with everything \u{1b}[3mit\u{1b}[23m needs to be installed, but not\n with its own dev dependencies, so \u{1b}[32m--dev\u{1b}[39m does not grow without bounds.\n\n A package often suggests packages that are not in the repositories rig\n installs from, e.g. Bioconductor packages. Those cannot be installed, and\n by default rig reports them and installs nothing.\n \u{1b}[32m--ignore-unavailable\u{1b}[39m installs the rest of the dev dependencies instead,\n and names the ones it skipped. It only applies to dev dependencies: a hard\n dependency that is not available is always an error, and so is a dev\n dependency that exists but has no version that fits.\n\n\u{1b}[1m\u{1b}[34mBinary and source packages:\u{1b}[39m\u{1b}[22m\n A binary package is a package that has already been built for your platform\n and R version. Installing one is unpacking it into the library, so rig does\n that itself and never starts R.\n\n A package with no binary build is installed from its source tarball, with\n \u{1b}[32mR CMD INSTALL\u{1b}[39m, which does start R, and needs whatever that package needs\n to compile. The output of the compilation goes into a log file per package,\n in a \u{1b}[32m_logs\u{1b}[39m directory inside the library, and rig points at the log when an\n installation fails.\n\n \u{1b}[32m--platform\u{1b}[39m installs for a platform other than this machine's, and\n \u{1b}[32m--platform source\u{1b}[39m installs source packages only. \u{1b}[32m--prefer-binary\u{1b}[39m trades\n a newer version for an older one that has a binary build, which is useful\n when compiling is expensive; it takes the number of versions to look back\n through, e.g. \u{1b}[32m--prefer-binary=5\u{1b}[39m, and defaults to 3.\n\n\u{1b}[1m\u{1b}[34mPackages rig builds itself:\u{1b}[39m\u{1b}[22m\n Compiling a package produces exactly what a repository would have served as\n a binary package, so rig keeps it: a source install is archived into the\n cache, with the same file name \u{1b}[32mR CMD INSTALL --build\u{1b}[39m would have given it,\n and installing that package again unpacks the archive instead of compiling\n it a second time. That covers another library, another project, and\n \u{1b}[32m--reinstall\u{1b}[39m, which reinstalls a package but does not recompile it.\n\n A cache entry belongs to one platform, one R minor version, one source\n tarball, one set of versions of the packages it is compiled against, and one\n set of \u{1b}[32m~/.R/Makevars\u{1b}[39m files. Change any of those and the package is\n compiled again. What it does \u{1b}[3mnot\u{1b}[23m cover is your compiler, the system\n libraries the package found when it was configured, and the arguments it was\n configured with; a machine whose toolchain changed under it can hold an entry\n that no longer matches, and the way out is to delete it. \u{1b}[32mrig system dirs --cache\u{1b}[39m says where the cache is.\n\n \u{1b}[32m--no-cache\u{1b}[39m turns all of this off for one run: rig then downloads the\n repository metadata and the package files again, compiles every source\n package rather than unpacking one it built earlier, and adds nothing to the\n cache. See \u{1b}[32mrig config\u{1b}[39m.\n\n\u{1b}[1m\u{1b}[34mWhat gets skipped:\u{1b}[39m\u{1b}[22m\n rig does not install a package that is already installed and up to date, so\n running the same command twice does nothing the second time.\n\n Being up to date is more than having the right version number. A repository\n can publish several builds of one version, and a package with compiled code\n only works with the versions of the packages it was compiled against — an R\n that loads a package built against a different one can crash rather than\n complain. So rig keeps track of which build each package it installs came\n from, and what that build was compiled against, and reinstalls a package\n whose build is no longer the one the resolution picked.\n\n That check cascades: replacing a package also replaces the packages that\n were compiled against it, and the packages compiled against those.\n\n rig only knows this about packages it installed itself, so a package that R,\n pak or renv installed is always reinstalled rather than assumed to match.\n \u{1b}[32m--reinstall\u{1b}[39m installs everything in the resolution regardless.\n\n\u{1b}[1m\u{1b}[34mWhich library:\u{1b}[39m\u{1b}[22m\n By default rig installs into the default library of the default R version,\n i.e. the library that \u{1b}[32mrig library default\u{1b}[39m reports, and the\n one R installs packages into.\n\n \u{1b}[32m--library\u{1b}[39m (\u{1b}[32m-l\u{1b}[39m) selects another library. It takes either the name of a\n library of the R version, as \u{1b}[32mrig library list\u{1b}[39m prints them,\n or the path of a library directory:\n\n rig pkg install --library myproject cli\n rig pkg install --library /usr/lib/R/site-library cli\n\n A path is used as it is, and is created if it does not exist yet, so it does\n not need to belong to an R version rig manages.\n\n \u{1b}[32m--r-version\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) selects the library of another R version, instead of\n the default one, as it does for the \u{1b}[32mrig library\u{1b}[39m commands.\n It has no effect on which library \u{1b}[32m--library\u{1b}[39m names when that is a path, but\n it still decides which binary packages fit, and which \u{1b}[32mR\u{1b}[39m installs a source\n package.\n\n In admin mode the site and system libraries of\n an R installation belong to the administrator, so installing into them needs\n \u{1b}[32msudo\u{1b}[39m (an administrator account on Windows). Your own user library never\n does."; +const HELP_PKG_INSTALL: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Install one or more R packages, and everything they need, into an R package\n library.\n\n rig pkg install cli glue\n\n ✓ Solved dependencies\n 2 of 2 packages to install (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n Package Version Type Action Reason\n cli 3.6.3 binary install not installed\n glue 1.8.0 binary install not installed\n ✓ Installed 2 packages (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n\n rig resolves the whole dependency tree first, the same way\n \u{1b}[32mrig proj lock\u{1b}[39m does for a project, so a package is only\n installed if every package it needs can be installed with it, at versions\n that work together. \u{1b}[32m--dry-run\u{1b}[39m runs the resolution and reports what it\n would install, without installing anything.\n\n Package names are case sensitive, as they are in R. Naming the same package\n twice is not an error, it is installed once.\n\n\u{1b}[1m\u{1b}[34mDev dependencies:\u{1b}[39m\u{1b}[22m\n By default rig installs the hard dependencies only: \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m\n and \u{1b}[32mLinkingTo\u{1b}[39m, i.e. the packages that need to be installed to use the\n package. \u{1b}[32m--dev\u{1b}[39m also installs the soft dependencies, \u{1b}[32mSuggests\u{1b}[39m and\n \u{1b}[32mEnhances\u{1b}[39m, which are typically only needed to run the tests, build the\n vignettes or use some optional feature.\n\n \u{1b}[32m--dev\u{1b}[39m applies to the packages named on the command line only. A dev\n dependency is installed with everything \u{1b}[3mit\u{1b}[23m needs to be installed, but not\n with its own dev dependencies, so \u{1b}[32m--dev\u{1b}[39m does not grow without bounds.\n\n A package often suggests packages that are not in the repositories rig\n installs from, e.g. Bioconductor packages. Those cannot be installed, and\n by default rig reports them and installs nothing.\n \u{1b}[32m--ignore-unavailable\u{1b}[39m installs the rest of the dev dependencies instead,\n and names the ones it skipped. It only applies to dev dependencies: a hard\n dependency that is not available is always an error, and so is a dev\n dependency that exists but has no version that fits.\n\n\u{1b}[1m\u{1b}[34mBinary and source packages:\u{1b}[39m\u{1b}[22m\n A binary package is a package that has already been built for your platform\n and R version. Installing one is unpacking it into the library, so rig does\n that itself and never starts R.\n\n A package with no binary build is installed from its source tarball, with\n \u{1b}[32mR CMD INSTALL\u{1b}[39m, which does start R, and needs whatever that package needs\n to compile. The output of the compilation goes into a log file per package,\n in a \u{1b}[32m_logs\u{1b}[39m directory inside the library, and rig points at the log when an\n installation fails.\n\n \u{1b}[32m--platform\u{1b}[39m installs for a platform other than this machine's, and\n \u{1b}[32m--platform source\u{1b}[39m installs source packages only. \u{1b}[32m--prefer-binary\u{1b}[39m trades\n a newer version for an older one that has a binary build, which is useful\n when compiling is expensive; it takes the number of versions to look back\n through, e.g. \u{1b}[32m--prefer-binary=5\u{1b}[39m, and defaults to 3.\n\n\u{1b}[1m\u{1b}[34mPackages rig builds itself:\u{1b}[39m\u{1b}[22m\n Compiling a package produces exactly what a repository would have served as\n a binary package, so rig keeps it: a source install is archived into the\n cache, with the same file name \u{1b}[32mR CMD INSTALL --build\u{1b}[39m would have given it,\n and installing that package again unpacks the archive instead of compiling\n it a second time. That covers another library, another project, and\n \u{1b}[32m--reinstall\u{1b}[39m, which reinstalls a package but does not recompile it.\n\n A cache entry belongs to one platform, one R minor version, one source\n tarball, one set of versions of the packages it is compiled against, and one\n set of \u{1b}[32m~/.R/Makevars\u{1b}[39m files. Change any of those and the package is\n compiled again. What it does \u{1b}[3mnot\u{1b}[23m cover is your compiler, the system\n libraries the package found when it was configured, and the arguments it was\n configured with; a machine whose toolchain changed under it can hold an entry\n that no longer matches, and the way out is to delete it. \u{1b}[32mrig system dirs --cache\u{1b}[39m says where the cache is.\n\n \u{1b}[32m--no-cache\u{1b}[39m turns all of this off for one run: rig then downloads the\n repository metadata and the package files again, compiles every source\n package rather than unpacking one it built earlier, and adds nothing to the\n cache. See \u{1b}[32mrig config\u{1b}[39m.\n\n\u{1b}[1m\u{1b}[34mWhat gets skipped:\u{1b}[39m\u{1b}[22m\n rig does not install a package that is already installed and up to date, so\n running the same command twice does nothing the second time.\n\n Being up to date is more than having the right version number. A repository\n can publish several builds of one version, and a package with compiled code\n only works with the versions of the packages it was compiled against — an R\n that loads a package built against a different one can crash rather than\n complain. So rig keeps track of which build each package it installs came\n from, and what that build was compiled against, and reinstalls a package\n whose build is no longer the one the resolution picked.\n\n That check cascades: replacing a package also replaces the packages that\n were compiled against it, and the packages compiled against those.\n\n rig only knows this about packages it installed itself, so a package that R,\n pak or renv installed is always reinstalled rather than assumed to match.\n \u{1b}[32m--reinstall\u{1b}[39m installs everything in the resolution regardless.\n\n\u{1b}[1m\u{1b}[34mWhich library:\u{1b}[39m\u{1b}[22m\n By default rig installs into the default library of the default R version,\n i.e. the library that \u{1b}[32mrig library default\u{1b}[39m reports, and the\n one R installs packages into.\n\n \u{1b}[32m--library\u{1b}[39m (\u{1b}[32m-l\u{1b}[39m) selects another library. It takes either the name of a\n library of the R version, as \u{1b}[32mrig library list\u{1b}[39m prints them,\n or the path of a library directory:\n\n rig pkg install --library myproject cli\n rig pkg install --library /usr/lib/R/site-library cli\n\n A path is used as it is, and is created if it does not exist yet, so it does\n not need to belong to an R version rig manages.\n\n \u{1b}[32m--r-version\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) selects the library of another R version, instead of\n the default one, as it does for the \u{1b}[32mrig library\u{1b}[39m commands.\n It has no effect on which library \u{1b}[32m--library\u{1b}[39m names when that is a path, but\n it still decides which binary packages fit, and which \u{1b}[32mR\u{1b}[39m installs a source\n package.\n\n In admin mode the site and system libraries of\n an R installation belong to the administrator, so installing into them needs\n \u{1b}[32msudo\u{1b}[39m (an administrator account on Windows). Your own user library never\n does."; const ABOUT_PKG_LIST: &str = "Packages installed in a library"; const HELP_PKG_LIST: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n List the packages installed in an R package library, without starting R.\n\n 312 packages (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n\n Package Version Built Platform Source\n -----------------------------------------------------------------------------\n cli 3.6.3 4.4.0 aarch64-apple-darwin20 CRAN\n glue 1.8.0 4.4.1 aarch64-apple-darwin20 CRAN\n asciicast 2.3.1.9000 4.4.1 aarch64-apple-darwin20 github::r-lib/asciicast\n mypkg 0.0.1 4.4.1 - -\n\n The first line names the number of packages and the library they were found\n in. Each line below it names a package, its version, the R version it was\n built for, the platform it was built for, and where it was installed from.\n\n \u{1b}[32mPlatform\u{1b}[39m is empty for a package installed from source. \u{1b}[32mSource\u{1b}[39m is the\n repository the package came from, e.g. \u{1b}[32mCRAN\u{1b}[39m, and for a package installed\n from somewhere else it names that place instead, in the package reference\n syntax pak uses: \u{1b}[32mgithub::/\u{1b}[39m for a GitHub install, \u{1b}[32mgit::\u{1b}[39m\n for a git one, and so on. It is empty for a package installed from a local\n directory, as \u{1b}[32mR CMD INSTALL\u{1b}[39m and \u{1b}[32mdevtools::install()\u{1b}[39m do, because such a\n package records nothing about where its source was.\n\n A field the package's \u{1b}[32mDESCRIPTION\u{1b}[39m does not have is shown as \u{1b}[32m-\u{1b}[39m. Use\n \u{1b}[32m--json\u{1b}[39m for machine readable output, which reports the repository or remote\n type as \u{1b}[32msource\u{1b}[39m and the remote itself as \u{1b}[32mremote\u{1b}[39m, separately.\n\n This subcommand and \u{1b}[32mrig pkg remove\u{1b}[39m read an \u{1b}[3minstalled\u{1b}[23m\n library; the others, e.g. \u{1b}[32mrig pkg available\u{1b}[39m, read the\n package repositories that packages are installed \u{1b}[3mfrom\u{1b}[23m.\n\n\u{1b}[1m\u{1b}[34mWhich library:\u{1b}[39m\u{1b}[22m\n By default rig lists the default library of the default R version, i.e. the\n library that \u{1b}[32mrig library default\u{1b}[39m reports, and the one R\n installs packages into.\n\n \u{1b}[32m--library\u{1b}[39m (\u{1b}[32m-l\u{1b}[39m) selects another library. It takes either the name of a\n library of the R version, as \u{1b}[32mrig library list\u{1b}[39m prints them, or\n the path of a library directory:\n\n rig pkg list --library myproject\n rig pkg list --library /usr/lib/R/site-library\n\n A path is used as it is, so it does not need to belong to an R version rig\n manages, and rig does not need an R version at all to list it.\n\n \u{1b}[32m--r-version\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) lists the library of another R version, instead of the\n default one, as it does for the \u{1b}[32mrig library\u{1b}[39m commands. It has\n no effect when \u{1b}[32m--library\u{1b}[39m is a path.\n\n Subdirectories that are not packages are left out: rig's own libraries of a\n main library, and the leftovers of an interrupted installation."; const ABOUT_PKG_REMOVE: &str = "Remove packages from a library"; const HELP_PKG_REMOVE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Delete one or more installed packages from an R package library, without\n starting R.\n\n rig pkg remove cli glue\n\n ▶ Removing cli 3.6.3 from /Users/gaborcsardi/Library/R/arm64/4.4/library/cli...\n ▶ Removing glue 1.8.0 from /Users/gaborcsardi/Library/R/arm64/4.4/library/glue...\n ✓ Removed 2 packages (R 4.4.1, main: /Users/gaborcsardi/Library/R/arm64/4.4/library)\n\n Removing a package deletes its directory in the library, which is what\n \u{1b}[32mR CMD REMOVE\u{1b}[39m and \u{1b}[32mremove.packages()\u{1b}[39m do as well.\n\n Package names are case sensitive, as they are in R, and every package named\n must be installed in the library: if one of them is not, then rig removes\n none of them. Naming the same package twice is not an error, it is removed\n once.\n\n rig does not check whether another installed package needs the one being\n removed. Use \u{1b}[32mrig pkg list\u{1b}[39m to see what is installed, and\n \u{1b}[32m--json\u{1b}[39m for machine readable output about what was removed.\n\n The base packages that ship with R (\u{1b}[32mbase\u{1b}[39m, \u{1b}[32mstats\u{1b}[39m, \u{1b}[32mutils\u{1b}[39m, ...) are part\n of the R installation, and R does not work without them, so rig refuses to\n remove them unless \u{1b}[32m--force\u{1b}[39m is also given.\n\n\u{1b}[1m\u{1b}[34mWhich library:\u{1b}[39m\u{1b}[22m\n By default rig removes the packages from the default library of the default R\n version, i.e. the library that \u{1b}[32mrig library default\u{1b}[39m reports,\n and the one R installs packages into.\n\n \u{1b}[32m--library\u{1b}[39m (\u{1b}[32m-l\u{1b}[39m) selects another library. It takes either the name of a\n library of the R version, as \u{1b}[32mrig library list\u{1b}[39m prints them, or\n the path of a library directory:\n\n rig pkg remove --library myproject cli\n rig pkg remove --library /usr/lib/R/site-library cli\n\n A path is used as it is, so it does not need to belong to an R version rig\n manages, and rig does not need an R version at all to remove packages from\n it.\n\n \u{1b}[32m--r-version\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) selects the library of another R version, instead of the\n default one, as it does for the \u{1b}[32mrig library\u{1b}[39m commands. It has\n no effect when \u{1b}[32m--library\u{1b}[39m is a path.\n\n In admin mode the site and system libraries of\n an R installation belong to the administrator, so removing a package from\n them needs \u{1b}[32msudo\u{1b}[39m (an administrator account on Windows). Your own user\n library never does. To remove a whole library, with all the packages in it,\n use \u{1b}[32mrig library rm\u{1b}[39m instead."; const ABOUT_PKG_TREE: &str = "Dependency tree of a package in the repositories"; -const HELP_PKG_TREE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show everything a package needs, directly or indirectly, as a tree: the same\n closure \u{1b}[32mrig pkg deps --recursive\u{1b}[39m lists in a flat table, laid\n out by the shape of the dependency graph.\n\n dplyr 1.1.4 — 13 direct, 30 total\n ├── R (>= 3.5.0) [D]\n ├── cli 3.6.4 (>= 3.4.0)\n │ ├── R (>= 3.4) [D]\n │ └── utils\n ├── lifecycle 1.0.4 (>= 1.0.3)\n │ ├── cli 3.6.4 (>= 3.4.0) (*)\n │ └── rlang 1.1.6 (>= 1.1.0)\n │ └── R (>= 3.5.0) [D]\n └── vctrs 0.6.5 (>= 0.6.4)\n └── cpp11 0.5.2 [L]\n [Suggests]\n └── tidyr 1.3.1 (>= 1.3.0)\n └── cpp11 0.5.2 (>= 0.4.0) [L] (*)\n\n The first line names the package version, how many dependencies it has\n directly and how many distinct packages there are in the whole tree. Each line\n below names a package, the version currently on CRAN, and the version\n requirement it is needed with, if it has one.\n\n \u{1b}[32m--version\u{1b}[39m asks about a specific version, including versions CRAN has\n archived. \u{1b}[32m--json\u{1b}[39m gives machine readable output, as one nested object.\n \u{1b}[32mrig proj tree\u{1b}[39m shows the same tree for the\n dependencies a project declares.\n\n\u{1b}[1m\u{1b}[34mReading the tree:\u{1b}[39m\u{1b}[22m\n A package that several others need is expanded only once, under its first\n occurrence; later occurrences are a single line marked \u{1b}[32m(*)\u{1b}[39m, meaning \"its\n dependencies are above\". This is also what makes dependency cycles end on\n their own.\n\n A mark at the end of a line says how the package is needed; \u{1b}[32mImports\u{1b}[39m is the\n common case and is not marked.\n\n - \u{1b}[32m[D]\u{1b}[39m — a \u{1b}[32mDepends\u{1b}[39m, so the package is \u{1b}[3mattached\u{1b}[23m, not merely loaded.\n - \u{1b}[32m[L]\u{1b}[39m — a \u{1b}[32mLinkingTo\u{1b}[39m, so this package is compiled against it.\n - \u{1b}[32m[DL]\u{1b}[39m — both.\n\n Dependencies are listed with R first, then grouped by dependency type, in the\n order R lists the fields in, and by name within a type. R and the base\n packages, e.g. \u{1b}[32mutils\u{1b}[39m, are shown with their version requirement but without a\n version of their own, as they are part of R; \u{1b}[32m--no-base\u{1b}[39m leaves them out\n altogether. A package that is not in the repositories is shown with \u{1b}[32m?\u{1b}[39m for\n its version.\n\n By default rig follows the hard dependencies only. \u{1b}[32m--dev\u{1b}[39m adds \u{1b}[32mSuggests\u{1b}[39m and\n \u{1b}[32mEnhances\u{1b}[39m, in their own \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections. As in\n \u{1b}[32mrig pkg deps\u{1b}[39m, \u{1b}[32m--dev\u{1b}[39m applies to the queried package only, so these sections\n only ever appear at the top of the tree.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in the\n tree, so a version requirement that would force an older version, with\n different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj solve\u{1b}[39m for a resolution that is consistent across\n versions.\n\n\u{1b}[1m\u{1b}[34mInverting the tree:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--why \u{1b}[39m (alias \u{1b}[32m--explain\u{1b}[39m) inverts the tree: the named package is\n the root and the tree grows towards the packages that need it, down to the\n queried package, which becomes a leaf.\n\n glue 1.8.1 — 4 direct dependents, 5 total\n ├── dplyr 1.2.1 (needs >= 1.3.2)\n ├── pillar 1.11.1\n │ └── dplyr 1.2.1 (needs >= 1.9.0)\n └── vctrs 0.7.3\n ├── dplyr 1.2.1 (needs >= 0.7.1)\n └── pillar 1.11.1 (needs >= 0.5.0) (*)\n\n Each line says how \u{1b}[3mthat\u{1b}[23m package needs the one \u{1b}[1mabove\u{1b}[22m it, hence \u{1b}[32mneeds\u{1b}[39m;\n the \u{1b}[32m[D]\u{1b}[39m, \u{1b}[32m[L]\u{1b}[39m, \u{1b}[32m[S]\u{1b}[39m and \u{1b}[32m[E]\u{1b}[39m marks describe the same edge. \u{1b}[32m[S]\u{1b}[39m and \u{1b}[32m[E]\u{1b}[39m\n take the place of the \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections, which in an\n inverted tree would be one line deep inside it.\n\n \u{1b}[32m--why\u{1b}[39m searches the tree only, not the repositories, so \u{1b}[32m--version\u{1b}[39m, \u{1b}[32m--dev\u{1b}[39m\n and \u{1b}[32m--no-base\u{1b}[39m apply as above, and a package that is not in the tree is an\n error."; +const HELP_PKG_TREE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show everything a package needs, directly or indirectly, as a tree: the same\n closure \u{1b}[32mrig pkg deps --recursive\u{1b}[39m lists in a flat table, laid\n out by the shape of the dependency graph.\n\n dplyr 1.1.4 — 13 direct, 30 total\n ├── R (>= 3.5.0) [D]\n ├── cli 3.6.4 (>= 3.4.0)\n │ ├── R (>= 3.4) [D]\n │ └── utils\n ├── lifecycle 1.0.4 (>= 1.0.3)\n │ ├── cli 3.6.4 (>= 3.4.0) (*)\n │ └── rlang 1.1.6 (>= 1.1.0)\n │ └── R (>= 3.5.0) [D]\n └── vctrs 0.6.5 (>= 0.6.4)\n └── cpp11 0.5.2 [L]\n [Suggests]\n └── tidyr 1.3.1 (>= 1.3.0)\n └── cpp11 0.5.2 (>= 0.4.0) [L] (*)\n\n The first line names the package version, how many dependencies it has\n directly and how many distinct packages there are in the whole tree. Each line\n below names a package, the version currently on CRAN, and the version\n requirement it is needed with, if it has one.\n\n \u{1b}[32m--version\u{1b}[39m asks about a specific version, including versions CRAN has\n archived. \u{1b}[32m--json\u{1b}[39m gives machine readable output, as one nested object.\n \u{1b}[32mrig proj tree\u{1b}[39m shows the same tree for the\n dependencies a project declares.\n\n\u{1b}[1m\u{1b}[34mReading the tree:\u{1b}[39m\u{1b}[22m\n A package that several others need is expanded only once, under its first\n occurrence; later occurrences are a single line marked \u{1b}[32m(*)\u{1b}[39m, meaning \"its\n dependencies are above\". This is also what makes dependency cycles end on\n their own.\n\n A mark at the end of a line says how the package is needed; \u{1b}[32mImports\u{1b}[39m is the\n common case and is not marked.\n\n - \u{1b}[32m[D]\u{1b}[39m — a \u{1b}[32mDepends\u{1b}[39m, so the package is \u{1b}[3mattached\u{1b}[23m, not merely loaded.\n - \u{1b}[32m[L]\u{1b}[39m — a \u{1b}[32mLinkingTo\u{1b}[39m, so this package is compiled against it.\n - \u{1b}[32m[DL]\u{1b}[39m — both.\n\n Dependencies are listed with R first, then grouped by dependency type, in the\n order R lists the fields in, and by name within a type. R and the base\n packages, e.g. \u{1b}[32mutils\u{1b}[39m, are shown with their version requirement but without a\n version of their own, as they are part of R; \u{1b}[32m--no-base\u{1b}[39m leaves them out\n altogether. A package that is not in the repositories is shown with \u{1b}[32m?\u{1b}[39m for\n its version.\n\n By default rig follows the hard dependencies only. \u{1b}[32m--dev\u{1b}[39m adds \u{1b}[32mSuggests\u{1b}[39m and\n \u{1b}[32mEnhances\u{1b}[39m, in their own \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections. As in\n \u{1b}[32mrig pkg deps\u{1b}[39m, \u{1b}[32m--dev\u{1b}[39m applies to the queried package only, so these sections\n only ever appear at the top of the tree.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in the\n tree, so a version requirement that would force an older version, with\n different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj lock\u{1b}[39m for a resolution that is consistent across\n versions.\n\n\u{1b}[1m\u{1b}[34mInverting the tree:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--why \u{1b}[39m (alias \u{1b}[32m--explain\u{1b}[39m) inverts the tree: the named package is\n the root and the tree grows towards the packages that need it, down to the\n queried package, which becomes a leaf.\n\n glue 1.8.1 — 4 direct dependents, 5 total\n ├── dplyr 1.2.1 (needs >= 1.3.2)\n ├── pillar 1.11.1\n │ └── dplyr 1.2.1 (needs >= 1.9.0)\n └── vctrs 0.7.3\n ├── dplyr 1.2.1 (needs >= 0.7.1)\n └── pillar 1.11.1 (needs >= 0.5.0) (*)\n\n Each line says how \u{1b}[3mthat\u{1b}[23m package needs the one \u{1b}[1mabove\u{1b}[22m it, hence \u{1b}[32mneeds\u{1b}[39m;\n the \u{1b}[32m[D]\u{1b}[39m, \u{1b}[32m[L]\u{1b}[39m, \u{1b}[32m[S]\u{1b}[39m and \u{1b}[32m[E]\u{1b}[39m marks describe the same edge. \u{1b}[32m[S]\u{1b}[39m and \u{1b}[32m[E]\u{1b}[39m\n take the place of the \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections, which in an\n inverted tree would be one line deep inside it.\n\n \u{1b}[32m--why\u{1b}[39m searches the tree only, not the repositories, so \u{1b}[32m--version\u{1b}[39m, \u{1b}[32m--dev\u{1b}[39m\n and \u{1b}[32m--no-base\u{1b}[39m apply as above, and a package that is not in the tree is an\n error."; const ABOUT_PKG: &str = "Manage R packages (experimental)"; const HELP_PKG: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Look up R packages, in the package repositories rig configures for your R\n installations and in the libraries they are installed into, and install\n them, mostly without starting R.\n\n \u{1b}[32mrig pkg available\u{1b}[39m lists every package the\n repositories offer, \u{1b}[32mrig pkg info\u{1b}[39m shows the\n \u{1b}[32mDESCRIPTION\u{1b}[39m of one package, or, with \u{1b}[32m--versions\u{1b}[39m, all of its versions,\n \u{1b}[32mrig pkg deps\u{1b}[39m lists the packages one package needs,\n directly or, with \u{1b}[32m--recursive\u{1b}[39m, transitively, and\n \u{1b}[32mrig pkg tree\u{1b}[39m shows those transitive dependencies as a\n tree instead of a table.\n\n \u{1b}[32mrig pkg install\u{1b}[39m,\n \u{1b}[32mrig pkg list\u{1b}[39m and\n \u{1b}[32mrig pkg remove\u{1b}[39m are the subcommands that work on a\n package library instead of the repositories: they install packages and\n their dependencies into it, list the packages that are actually installed,\n and delete some of them.\n\n The repositories themselves are managed by \u{1b}[32mrig repos\u{1b}[39m, the\n libraries by \u{1b}[32mrig library\u{1b}[39m."; const ABOUT_PPM_BUILDS: &str = "List the published builds of a package"; @@ -62,16 +62,20 @@ const ABOUT_PPM_URL: &str = "Print the Posit Package Manager URL"; const HELP_PPM_URL: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Print the base URL of the Posit Package Manager instance the other\n \u{1b}[32mrig ppm\u{1b}[39m commands report on, and nothing else, so it can be\n used directly in a script:\n\n curl \"$(rig ppm url)/__api__/repos\"\n\n This is \u{1b}[32mhttps://packagemanager.posit.co\u{1b}[39m unless the\n \u{1b}[32mPACKAGEMANAGER_ADDRESS\u{1b}[39m environment variable is set, in which case it is\n that, with any trailing slash removed.\n\n The \u{1b}[32mRIG_PPM_STATUS_URL\u{1b}[39m environment variable overrides the URL of the\n status document alone, and takes precedence over \u{1b}[32mPACKAGEMANAGER_ADDRESS\u{1b}[39m\n for that one document. If you set it, this command still prints the base\n URL, while \u{1b}[32mrig ppm status\u{1b}[39m reports on the\n instance \u{1b}[32mRIG_PPM_STATUS_URL\u{1b}[39m names and shows which URL that was."; const ABOUT_PPM: &str = "Query Posit Package Manager (experimental)"; const HELP_PPM: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Ask Posit Package Manager (P3M) what it offers: which platforms and R\n versions it builds binary packages for, and which builds exist for a\n package. Nothing here changes anything on your machine.\n\n \u{1b}[32mrig ppm platforms\u{1b}[39m and\n \u{1b}[32mrig ppm r-versions\u{1b}[39m list the build targets and R\n versions, \u{1b}[32mrig ppm status\u{1b}[39m shows P3M's whole status\n report, \u{1b}[32mrig ppm builds\u{1b}[39m lists the published builds of\n one package, and \u{1b}[32mrig ppm url\u{1b}[39m prints the URL rig is\n talking to.\n\n This is about P3M itself. To manage the repositories configured for your R\n installations, including P3M ones, use \u{1b}[32mrig repos\u{1b}[39m; to look up\n package metadata in those repositories, use \u{1b}[32mrig pkg\u{1b}[39m.\n\n\u{1b}[1m\u{1b}[34mWhich server:\u{1b}[39m\u{1b}[22m\n By default rig reports on the public instance,\n \u{1b}[32mhttps://packagemanager.posit.co\u{1b}[39m. Set the \u{1b}[32mPACKAGEMANAGER_ADDRESS\u{1b}[39m\n environment variable to the base URL of your own P3M instance to report on\n that instead. \u{1b}[32mrig ppm url\u{1b}[39m prints whichever one is in effect.\n\n One command is different: \u{1b}[32mrig ppm builds\u{1b}[39m reads a package build index that\n rig publishes itself, derived from P3M, because P3M has no endpoint that\n lists a package's builds. That index always comes from rig's own host, and\n \u{1b}[32mPACKAGEMANAGER_ADDRESS\u{1b}[39m does not redirect it."; -const ABOUT_PROJ_DEPLOY: &str = "Deploy project dependencies"; -const HELP_PROJ_DEPLOY: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Install the resolved dependencies of an R project into a package library.\n\n rig solves the project dependencies and installs them into the library\n given by \u{1b}[32m--library\u{1b}[39m. Use \u{1b}[32m--r-binary\u{1b}[39m to select which R to build against\n (default: \u{1b}[32mR\u{1b}[39m) and \u{1b}[32m--max-concurrent\u{1b}[39m to limit the number of simultaneous\n installations (default: 4)."; const ABOUT_PROJ_DEPS: &str = "Show project dependencies"; -const HELP_PROJ_DEPS: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show the dependencies of an R project, in a table: every package the\n project depends on, the dependency type (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m,\n \u{1b}[32mLinkingTo\u{1b}[39m) and the version requirement, if it has one.\n\n By default rig reads the project manifest (e.g. \u{1b}[32mDESCRIPTION\u{1b}[39m) in the\n current directory; use \u{1b}[32m--input\u{1b}[39m to point to a different file. Add \u{1b}[32m--dev\u{1b}[39m\n to include development dependencies. Use \u{1b}[32m--json\u{1b}[39m for machine readable\n output.\n\n The plain listing only reads the manifest, so it needs neither R nor the\n package repositories.\n\n\u{1b}[1m\u{1b}[34mRecursive dependencies:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--recursive\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) shows the whole dependency closure: not only the\n packages the project needs directly, but also the packages \u{1b}[3mthose\u{1b}[23m need,\n and so on. Each package appears once, with the version currently on CRAN,\n the \u{1b}[32mDepth\u{1b}[39m column giving its distance from the project, and the\n \u{1b}[32mNeeded by\u{1b}[39m column naming the packages that pull it in. This needs the\n package metadata of the repositories, which rig downloads if it does not\n have it yet.\n\n \u{1b}[32mrig proj tree\u{1b}[39m shows the same closure as a tree, laid\n out by the shape of the dependency graph, so you can see \u{1b}[3mhow\u{1b}[23m each\n package is pulled in and not only \u{1b}[3mthat\u{1b}[23m it is.\n\n A recursive listing only ever follows hard dependencies, also below a\n development dependency added by \u{1b}[32m--dev\u{1b}[39m, so \u{1b}[32m--dev --recursive\u{1b}[39m means the\n project's own dev dependencies plus everything they need to be installed.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in\n the closure, so a version requirement that would force an older version,\n with different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj solve\u{1b}[39m for a resolution that is consistent\n across versions."; -const ABOUT_PROJ_SOLVE: &str = "Solve project dependencies"; -const HELP_PROJ_SOLVE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Resolve the dependencies of an R project to a concrete set of package\n versions.\n\n rig reads the project manifest (e.g. \u{1b}[32mDESCRIPTION\u{1b}[39m; override with\n \u{1b}[32m--input\u{1b}[39m) and uses its built-in solver to find a compatible set of\n package versions from the configured repositories, without running R.\n\n Use \u{1b}[32m--r-version\u{1b}[39m to solve for a specific R version, \u{1b}[32m--dev\u{1b}[39m to include\n development dependencies, and \u{1b}[32m--renv\u{1b}[39m to write the result as an\n \u{1b}[32mrenv.lock\u{1b}[39m file.\n\n\u{1b}[1m\u{1b}[34mSource and binary packages:\u{1b}[39m\u{1b}[22m\n The solver considers binary packages as well as source packages, and\n prefers a binary build when one is available for the same version. Which\n artifact each package is installed from is part of what the solve decides,\n because a binary is only usable together with the exact versions of its\n \u{1b}[32mLinkingTo\u{1b}[39m dependencies that it was compiled against. If those versions\n conflict with the rest of the project, rig picks another build of that\n package, or falls back to its source tarball.\n\n By default a binary build never changes \u{1b}[3mwhich version\u{1b}[23m rig picks: the\n newest suitable version wins, and a binary of it is used if there is one.\n Pass \u{1b}[32m--prefer-binary\u{1b}[39m to let an older version win instead, when the newest\n one has no binary but an older one does — typically because a version was\n released so recently that it has not been built yet. Only the three newest\n versions of a package are considered; \u{1b}[32m--prefer-binary=5\u{1b}[39m considers five.\n Versions held back this way are marked in the output.\n\n Trading a version away for a binary is not free: the binary pins its\n \u{1b}[32mLinkingTo\u{1b}[39m dependencies to the versions it was compiled against, and those\n dependencies then prefer their own binaries in turn, so a whole project can\n end up on older versions.\n\n By default rig solves for the machine it runs on. Use \u{1b}[32m--platform\u{1b}[39m to solve\n for a different one, e.g. to write a lockfile on macOS for a Linux\n deployment:\n\n rig proj solve --platform ubuntu-24.04\n\n \u{1b}[32m--platform source\u{1b}[39m solves for source packages only, and does not download\n any binary package metadata. rig also falls back to source packages when\n there are no binaries for a platform at all. There is then nothing for\n \u{1b}[32m--prefer-binary\u{1b}[39m to prefer, and rig ignores it.\n\n rig keeps the repository metadata and the binary package indices it solves\n from in its cache, and refreshes them once a day. \u{1b}[32m--no-cache\u{1b}[39m downloads\n them again instead, and writes nothing to the cache, which is the way to\n solve against a package that was published minutes ago. It is a good deal\n slower, because the metadata it re-downloads is large. See\n \u{1b}[32mrig config\u{1b}[39m.\n\n The \u{1b}[32mpkg.lock\u{1b}[39m file records, for every package, whether it is a source or a\n binary package and the URL it is downloaded from. It also records where the\n file is cached, which is per \u{1b}[3mbuild\u{1b}[23m rather than per version: a repository\n can offer several binaries of one version for one platform and R version,\n and they are cached side by side."; +const HELP_PROJ_DEPS: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show the dependencies of an R project, in a table: every package the\n project depends on, the dependency type (\u{1b}[32mDepends\u{1b}[39m, \u{1b}[32mImports\u{1b}[39m,\n \u{1b}[32mLinkingTo\u{1b}[39m) and the version requirement, if it has one.\n\n rig reads the project manifest, \u{1b}[32mrproj.toml\u{1b}[39m, in the current directory. Add\n \u{1b}[32m--dev\u{1b}[39m to include development dependencies. Use \u{1b}[32m--json\u{1b}[39m for machine\n readable output.\n\n The plain listing only reads the manifest, so it needs neither R nor the\n package repositories.\n\n\u{1b}[1m\u{1b}[34mRecursive dependencies:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--recursive\u{1b}[39m (\u{1b}[32m-r\u{1b}[39m) shows the whole dependency closure: not only the\n packages the project needs directly, but also the packages \u{1b}[3mthose\u{1b}[23m need,\n and so on. Each package appears once, with the version currently on CRAN,\n the \u{1b}[32mDepth\u{1b}[39m column giving its distance from the project, and the\n \u{1b}[32mNeeded by\u{1b}[39m column naming the packages that pull it in. This needs the\n package metadata of the repositories, which rig downloads if it does not\n have it yet.\n\n \u{1b}[32mrig proj tree\u{1b}[39m shows the same closure as a tree, laid\n out by the shape of the dependency graph, so you can see \u{1b}[3mhow\u{1b}[23m each\n package is pulled in and not only \u{1b}[3mthat\u{1b}[23m it is.\n\n A recursive listing only ever follows hard dependencies, also below a\n development dependency added by \u{1b}[32m--dev\u{1b}[39m, so \u{1b}[32m--dev --recursive\u{1b}[39m means the\n project's own dev dependencies plus everything they need to be installed.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in\n the closure, so a version requirement that would force an older version,\n with different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj lock\u{1b}[39m for a resolution that is consistent\n across versions."; +const ABOUT_PROJ_IMPORT: &str = "Import a DESCRIPTION file's dependencies into rproj.toml"; +const HELP_PROJ_IMPORT: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Read a \u{1b}[32mDESCRIPTION\u{1b}[39m file and merge its dependencies into \u{1b}[32mrproj.toml\u{1b}[39m, rig's\n project and package manifest. If \u{1b}[32mrproj.toml\u{1b}[39m does not exist yet, it is\n created first, named after the DESCRIPTION file's \u{1b}[32mPackage:\u{1b}[39m field.\n\n \u{1b}[32mDepends\u{1b}[39m and \u{1b}[32mImports\u{1b}[39m land in the \u{1b}[32m[dependencies]\u{1b}[39m table (\u{1b}[32mDepends\u{1b}[39m\n packages are marked to attach on load); \u{1b}[32mLinkingTo\u{1b}[39m also lands in\n \u{1b}[32m[linking-dependencies]\u{1b}[39m. \u{1b}[32mSuggests\u{1b}[39m is imported into\n \u{1b}[32m[dependency-groups.test]\u{1b}[39m and \u{1b}[32mEnhances\u{1b}[39m into\n \u{1b}[32m[dependency-groups.enhances]\u{1b}[39m.\n\n By default rig reads \u{1b}[32mDESCRIPTION\u{1b}[39m in the current directory; use \u{1b}[32m--input\u{1b}[39m\n to point to a different file.\n\n Importing a package already listed in \u{1b}[32mrproj.toml\u{1b}[39m overwrites its entry\n with the version requirement from the DESCRIPTION file. Because\n \u{1b}[32mrproj.toml\u{1b}[39m is rewritten in full, any comments or custom formatting in an\n existing file are not preserved."; +const ABOUT_PROJ_INIT: &str = "Create a new R project"; +const HELP_PROJ_INIT: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Set up an R project in the current directory: the \u{1b}[32mrproj.toml\u{1b}[39m manifest, plus\n the part of the project's virtual environment (\u{1b}[32m.rvenv\u{1b}[39m) that belongs in\n version control.\n\n \u{1b}[32mrproj.toml\u{1b}[39m is rig's modern project and package file. It describes the\n project's metadata and its R and package dependencies, and can do everything\n a \u{1b}[32mDESCRIPTION\u{1b}[39m file can, plus dependency groups, optional dependencies,\n workspaces and declared scripts. \u{1b}[32mrig proj init\u{1b}[39m writes a minimal skeleton — a\n \u{1b}[32m[project]\u{1b}[39m table with the name (taken from the current directory) and\n version, and a \u{1b}[32m[dependencies]\u{1b}[39m table with a single R requirement — that you\n then fill in. Use \u{1b}[32mrig proj import\u{1b}[39m instead to take the\n dependencies from an existing \u{1b}[32mDESCRIPTION\u{1b}[39m.\n\n\u{1b}[1m\u{1b}[34mFiles:\u{1b}[39m\u{1b}[22m\n \u{1b}[32mrig proj init\u{1b}[39m creates these, and nothing else. All of them are meant to be\n committed, so that a fresh clone of the project works right away:\n\n - \u{1b}[32mrproj.toml\u{1b}[39m — the manifest. Its R requirement is \u{1b}[32m>= .\u{1b}[39m of\n the project's R version.\n - \u{1b}[32m.Renviron\u{1b}[39m — points R at the project library, \u{1b}[32m.rvenv/lib\u{1b}[39m. This is what\n makes the project work in an editor (RStudio, Positron, VS Code), which\n starts R itself.\n - \u{1b}[32m.gitignore\u{1b}[39m — a marked \u{1b}[32m# rig rvenv start\u{1b}[39m / \u{1b}[32m# rig rvenv end\u{1b}[39m block that\n ignores everything in \u{1b}[32m.rvenv\u{1b}[39m except the library directory. An existing\n \u{1b}[32m.gitignore\u{1b}[39m is \u{1b}[3mnot\u{1b}[23m replaced: rig only adds or refreshes its own block,\n and leaves the rest of the file alone.\n - \u{1b}[32m.rvenv/lib/.gitignore\u{1b}[39m — keeps the library directory itself, and the \u{1b}[32mrig\u{1b}[39m\n package in it, in version control, and ignores the installed dependencies.\n The directory has to exist in every checkout, because plain R does not\n create a missing library directory.\n - \u{1b}[32m.rvenv/lib/rig\u{1b}[39m — a small, pre-built R package that rig manages. It is not\n a dependency of your project. \u{1b}[32m.Renviron\u{1b}[39m loads it in every R session\n started in the project, where it turns the relative library path into an\n absolute one — so that R processes started from a subdirectory still use the\n project library — and warns while the project is out of sync with\n \u{1b}[32mrproj.lock\u{1b}[39m.\n\n The rest of \u{1b}[32m.rvenv\u{1b}[39m is machine-specific and is created by\n \u{1b}[32mrig proj sync\u{1b}[39m, which installs the project's dependencies\n into \u{1b}[32m.rvenv/lib\u{1b}[39m.\n\n Note that \u{1b}[32mR --vanilla\u{1b}[39m ignores \u{1b}[32m.Renviron\u{1b}[39m, and so does not use the project\n library.\n\n\u{1b}[1m\u{1b}[34mOptions:\u{1b}[39m\u{1b}[22m\n \u{1b}[32m--r-version\u{1b}[39m sets the R version the project is for. It does not have to be\n installed. Defaults to the current default R version, or the current R\n release if there is no default.\n\n rig refuses to overwrite any of the files above; pass \u{1b}[32m--force\u{1b}[39m to replace\n them. \u{1b}[32m--force\u{1b}[39m still does not rewrite the whole \u{1b}[32m.gitignore\u{1b}[39m, only rig's\n block in it."; +const ABOUT_PROJ_LOCK: &str = "Resolve project dependencies and write rproj.lock"; +const HELP_PROJ_LOCK: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Resolve the dependencies of an R project to a concrete set of package\n versions, and write the result to \u{1b}[32mrproj.lock\u{1b}[39m.\n\n rig reads the project manifest, \u{1b}[32mrproj.toml\u{1b}[39m, in the current directory, and\n uses its built-in solver to find a compatible set of package versions from\n the configured repositories, without running R.\n\n Development dependencies are included by default. Use \u{1b}[32m--r-version\u{1b}[39m to solve\n for a specific R version, \u{1b}[32m--no-dev\u{1b}[39m to leave out development dependencies,\n and \u{1b}[32m--renv\u{1b}[39m to also write the result as an \u{1b}[32mrenv.lock\u{1b}[39m file.\n\n \u{1b}[32mrproj.lock\u{1b}[39m currently records a single \u{1b}[32m(R version, platform)\u{1b}[39m target;\n \u{1b}[32mrig proj sync\u{1b}[39m installs that target. Solving for several\n targets in one lockfile is planned but not implemented yet.\n\n\u{1b}[1m\u{1b}[34mThe R version:\u{1b}[39m\u{1b}[22m\n Without \u{1b}[32m--r-version\u{1b}[39m rig solves for the default R version, provided the\n manifest's own \u{1b}[32mR\u{1b}[39m requirement allows it. If it does not, rig takes the newest\n installed R version that does, and failing that the current R release. The\n version it picks does not have to be installed: \u{1b}[32mrig proj lock\u{1b}[39m never runs R,\n and \u{1b}[32mrig proj sync\u{1b}[39m installs the R version the lock file\n names.\n\n\u{1b}[1m\u{1b}[34mSource and binary packages:\u{1b}[39m\u{1b}[22m\n The solver considers binary packages as well as source packages, and\n prefers a binary build when one is available for the same version. Which\n artifact each package is installed from is part of what the solve decides,\n because a binary is only usable together with the exact versions of its\n \u{1b}[32mLinkingTo\u{1b}[39m dependencies that it was compiled against. If those versions\n conflict with the rest of the project, rig picks another build of that\n package, or falls back to its source tarball.\n\n By default a binary build never changes \u{1b}[3mwhich version\u{1b}[23m rig picks: the\n newest suitable version wins, and a binary of it is used if there is one.\n Pass \u{1b}[32m--prefer-binary\u{1b}[39m to let an older version win instead, when the newest\n one has no binary but an older one does — typically because a version was\n released so recently that it has not been built yet. Only the three newest\n versions of a package are considered; \u{1b}[32m--prefer-binary=5\u{1b}[39m considers five.\n Versions held back this way are marked in the output.\n\n Trading a version away for a binary is not free: the binary pins its\n \u{1b}[32mLinkingTo\u{1b}[39m dependencies to the versions it was compiled against, and those\n dependencies then prefer their own binaries in turn, so a whole project can\n end up on older versions.\n\n By default rig solves for the machine it runs on. Use \u{1b}[32m--platform\u{1b}[39m to solve\n for a different one, e.g. to write a lockfile on macOS for a Linux\n deployment:\n\n rig proj lock --platform ubuntu-24.04\n\n \u{1b}[32m--platform source\u{1b}[39m solves for source packages only, and does not download\n any binary package metadata. rig also falls back to source packages when\n there are no binaries for a platform at all. There is then nothing for\n \u{1b}[32m--prefer-binary\u{1b}[39m to prefer, and rig ignores it.\n\n rig keeps the repository metadata and the binary package indices it solves\n from in its cache, and refreshes them once a day. \u{1b}[32m--no-cache\u{1b}[39m downloads\n them again instead, and writes nothing to the cache, which is the way to\n solve against a package that was published minutes ago. It is a good deal\n slower, because the metadata it re-downloads is large. See\n \u{1b}[32mrig config\u{1b}[39m.\n\n The \u{1b}[32mrproj.lock\u{1b}[39m file records, for every package, whether it is a source or a\n binary package and the URL it is downloaded from. It also records where the\n file is cached, which is per \u{1b}[3mbuild\u{1b}[23m rather than per version: a repository\n can offer several binaries of one version for one platform and R version,\n and they are cached side by side."; +const ABOUT_PROJ_SYNC: &str = "Install the dependencies rproj.lock resolved"; +const HELP_PROJ_SYNC: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Bring an R project's environment in line with its \u{1b}[32mrproj.lock\u{1b}[39m: install the\n resolved dependencies, and write the rest of the \u{1b}[32m.rvenv\u{1b}[39m layout.\n\n rig looks for the project in the current directory and its parents, reads its\n \u{1b}[32mrproj.lock\u{1b}[39m (written by \u{1b}[32mrig proj lock\u{1b}[39m) and installs the\n packages into the project library, \u{1b}[32m.rvenv/lib\u{1b}[39m. If the project has no\n \u{1b}[32mrproj.lock\u{1b}[39m yet, rig runs \u{1b}[32mrig proj lock\u{1b}[39m with its default\n options first, to create one. That library is created by\n \u{1b}[32mrig proj init\u{1b}[39m, together with the \u{1b}[32m.gitignore\u{1b}[39m files that\n keep it in version control, so \u{1b}[32mrig proj sync\u{1b}[39m fails if it is missing. Pass\n \u{1b}[32m--library\u{1b}[39m to install somewhere else instead.\n\n Development dependencies are installed by default. \u{1b}[32m--no-dev\u{1b}[39m leaves them\n out. \u{1b}[32m--max-concurrent\u{1b}[39m limits the number of simultaneous installations\n (default: 8).\n\n\u{1b}[1m\u{1b}[34mThe R version:\u{1b}[39m\u{1b}[22m\n The lock file records the R version its solve is valid for, and that is the R\n rig installs the packages with -- not whatever \u{1b}[32mR\u{1b}[39m is on the \u{1b}[32mPATH\u{1b}[39m. It has to\n be that very version: another patch release of the same minor version would\n run the packages, but it is not the R the project was solved for, so rig does\n not quietly use it.\n\n If that R version is not installed, rig installs it first, the way\n \u{1b}[32mrig add\u{1b}[39m would; pass \u{1b}[32m--no-install-r\u{1b}[39m to fail instead, e.g. in CI.\n rig never rewrites \u{1b}[32mrproj.lock\u{1b}[39m to an R version that is already installed --\n run \u{1b}[32mrig proj lock\u{1b}[39m to change the R version a project is\n locked for.\n\n\u{1b}[1m\u{1b}[34mWhat sync writes:\u{1b}[39m\u{1b}[22m\n Everything below \u{1b}[32m.rvenv\u{1b}[39m, except the library and the shim package in it, is\n machine-specific, is not committed, and is rewritten on every sync:\n\n - \u{1b}[32m.rvenv/bin/R\u{1b}[39m and \u{1b}[32m.rvenv/bin/Rscript\u{1b}[39m, wrapper scripts that set the\n project's environment and then hand over to the real R. Run them directly,\n or put \u{1b}[32m.rvenv/bin\u{1b}[39m on your \u{1b}[32mPATH\u{1b}[39m. They also pass \u{1b}[32mR CMD ...\u{1b}[39m through.\n - \u{1b}[32m.rvenv/bin/activate\u{1b}[39m and its \u{1b}[32mactivate.csh\u{1b}[39m / \u{1b}[32mactivate.fish\u{1b}[39m /\n \u{1b}[32mactivate.bat\u{1b}[39m / \u{1b}[32mActivate.ps1\u{1b}[39m siblings, for the shells that prefer to be\n activated. Source the one for your shell, and \u{1b}[32mdeactivate\u{1b}[39m when you are\n done. Activation is a convenience, not a requirement: the wrappers work\n without it, and an R session started by an IDE picks the project up through\n the project's \u{1b}[32m.Renviron\u{1b}[39m.\n - \u{1b}[32m.rvenv/rvenv.cfg\u{1b}[39m, which records the R version, the platform and the\n architecture the environment was built for. rig warns when it syncs an\n environment that was built for a different R.\n - \u{1b}[32m.rvenv/etc/repositories\u{1b}[39m, which the wrappers point \u{1b}[32mR_REPOSITORIES\u{1b}[39m at. It\n lists P3M first, at the binary URL of the platform the lock file was solved\n for, so that an \u{1b}[32minstall.packages()\u{1b}[39m in the environment installs the same\n binary packages \u{1b}[32mrig proj sync\u{1b}[39m does. The repositories from \u{1b}[32mrproj.toml\u{1b}[39m\n follow it, at lower precedence. A lock file solved for source packages only\n has no P3M entry, and then the file holds the \u{1b}[32mrproj.toml\u{1b}[39m repositories\n alone (CRAN, if it names none).\n\n \u{1b}[32mR --vanilla\u{1b}[39m ignores the project's \u{1b}[32m.Renviron\u{1b}[39m, so it only stays inside the\n project when started through the wrappers.\n\n After a successful sync rig records the lock file it installed from in\n \u{1b}[32m.rvenv/lib/.synced\u{1b}[39m. The \u{1b}[32mrig\u{1b}[39m package in the project library compares the\n two, and warns in every R session while the project library does not match\n \u{1b}[32mrproj.lock\u{1b}[39m."; const ABOUT_PROJ_TREE: &str = "Dependency tree of a project"; -const HELP_PROJ_TREE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show everything an R project needs, directly or indirectly, as a tree: the\n same closure \u{1b}[32mrig proj deps --recursive\u{1b}[39m lists in a flat\n table, laid out by the shape of the dependency graph.\n\n myproject 0.1.0 — 3 direct, 24 total\n ├── R (>= 4.1) [D]\n ├── cli 3.6.4\n │ ├── R (>= 3.4) [D]\n │ └── utils\n └── dplyr 1.1.4 (>= 1.1.0)\n ├── cli 3.6.4 (>= 3.4.0) (*)\n └── vctrs 0.6.5 (>= 0.6.4)\n └── cpp11 0.5.2 [L]\n [Suggests]\n └── testthat 3.2.3 (>= 3.1.5)\n\n The first line names the project and its version, how many dependencies it\n declares directly and how many distinct packages there are in the whole tree.\n Each line below names a package, the version currently in the repositories,\n and the version requirement it is needed with, if it has one.\n\n By default rig reads the project manifest (e.g. \u{1b}[32mDESCRIPTION\u{1b}[39m) in the current\n directory; use \u{1b}[32m--input\u{1b}[39m to point to a different file. Unlike\n \u{1b}[32mrig proj deps\u{1b}[39m, the tree needs the package metadata of the\n repositories, which rig downloads if it does not have it yet. It does not need\n R. \u{1b}[32m--json\u{1b}[39m gives machine readable output, as one nested object.\n\n\u{1b}[1m\u{1b}[34mReading the tree:\u{1b}[39m\u{1b}[22m\n A package that several others need is expanded only once, under its first\n occurrence; later occurrences are marked \u{1b}[32m(*)\u{1b}[39m, meaning \"its dependencies are\n above\". \u{1b}[32m--dev\u{1b}[39m adds the project's development dependencies, in their own\n \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections; \u{1b}[32m--no-base\u{1b}[39m leaves out R and the base\n packages. Among the hard dependencies, \u{1b}[32mImports\u{1b}[39m is not marked, \u{1b}[32m[D]\u{1b}[39m is a\n \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32m[L]\u{1b}[39m a \u{1b}[32mLinkingTo\u{1b}[39m, \u{1b}[32m[DL]\u{1b}[39m both.\n\n \u{1b}[32m--why \u{1b}[39m (alias \u{1b}[32m--explain\u{1b}[39m) inverts the tree, so that the named\n package is the root and the tree grows towards the packages that need it, down\n to the project itself. Each line then says how \u{1b}[3mthat\u{1b}[23m package needs the one\n above it, hence \u{1b}[32mneeds\u{1b}[39m.\n\n \u{1b}[32mrig pkg tree\u{1b}[39m, which shows the same tree for a package\n in the repositories, describes all of this in full.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in the\n tree, so a version requirement that would force an older version, with\n different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj solve\u{1b}[39m for a resolution that is consistent across\n versions."; +const HELP_PROJ_TREE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Show everything an R project needs, directly or indirectly, as a tree: the\n same closure \u{1b}[32mrig proj deps --recursive\u{1b}[39m lists in a flat\n table, laid out by the shape of the dependency graph.\n\n myproject 0.1.0 — 3 direct, 24 total\n ├── R (>= 4.1) [D]\n ├── cli 3.6.4\n │ ├── R (>= 3.4) [D]\n │ └── utils\n └── dplyr 1.1.4 (>= 1.1.0)\n ├── cli 3.6.4 (>= 3.4.0) (*)\n └── vctrs 0.6.5 (>= 0.6.4)\n └── cpp11 0.5.2 [L]\n [Suggests]\n └── testthat 3.2.3 (>= 3.1.5)\n\n The first line names the project and its version, how many dependencies it\n declares directly and how many distinct packages there are in the whole tree.\n Each line below names a package, the version currently in the repositories,\n and the version requirement it is needed with, if it has one.\n\n rig reads the project manifest, \u{1b}[32mrproj.toml\u{1b}[39m, in the current directory. Unlike\n \u{1b}[32mrig proj deps\u{1b}[39m, the tree needs the package metadata of the\n repositories, which rig downloads if it does not have it yet. It does not need\n R. \u{1b}[32m--json\u{1b}[39m gives machine readable output, as one nested object.\n\n\u{1b}[1m\u{1b}[34mReading the tree:\u{1b}[39m\u{1b}[22m\n A package that several others need is expanded only once, under its first\n occurrence; later occurrences are marked \u{1b}[32m(*)\u{1b}[39m, meaning \"its dependencies are\n above\". \u{1b}[32m--dev\u{1b}[39m adds the project's development dependencies, in their own\n \u{1b}[32m[Suggests]\u{1b}[39m and \u{1b}[32m[Enhances]\u{1b}[39m sections; \u{1b}[32m--no-base\u{1b}[39m leaves out R and the base\n packages. Among the hard dependencies, \u{1b}[32mImports\u{1b}[39m is not marked, \u{1b}[32m[D]\u{1b}[39m is a\n \u{1b}[32mDepends\u{1b}[39m, \u{1b}[32m[L]\u{1b}[39m a \u{1b}[32mLinkingTo\u{1b}[39m, \u{1b}[32m[DL]\u{1b}[39m both.\n\n \u{1b}[32m--why \u{1b}[39m (alias \u{1b}[32m--explain\u{1b}[39m) inverts the tree, so that the named\n package is the root and the tree grows towards the packages that need it, down\n to the project itself. Each line then says how \u{1b}[3mthat\u{1b}[23m package needs the one\n above it, hence \u{1b}[32mneeds\u{1b}[39m.\n\n \u{1b}[32mrig pkg tree\u{1b}[39m, which shows the same tree for a package\n in the repositories, describes all of this in full.\n\n rig follows the dependencies of the \u{1b}[3mlatest\u{1b}[23m version of every package in the\n tree, so a version requirement that would force an older version, with\n different dependencies, is not taken into account. Use\n \u{1b}[32mrig proj lock\u{1b}[39m for a resolution that is consistent across\n versions."; const ABOUT_PROJ: &str = "Manage R projects (experimental)"; -const HELP_PROJ: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Manage R projects (experimental).\n\n A project is a directory with a package manifest, typically a\n \u{1b}[32mDESCRIPTION\u{1b}[39m file, that declares the R packages the project depends on.\n \u{1b}[32mrig proj\u{1b}[39m resolves those dependencies against the configured package\n repositories and can install them into a project library.\n\n \u{1b}[32mrig proj deps\u{1b}[39m shows the direct and recursive dependencies of the\n project.\n \u{1b}[32mrig proj tree\u{1b}[39m shows the recursive dependencies as a tree, so you can\n see how each package is pulled in.\n \u{1b}[32mrig proj solve\u{1b}[39m resolves the full dependency tree to a concrete set of\n package versions, and can write the result to an \u{1b}[32mrenv.lock\u{1b}[39m file.\n \u{1b}[32mrig proj deploy\u{1b}[39m installs the resolved dependencies into a package\n library.\n\n Dependencies are resolved with rig's built-in solver, so R does not need\n to be running for \u{1b}[32mrig proj deps\u{1b}[39m, \u{1b}[32mrig proj tree\u{1b}[39m and \u{1b}[32mrig proj solve\u{1b}[39m.\n\n \u{1b}[32mrig proj\u{1b}[39m is currently experimental, and might change in future\n versions. Feedback is appreciated."; +const HELP_PROJ: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Manage R projects (experimental).\n\n A project is a directory with a package manifest, typically a\n \u{1b}[32mDESCRIPTION\u{1b}[39m file, that declares the R packages the project depends on.\n \u{1b}[32mrig proj\u{1b}[39m resolves those dependencies against the configured package\n repositories and can install them into a project library.\n\n \u{1b}[32mrig proj import\u{1b}[39m reads a \u{1b}[32mDESCRIPTION\u{1b}[39m file and merges its dependencies\n into \u{1b}[32mrproj.toml\u{1b}[39m, creating it first if needed.\n \u{1b}[32mrig proj deps\u{1b}[39m shows the direct and recursive dependencies of the\n project.\n \u{1b}[32mrig proj tree\u{1b}[39m shows the recursive dependencies as a tree, so you can\n see how each package is pulled in.\n \u{1b}[32mrig proj lock\u{1b}[39m resolves the full dependency tree to a concrete set of\n package versions, writes the result to \u{1b}[32mrproj.lock\u{1b}[39m, and can also write\n an \u{1b}[32mrenv.lock\u{1b}[39m file.\n \u{1b}[32mrig proj sync\u{1b}[39m installs the dependencies \u{1b}[32mrproj.lock\u{1b}[39m resolved into a\n package library.\n\n Dependencies are resolved with rig's built-in solver, so R does not need\n to be running for \u{1b}[32mrig proj deps\u{1b}[39m, \u{1b}[32mrig proj tree\u{1b}[39m and \u{1b}[32mrig proj lock\u{1b}[39m.\n\n \u{1b}[32mrig proj\u{1b}[39m is currently experimental, and might change in future\n versions. Feedback is appreciated."; const ABOUT_REPOS_AVAILABLE: &str = "List available R package repositories"; const HELP_REPOS_AVAILABLE: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n List the package repositories that rig knows about and can set up.\n\n These are the repositories you can enable with \u{1b}[32m--with-repos\u{1b}[39m when running\n \u{1b}[32mrig add\u{1b}[39m or \u{1b}[32mrig repos setup\u{1b}[39m.\n\n Without arguments rig prints one row per repository: its name, whether it is\n part of the default repository set, and its title.\n\n Pass a repository name to see its description and its URLs, together with the\n platforms, architectures and R versions each URL applies to. Repository names\n are matched case insensitively.\n\n\u{1b}[1m\u{1b}[34mExamples:\u{1b}[39m\u{1b}[22m\n # List all repositories rig knows about\n rig repos available\n\n # Show the URLs of one repository\n rig repos available P3M"; const ABOUT_REPOS_LIST: &str = "List configured R package repositories"; @@ -97,7 +101,7 @@ const HELP_RTOOLS_RM: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22 const ABOUT_RTOOLS: &str = "Manage Rtools installations"; const HELP_RTOOLS: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Manage Rtools installations (Windows only).\n\n Rtools is the collection of build tools (compilers, \u{1b}[32mmake\u{1b}[39m, etc.) needed\n to build R packages from source on Windows. Each R version needs a\n matching Rtools version.\n\n \u{1b}[32mrig rtools list\u{1b}[39m lists the installed Rtools versions.\n \u{1b}[32mrig rtools add\u{1b}[39m installs Rtools, by default every version needed by the\n currently installed R versions.\n \u{1b}[32mrig rtools rm\u{1b}[39m removes Rtools versions.\n\n On non-Windows platforms this command does nothing and is hidden."; const ABOUT_RUN: &str = "Run R, an R script or an R project"; -const HELP_RUN: &str = "\u{1b}[1m\u{1b}[34mDescription:\u{1b}[39m\u{1b}[22m\n Run R, an R script or an R project, using the selected R version.\n\n All of these examples allow an \u{1b}[32m--r-version\u{1b}[39m argument, to use a specific\n R version.\n\n rig run # start R\n rig run -f # run an R script\n rig run -e # evaluate an R expression\n rig run ::