#!/bin/sh # Install R packages into the CI library with uvr (https://github.com/nbafrank/uvr). # # Usage: # local/uvr-install.sh httr2 jsonlite # local/uvr-install.sh forgejo::codefloe.com/rpkgs/bincraft@v4.4.3 # # Replaces `pak::pak(...)`. uvr is project-scoped: `uvr add` refuses to run # outside a project and always writes to `.uvr/library/`, and only # `uvr sync --library` can target an existing library. The project is therefore # minted in a scratch directory under TMPDIR and thrown away afterwards; that # also keeps `uvr init`'s `.Rprofile` out of the repo checkout, where it would # hijack `.libPaths()` for every other R call in the pipeline. # # Pruning is a no-op here: uvr disables it whenever `--library` is passed, # precisely because such a target may be shared (`/mnt/cache/R-pkgs` holds # bincraft and its dependencies alongside whatever this script installs). # # System dependencies come from uvr's vendored r-system-requirements rules, so # `pak::sysreqs_db_update()` and `PKG_SYSREQS_PLATFORM` are no longer needed. # # Environment: # UVR_R_BIN R interpreter to install for; set by install-bincraft.R so # the per-R-minor passes target their own R, not the primary # R_VERSION fallback interpreter selector (/opt/R//bin/R) # UVR_TARGET_LIB target library; defaults to R_LIBS_USER, then to the # active R's .libPaths()[1] (which is where pak wrote) # UVR_INSTALL_DIR where the uvr binary lands (default /usr/local/bin) set -eu # renovate: datasource=github-releases depName=nbafrank/uvr UVR_PIN="v0.4.4" if [ "$#" -eq 0 ]; then echo "usage: $0 ..." >&2 exit 2 fi # The build images keep R under /opt/R/ and off PATH. uvr resolves the # interpreter via PATH and never downloads one unless `uvr r install` is run, so # put the requested R first. r_bin="${UVR_R_BIN:-}" if [ -z "$r_bin" ] && [ -n "${R_VERSION:-}" ] && [ -x "/opt/R/${R_VERSION}/bin/R" ]; then r_bin="/opt/R/${R_VERSION}/bin/R" fi if [ -n "$r_bin" ]; then PATH="$(dirname "$r_bin"):$PATH" export PATH else r_bin="$(command -v R)" fi target_lib="${UVR_TARGET_LIB:-${R_LIBS_USER:-}}" if [ -z "$target_lib" ]; then target_lib="$("$r_bin" --no-echo --no-save -e 'cat(.libPaths()[1])')" fi if [ -z "$target_lib" ]; then echo "error: could not determine a target library; set UVR_TARGET_LIB" >&2 exit 2 fi mkdir -p "$target_lib" # Pin the manifest to the active R so the lockfile's R stays in step with the # library's R sentinel. Without that, uvr can decide the library is ABI-stale # and wipe it -- and this target is shared with bincraft. uvr only discovers R # via PATH/R_HOME (it does not scan /opt/R), so the R put on PATH above is the # only candidate this constraint can resolve to. # shellcheck disable=SC2016 # $major/$minor are R expressions, not shell vars r_full="$("$r_bin" --no-echo --no-save -e 'cat(paste(R.version$major, R.version$minor, sep = "."))')" install_dir="${UVR_INSTALL_DIR:-/usr/local/bin}" uvr_bin="${install_dir}/uvr" if [ ! -x "$uvr_bin" ]; then echo "Bootstrapping uvr ${UVR_PIN} into ${install_dir}" UVR_INSTALL_DIR="$install_dir" UVR_VERSION="$UVR_PIN" \ sh -c 'curl -fsSL https://raw.githubusercontent.com/nbafrank/uvr/main/install.sh | sh' fi project_dir="${TMPDIR:-/tmp}/uvr-ci-$$" rm -rf "$project_dir" mkdir -p "$project_dir" trap 'rm -rf "$project_dir"' EXIT cd "$project_dir" "$uvr_bin" init --here --r-version "$r_full" # --no-install: resolve and lock only. The install happens in the sync below, # which is the only command that honours --library. "$uvr_bin" add --no-install "$@" "$uvr_bin" sync --library "$target_lib" --install-system-deps