├── .Rbuildignore ├── .github ├── FUNDING.yml └── workflows │ ├── build.yml │ └── docker.yml ├── .gitignore ├── DESCRIPTION ├── LICENSE ├── NAMESPACE ├── NEWS.md ├── R ├── integration.R ├── manager.R ├── os.R ├── renv.R ├── rspm.R ├── userdir.R ├── utils.R ├── zzz_centos_base.R ├── zzz_centos_like.R ├── zzz_debian_base.R ├── zzz_debian_like.R ├── zzz_opensuse_base.R ├── zzz_opensuse_like.R └── zzz_rpm.R ├── README.md ├── _pkgdown.yml ├── cran-comments.md ├── docker ├── stream8 │ └── Dockerfile └── stream9 │ └── Dockerfile ├── docs ├── 404.html ├── LICENSE-text.html ├── assets │ ├── rspm_sf.gif │ └── rspm_units.gif ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── deps │ ├── bootstrap-5.2.2 │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ └── bootstrap.min.css │ ├── bootstrap-5.3.1 │ │ ├── bootstrap.bundle.min.js │ │ ├── bootstrap.bundle.min.js.map │ │ └── bootstrap.min.css │ ├── bootstrap-toc-1.0.1 │ │ └── bootstrap-toc.min.js │ ├── clipboard.js-2.0.11 │ │ └── clipboard.min.js │ ├── data-deps.txt │ ├── font-awesome-6.4.2 │ │ ├── css │ │ │ ├── all.css │ │ │ ├── all.min.css │ │ │ ├── v4-shims.css │ │ │ └── v4-shims.min.css │ │ └── webfonts │ │ │ ├── fa-brands-400.ttf │ │ │ ├── fa-brands-400.woff2 │ │ │ ├── fa-regular-400.ttf │ │ │ ├── fa-regular-400.woff2 │ │ │ ├── fa-solid-900.ttf │ │ │ ├── fa-solid-900.woff2 │ │ │ ├── fa-v4compatibility.ttf │ │ │ └── fa-v4compatibility.woff2 │ ├── headroom-0.11.0 │ │ ├── headroom.min.js │ │ └── jQuery.headroom.min.js │ ├── jquery-3.6.0 │ │ ├── jquery-3.6.0.js │ │ ├── jquery-3.6.0.min.js │ │ └── jquery-3.6.0.min.map │ └── search-1.0.0 │ │ ├── autocomplete.jquery.min.js │ │ ├── fuse.min.js │ │ └── mark.min.js ├── docsearch.css ├── docsearch.js ├── index.html ├── katex-auto.js ├── lightswitch.js ├── link.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Rplot001.png │ ├── index.html │ ├── integration.html │ ├── manager.html │ ├── renv_init.html │ └── rspm-package.html ├── search.json └── sitemap.xml ├── inst ├── COPYRIGHTS ├── resources │ └── activate.R └── tinytest │ ├── test_integration_ci.R │ ├── test_manager_ci.R │ └── test_renv.R ├── man ├── integration.Rd ├── manager.Rd ├── renv_init.Rd └── rspm-package.Rd ├── rspm.Rproj └── tests └── tinytest.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | ^\.github$ 4 | ^docs$ 5 | ^docker$ 6 | ^_pkgdown.yml$ 7 | ^cran-comments\.md$ 8 | ^CRAN-RELEASE$ 9 | ^debian 10 | ^CRAN-SUBMISSION$ 11 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: Enchufa2 4 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | on: [push, pull_request] 3 | 4 | jobs: 5 | build: 6 | if: ${{ !contains(github.event.head_commit.message, '[ci skip]') }} 7 | runs-on: ubuntu-latest 8 | name: ${{ matrix.image }}:${{ matrix.tag }} 9 | container: 10 | image: ${{ matrix.repo }}${{ matrix.image }}:${{ matrix.tag }} 11 | 12 | strategy: 13 | fail-fast: false 14 | matrix: 15 | include: 16 | - {image: 'centos', tag: 'stream8', repo: 'ghcr.io/cran4linux/r-'} 17 | - {image: 'centos', tag: 'stream9', repo: 'ghcr.io/cran4linux/r-'} 18 | - {image: 'ubuntu', tag: '20.04', repo: 'rocker/r-'} 19 | - {image: 'ubuntu', tag: '22.04', repo: 'rocker/r-'} 20 | #- {image: 'base', tag: 'latest', repo: 'rocker/r-'} # units not available 21 | #- {image: 'leap', tag: '15.4', repo: 'opensuse/'} 22 | #- {image: 'leap', tag: '15.5', repo: 'opensuse/'} 23 | 24 | steps: 25 | - name: Install dependencies (Ubuntu) 26 | if: ${{ matrix.image == 'ubuntu' || matrix.image == 'base' }} 27 | run: | 28 | apt update && apt install -y apt-file 29 | 30 | - name: Install dependencies (openSUSE) 31 | if: ${{ matrix.image == 'leap' }} 32 | run: | 33 | zypper addrepo https://download.opensuse.org/repositories/Education/${{ matrix.tag }}/Education.repo 34 | zypper --no-gpg-checks install -y tar R-base # no binaries available :( 35 | 36 | - uses: actions/checkout@v3 37 | 38 | - name: Check 39 | env: 40 | _R_CHECK_CRAN_INCOMING_REMOTE_: false 41 | run: | 42 | export LANG=$(locale -a | grep utf8 | head -n1) 43 | Rscript -e 'install.packages(c("renv", "tinytest"), repos="https://cran.r-project.org")' 44 | R CMD build . && mkdir check 45 | useradd -m rspm && chown rspm:rspm check 46 | su rspm -c "R CMD check rspm_*.tar.gz --no-manual -o check" 47 | 48 | - name: Upload check results 49 | if: ${{ failure() }} 50 | uses: actions/upload-artifact@master 51 | with: 52 | name: r-${{ matrix.image }}-${{ matrix.tag }}-results 53 | path: check 54 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker images 2 | 3 | on: 4 | workflow_dispatch: 5 | schedule: 6 | - cron: '0 5 * * 2' 7 | 8 | jobs: 9 | docker: 10 | runs-on: ubuntu-latest 11 | name: ${{ matrix.tag }} 12 | permissions: 13 | packages: write 14 | contents: read 15 | 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | tag: [stream8, stream9] 20 | 21 | env: 22 | REGISTRY: ghcr.io 23 | IMAGE: cran4linux/r-centos 24 | 25 | steps: 26 | - name: Checkout 27 | uses: actions/checkout@v3 28 | 29 | - name: Set up Docker Buildx 30 | uses: docker/setup-buildx-action@v2 31 | 32 | - name: Cache Docker layers 33 | uses: actions/cache@v3 34 | with: 35 | path: /tmp/.buildx-cache 36 | key: ${{ runner.os }}-buildx-${{ matrix.tag }}-${{ github.sha }} 37 | restore-keys: | 38 | ${{ runner.os }}-buildx-${{ matrix.tag }}- 39 | 40 | - name: Login to registry 41 | uses: docker/login-action@v2 42 | with: 43 | registry: ${{ env.REGISTRY }} 44 | username: ${{ github.actor }} 45 | password: ${{ secrets.GITHUB_TOKEN }} 46 | 47 | - name: Build and push 48 | uses: docker/build-push-action@v4 49 | with: 50 | context: docker/${{ matrix.tag }} 51 | pull: true 52 | push: true 53 | tags: ${{ env.REGISTRY }}/${{ env.IMAGE }}:${{ matrix.tag }} 54 | cache-from: type=local,src=/tmp/.buildx-cache 55 | cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max 56 | 57 | - name: Move cache 58 | run: | 59 | rm -rf /tmp/.buildx-cache 60 | mv /tmp/.buildx-cache-new /tmp/.buildx-cache 61 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: rspm 2 | Type: Package 3 | Title: 'RStudio' Package Manager 4 | Version: 0.6.1 5 | Authors@R: c( 6 | person("Iñaki", "Ucar", email="iucar@fedoraproject.org", 7 | role=c("aut", "cph", "cre"), comment=c(ORCID="0000-0001-6403-5550")), 8 | person("R Core Team", role=c("aut", "cph"))) 9 | Description: Enables binary package installations on Linux distributions. 10 | Provides access to 'RStudio' public repositories at 11 | , and transparent management of 12 | system requirements without administrative privileges. Currently supported 13 | distributions are 'CentOS' / 'RHEL' 7-9, and several 'RHEL' derivatives 14 | ('Rocky Linux', 'AlmaLinux', 'Oracle Linux', and 'Amazon Linux'), 15 | 'openSUSE' / 'SLES' 15.4-5, 'Debian' 11-12, and 'Ubuntu' LTS 20-22. 16 | License: GPL-2 | GPL-3 | MIT + file LICENSE 17 | Copyright: file COPYRIGHTS 18 | Encoding: UTF-8 19 | OS_type: unix 20 | Suggests: renv, tinytest 21 | URL: https://cran4linux.github.io/rspm/ 22 | BugReports: https://github.com/cran4linux/rspm/issues 23 | RoxygenNote: 7.3.1 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2022-2023 2 | COPYRIGHT HOLDER: Iñaki Ucar 3 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(disable) 4 | export(enable) 5 | export(install_sysreqs) 6 | export(missing_sysreqs) 7 | export(renv_init) 8 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # rspm 0.6.1 2 | 3 | - Fix regexp escaping in `apt-file` calls for Debian-like systems (#32). 4 | 5 | # rspm 0.6.0 6 | 7 | - Add support for Pop!_OS (#26 addressing #25). 8 | - Add support for Amazon Linux 2023 (#28 addressing #27). 9 | 10 | # rspm 0.5.3 11 | 12 | - Drop test on failure to avoid test failures on CRAN. 13 | 14 | # rspm 0.5.2 15 | 16 | - Don't use `expect_match` for now to avoid test failures on CRAN. 17 | 18 | # rspm 0.5.1 19 | 20 | - Export `missing_sysreqs()` for debugging purposes. 21 | - Fix call to tinytest function from namespace. 22 | - Update supported systems. 23 | 24 | # rspm 0.5.0 25 | 26 | - Move to cran4linux org on GitHub, update URLs. 27 | - Add support for Debian 11 and 12 (#21). 28 | 29 | # rspm 0.4.0 30 | 31 | - Implement root mode to improve Docker workflows (#20 addressing #17). 32 | - Internal refactoring to improve extensibility (as part of #20). 33 | - Remove libs' arch subfolder in Ubuntu to fix relative path issues (#19). 34 | 35 | # rspm 0.3.1 36 | 37 | - Fix version detection in CentOS (#18 addressing #16). 38 | - Fix unpacking for new rpm versions (as part of #18). 39 | 40 | # rspm 0.3.0 41 | 42 | - Add support for CentOS/RHEL 9 and derivatives (#13 addressing #12). 43 | 44 | # rspm 0.2.3 45 | 46 | - Fix non-root unpacking for old rpm/dpkg versions (#11 addressing #9, #10). 47 | 48 | # rspm 0.2.2 49 | 50 | - Fix root permission requirement for yum-based systems (#9). 51 | - Clean up empty user directory. 52 | 53 | # rspm 0.2.1 54 | 55 | - Fix .Rprofile enabling error (#8). 56 | - Some fixes requested by CRAN. 57 | 58 | # rspm 0.2.0 59 | 60 | - Add support for CentOS 7, RHEL 7 and 8 (#1). 61 | - Add support for several RHEL derivatives: Rocky Linux 8, AlmaLinux 8, 62 | Oracle Linux 7 and 8, Amazon Linux 2 (#2). 63 | - Add support for openSUSE / SLES 15.3 (#3). 64 | - Add support for `renv` projects via `rspm::renv_init()` (#5 closing #4). 65 | 66 | # rspm 0.1.0 67 | 68 | - Initial release, with support for CentOS 8 and Ubuntu 18.04, 20.04 and 22.04. 69 | -------------------------------------------------------------------------------- /R/integration.R: -------------------------------------------------------------------------------- 1 | #' Enable/Disable RStudio Package Manager 2 | #' 3 | #' Functions to enable or disable RSPM repos as well as the integration of 4 | #' \code{\link{install_sysreqs}} into \code{install.packages} and 5 | #' \code{update.packages}. When enabled, binary packages are installed from 6 | #' RSPM if available, and system requirements are transparently resolved and 7 | #' installed without root privileges. 8 | #' 9 | #' @return No return value, called for side effects. 10 | #' 11 | #' @details To enable \pkg{rspm} permanently, include the following into your 12 | #' \code{.Rprofile}: 13 | #' 14 | #' \code{suppressMessages(rspm::enable())} 15 | #' 16 | #' @seealso \code{\link{renv_init}} for \pkg{renv} projects. 17 | #' 18 | #' @examples 19 | #' \dontrun{ 20 | #' # install 'units' and all its dependencies from the system repos 21 | #' rspm::enable() 22 | #' install.packages("units") 23 | #' 24 | #' # install packages again from CRAN 25 | #' rspm::disable() 26 | #' install.packages("errors") 27 | #' } 28 | #' 29 | #' @name integration 30 | #' @export 31 | enable <- function() { 32 | check_requirements() 33 | enable_repo() 34 | expr <- quote(rspm::install_sysreqs()) 35 | opt$utils <- !exists("install.packages") 36 | if (opt$utils) { 37 | trace(utils::install.packages, exit=expr, print=FALSE) 38 | trace(utils::update.packages, exit=expr, print=FALSE) 39 | } else { 40 | trace(install.packages, exit=expr, print=FALSE) 41 | trace(update.packages, exit=expr, print=FALSE) 42 | } 43 | invisible() 44 | } 45 | 46 | #' @name integration 47 | #' @export 48 | disable <- function() { 49 | disable_repo() 50 | if (isTRUE(opt$utils)) { 51 | untrace(utils::install.packages) 52 | untrace(utils::update.packages) 53 | } else { 54 | untrace(install.packages) 55 | untrace(update.packages) 56 | } 57 | invisible() 58 | } 59 | 60 | globalVariables(c("install.packages", "update.packages")) 61 | url <- "https://packagemanager.posit.co/all/__linux__/%s/latest" 62 | opt <- new.env(parent=emptyenv()) 63 | 64 | enable_repo <- function() { 65 | if (is.null(opt$repos)) 66 | opt$repos <- getOption("repos") 67 | options(repos = c(RSPM = sprintf(url, os()$code))) 68 | } 69 | 70 | disable_repo <- function() { 71 | if (!is.null(opt$repos)) 72 | options(repos = opt$repos) 73 | opt$repos <- NULL 74 | } 75 | 76 | .onLoad <- function(libname, pkgname) { 77 | options(HTTPUserAgent = sprintf("R/%s R (%s)", getRversion(), paste( 78 | getRversion(), R.version["platform"], R.version["arch"], R.version["os"]))) 79 | 80 | user_dir_init() 81 | } 82 | -------------------------------------------------------------------------------- /R/manager.R: -------------------------------------------------------------------------------- 1 | #' Manage System Requirements 2 | #' 3 | #' Detect, install and configure system requirements. This function is 4 | #' automatically called when the package is enabled via \code{\link{enable}}. 5 | #' It can also be called manually at any time to update the system requirements. 6 | #' 7 | #' @return \code{install_sysreqs}: No return value, called for side effects. 8 | #' 9 | #' @examples 10 | #' \dontrun{ 11 | #' # install 'units' without enabling the integration 12 | #' install.packages("units") 13 | #' # then trigger the installation of system requirements manually 14 | #' rspm::install_sysreqs() 15 | #' } 16 | #' 17 | #' @name manager 18 | #' @export 19 | install_sysreqs <- function() { 20 | message("Inspecting installed packages...") 21 | 22 | # get missing libraries 23 | if (!length(libs <- missing_sysreqs())) 24 | return(invisible()) 25 | 26 | # install unique sysreqs 27 | message("Downloading and installing sysreqs...") 28 | os_install_sysreqs(unique(unlist(libs))) 29 | 30 | # if this failed, try one by one 31 | if (length(libs) == length(missing_sysreqs())) { 32 | message("Installation failed! Trying package by package...") 33 | for (i in seq_along(libs)) { 34 | pkg <- strsplit(basename(names(libs)[i]), ".", fixed=TRUE)[[1]][1] 35 | message("Downloading and installing sysreqs for ", pkg, "...") 36 | os_install_sysreqs(libs[[i]]) 37 | } 38 | } 39 | 40 | # update rpath 41 | if (!root()) set_rpath() 42 | } 43 | 44 | #' @return \code{missing_sysreqs}: A list of missing libraries, for debugging. 45 | #' @name manager 46 | #' @export 47 | missing_sysreqs <- function() { 48 | libs <- ldd() 49 | lib.loc <- attr(libs, "lib.loc") 50 | 51 | libs <- lapply(libs, function(x) grep("not found$", x, value=TRUE)) 52 | libs <- lapply(libs, function(x) sapply(strsplit(x, " => "), "[", 1)) 53 | 54 | libs <- Filter(length, libs) 55 | attr(libs, "lib.loc") <- lib.loc 56 | libs 57 | } 58 | 59 | ldd <- function(lib.loc = NULL) { 60 | lib.loc <- user_lib(lib.loc) 61 | ldd <- check_requirements("ldd") 62 | 63 | libs <- list.files(lib.loc, "\\.so$", full.names=TRUE, recursive=TRUE) 64 | libs <- system_(ldd, p(libs), "2>&1") 65 | libs <- split(libs, findInterval(seq_along(libs), grep(":$", libs))) 66 | names(libs) <- gsub(paste0(lib.loc, "/|:"), "", sapply(libs, "[", 1)) 67 | libs <- lapply(lapply(libs, "[", -1), trimws) 68 | 69 | attr(libs, "lib.loc") <- lib.loc 70 | libs 71 | } 72 | 73 | set_rpath <- function(lib.loc = NULL) { 74 | lib.loc <- user_lib(lib.loc) 75 | patchelf <- check_requirements("patchelf") 76 | message("Configuring sysreqs...") 77 | 78 | slibs <- list.files(user_dir("usr"), "\\.so", full.names=TRUE, recursive=TRUE) 79 | slibs <- slibs[!is.na(file.info(slibs)$size)] 80 | rlibs <- list.files(lib.loc, "\\.so$", full.names=TRUE, recursive=TRUE) 81 | alibs <- c(rlibs, slibs) 82 | alibs <- alibs[!alibs %in% sapply(getLoadedDLLs(), "[[", "path")] 83 | rpath <- paste(unique(dirname(slibs)), collapse=":") 84 | 85 | for (lib in alibs) 86 | system_(patchelf, "--set-rpath", rpath, lib, "2>&1") 87 | 88 | invisible() 89 | } 90 | -------------------------------------------------------------------------------- /R/os.R: -------------------------------------------------------------------------------- 1 | os_requirements <- function() { 2 | get(paste0(os()$id, "_requirements"))() 3 | } 4 | 5 | os_install <- function(pkgs) { 6 | get(paste0(os()$id, "_install"))(pkgs) 7 | } 8 | 9 | os_install_sysreqs <- function(libs) { 10 | get(paste0(os()$id, "_install_sysreqs"))(libs) 11 | } 12 | 13 | os <- function() { 14 | if (!file.exists("/etc/os-release")) 15 | stop("OS not supported", call.=FALSE) 16 | os <- utils::read.table("/etc/os-release", sep="=", col.names=c("var", "val"), 17 | stringsAsFactors=FALSE) 18 | os <- stats::setNames(as.list(os$val), os$var) 19 | code <- switch( 20 | id <- strsplit(os$ID, "-")[[1]][1], 21 | "debian" = , "ubuntu" = , "pop" = os$VERSION_CODENAME, 22 | "centos" = , "rocky" = , "almalinux" = , "ol" = , "rhel" = 23 | paste0(if ((ver <- safe_version(os$VERSION_ID)$major) < 9) 24 | "centos" else "rhel", ver), 25 | "amzn" = switch( 26 | os$VERSION_ID, 27 | "2" = "centos7", 28 | "2023" = "rhel9", 29 | stop("OS not supported", call.=FALSE)), 30 | "sles" = , "opensuse" = 31 | paste0("opensuse", sub("\\.", "", os$VERSION_ID)), 32 | stop("OS not supported", call.=FALSE) 33 | ) 34 | list(id = id, code = code) 35 | } 36 | -------------------------------------------------------------------------------- /R/renv.R: -------------------------------------------------------------------------------- 1 | #' Initialize an \pkg{renv} Project 2 | #' 3 | #' Substitutes \code{renv::init()} to initialize a new \pkg{renv} project with 4 | #' \pkg{rspm} enabled. This function sets the appropriate infrastructure to 5 | #' activate the integration. Then, packages can be installed normally via 6 | #' \code{install.packages} and \code{update.packages}. 7 | #' 8 | #' @param ... Arguments to be passed to \code{renv::init()}. 9 | #' 10 | #' @return The project directory, invisibly. This function is called for its 11 | #' side effects. 12 | #' 13 | #' @details Note that, if \code{renv::install} or \code{renv::update} are called 14 | #' directly, then \code{rspm::install_sysreqs()} needs to be called manually. 15 | #' 16 | #' @examples 17 | #' \dontrun{ 18 | #' # initialize a new project (with an empty R library) 19 | #' rspm::renv_init() 20 | #' 21 | #' # install 'units' and all its dependencies from the system repos 22 | #' install.packages("units") 23 | #' 24 | #' # install a specific version and install dependencies manually 25 | #' renv::install("units@0.8-0") 26 | #' rspm::install_sysreqs() 27 | #' } 28 | #' 29 | #' @export 30 | renv_init <- function(...) { 31 | if (!requireNamespace("renv", quietly=TRUE)) 32 | stop("please install 'renv' for this functionality", call.=FALSE) 33 | 34 | project <- renv::init(...) 35 | renv_install() 36 | renv_append(project) 37 | 38 | invisible(project) 39 | } 40 | 41 | renv_install <- function() { 42 | libpath <- renv::paths$library() 43 | if (!dir.exists(file.path(libpath, "rspm"))) 44 | file.copy(system.file(package="rspm"), libpath, recursive=TRUE) 45 | } 46 | 47 | renv_append <- function(project = ".") { 48 | target <- file.path(project, "renv/activate.R") 49 | if (any(grepl("rspm::enable()", readLines(target)))) 50 | return() 51 | source <- readLines(system.file("resources/activate.R", package="rspm")) 52 | source <- gsub("VERSION", utils::packageVersion("rspm"), source) 53 | cat("", source, "", file=target, sep="\n", append=TRUE) 54 | } 55 | -------------------------------------------------------------------------------- /R/rspm.R: -------------------------------------------------------------------------------- 1 | #' \pkg{rspm}: RStudio Package Manager 2 | #' 3 | #' Enables binary package installations on Linux distributions. 4 | #' Provides access to RStudio public repositories at 5 | #' \url{https://packagemanager.posit.co}, and transparent management of 6 | #' system requirements without administrative privileges. Currently supported 7 | #' distributions are CentOS / RHEL 7-9, and several RHEL derivatives 8 | #' (Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux), 9 | #' openSUSE / SLES 15.4-5, Debian 11-12, and Ubuntu LTS 20-22. 10 | #' 11 | #' @author Iñaki Ucar 12 | #' 13 | #' @references \url{https://cran4linux.github.io/rspm/} 14 | #' 15 | #' @name rspm-package 16 | #' 17 | #' @seealso \code{\link{manager}}, \code{\link{integration}} 18 | "_PACKAGE" 19 | -------------------------------------------------------------------------------- /R/userdir.R: -------------------------------------------------------------------------------- 1 | # File src/library/tools/R/userdir.R 2 | # Part of the R package, https://www.R-project.org 3 | # 4 | # Copyright (C) 2020 The R Core Team 5 | # 6 | # This program is free software; you can redistribute it and/or modify 7 | # it under the terms of the GNU General Public License as published by 8 | # the Free Software Foundation; either version 2 of the License, or 9 | # (at your option) any later version. 10 | # 11 | # This program is distributed in the hope that it will be useful, 12 | # but WITHOUT ANY WARRANTY; without even the implied warranty of 13 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 | # GNU General Public License for more details. 15 | # 16 | # A copy of the GNU General Public License is available at 17 | # https://www.R-project.org/Licenses/ 18 | 19 | R_user_dir <- 20 | function(package, which = c("data", "config", "cache")) 21 | { 22 | stopifnot(is.character(package), length(package) == 1L) 23 | 24 | which <- match.arg(which) 25 | 26 | home <- normalizePath("~") 27 | 28 | path <- 29 | switch(which, 30 | data = { 31 | if(nzchar(p <- Sys.getenv("R_USER_DATA_DIR"))) 32 | p 33 | else if(nzchar(p <- Sys.getenv("XDG_DATA_HOME"))) 34 | p 35 | else if(.Platform$OS.type == "windows") 36 | file.path(Sys.getenv("APPDATA"), "R", "data") 37 | else if(Sys.info()["sysname"] == "Darwin") 38 | file.path(home, "Library", "Application Support", 39 | "org.R-project.R") 40 | else 41 | file.path(home, ".local", "share") 42 | }, 43 | config = { 44 | if(nzchar(p <- Sys.getenv("R_USER_CONFIG_DIR"))) 45 | p 46 | else if(nzchar(p <- Sys.getenv("XDG_CONFIG_HOME"))) 47 | p 48 | else if(.Platform$OS.type == "windows") 49 | file.path(Sys.getenv("APPDATA"), "R", "config") 50 | else if(Sys.info()["sysname"] == "Darwin") 51 | file.path(home, "Library", "Preferences", 52 | "org.R-project.R") 53 | else 54 | file.path(home, ".config") 55 | }, 56 | cache = { 57 | if(nzchar(p <- Sys.getenv("R_USER_CACHE_DIR"))) 58 | p 59 | else if(nzchar(p <- Sys.getenv("XDG_CACHE_HOME"))) 60 | p 61 | else if(.Platform$OS.type == "windows") 62 | file.path(Sys.getenv("LOCALAPPDATA"), "R", "cache") 63 | else if(Sys.info()["sysname"] == "Darwin") 64 | file.path(home, "Library", "Caches", 65 | "org.R-project.R") 66 | else 67 | file.path(home, ".cache") 68 | }) 69 | 70 | file.path(path, "R", package) 71 | } 72 | -------------------------------------------------------------------------------- /R/utils.R: -------------------------------------------------------------------------------- 1 | p <- function(...) paste(..., collapse=" ") 2 | system <- function(...) base::system(p(...), intern=FALSE) 3 | system_ <- function(...) suppressWarnings(base::system(p(...), intern=TRUE)) 4 | safe_version <- function(x) package_version(paste0(x, "-1")) 5 | root <- function() Sys.info()["effective_user"] == "root" 6 | 7 | user_dir_base <- NULL 8 | 9 | user_dir <- function(path) { 10 | user_dir <- user_dir_base 11 | if (is.null(user_dir)) { 12 | tenv <- asNamespace("tools") 13 | if (exists("R_user_dir", tenv)) 14 | R_user_dir <- get("R_user_dir", tenv) 15 | user_dir <- R_user_dir("rspm") 16 | } 17 | if (!missing(path)) 18 | user_dir <- file.path(user_dir, path) 19 | user_dir 20 | } 21 | 22 | user_dir_init <- function() { 23 | if (!is.null(user_dir_base)) return() 24 | 25 | if (is.na(path <- Sys.getenv("RSPM_USER_DIR", unset=NA))) 26 | path <- user_dir() 27 | user_dir_base <<- path 28 | dir.create(user_dir(), showWarnings=FALSE, recursive=TRUE, mode="0755") 29 | 30 | reg.finalizer(opt, onexit=TRUE, function(opt) { 31 | path <- user_dir_base 32 | while (length(setdiff(dir(path, all.files=TRUE), c(".", ".."))) == 0) { 33 | unlink(path, recursive=TRUE, force=TRUE) 34 | path <- dirname(path) 35 | } 36 | }) 37 | } 38 | 39 | user_lib <- function(lib.loc = NULL) { 40 | if (is.null(lib.loc)) 41 | lib.loc <- .libPaths()[1] 42 | lib.loc 43 | } 44 | 45 | check_requirements <- function(cmd) { 46 | preqs <- Sys.which(os_requirements()) 47 | if (length(x <- names(preqs)[preqs == ""])) 48 | stop("please, install the following required utilities: ", x, call.=FALSE) 49 | 50 | reqs <- c("ldd", if (!root()) "patchelf") 51 | reqs <- Sys.which(reqs) 52 | idx <- reqs == "" 53 | names(reqs)[idx] <- file.path(user_dir("usr/bin"), names(reqs)[idx]) 54 | reqs <- Sys.which(names(reqs)) 55 | 56 | if (length(missing <- basename(names(reqs))[reqs == ""])) { 57 | message("Downloading and installing required utilities...") 58 | os_install(missing) 59 | reqs <- Sys.which(names(reqs)) 60 | } 61 | 62 | names(reqs) <- basename(names(reqs)) 63 | if (any(reqs == "")) 64 | stop("something went wrong, utilities not available", call.=FALSE) 65 | reqs <- c(preqs, reqs) 66 | 67 | if (missing(cmd)) reqs else reqs[cmd] 68 | } 69 | -------------------------------------------------------------------------------- /R/zzz_centos_base.R: -------------------------------------------------------------------------------- 1 | centos_requirements <- function() rpm_requirements() 2 | 3 | centos_install <- function(pkgs) { 4 | if (root()) return(centos_install_root(pkgs)) 5 | 6 | dir.create(temp <- tempfile("rspm_")) 7 | old <- setwd(temp) 8 | on.exit({ setwd(old); unlink(temp, recursive=TRUE, force=TRUE) }) 9 | 10 | cmd <- if (Sys.which("dnf") != "") 11 | "dnf download" else "yumdownloader" 12 | system(p(cmd, "--resolve"), p(pkgs)) 13 | rpm_install() 14 | } 15 | 16 | centos_install_root <- function(pkgs) { 17 | cmd <- if (Sys.which("dnf") != "") 18 | "dnf" else "yum" 19 | system(cmd, "-y install", p(pkgs)) 20 | } 21 | 22 | centos_install_sysreqs <- function(libs) { 23 | os_install(paste0("*/", libs, collapse=" ")) 24 | } 25 | -------------------------------------------------------------------------------- /R/zzz_centos_like.R: -------------------------------------------------------------------------------- 1 | centos_requirements -> 2 | rhel_requirements -> 3 | amzn_requirements -> 4 | rocky_requirements -> 5 | almalinux_requirements -> 6 | ol_requirements 7 | 8 | centos_install -> 9 | rhel_install -> 10 | amzn_install -> 11 | rocky_install -> 12 | almalinux_install -> 13 | ol_install 14 | 15 | centos_install_sysreqs -> 16 | rhel_install_sysreqs -> 17 | amzn_install_sysreqs -> 18 | rocky_install_sysreqs -> 19 | almalinux_install_sysreqs -> 20 | ol_install_sysreqs 21 | -------------------------------------------------------------------------------- /R/zzz_debian_base.R: -------------------------------------------------------------------------------- 1 | debian_requirements <- function() c("apt-file") 2 | 3 | debian_install <- function(pkgs) { 4 | if (root()) return(debian_install_root(pkgs)) 5 | 6 | system("apt-get", debian_options(), "update") 7 | system("apt-get", debian_options(), "-y -d install", p(pkgs)) 8 | debs <- user_dir("var/cache/apt/archives/*.deb") 9 | on.exit(unlink(Sys.glob(debs))) 10 | dpkg_install(debs) 11 | fix_libs() 12 | } 13 | 14 | debian_install_root <- function(pkgs) { 15 | system("apt-get update") 16 | system("apt-get -y install", p(pkgs)) 17 | } 18 | 19 | dpkg_install <- function(debs) { 20 | ver <- strsplit(system_("dpkg --version"), " ")[[1]][7] 21 | if (package_version(ver) >= "1000.0") { # disable, was 1.21 22 | system("dpkg --unpack --force-not-root --force-script-chrootless", 23 | "--root", user_dir(), debs) 24 | } else { 25 | for (file in Sys.glob(debs)) 26 | system("dpkg-deb -x", file, user_dir()) 27 | } 28 | } 29 | 30 | # move libs from x86_64-linux-gnu one level up (see #19) 31 | fix_libs <- function() { 32 | libs <- Sys.glob(user_dir("usr/lib/*-linux-gnu/*")) 33 | file.copy(libs, user_dir("usr/lib/"), recursive=TRUE) 34 | unlink(libs, recursive=TRUE) 35 | } 36 | 37 | debian_install_sysreqs <- function(libs) { 38 | apt_file <- check_requirements("apt-file") 39 | 40 | # get package names 41 | patt <- paste0("'(", paste(libs, collapse="|"), ")'") 42 | patt <- gsub("(\\.|\\+)", "\\\\\\1", patt) 43 | system(apt_file, debian_options(), "update") 44 | pkgs <- system_(apt_file, debian_options(), "-l search --regexp", patt) 45 | 46 | # download and unpack 47 | os_install(pkgs) 48 | } 49 | 50 | debian_options <- function() { 51 | if (root()) return(NULL) 52 | 53 | lists <- file.path(user_dir("var"), "lib/apt/lists") 54 | cache <- file.path(user_dir("var"), "cache/apt/archives") 55 | dir.create(lists, showWarnings=FALSE, recursive=TRUE, mode="0755") 56 | dir.create(cache, showWarnings=FALSE, recursive=TRUE, mode="0755") 57 | paste0("-o Dir::State::Lists=", lists, " -o Dir::Cache=", dirname(cache), 58 | " -o Debug::NoLocking=1") 59 | } 60 | -------------------------------------------------------------------------------- /R/zzz_debian_like.R: -------------------------------------------------------------------------------- 1 | debian_requirements -> 2 | ubuntu_requirements -> 3 | pop_requirements 4 | 5 | debian_install -> 6 | ubuntu_install -> 7 | pop_install 8 | 9 | debian_install_sysreqs -> 10 | ubuntu_install_sysreqs -> 11 | pop_install_sysreqs 12 | -------------------------------------------------------------------------------- /R/zzz_opensuse_base.R: -------------------------------------------------------------------------------- 1 | opensuse_requirements <- function() rpm_requirements() 2 | 3 | opensuse_install <- function(pkgs) { 4 | if (root()) return(opensuse_install_root(pkgs)) 5 | 6 | dir.create(temp <- tempfile("rspm_")) 7 | old <- setwd(temp) 8 | on.exit({ setwd(old); unlink(temp, recursive=TRUE, force=TRUE) }) 9 | 10 | system("zypper --pkg-cache-dir . install -dy", p(pkgs)) 11 | rpm_install() 12 | } 13 | 14 | opensuse_install_root <- function(pkgs) { 15 | system("zypper install -y", p(pkgs)) 16 | } 17 | 18 | opensuse_install_sysreqs <- function(libs) { 19 | # get package names 20 | pkgs <- system_("zypper search --provides", p(libs)) 21 | pkgs <- grep("package$", pkgs, value=TRUE) 22 | pkgs <- trimws(sapply(strsplit(pkgs, "\\|"), "[", 2)) 23 | 24 | # download and unpack 25 | os_install(pkgs) 26 | } 27 | -------------------------------------------------------------------------------- /R/zzz_opensuse_like.R: -------------------------------------------------------------------------------- 1 | opensuse_requirements -> 2 | sles_requirements 3 | 4 | opensuse_install -> 5 | sles_install 6 | 7 | opensuse_install_sysreqs -> 8 | sles_install_sysreqs 9 | -------------------------------------------------------------------------------- /R/zzz_rpm.R: -------------------------------------------------------------------------------- 1 | rpm_version <- function() { 2 | if (Sys.which("rpm") == "") 3 | stop("rpm not found", call.=FALSE) 4 | ver <- strsplit(system_("rpm --version"), " ")[[1]][3] 5 | package_version(ver) 6 | } 7 | 8 | rpm_requirements <- function() { 9 | ver <- rpm_version() 10 | # disable this altogether, it seems to fail in docker environments 11 | if (ver >= "1000.0") { 12 | rpm_requirements <- c() 13 | } else if (ver >= "4.12") { 14 | rpm_requirements <- c("cat", "tar") 15 | } else { 16 | rpm_requirements <- c("cpio") 17 | } 18 | } 19 | 20 | rpm_install <- function() { 21 | ver <- rpm_version() 22 | # disable this altogether, it seems to fail in docker environments 23 | if (ver >= "1000.0") { 24 | system("rpm -i --nodeps --noscripts --notriggers --nosignature --excludedocs", 25 | "--root", user_dir(), p(list.files(pattern=".rpm$", recursive=TRUE))) 26 | } else if (ver >= "4.12") { 27 | for (file in list.files(pattern=".rpm$", recursive=TRUE)) 28 | system("cat", file, "| rpm2archive - | tar xfz - -C", user_dir()) 29 | } else { 30 | for (file in list.files(pattern=".rpm$", recursive=TRUE)) 31 | system("rpm2cpio", file, "| (cd", user_dir(), "; cpio -dium --quiet)") 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rspm: RStudio Package Manager 2 | 3 | 4 | [![Build Status](https://github.com/cran4linux/rspm/workflows/build/badge.svg)](https://github.com/cran4linux/rspm/actions) 5 | [![CRAN\_Status\_Badge](https://www.r-pkg.org/badges/version/rspm)](https://cran.r-project.org/package=rspm) 6 | [![Downloads](https://cranlogs.r-pkg.org/badges/rspm)](https://cran.r-project.org/package=rspm) 7 | 8 | 9 | ## Key features 10 | 11 | - Connects to [RStudio Public Package Manager](https://packagemanager.posit.co/) 12 | to provide **fast binary installations** of R packages on Linux. 13 | - **Complete coverage** of CRAN and BioConductor packages. 14 | - **Full integration** with the system package manager to resolve, download and 15 | configure system requirements automagically without leaving your R console. 16 | - **Fully user mode**, no root privileges required. 17 | - Support for **CentOS / RHEL** 7, 8 and 9. 18 | - Support for **RHEL derivatives**: 19 | Rocky Linux 8-9, AlmaLinux 8-9, Oracle Linux 7-9, Amazon Linux 2-2023. 20 | - Support for **openSUSE / SLES** 15.4 and 15.5. 21 | - Support for **Debian** 11 and 12 (requires `apt-file`). 22 | - Support for **Ubuntu** 20.04 and 22.04 (requires `apt-file`). 23 | 24 | Both R packages and system dependencies **are installed into the user home**. 25 | For lightning-fast system-based installations (which have other advantages, 26 | such as multitenancy, reversibility and automatic updates, still without root 27 | privileges), see the [bspm](https://cran4linux.github.io/bspm/) package and 28 | projects such as [cran2copr](https://github.com/cran4linux/cran2copr) for Fedora 29 | or [r2u](https://github.com/eddelbuettel/r2u) for Ubuntu. 30 | 31 | ## Demo 32 | 33 | Here we enable `rspm` and trigger a binary installation of the `units` package. 34 | Then, we can see how the UDUNITS-2 dependency is detected, downloaded and 35 | configured. 36 | 37 | ![](https://github.com/cran4linux/rspm/blob/main/docs/assets/rspm_units.gif?raw=true) 38 | 39 | ## Installation and usage 40 | 41 | You can install it directly from GitHub using the `remotes` package: 42 | 43 | ```r 44 | remotes::install_github("cran4linux/rspm") 45 | ``` 46 | 47 | ### Basic usage 48 | 49 | You just need to enable it once for your session, and then you can install or 50 | update packages normally via `install.packages` or `update.packages`. 51 | 52 | ```r 53 | rspm::enable() 54 | install.packages("units") 55 | ``` 56 | 57 | Packages with system requirements, like the one above, will be scanned and 58 | configured automatically. Typically, everything will just work without any 59 | further action. But if something gets misconfigured for some reason, it is 60 | possible to manually trigger a reconfiguration with the following command: 61 | 62 | ```r 63 | rspm::install_sysreqs() 64 | ``` 65 | 66 | To enable it by default for all sessions, put the following into your `.Rprofile`: 67 | 68 | ```r 69 | rspm::enable() # wrap it in suppressMessages() to suppress the initial message 70 | ``` 71 | 72 | ### {renv} projects 73 | 74 | To initialize an `renv` project with `rspm` support, just run the following: 75 | 76 | ```r 77 | rspm::renv_init() 78 | ``` 79 | 80 | This command runs `renv::init()` for you and then installs the infrastructure 81 | required for the integration with `install.packages` and `update.packages`. 82 | Note that, if `renv::install` or `renv::update` are called directly, then 83 | `rspm::install_sysreqs()` needs to be called manually. 84 | 85 | ### Docker workflows 86 | 87 | In Docker containers, system requirements can be installed directly as root. 88 | Therefore, it is enough to include in your Dockerfile the following line 89 | right after `renv::restore()`: 90 | 91 | ```Dockerfile 92 | RUN Rscript -e 'renv::install("rspm"); rspm::install_sysreqs()' 93 | ``` 94 | 95 | ## Technical details 96 | 97 | Since _always_, Linux R users have been struggling with source installations and 98 | manual management of build dependencies. Several projects over the years tried 99 | to lessen this pain by building repositories of binaries that complement and 100 | scale up the offer by various distributions. See e.g. the 101 | [c2d4u.team/c2d4u4.0+](https://launchpad.net/~c2d4u.team/+archive/ubuntu/c2d4u4.0+) 102 | PPA repo for Ubuntu or, more recently, the 103 | [autoCRAN](https://build.opensuse.org/project/show/devel:languages:R:autoCRAN) 104 | OBS repo for OpenSUSE, the 105 | [iucar/cran](https://copr.fedorainfracloud.org/coprs/iucar/cran/) Copr repo for 106 | Fedora, the [ArchRPkgs](https://github.com/dvdesolve/ArchRPkgs) repo for Arch 107 | and the [r2u](https://github.com/eddelbuettel/r2u) repo again for Ubuntu. 108 | These are tightly integrated and can be fully managed without leaving the R 109 | console thanks to the [bspm](https://cran4linux.github.io/bspm/) package. 110 | See [this paper](https://arxiv.org/abs/2103.08069) for a detailed review. 111 | 112 | On the other hand, RStudio recently took a complementary approach by building 113 | binaries---for various distributions, R versions and architectures---and serving 114 | them via their own CRAN mirror, also called the 115 | [RStudio Public Package Manager (RSPM)](https://packagemanager.posit.co/). 116 | In contrast to the previous solutions, this method allows the user to install 117 | binary packages as _user packages_ under their home directory (virtually 118 | anywhere), instead of as _system packages_. The main issue is that the user has 119 | still to manage run-time system requirements themselves (i.e., shared libraries 120 | required by some packages to work), so this method by itself produces 121 | installations that are fundamentally broken. 122 | 123 | To fill this gap, this package not only provides an easy setup of RSPM, but also 124 | monitors and scans every installation for missing system requirements, and then 125 | automatically downloads, installs and configures them, relieving the user of 126 | this task. This is done following the same complementary philosophy: 127 | **everything is installed as _user packages_ under the home directory**. More 128 | specifically, this package uses the path `~/.local/share/R/rspm` for this. 129 | 130 | The main technical issue here is that libraries are search for only in a few 131 | pre-configured places that belong to the system (such as `/usr/lib`), and thus 132 | we need a mechanism to feed our new user-hosted library paths to R packages, 133 | hopefully without restarting R and managing environment variables. This is 134 | achieved by **automatically updating the `RPATH`** of every `.so` binary in our 135 | user R packages. This `RPATH` is an optional entry that lives in the header 136 | of ELF executables and shared libraries, and it is used by the dynamic linker 137 | as the primary search path if exists. Therefore, it is the perfect mechanism 138 | for this task, because it can be applied dynamically as new installations are 139 | made, and without requiring any special privilege. 140 | 141 | ## Support 142 | 143 | If you find any bug or you'd like to request support for other distributions 144 | (importantly, they must be supported by RStudio), please file issues at our 145 | [GitHub issue tracker](https://github.com/cran4linux/rspm/issues). 146 | Note though that some quirks may be expected: 147 | 148 | - _Some library is not found_. This means that the library version in your 149 | system is different from what RStudio had when the package was built. This is 150 | more likely to happen in derivatives (e.g. Amazon Linux) that drift away from 151 | their parent. 152 | - _Some package is installed from source_. This means that RStudio has no 153 | binary version for that package. 154 | 155 | There is nothing _we_ can do from `rspm` in either case, so please **do not** 156 | file issues about them. Unfortunately, the best _you_ can do is to install the 157 | development packages for the required library and force a source installation 158 | (i.e. _business as usual_). 159 | 160 | ## Disclaimer 161 | 162 | _RStudio_ is a registered trademark of [Posit](https://posit.co/). 163 | This software provides access to a public repository maintained by RStudio and 164 | provided to the open-source community for free, but has no association with it. 165 | -------------------------------------------------------------------------------- /_pkgdown.yml: -------------------------------------------------------------------------------- 1 | template: 2 | bootstrap: 5 3 | -------------------------------------------------------------------------------- /cran-comments.md: -------------------------------------------------------------------------------- 1 | ## Minor release 2 | Bugfix for Ubuntu systems. 3 | 4 | ## Test environments 5 | - ubuntu:22.04, ubuntu:20.04 on GitHub 6 | - centos:stream9, centos:stream8 on GitHub 7 | 8 | ## R CMD check results 9 | 0 errors | 0 warnings | 0 notes 10 | -------------------------------------------------------------------------------- /docker/stream8/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream8 2 | 3 | LABEL org.opencontainers.image.licenses="GPL-2.0" \ 4 | org.opencontainers.image.source="https://github.com/cran4linux/rspm" \ 5 | org.opencontainers.image.authors="Iñaki Ucar " 6 | 7 | # install R 8 | RUN echo "install_weak_deps=False" >> /etc/dnf/dnf.conf \ 9 | && sed -i -e 's/mirrorlist=/#mirrorlist=/g' -e 's/#baseurl=/baseurl=/g' \ 10 | -e 's/mirror.centos.org/vault.centos.org/g' /etc/yum.repos.d/*.repo \ 11 | && dnf -y install 'dnf-command(config-manager)' \ 12 | && dnf config-manager --set-enabled powertools \ 13 | && dnf -y install epel-release epel-next-release \ 14 | && dnf -y install R-core-devel \ 15 | && dnf -y clean all 16 | 17 | CMD ["bash"] 18 | -------------------------------------------------------------------------------- /docker/stream9/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM quay.io/centos/centos:stream9 2 | 3 | LABEL org.opencontainers.image.licenses="GPL-2.0" \ 4 | org.opencontainers.image.source="https://github.com/cran4linux/rspm" \ 5 | org.opencontainers.image.authors="Iñaki Ucar " 6 | 7 | # install R 8 | RUN echo "install_weak_deps=False" >> /etc/dnf/dnf.conf \ 9 | && dnf -y install 'dnf-command(config-manager)' \ 10 | && dnf config-manager --set-enabled crb \ 11 | && dnf -y install epel-release epel-next-release \ 12 | && dnf -y install R-core-devel /usr/bin/su \ 13 | && dnf -y clean all 14 | 15 | CMD ["bash"] 16 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • rspm 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Skip to contents 17 | 18 | 19 |
46 |
47 |
52 | 53 | Content not found. Please use links in the navbar. 54 | 55 |
56 |
57 | 58 | 59 |
62 | 63 | 66 | 67 |
68 |
69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /docs/LICENSE-text.html: -------------------------------------------------------------------------------- 1 | 2 | License • rspm 3 | Skip to contents 4 | 5 | 6 |
28 |
29 |
34 | 35 |
YEAR: 2022-2023
36 | COPYRIGHT HOLDER: Iñaki Ucar
37 | 
38 | 39 |
40 | 41 | 42 |
45 | 46 | 49 | 50 |
51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /docs/assets/rspm_sf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/assets/rspm_sf.gif -------------------------------------------------------------------------------- /docs/assets/rspm_units.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/assets/rspm_units.gif -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • rspm 3 | Skip to contents 4 | 5 | 6 |
28 |
29 |
33 | 34 |
35 |

Authors

36 | 37 |
  • 38 |

    Iñaki Ucar. Author, copyright holder, maintainer. 39 |

    40 |
  • 41 |
  • 42 |

    R Core Team. Author, copyright holder. 43 |

    44 |
  • 45 |
46 | 47 |
48 |

Citation

49 |

Source: DESCRIPTION

50 | 51 |

Ucar I, R Core Team (2024). 52 | rspm: 'RStudio' Package Manager. 53 | R package version 0.6.1, https://cran4linux.github.io/rspm/. 54 |

55 |
@Manual{,
56 |   title = {rspm: 'RStudio' Package Manager},
57 |   author = {Iñaki Ucar and {R Core Team}},
58 |   year = {2024},
59 |   note = {R package version 0.6.1},
60 |   url = {https://cran4linux.github.io/rspm/},
61 | }
62 |
63 | 64 |
66 | 67 | 68 |
71 | 72 | 75 | 76 |
77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/deps/bootstrap-toc-1.0.1/bootstrap-toc.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v1.0.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | !function(a){"use strict";window.Toc={helpers:{findOrFilter:function(e,t){var n=e.find(t);return e.filter(t).add(n).filter(":not([data-toc-skip])")},generateUniqueIdBase:function(e){return a(e).text().trim().replace(/\'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]\.\/\(\)\*\\\n\t\b\v]/g,"-").replace(/-{2,}/g,"-").substring(0,64).replace(/^-+|-+$/gm,"").toLowerCase()||e.tagName.toLowerCase()},generateUniqueId:function(e){for(var t=this.generateUniqueIdBase(e),n=0;;n++){var r=t;if(0')},createChildNavList:function(e){var t=this.createNavList();return e.append(t),t},generateNavEl:function(e,t){var n=a('');n.attr("href","#"+e),n.text(t);var r=a("
  • ");return r.append(n),r},generateNavItem:function(e){var t=this.generateAnchor(e),n=a(e),r=n.data("toc-text")||n.text();return this.generateNavEl(t,r)},getTopLevel:function(e){for(var t=1;t<=6;t++){if(1 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-v4compatibility.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-v4compatibility.ttf -------------------------------------------------------------------------------- /docs/deps/font-awesome-6.4.2/webfonts/fa-v4compatibility.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/deps/font-awesome-6.4.2/webfonts/fa-v4compatibility.woff2 -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.11.0 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=ls.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t,n){n=n||{},Object.assign(this,o.options,n),this.classes=Object.assign({},o.options.classes,n.classes),this.elem=t,this.tolerance=function(t){return t===Object(t)?t:{down:t,up:t}}(this.tolerance),this.initialised=!1,this.frozen=!1}return o.prototype={constructor:o,init:function(){return o.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},o.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},o.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),o}); -------------------------------------------------------------------------------- /docs/deps/headroom-0.11.0/jQuery.headroom.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * headroom.js v0.9.4 - Give your page some headroom. Hide your header until you need it 3 | * Copyright (c) 2017 Nick Williams - http://wicky.nillia.ms/headroom.js 4 | * License: MIT 5 | */ 6 | 7 | !function(a){a&&(a.fn.headroom=function(b){return this.each(function(){var c=a(this),d=c.data("headroom"),e="object"==typeof b&&b;e=a.extend(!0,{},Headroom.options,e),d||(d=new Headroom(this,e),d.init(),c.data("headroom",d)),"string"==typeof b&&(d[b](),"destroy"===b&&c.removeData("headroom"))})},a("[data-headroom]").each(function(){var b=a(this);b.headroom(b.data())}))}(window.Zepto||window.jQuery); -------------------------------------------------------------------------------- /docs/deps/search-1.0.0/mark.min.js: -------------------------------------------------------------------------------- 1 | /*!*************************************************** 2 | * mark.js v8.11.1 3 | * https://markjs.io/ 4 | * Copyright (c) 2014–2018, Julian Kühnel 5 | * Released under the MIT license https://git.io/vwTVl 6 | *****************************************************/ 7 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):e.Mark=t()}(this,function(){"use strict";var e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},t=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},n=function(){function e(e,t){for(var n=0;n1&&void 0!==arguments[1])||arguments[1],i=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:5e3;t(this,e),this.ctx=n,this.iframes=r,this.exclude=i,this.iframesTimeout=o}return n(e,[{key:"getContexts",value:function(){var e=[];return(void 0!==this.ctx&&this.ctx?NodeList.prototype.isPrototypeOf(this.ctx)?Array.prototype.slice.call(this.ctx):Array.isArray(this.ctx)?this.ctx:"string"==typeof this.ctx?Array.prototype.slice.call(document.querySelectorAll(this.ctx)):[this.ctx]:[]).forEach(function(t){var n=e.filter(function(e){return e.contains(t)}).length>0;-1!==e.indexOf(t)||n||e.push(t)}),e}},{key:"getIframeContents",value:function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){},r=void 0;try{var i=e.contentWindow;if(r=i.document,!i||!r)throw new Error("iframe inaccessible")}catch(e){n()}r&&t(r)}},{key:"isIframeBlank",value:function(e){var t=e.getAttribute("src").trim();return"about:blank"===e.contentWindow.location.href&&"about:blank"!==t&&t}},{key:"observeIframeLoad",value:function(e,t,n){var r=this,i=!1,o=null,a=function a(){if(!i){i=!0,clearTimeout(o);try{r.isIframeBlank(e)||(e.removeEventListener("load",a),r.getIframeContents(e,t,n))}catch(e){n()}}};e.addEventListener("load",a),o=setTimeout(a,this.iframesTimeout)}},{key:"onIframeReady",value:function(e,t,n){try{"complete"===e.contentWindow.document.readyState?this.isIframeBlank(e)?this.observeIframeLoad(e,t,n):this.getIframeContents(e,t,n):this.observeIframeLoad(e,t,n)}catch(e){n()}}},{key:"waitForIframes",value:function(e,t){var n=this,r=0;this.forEachIframe(e,function(){return!0},function(e){r++,n.waitForIframes(e.querySelector("html"),function(){--r||t()})},function(e){e||t()})}},{key:"forEachIframe",value:function(t,n,r){var i=this,o=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},a=t.querySelectorAll("iframe"),s=a.length,c=0;a=Array.prototype.slice.call(a);var u=function(){--s<=0&&o(c)};s||u(),a.forEach(function(t){e.matches(t,i.exclude)?u():i.onIframeReady(t,function(e){n(t)&&(c++,r(e)),u()},u)})}},{key:"createIterator",value:function(e,t,n){return document.createNodeIterator(e,t,n,!1)}},{key:"createInstanceOnIframe",value:function(t){return new e(t.querySelector("html"),this.iframes)}},{key:"compareNodeIframe",value:function(e,t,n){if(e.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_PRECEDING){if(null===t)return!0;if(t.compareDocumentPosition(n)&Node.DOCUMENT_POSITION_FOLLOWING)return!0}return!1}},{key:"getIteratorNode",value:function(e){var t=e.previousNode();return{prevNode:t,node:null===t?e.nextNode():e.nextNode()&&e.nextNode()}}},{key:"checkIframeFilter",value:function(e,t,n,r){var i=!1,o=!1;return r.forEach(function(e,t){e.val===n&&(i=t,o=e.handled)}),this.compareNodeIframe(e,t,n)?(!1!==i||o?!1===i||o||(r[i].handled=!0):r.push({val:n,handled:!0}),!0):(!1===i&&r.push({val:n,handled:!1}),!1)}},{key:"handleOpenIframes",value:function(e,t,n,r){var i=this;e.forEach(function(e){e.handled||i.getIframeContents(e.val,function(e){i.createInstanceOnIframe(e).forEachNode(t,n,r)})})}},{key:"iterateThroughNodes",value:function(e,t,n,r,i){for(var o,a=this,s=this.createIterator(t,e,r),c=[],u=[],l=void 0,h=void 0;void 0,o=a.getIteratorNode(s),h=o.prevNode,l=o.node;)this.iframes&&this.forEachIframe(t,function(e){return a.checkIframeFilter(l,h,e,c)},function(t){a.createInstanceOnIframe(t).forEachNode(e,function(e){return u.push(e)},r)}),u.push(l);u.forEach(function(e){n(e)}),this.iframes&&this.handleOpenIframes(c,e,n,r),i()}},{key:"forEachNode",value:function(e,t,n){var r=this,i=arguments.length>3&&void 0!==arguments[3]?arguments[3]:function(){},o=this.getContexts(),a=o.length;a||i(),o.forEach(function(o){var s=function(){r.iterateThroughNodes(e,o,t,n,function(){--a<=0&&i()})};r.iframes?r.waitForIframes(o,s):s()})}}],[{key:"matches",value:function(e,t){var n="string"==typeof t?[t]:t,r=e.matches||e.matchesSelector||e.msMatchesSelector||e.mozMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector;if(r){var i=!1;return n.every(function(t){return!r.call(e,t)||(i=!0,!1)}),i}return!1}}]),e}(),o=function(){function o(e){t(this,o),this.ctx=e,this.ie=!1;var n=window.navigator.userAgent;(n.indexOf("MSIE")>-1||n.indexOf("Trident")>-1)&&(this.ie=!0)}return n(o,[{key:"log",value:function(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"debug",r=this.opt.log;this.opt.debug&&"object"===(void 0===r?"undefined":e(r))&&"function"==typeof r[n]&&r[n]("mark.js: "+t)}},{key:"escapeStr",value:function(e){return e.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g,"\\$&")}},{key:"createRegExp",value:function(e){return"disabled"!==this.opt.wildcards&&(e=this.setupWildcardsRegExp(e)),e=this.escapeStr(e),Object.keys(this.opt.synonyms).length&&(e=this.createSynonymsRegExp(e)),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),this.opt.diacritics&&(e=this.createDiacriticsRegExp(e)),e=this.createMergedBlanksRegExp(e),(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.createJoinersRegExp(e)),"disabled"!==this.opt.wildcards&&(e=this.createWildcardsRegExp(e)),e=this.createAccuracyRegExp(e)}},{key:"createSynonymsRegExp",value:function(e){var t=this.opt.synonyms,n=this.opt.caseSensitive?"":"i",r=this.opt.ignoreJoiners||this.opt.ignorePunctuation.length?"\0":"";for(var i in t)if(t.hasOwnProperty(i)){var o=t[i],a="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(i):this.escapeStr(i),s="disabled"!==this.opt.wildcards?this.setupWildcardsRegExp(o):this.escapeStr(o);""!==a&&""!==s&&(e=e.replace(new RegExp("("+this.escapeStr(a)+"|"+this.escapeStr(s)+")","gm"+n),r+"("+this.processSynomyms(a)+"|"+this.processSynomyms(s)+")"+r))}return e}},{key:"processSynomyms",value:function(e){return(this.opt.ignoreJoiners||this.opt.ignorePunctuation.length)&&(e=this.setupIgnoreJoinersRegExp(e)),e}},{key:"setupWildcardsRegExp",value:function(e){return(e=e.replace(/(?:\\)*\?/g,function(e){return"\\"===e.charAt(0)?"?":""})).replace(/(?:\\)*\*/g,function(e){return"\\"===e.charAt(0)?"*":""})}},{key:"createWildcardsRegExp",value:function(e){var t="withSpaces"===this.opt.wildcards;return e.replace(/\u0001/g,t?"[\\S\\s]?":"\\S?").replace(/\u0002/g,t?"[\\S\\s]*?":"\\S*")}},{key:"setupIgnoreJoinersRegExp",value:function(e){return e.replace(/[^(|)\\]/g,function(e,t,n){var r=n.charAt(t+1);return/[(|)\\]/.test(r)||""===r?e:e+"\0"})}},{key:"createJoinersRegExp",value:function(e){var t=[],n=this.opt.ignorePunctuation;return Array.isArray(n)&&n.length&&t.push(this.escapeStr(n.join(""))),this.opt.ignoreJoiners&&t.push("\\u00ad\\u200b\\u200c\\u200d"),t.length?e.split(/\u0000+/).join("["+t.join("")+"]*"):e}},{key:"createDiacriticsRegExp",value:function(e){var t=this.opt.caseSensitive?"":"i",n=this.opt.caseSensitive?["aàáảãạăằắẳẵặâầấẩẫậäåāą","AÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćč","CÇĆČ","dđď","DĐĎ","eèéẻẽẹêềếểễệëěēę","EÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïī","IÌÍỈĨỊÎÏĪ","lł","LŁ","nñňń","NÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøō","OÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rř","RŘ","sšśșş","SŠŚȘŞ","tťțţ","TŤȚŢ","uùúủũụưừứửữựûüůū","UÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿ","YÝỲỶỸỴŸ","zžżź","ZŽŻŹ"]:["aàáảãạăằắẳẵặâầấẩẫậäåāąAÀÁẢÃẠĂẰẮẲẴẶÂẦẤẨẪẬÄÅĀĄ","cçćčCÇĆČ","dđďDĐĎ","eèéẻẽẹêềếểễệëěēęEÈÉẺẼẸÊỀẾỂỄỆËĚĒĘ","iìíỉĩịîïīIÌÍỈĨỊÎÏĪ","lłLŁ","nñňńNÑŇŃ","oòóỏõọôồốổỗộơởỡớờợöøōOÒÓỎÕỌÔỒỐỔỖỘƠỞỠỚỜỢÖØŌ","rřRŘ","sšśșşSŠŚȘŞ","tťțţTŤȚŢ","uùúủũụưừứửữựûüůūUÙÚỦŨỤƯỪỨỬỮỰÛÜŮŪ","yýỳỷỹỵÿYÝỲỶỸỴŸ","zžżźZŽŻŹ"],r=[];return e.split("").forEach(function(i){n.every(function(n){if(-1!==n.indexOf(i)){if(r.indexOf(n)>-1)return!1;e=e.replace(new RegExp("["+n+"]","gm"+t),"["+n+"]"),r.push(n)}return!0})}),e}},{key:"createMergedBlanksRegExp",value:function(e){return e.replace(/[\s]+/gim,"[\\s]+")}},{key:"createAccuracyRegExp",value:function(e){var t=this,n=this.opt.accuracy,r="string"==typeof n?n:n.value,i="";switch(("string"==typeof n?[]:n.limiters).forEach(function(e){i+="|"+t.escapeStr(e)}),r){case"partially":default:return"()("+e+")";case"complementary":return"()([^"+(i="\\s"+(i||this.escapeStr("!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~¡¿")))+"]*"+e+"[^"+i+"]*)";case"exactly":return"(^|\\s"+i+")("+e+")(?=$|\\s"+i+")"}}},{key:"getSeparatedKeywords",value:function(e){var t=this,n=[];return e.forEach(function(e){t.opt.separateWordSearch?e.split(" ").forEach(function(e){e.trim()&&-1===n.indexOf(e)&&n.push(e)}):e.trim()&&-1===n.indexOf(e)&&n.push(e)}),{keywords:n.sort(function(e,t){return t.length-e.length}),length:n.length}}},{key:"isNumeric",value:function(e){return Number(parseFloat(e))==e}},{key:"checkRanges",value:function(e){var t=this;if(!Array.isArray(e)||"[object Object]"!==Object.prototype.toString.call(e[0]))return this.log("markRanges() will only accept an array of objects"),this.opt.noMatch(e),[];var n=[],r=0;return e.sort(function(e,t){return e.start-t.start}).forEach(function(e){var i=t.callNoMatchOnInvalidRanges(e,r),o=i.start,a=i.end;i.valid&&(e.start=o,e.length=a-o,n.push(e),r=a)}),n}},{key:"callNoMatchOnInvalidRanges",value:function(e,t){var n=void 0,r=void 0,i=!1;return e&&void 0!==e.start?(r=(n=parseInt(e.start,10))+parseInt(e.length,10),this.isNumeric(e.start)&&this.isNumeric(e.length)&&r-t>0&&r-n>0?i=!0:(this.log("Ignoring invalid or overlapping range: "+JSON.stringify(e)),this.opt.noMatch(e))):(this.log("Ignoring invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:n,end:r,valid:i}}},{key:"checkWhitespaceRanges",value:function(e,t,n){var r=void 0,i=!0,o=n.length,a=t-o,s=parseInt(e.start,10)-a;return(r=(s=s>o?o:s)+parseInt(e.length,10))>o&&(r=o,this.log("End range automatically set to the max value of "+o)),s<0||r-s<0||s>o||r>o?(i=!1,this.log("Invalid range: "+JSON.stringify(e)),this.opt.noMatch(e)):""===n.substring(s,r).replace(/\s+/g,"")&&(i=!1,this.log("Skipping whitespace only range: "+JSON.stringify(e)),this.opt.noMatch(e)),{start:s,end:r,valid:i}}},{key:"getTextNodes",value:function(e){var t=this,n="",r=[];this.iterator.forEachNode(NodeFilter.SHOW_TEXT,function(e){r.push({start:n.length,end:(n+=e.textContent).length,node:e})},function(e){return t.matchesExclude(e.parentNode)?NodeFilter.FILTER_REJECT:NodeFilter.FILTER_ACCEPT},function(){e({value:n,nodes:r})})}},{key:"matchesExclude",value:function(e){return i.matches(e,this.opt.exclude.concat(["script","style","title","head","html"]))}},{key:"wrapRangeInTextNode",value:function(e,t,n){var r=this.opt.element?this.opt.element:"mark",i=e.splitText(t),o=i.splitText(n-t),a=document.createElement(r);return a.setAttribute("data-markjs","true"),this.opt.className&&a.setAttribute("class",this.opt.className),a.textContent=i.textContent,i.parentNode.replaceChild(a,i),o}},{key:"wrapRangeInMappedTextNode",value:function(e,t,n,r,i){var o=this;e.nodes.every(function(a,s){var c=e.nodes[s+1];if(void 0===c||c.start>t){if(!r(a.node))return!1;var u=t-a.start,l=(n>a.end?a.end:n)-a.start,h=e.value.substr(0,a.start),f=e.value.substr(l+a.start);if(a.node=o.wrapRangeInTextNode(a.node,u,l),e.value=h+f,e.nodes.forEach(function(t,n){n>=s&&(e.nodes[n].start>0&&n!==s&&(e.nodes[n].start-=l),e.nodes[n].end-=l)}),n-=l,i(a.node.previousSibling,a.start),!(n>a.end))return!1;t=a.end}return!0})}},{key:"wrapMatches",value:function(e,t,n,r,i){var o=this,a=0===t?0:t+1;this.getTextNodes(function(t){t.nodes.forEach(function(t){t=t.node;for(var i=void 0;null!==(i=e.exec(t.textContent))&&""!==i[a];)if(n(i[a],t)){var s=i.index;if(0!==a)for(var c=1;c"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | RStudio Package Manager • rspm 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | Skip to contents 19 | 20 | 21 |
    48 |
    49 |
    50 | 52 | 53 | 54 |
    55 |

    Key features 56 |

    57 |
      58 |
    • Connects to RStudio Public Package Manager to provide fast binary installations of R packages on Linux.
    • 59 |
    • 60 | Complete coverage of CRAN and BioConductor packages.
    • 61 |
    • 62 | Full integration with the system package manager to resolve, download and configure system requirements automagically without leaving your R console.
    • 63 |
    • 64 | Fully user mode, no root privileges required.
    • 65 |
    • Support for CentOS / RHEL 7, 8 and 9.
    • 66 |
    • Support for RHEL derivatives: Rocky Linux 8-9, AlmaLinux 8-9, Oracle Linux 7-9, Amazon Linux 2-2023.
    • 67 |
    • Support for openSUSE / SLES 15.4 and 15.5.
    • 68 |
    • Support for Debian 11 and 12 (requires apt-file).
    • 69 |
    • Support for Ubuntu 20.04 and 22.04 (requires apt-file).
    • 70 |
    71 |

    Both R packages and system dependencies are installed into the user home. For lightning-fast system-based installations (which have other advantages, such as multitenancy, reversibility and automatic updates, still without root privileges), see the bspm package and projects such as cran2copr for Fedora or r2u for Ubuntu.

    72 |
    73 |
    74 |

    Demo 75 |

    76 |

    Here we enable rspm and trigger a binary installation of the units package. Then, we can see how the UDUNITS-2 dependency is detected, downloaded and configured.

    77 |

    78 |
    79 |
    80 |

    Installation and usage 81 |

    82 |

    You can install it directly from GitHub using the remotes package:

    83 |
     84 | remotes::install_github("cran4linux/rspm")
    85 |
    86 |

    Basic usage 87 |

    88 |

    You just need to enable it once for your session, and then you can install or update packages normally via install.packages or update.packages.

    89 |
     90 | rspm::enable()
     91 | install.packages("units")
    92 |

    Packages with system requirements, like the one above, will be scanned and configured automatically. Typically, everything will just work without any further action. But if something gets misconfigured for some reason, it is possible to manually trigger a reconfiguration with the following command:

    93 |
     94 | rspm::install_sysreqs()
    95 |

    To enable it by default for all sessions, put the following into your .Rprofile:

    96 |
     97 | rspm::enable() # wrap it in suppressMessages() to suppress the initial message
    98 |
    99 |
    100 |

    {renv} projects 101 |

    102 |

    To initialize an renv project with rspm support, just run the following:

    103 |
    104 | rspm::renv_init()
    105 |

    This command runs renv::init() for you and then installs the infrastructure required for the integration with install.packages and update.packages. Note that, if renv::install or renv::update are called directly, then rspm::install_sysreqs() needs to be called manually.

    106 |
    107 |
    108 |

    Docker workflows 109 |

    110 |

    In Docker containers, system requirements can be installed directly as root. Therefore, it is enough to include in your Dockerfile the following line right after renv::restore():

    111 |
    RUN Rscript -e 'renv::install("rspm"); rspm::install_sysreqs()'
    112 |
    113 |
    114 |
    115 |

    Technical details 116 |

    117 |

    Since always, Linux R users have been struggling with source installations and manual management of build dependencies. Several projects over the years tried to lessen this pain by building repositories of binaries that complement and scale up the offer by various distributions. See e.g. the c2d4u.team/c2d4u4.0+ PPA repo for Ubuntu or, more recently, the autoCRAN OBS repo for OpenSUSE, the iucar/cran Copr repo for Fedora, the ArchRPkgs repo for Arch and the r2u repo again for Ubuntu. These are tightly integrated and can be fully managed without leaving the R console thanks to the bspm package. See this paper for a detailed review.

    118 |

    On the other hand, RStudio recently took a complementary approach by building binaries—for various distributions, R versions and architectures—and serving them via their own CRAN mirror, also called the RStudio Public Package Manager (RSPM). In contrast to the previous solutions, this method allows the user to install binary packages as user packages under their home directory (virtually anywhere), instead of as system packages. The main issue is that the user has still to manage run-time system requirements themselves (i.e., shared libraries required by some packages to work), so this method by itself produces installations that are fundamentally broken.

    119 |

    To fill this gap, this package not only provides an easy setup of RSPM, but also monitors and scans every installation for missing system requirements, and then automatically downloads, installs and configures them, relieving the user of this task. This is done following the same complementary philosophy: everything is installed as user packages under the home directory. More specifically, this package uses the path ~/.local/share/R/rspm for this.

    120 |

    The main technical issue here is that libraries are search for only in a few pre-configured places that belong to the system (such as /usr/lib), and thus we need a mechanism to feed our new user-hosted library paths to R packages, hopefully without restarting R and managing environment variables. This is achieved by automatically updating the RPATH of every .so binary in our user R packages. This RPATH is an optional entry that lives in the header of ELF executables and shared libraries, and it is used by the dynamic linker as the primary search path if exists. Therefore, it is the perfect mechanism for this task, because it can be applied dynamically as new installations are made, and without requiring any special privilege.

    121 |
    122 |
    123 |

    Support 124 |

    125 |

    If you find any bug or you’d like to request support for other distributions (importantly, they must be supported by RStudio), please file issues at our GitHub issue tracker. Note though that some quirks may be expected:

    126 |
      127 |
    • 128 | Some library is not found. This means that the library version in your system is different from what RStudio had when the package was built. This is more likely to happen in derivatives (e.g. Amazon Linux) that drift away from their parent.
    • 129 |
    • 130 | Some package is installed from source. This means that RStudio has no binary version for that package.
    • 131 |
    132 |

    There is nothing we can do from rspm in either case, so please do not file issues about them. Unfortunately, the best you can do is to install the development packages for the required library and force a source installation (i.e. business as usual).

    133 |
    134 |
    135 |

    Disclaimer 136 |

    137 |

    RStudio is a registered trademark of Posit. This software provides access to a public repository maintained by RStudio and provided to the open-source community for free, but has no association with it.

    138 |
    139 |
    140 |
    184 |
    185 | 186 | 187 |
    190 | 191 | 194 | 195 |
    196 |
    197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | -------------------------------------------------------------------------------- /docs/katex-auto.js: -------------------------------------------------------------------------------- 1 | // https://github.com/jgm/pandoc/blob/29fa97ab96b8e2d62d48326e1b949a71dc41f47a/src/Text/Pandoc/Writers/HTML.hs#L332-L345 2 | document.addEventListener("DOMContentLoaded", function () { 3 | var mathElements = document.getElementsByClassName("math"); 4 | var macros = []; 5 | for (var i = 0; i < mathElements.length; i++) { 6 | var texText = mathElements[i].firstChild; 7 | if (mathElements[i].tagName == "SPAN") { 8 | katex.render(texText.data, mathElements[i], { 9 | displayMode: mathElements[i].classList.contains("display"), 10 | throwOnError: false, 11 | macros: macros, 12 | fleqn: false 13 | }); 14 | }}}); 15 | -------------------------------------------------------------------------------- /docs/lightswitch.js: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | * Color mode toggler for Bootstrap's docs (https://getbootstrap.com/) 4 | * Copyright 2011-2023 The Bootstrap Authors 5 | * Licensed under the Creative Commons Attribution 3.0 Unported License. 6 | * Updates for {pkgdown} by the {bslib} authors, also licensed under CC-BY-3.0. 7 | */ 8 | 9 | const getStoredTheme = () => localStorage.getItem('theme') 10 | const setStoredTheme = theme => localStorage.setItem('theme', theme) 11 | 12 | const getPreferredTheme = () => { 13 | const storedTheme = getStoredTheme() 14 | if (storedTheme) { 15 | return storedTheme 16 | } 17 | 18 | return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light' 19 | } 20 | 21 | const setTheme = theme => { 22 | if (theme === 'auto') { 23 | document.documentElement.setAttribute('data-bs-theme', (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light')) 24 | } else { 25 | document.documentElement.setAttribute('data-bs-theme', theme) 26 | } 27 | } 28 | 29 | function bsSetupThemeToggle () { 30 | 'use strict' 31 | 32 | const showActiveTheme = (theme, focus = false) => { 33 | var activeLabel, activeIcon; 34 | 35 | document.querySelectorAll('[data-bs-theme-value]').forEach(element => { 36 | const buttonTheme = element.getAttribute('data-bs-theme-value') 37 | const isActive = buttonTheme == theme 38 | 39 | element.classList.toggle('active', isActive) 40 | element.setAttribute('aria-pressed', isActive) 41 | 42 | if (isActive) { 43 | activeLabel = element.textContent; 44 | activeIcon = element.querySelector('span').classList.value; 45 | } 46 | }) 47 | 48 | const themeSwitcher = document.querySelector('#dropdown-lightswitch') 49 | if (!themeSwitcher) { 50 | return 51 | } 52 | 53 | themeSwitcher.setAttribute('aria-label', activeLabel) 54 | themeSwitcher.querySelector('span').classList.value = activeIcon; 55 | 56 | if (focus) { 57 | themeSwitcher.focus() 58 | } 59 | } 60 | 61 | window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { 62 | const storedTheme = getStoredTheme() 63 | if (storedTheme !== 'light' && storedTheme !== 'dark') { 64 | setTheme(getPreferredTheme()) 65 | } 66 | }) 67 | 68 | window.addEventListener('DOMContentLoaded', () => { 69 | showActiveTheme(getPreferredTheme()) 70 | 71 | document 72 | .querySelectorAll('[data-bs-theme-value]') 73 | .forEach(toggle => { 74 | toggle.addEventListener('click', () => { 75 | const theme = toggle.getAttribute('data-bs-theme-value') 76 | setTheme(theme) 77 | setStoredTheme(theme) 78 | showActiveTheme(theme, true) 79 | }) 80 | }) 81 | }) 82 | } 83 | 84 | setTheme(getPreferredTheme()); 85 | bsSetupThemeToggle(); 86 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/news/index.html: -------------------------------------------------------------------------------- 1 | 2 | Changelog • rspm 3 | Skip to contents 4 | 5 | 6 |
    28 |
    29 |
    34 | 35 |
    36 |

    rspm 0.6.1

    37 |
    • Fix regexp escaping in apt-file calls for Debian-like systems (#32).
    • 38 |
    39 |
    40 |

    rspm 0.6.0

    CRAN release: 2024-06-21

    41 |
    • Add support for Pop!_OS (#26 addressing #25).
    • 42 |
    • Add support for Amazon Linux 2023 (#28 addressing #27).
    • 43 |
    44 |
    45 |

    rspm 0.5.3

    CRAN release: 2024-05-20

    46 |
    • Drop test on failure to avoid test failures on CRAN.
    • 47 |
    48 |
    49 |

    rspm 0.5.2

    CRAN release: 2024-05-04

    50 |
    • Don’t use expect_match for now to avoid test failures on CRAN.
    • 51 |
    52 |
    53 |

    rspm 0.5.1

    CRAN release: 2024-05-01

    54 |
    • Export missing_sysreqs() for debugging purposes.
    • 55 |
    • Fix call to tinytest function from namespace.
    • 56 |
    • Update supported systems.
    • 57 |
    58 |
    59 |

    rspm 0.5.0

    CRAN release: 2023-11-25

    60 |
    • Move to cran4linux org on GitHub, update URLs.
    • 61 |
    • Add support for Debian 11 and 12 (#21).
    • 62 |
    63 |
    64 |

    rspm 0.4.0

    CRAN release: 2023-04-14

    65 |
    • Implement root mode to improve Docker workflows (#20 addressing #17).
    • 66 |
    • Internal refactoring to improve extensibility (as part of #20).
    • 67 |
    • Remove libs’ arch subfolder in Ubuntu to fix relative path issues (#19).
    • 68 |
    69 |
    70 |

    rspm 0.3.1

    CRAN release: 2023-03-26

    71 |
    • Fix version detection in CentOS (#18 addressing #16).
    • 72 |
    • Fix unpacking for new rpm versions (as part of #18).
    • 73 |
    74 |
    75 |

    rspm 0.3.0

    CRAN release: 2022-12-22

    76 |
    • Add support for CentOS/RHEL 9 and derivatives (#13 addressing #12).
    • 77 |
    78 |
    79 |

    rspm 0.2.3

    CRAN release: 2022-11-21

    80 |
    • Fix non-root unpacking for old rpm/dpkg versions (#11 addressing #9, #10).
    • 81 |
    82 |
    83 |

    rspm 0.2.2

    CRAN release: 2022-09-15

    84 |
    • Fix root permission requirement for yum-based systems (#9).
    • 85 |
    • Clean up empty user directory.
    • 86 |
    87 |
    88 |

    rspm 0.2.1

    CRAN release: 2022-08-16

    89 |
    • Fix .Rprofile enabling error (#8).
    • 90 |
    • Some fixes requested by CRAN.
    • 91 |
    92 |
    93 |

    rspm 0.2.0

    94 |
    • Add support for CentOS 7, RHEL 7 and 8 (#1).
    • 95 |
    • Add support for several RHEL derivatives: Rocky Linux 8, AlmaLinux 8, Oracle Linux 7 and 8, Amazon Linux 2 (#2).
    • 96 |
    • Add support for openSUSE / SLES 15.3 (#3).
    • 97 |
    • Add support for renv projects via rspm::renv_init() (#5 closing #4).
    • 98 |
    99 |
    100 |

    rspm 0.1.0

    101 |
    • Initial release, with support for CentOS 8 and Ubuntu 18.04, 20.04 and 22.04.
    • 102 |
    103 |
    105 | 106 | 107 |
    110 | 111 | 114 | 115 |
    116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | position: relative; 22 | } 23 | 24 | body > .container { 25 | display: flex; 26 | height: 100%; 27 | flex-direction: column; 28 | } 29 | 30 | body > .container .row { 31 | flex: 1 0 auto; 32 | } 33 | 34 | footer { 35 | margin-top: 45px; 36 | padding: 35px 0 36px; 37 | border-top: 1px solid #e5e5e5; 38 | color: #666; 39 | display: flex; 40 | flex-shrink: 0; 41 | } 42 | footer p { 43 | margin-bottom: 0; 44 | } 45 | footer div { 46 | flex: 1; 47 | } 48 | footer .pkgdown { 49 | text-align: right; 50 | } 51 | footer p { 52 | margin-bottom: 0; 53 | } 54 | 55 | img.icon { 56 | float: right; 57 | } 58 | 59 | /* Ensure in-page images don't run outside their container */ 60 | .contents img { 61 | max-width: 100%; 62 | height: auto; 63 | } 64 | 65 | /* Fix bug in bootstrap (only seen in firefox) */ 66 | summary { 67 | display: list-item; 68 | } 69 | 70 | /* Typographic tweaking ---------------------------------*/ 71 | 72 | .contents .page-header { 73 | margin-top: calc(-60px + 1em); 74 | } 75 | 76 | dd { 77 | margin-left: 3em; 78 | } 79 | 80 | /* Section anchors ---------------------------------*/ 81 | 82 | a.anchor { 83 | display: none; 84 | margin-left: 5px; 85 | width: 20px; 86 | height: 20px; 87 | 88 | background-image: url(./link.svg); 89 | background-repeat: no-repeat; 90 | background-size: 20px 20px; 91 | background-position: center center; 92 | } 93 | 94 | h1:hover .anchor, 95 | h2:hover .anchor, 96 | h3:hover .anchor, 97 | h4:hover .anchor, 98 | h5:hover .anchor, 99 | h6:hover .anchor { 100 | display: inline-block; 101 | } 102 | 103 | /* Fixes for fixed navbar --------------------------*/ 104 | 105 | .contents h1, .contents h2, .contents h3, .contents h4 { 106 | padding-top: 60px; 107 | margin-top: -40px; 108 | } 109 | 110 | /* Navbar submenu --------------------------*/ 111 | 112 | .dropdown-submenu { 113 | position: relative; 114 | } 115 | 116 | .dropdown-submenu>.dropdown-menu { 117 | top: 0; 118 | left: 100%; 119 | margin-top: -6px; 120 | margin-left: -1px; 121 | border-radius: 0 6px 6px 6px; 122 | } 123 | 124 | .dropdown-submenu:hover>.dropdown-menu { 125 | display: block; 126 | } 127 | 128 | .dropdown-submenu>a:after { 129 | display: block; 130 | content: " "; 131 | float: right; 132 | width: 0; 133 | height: 0; 134 | border-color: transparent; 135 | border-style: solid; 136 | border-width: 5px 0 5px 5px; 137 | border-left-color: #cccccc; 138 | margin-top: 5px; 139 | margin-right: -10px; 140 | } 141 | 142 | .dropdown-submenu:hover>a:after { 143 | border-left-color: #ffffff; 144 | } 145 | 146 | .dropdown-submenu.pull-left { 147 | float: none; 148 | } 149 | 150 | .dropdown-submenu.pull-left>.dropdown-menu { 151 | left: -100%; 152 | margin-left: 10px; 153 | border-radius: 6px 0 6px 6px; 154 | } 155 | 156 | /* Sidebar --------------------------*/ 157 | 158 | #pkgdown-sidebar { 159 | margin-top: 30px; 160 | position: -webkit-sticky; 161 | position: sticky; 162 | top: 70px; 163 | } 164 | 165 | #pkgdown-sidebar h2 { 166 | font-size: 1.5em; 167 | margin-top: 1em; 168 | } 169 | 170 | #pkgdown-sidebar h2:first-child { 171 | margin-top: 0; 172 | } 173 | 174 | #pkgdown-sidebar .list-unstyled li { 175 | margin-bottom: 0.5em; 176 | } 177 | 178 | /* bootstrap-toc tweaks ------------------------------------------------------*/ 179 | 180 | /* All levels of nav */ 181 | 182 | nav[data-toggle='toc'] .nav > li > a { 183 | padding: 4px 20px 4px 6px; 184 | font-size: 1.5rem; 185 | font-weight: 400; 186 | color: inherit; 187 | } 188 | 189 | nav[data-toggle='toc'] .nav > li > a:hover, 190 | nav[data-toggle='toc'] .nav > li > a:focus { 191 | padding-left: 5px; 192 | color: inherit; 193 | border-left: 1px solid #878787; 194 | } 195 | 196 | nav[data-toggle='toc'] .nav > .active > a, 197 | nav[data-toggle='toc'] .nav > .active:hover > a, 198 | nav[data-toggle='toc'] .nav > .active:focus > a { 199 | padding-left: 5px; 200 | font-size: 1.5rem; 201 | font-weight: 400; 202 | color: inherit; 203 | border-left: 2px solid #878787; 204 | } 205 | 206 | /* Nav: second level (shown on .active) */ 207 | 208 | nav[data-toggle='toc'] .nav .nav { 209 | display: none; /* Hide by default, but at >768px, show it */ 210 | padding-bottom: 10px; 211 | } 212 | 213 | nav[data-toggle='toc'] .nav .nav > li > a { 214 | padding-left: 16px; 215 | font-size: 1.35rem; 216 | } 217 | 218 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 219 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 220 | padding-left: 15px; 221 | } 222 | 223 | nav[data-toggle='toc'] .nav .nav > .active > a, 224 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 225 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 226 | padding-left: 15px; 227 | font-weight: 500; 228 | font-size: 1.35rem; 229 | } 230 | 231 | /* orcid ------------------------------------------------------------------- */ 232 | 233 | .orcid { 234 | font-size: 16px; 235 | color: #A6CE39; 236 | /* margins are required by official ORCID trademark and display guidelines */ 237 | margin-left:4px; 238 | margin-right:4px; 239 | vertical-align: middle; 240 | } 241 | 242 | /* Reference index & topics ----------------------------------------------- */ 243 | 244 | .ref-index th {font-weight: normal;} 245 | 246 | .ref-index td {vertical-align: top; min-width: 100px} 247 | .ref-index .icon {width: 40px;} 248 | .ref-index .alias {width: 40%;} 249 | .ref-index-icons .alias {width: calc(40% - 40px);} 250 | .ref-index .title {width: 60%;} 251 | 252 | .ref-arguments th {text-align: right; padding-right: 10px;} 253 | .ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} 254 | .ref-arguments .name {width: 20%;} 255 | .ref-arguments .desc {width: 80%;} 256 | 257 | /* Nice scrolling for wide elements --------------------------------------- */ 258 | 259 | table { 260 | display: block; 261 | overflow: auto; 262 | } 263 | 264 | /* Syntax highlighting ---------------------------------------------------- */ 265 | 266 | pre, code, pre code { 267 | background-color: #f8f8f8; 268 | color: #333; 269 | } 270 | pre, pre code { 271 | white-space: pre-wrap; 272 | word-break: break-all; 273 | overflow-wrap: break-word; 274 | } 275 | 276 | pre { 277 | border: 1px solid #eee; 278 | } 279 | 280 | pre .img, pre .r-plt { 281 | margin: 5px 0; 282 | } 283 | 284 | pre .img img, pre .r-plt img { 285 | background-color: #fff; 286 | } 287 | 288 | code a, pre a { 289 | color: #375f84; 290 | } 291 | 292 | a.sourceLine:hover { 293 | text-decoration: none; 294 | } 295 | 296 | .fl {color: #1514b5;} 297 | .fu {color: #000000;} /* function */ 298 | .ch,.st {color: #036a07;} /* string */ 299 | .kw {color: #264D66;} /* keyword */ 300 | .co {color: #888888;} /* comment */ 301 | 302 | .error {font-weight: bolder;} 303 | .warning {font-weight: bolder;} 304 | 305 | /* Clipboard --------------------------*/ 306 | 307 | .hasCopyButton { 308 | position: relative; 309 | } 310 | 311 | .btn-copy-ex { 312 | position: absolute; 313 | right: 0; 314 | top: 0; 315 | visibility: hidden; 316 | } 317 | 318 | .hasCopyButton:hover button.btn-copy-ex { 319 | visibility: visible; 320 | } 321 | 322 | /* headroom.js ------------------------ */ 323 | 324 | .headroom { 325 | will-change: transform; 326 | transition: transform 200ms linear; 327 | } 328 | .headroom--pinned { 329 | transform: translateY(0%); 330 | } 331 | .headroom--unpinned { 332 | transform: translateY(-100%); 333 | } 334 | 335 | /* mark.js ----------------------------*/ 336 | 337 | mark { 338 | background-color: rgba(255, 255, 51, 0.5); 339 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 340 | padding: 1px; 341 | } 342 | 343 | /* vertical spacing after htmlwidgets */ 344 | .html-widget { 345 | margin-bottom: 10px; 346 | } 347 | 348 | /* fontawesome ------------------------ */ 349 | 350 | .fab { 351 | font-family: "Font Awesome 5 Brands" !important; 352 | } 353 | 354 | /* don't display links in code chunks when printing */ 355 | /* source: https://stackoverflow.com/a/10781533 */ 356 | @media print { 357 | code a:link:after, code a:visited:after { 358 | content: ""; 359 | } 360 | } 361 | 362 | /* Section anchors --------------------------------- 363 | Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 364 | */ 365 | 366 | div.csl-bib-body { } 367 | div.csl-entry { 368 | clear: both; 369 | } 370 | .hanging-indent div.csl-entry { 371 | margin-left:2em; 372 | text-indent:-2em; 373 | } 374 | div.csl-left-margin { 375 | min-width:2em; 376 | float:left; 377 | } 378 | div.csl-right-inline { 379 | margin-left:2em; 380 | padding-left:1em; 381 | } 382 | div.csl-indent { 383 | margin-left: 2em; 384 | } 385 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('nav.navbar').headroom(); 6 | 7 | Toc.init({ 8 | $nav: $("#toc"), 9 | $scope: $("main h2, main h3, main h4, main h5, main h6") 10 | }); 11 | 12 | if ($('#toc').length) { 13 | $('body').scrollspy({ 14 | target: '#toc', 15 | offset: $("nav.navbar").outerHeight() + 1 16 | }); 17 | } 18 | 19 | // Activate popovers 20 | $('[data-bs-toggle="popover"]').popover({ 21 | container: 'body', 22 | html: true, 23 | trigger: 'focus', 24 | placement: "top", 25 | sanitize: false, 26 | }); 27 | 28 | $('[data-bs-toggle="tooltip"]').tooltip(); 29 | 30 | /* Clipboard --------------------------*/ 31 | 32 | function changeTooltipMessage(element, msg) { 33 | var tooltipOriginalTitle=element.getAttribute('data-bs-original-title'); 34 | element.setAttribute('data-bs-original-title', msg); 35 | $(element).tooltip('show'); 36 | element.setAttribute('data-bs-original-title', tooltipOriginalTitle); 37 | } 38 | 39 | if(ClipboardJS.isSupported()) { 40 | $(document).ready(function() { 41 | var copyButton = ""; 42 | 43 | $("div.sourceCode").addClass("hasCopyButton"); 44 | 45 | // Insert copy buttons: 46 | $(copyButton).prependTo(".hasCopyButton"); 47 | 48 | // Initialize tooltips: 49 | $('.btn-copy-ex').tooltip({container: 'body'}); 50 | 51 | // Initialize clipboard: 52 | var clipboard = new ClipboardJS('[data-clipboard-copy]', { 53 | text: function(trigger) { 54 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 55 | } 56 | }); 57 | 58 | clipboard.on('success', function(e) { 59 | changeTooltipMessage(e.trigger, 'Copied!'); 60 | e.clearSelection(); 61 | }); 62 | 63 | clipboard.on('error', function(e) { 64 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 65 | }); 66 | 67 | }); 68 | } 69 | 70 | /* Search marking --------------------------*/ 71 | var url = new URL(window.location.href); 72 | var toMark = url.searchParams.get("q"); 73 | var mark = new Mark("main#main"); 74 | if (toMark) { 75 | mark.mark(toMark, { 76 | accuracy: { 77 | value: "complementary", 78 | limiters: [",", ".", ":", "/"], 79 | } 80 | }); 81 | } 82 | 83 | /* Search --------------------------*/ 84 | /* Adapted from https://github.com/rstudio/bookdown/blob/2d692ba4b61f1e466c92e78fd712b0ab08c11d31/inst/resources/bs4_book/bs4_book.js#L25 */ 85 | // Initialise search index on focus 86 | var fuse; 87 | $("#search-input").focus(async function(e) { 88 | if (fuse) { 89 | return; 90 | } 91 | 92 | $(e.target).addClass("loading"); 93 | var response = await fetch($("#search-input").data("search-index")); 94 | var data = await response.json(); 95 | 96 | var options = { 97 | keys: ["what", "text", "code"], 98 | ignoreLocation: true, 99 | threshold: 0.1, 100 | includeMatches: true, 101 | includeScore: true, 102 | }; 103 | fuse = new Fuse(data, options); 104 | 105 | $(e.target).removeClass("loading"); 106 | }); 107 | 108 | // Use algolia autocomplete 109 | var options = { 110 | autoselect: true, 111 | debug: true, 112 | hint: false, 113 | minLength: 2, 114 | }; 115 | var q; 116 | async function searchFuse(query, callback) { 117 | await fuse; 118 | 119 | var items; 120 | if (!fuse) { 121 | items = []; 122 | } else { 123 | q = query; 124 | var results = fuse.search(query, { limit: 20 }); 125 | items = results 126 | .filter((x) => x.score <= 0.75) 127 | .map((x) => x.item); 128 | if (items.length === 0) { 129 | items = [{dir:"Sorry 😿",previous_headings:"",title:"No results found.",what:"No results found.",path:window.location.href}]; 130 | } 131 | } 132 | callback(items); 133 | } 134 | $("#search-input").autocomplete(options, [ 135 | { 136 | name: "content", 137 | source: searchFuse, 138 | templates: { 139 | suggestion: (s) => { 140 | if (s.title == s.what) { 141 | return `${s.dir} >
    ${s.title}
    `; 142 | } else if (s.previous_headings == "") { 143 | return `${s.dir} >
    ${s.title}
    > ${s.what}`; 144 | } else { 145 | return `${s.dir} >
    ${s.title}
    > ${s.previous_headings} > ${s.what}`; 146 | } 147 | }, 148 | }, 149 | }, 150 | ]).on('autocomplete:selected', function(event, s) { 151 | window.location.href = s.path + "?q=" + q + "#" + s.id; 152 | }); 153 | }); 154 | })(window.jQuery || window.$) 155 | 156 | document.addEventListener('keydown', function(event) { 157 | // Check if the pressed key is '/' 158 | if (event.key === '/') { 159 | event.preventDefault(); // Prevent any default action associated with the '/' key 160 | document.getElementById('search-input').focus(); // Set focus to the search input 161 | } 162 | }); 163 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.2.1 2 | pkgdown: 2.1.1 3 | pkgdown_sha: ~ 4 | articles: {} 5 | last_built: 2024-10-29T11:39Z 6 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/cran4linux/rspm/e06e2ed34f5bfb89302f087d0e1dd8ac24b00a4f/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | Package index • rspm 3 | Skip to contents 4 | 5 | 6 |
    28 |
    29 |
    33 | 34 |
    35 |

    All functions

    36 | 37 | 38 | 39 | 40 |
    41 | 42 | 43 | 44 | 45 |
    46 | 47 | enable() disable() 48 | 49 |
    50 |
    Enable/Disable RStudio Package Manager
    51 |
    52 | 53 | install_sysreqs() missing_sysreqs() 54 | 55 |
    56 |
    Manage System Requirements
    57 |
    58 | 59 | renv_init() 60 | 61 |
    62 |
    Initialize an renv Project
    63 |
    64 | 65 | rspm rspm-package 66 | 67 |
    68 |
    rspm: RStudio Package Manager
    69 |
    70 |
    71 | 72 | 73 |
    76 | 77 | 80 | 81 |
    82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | -------------------------------------------------------------------------------- /docs/reference/integration.html: -------------------------------------------------------------------------------- 1 | 2 | Enable/Disable RStudio Package Manager — integration • rspm 11 | Skip to contents 12 | 13 | 14 |
    36 |
    37 |
    43 | 44 |
    45 |

    Functions to enable or disable RSPM repos as well as the integration of 46 | install_sysreqs into install.packages and 47 | update.packages. When enabled, binary packages are installed from 48 | RSPM if available, and system requirements are transparently resolved and 49 | installed without root privileges.

    50 |
    51 | 52 |
    53 |

    Usage

    54 |
    enable()
     55 | 
     56 | disable()
    57 |
    58 | 59 |
    60 |

    Value

    61 |

    No return value, called for side effects.

    62 |
    63 |
    64 |

    Details

    65 |

    To enable rspm permanently, include the following into your 66 | .Rprofile:

    67 |

    suppressMessages(rspm::enable())

    68 |
    69 |
    70 |

    See also

    71 |

    renv_init for renv projects.

    72 |
    73 | 74 |
    75 |

    Examples

    76 |
    if (FALSE) { # \dontrun{
     77 | # install 'units' and all its dependencies from the system repos
     78 | rspm::enable()
     79 | install.packages("units")
     80 | 
     81 | # install packages again from CRAN
     82 | rspm::disable()
     83 | install.packages("errors")
     84 | } # }
     85 | 
     86 | 
    87 |
    88 |
    90 | 91 | 92 |
    95 | 96 | 99 | 100 |
    101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/reference/manager.html: -------------------------------------------------------------------------------- 1 | 2 | Manage System Requirements — manager • rspm 7 | Skip to contents 8 | 9 | 10 |
    32 |
    33 |
    39 | 40 |
    41 |

    Detect, install and configure system requirements. This function is 42 | automatically called when the package is enabled via enable. 43 | It can also be called manually at any time to update the system requirements.

    44 |
    45 | 46 |
    47 |

    Usage

    48 |
    install_sysreqs()
    49 | 
    50 | missing_sysreqs()
    51 |
    52 | 53 |
    54 |

    Value

    55 |

    install_sysreqs: No return value, called for side effects.

    56 |

    missing_sysreqs: A list of missing libraries, for debugging.

    57 |
    58 | 59 |
    60 |

    Examples

    61 |
    if (FALSE) { # \dontrun{
    62 | # install 'units' without enabling the integration
    63 | install.packages("units")
    64 | # then trigger the installation of system requirements manually
    65 | rspm::install_sysreqs()
    66 | } # }
    67 | 
    68 | 
    69 |
    70 |
    72 | 73 | 74 |
    77 | 78 | 81 | 82 |
    83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /docs/reference/renv_init.html: -------------------------------------------------------------------------------- 1 | 2 | Initialize an renv Project — renv_init • rspm 9 | Skip to contents 10 | 11 | 12 |
    34 |
    35 |
    41 | 42 |
    43 |

    Substitutes renv::init() to initialize a new renv project with 44 | rspm enabled. This function sets the appropriate infrastructure to 45 | activate the integration. Then, packages can be installed normally via 46 | install.packages and update.packages.

    47 |
    48 | 49 |
    50 |

    Usage

    51 |
    renv_init(...)
    52 |
    53 | 54 |
    55 |

    Arguments

    56 | 57 | 58 |
    ...
    59 |

    Arguments to be passed to renv::init().

    60 | 61 |
    62 |
    63 |

    Value

    64 |

    The project directory, invisibly. This function is called for its 65 | side effects.

    66 |
    67 |
    68 |

    Details

    69 |

    Note that, if renv::install or renv::update are called 70 | directly, then rspm::install_sysreqs() needs to be called manually.

    71 |
    72 | 73 |
    74 |

    Examples

    75 |
    if (FALSE) { # \dontrun{
     76 | # initialize a new project (with an empty R library)
     77 | rspm::renv_init()
     78 | 
     79 | # install 'units' and all its dependencies from the system repos
     80 | install.packages("units")
     81 | 
     82 | # install a specific version and install dependencies manually
     83 | renv::install("units@0.8-0")
     84 | rspm::install_sysreqs()
     85 | } # }
     86 | 
     87 | 
    88 |
    89 |
    91 | 92 | 93 |
    96 | 97 | 100 | 101 |
    102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | -------------------------------------------------------------------------------- /docs/reference/rspm-package.html: -------------------------------------------------------------------------------- 1 | 2 | rspm: RStudio Package Manager — rspm-package • rspm 15 | Skip to contents 16 | 17 | 18 |
    40 |
    41 |
    47 | 48 |
    49 |

    Enables binary package installations on Linux distributions. 50 | Provides access to RStudio public repositories at 51 | https://packagemanager.posit.co, and transparent management of 52 | system requirements without administrative privileges. Currently supported 53 | distributions are CentOS / RHEL 7-9, and several RHEL derivatives 54 | (Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux), 55 | openSUSE / SLES 15.4-5, Debian 11-12, and Ubuntu LTS 20-22.

    56 |
    57 | 58 | 59 |
    60 |

    References

    61 |

    https://cran4linux.github.io/rspm/

    62 |
    63 |
    64 |

    See also

    65 | 66 |
    67 |
    68 |

    Author

    69 |

    Iñaki Ucar

    70 |
    71 | 72 |
    74 | 75 | 76 |
    79 | 80 | 83 | 84 |
    85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /docs/search.json: -------------------------------------------------------------------------------- 1 | [{"path":"/authors.html","id":null,"dir":"","previous_headings":"","what":"Authors","title":"Authors and Citation","text":"Iñaki Ucar. Author, copyright holder, maintainer. R Core Team. Author, copyright holder.","code":""},{"path":"/authors.html","id":"citation","dir":"","previous_headings":"","what":"Citation","title":"Authors and Citation","text":"Ucar , R Core Team (2024). rspm: 'RStudio' Package Manager. R package version 0.6.1, https://cran4linux.github.io/rspm/.","code":"@Manual{, title = {rspm: 'RStudio' Package Manager}, author = {Iñaki Ucar and {R Core Team}}, year = {2024}, note = {R package version 0.6.1}, url = {https://cran4linux.github.io/rspm/}, }"},{"path":[]},{"path":"/index.html","id":"key-features","dir":"","previous_headings":"","what":"Key features","title":"RStudio Package Manager","text":"Connects RStudio Public Package Manager provide fast binary installations R packages Linux. Complete coverage CRAN BioConductor packages. Full integration system package manager resolve, download configure system requirements automagically without leaving R console. Fully user mode, root privileges required. Support CentOS / RHEL 7, 8 9. Support RHEL derivatives: Rocky Linux 8-9, AlmaLinux 8-9, Oracle Linux 7-9, Amazon Linux 2-2023. Support openSUSE / SLES 15.4 15.5. Support Debian 11 12 (requires apt-file). Support Ubuntu 20.04 22.04 (requires apt-file). R packages system dependencies installed user home. lightning-fast system-based installations (advantages, multitenancy, reversibility automatic updates, still without root privileges), see bspm package projects cran2copr Fedora r2u Ubuntu.","code":""},{"path":"/index.html","id":"demo","dir":"","previous_headings":"","what":"Demo","title":"RStudio Package Manager","text":"enable rspm trigger binary installation units package. , can see UDUNITS-2 dependency detected, downloaded configured.","code":""},{"path":"/index.html","id":"installation-and-usage","dir":"","previous_headings":"","what":"Installation and usage","title":"RStudio Package Manager","text":"can install directly GitHub using remotes package:","code":"remotes::install_github(\"cran4linux/rspm\")"},{"path":"/index.html","id":"basic-usage","dir":"","previous_headings":"Installation and usage","what":"Basic usage","title":"RStudio Package Manager","text":"just need enable session, can install update packages normally via install.packages update.packages. Packages system requirements, like one , scanned configured automatically. Typically, everything just work without action. something gets misconfigured reason, possible manually trigger reconfiguration following command: enable default sessions, put following .Rprofile:","code":"rspm::enable() install.packages(\"units\") rspm::install_sysreqs() rspm::enable() # wrap it in suppressMessages() to suppress the initial message"},{"path":"/index.html","id":"renv-projects","dir":"","previous_headings":"Installation and usage","what":"{renv} projects","title":"RStudio Package Manager","text":"initialize renv project rspm support, just run following: command runs renv::init() installs infrastructure required integration install.packages update.packages. Note , renv::install renv::update called directly, rspm::install_sysreqs() needs called manually.","code":"rspm::renv_init()"},{"path":"/index.html","id":"docker-workflows","dir":"","previous_headings":"Installation and usage","what":"Docker workflows","title":"RStudio Package Manager","text":"Docker containers, system requirements can installed directly root. Therefore, enough include Dockerfile following line right renv::restore():","code":"RUN Rscript -e 'renv::install(\"rspm\"); rspm::install_sysreqs()'"},{"path":"/index.html","id":"technical-details","dir":"","previous_headings":"","what":"Technical details","title":"RStudio Package Manager","text":"Since always, Linux R users struggling source installations manual management build dependencies. Several projects years tried lessen pain building repositories binaries complement scale offer various distributions. See e.g. c2d4u.team/c2d4u4.0+ PPA repo Ubuntu , recently, autoCRAN OBS repo OpenSUSE, iucar/cran Copr repo Fedora, ArchRPkgs repo Arch r2u repo Ubuntu. tightly integrated can fully managed without leaving R console thanks bspm package. See paper detailed review. hand, RStudio recently took complementary approach building binaries—various distributions, R versions architectures—serving via CRAN mirror, also called RStudio Public Package Manager (RSPM). contrast previous solutions, method allows user install binary packages user packages home directory (virtually anywhere), instead system packages. main issue user still manage run-time system requirements (.e., shared libraries required packages work), method produces installations fundamentally broken. fill gap, package provides easy setup RSPM, also monitors scans every installation missing system requirements, automatically downloads, installs configures , relieving user task. done following complementary philosophy: everything installed user packages home directory. specifically, package uses path ~/.local/share/R/rspm . main technical issue libraries search pre-configured places belong system (/usr/lib), thus need mechanism feed new user-hosted library paths R packages, hopefully without restarting R managing environment variables. achieved automatically updating RPATH every .binary user R packages. RPATH optional entry lives header ELF executables shared libraries, used dynamic linker primary search path exists. Therefore, perfect mechanism task, can applied dynamically new installations made, without requiring special privilege.","code":""},{"path":"/index.html","id":"support","dir":"","previous_headings":"","what":"Support","title":"RStudio Package Manager","text":"find bug ’d like request support distributions (importantly, must supported RStudio), please file issues GitHub issue tracker. Note though quirks may expected: library found. means library version system different RStudio package built. likely happen derivatives (e.g. Amazon Linux) drift away parent. package installed source. means RStudio binary version package. nothing can rspm either case, please file issues . Unfortunately, best can install development packages required library force source installation (.e. business usual).","code":""},{"path":"/index.html","id":"disclaimer","dir":"","previous_headings":"","what":"Disclaimer","title":"RStudio Package Manager","text":"RStudio registered trademark Posit. software provides access public repository maintained RStudio provided open-source community free, association .","code":""},{"path":"/reference/integration.html","id":null,"dir":"Reference","previous_headings":"","what":"Enable/Disable RStudio Package Manager — integration","title":"Enable/Disable RStudio Package Manager — integration","text":"Functions enable disable RSPM repos well integration install_sysreqs install.packages update.packages. enabled, binary packages installed RSPM available, system requirements transparently resolved installed without root privileges.","code":""},{"path":"/reference/integration.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Enable/Disable RStudio Package Manager — integration","text":"","code":"enable() disable()"},{"path":"/reference/integration.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Enable/Disable RStudio Package Manager — integration","text":"return value, called side effects.","code":""},{"path":"/reference/integration.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Enable/Disable RStudio Package Manager — integration","text":"enable rspm permanently, include following .Rprofile: suppressMessages(rspm::enable())","code":""},{"path":[]},{"path":"/reference/integration.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Enable/Disable RStudio Package Manager — integration","text":"","code":"if (FALSE) { # \\dontrun{ # install 'units' and all its dependencies from the system repos rspm::enable() install.packages(\"units\") # install packages again from CRAN rspm::disable() install.packages(\"errors\") } # }"},{"path":"/reference/manager.html","id":null,"dir":"Reference","previous_headings":"","what":"Manage System Requirements — manager","title":"Manage System Requirements — manager","text":"Detect, install configure system requirements. function automatically called package enabled via enable. can also called manually time update system requirements.","code":""},{"path":"/reference/manager.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Manage System Requirements — manager","text":"","code":"install_sysreqs() missing_sysreqs()"},{"path":"/reference/manager.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Manage System Requirements — manager","text":"install_sysreqs: return value, called side effects. missing_sysreqs: list missing libraries, debugging.","code":""},{"path":"/reference/manager.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Manage System Requirements — manager","text":"","code":"if (FALSE) { # \\dontrun{ # install 'units' without enabling the integration install.packages(\"units\") # then trigger the installation of system requirements manually rspm::install_sysreqs() } # }"},{"path":"/reference/renv_init.html","id":null,"dir":"Reference","previous_headings":"","what":"Initialize an renv Project — renv_init","title":"Initialize an renv Project — renv_init","text":"Substitutes renv::init() initialize new renv project rspm enabled. function sets appropriate infrastructure activate integration. , packages can installed normally via install.packages update.packages.","code":""},{"path":"/reference/renv_init.html","id":"ref-usage","dir":"Reference","previous_headings":"","what":"Usage","title":"Initialize an renv Project — renv_init","text":"","code":"renv_init(...)"},{"path":"/reference/renv_init.html","id":"arguments","dir":"Reference","previous_headings":"","what":"Arguments","title":"Initialize an renv Project — renv_init","text":"... Arguments passed renv::init().","code":""},{"path":"/reference/renv_init.html","id":"value","dir":"Reference","previous_headings":"","what":"Value","title":"Initialize an renv Project — renv_init","text":"project directory, invisibly. function called side effects.","code":""},{"path":"/reference/renv_init.html","id":"details","dir":"Reference","previous_headings":"","what":"Details","title":"Initialize an renv Project — renv_init","text":"Note , renv::install renv::update called directly, rspm::install_sysreqs() needs called manually.","code":""},{"path":"/reference/renv_init.html","id":"ref-examples","dir":"Reference","previous_headings":"","what":"Examples","title":"Initialize an renv Project — renv_init","text":"","code":"if (FALSE) { # \\dontrun{ # initialize a new project (with an empty R library) rspm::renv_init() # install 'units' and all its dependencies from the system repos install.packages(\"units\") # install a specific version and install dependencies manually renv::install(\"units@0.8-0\") rspm::install_sysreqs() } # }"},{"path":"/reference/rspm-package.html","id":null,"dir":"Reference","previous_headings":"","what":"rspm: RStudio Package Manager — rspm-package","title":"rspm: RStudio Package Manager — rspm-package","text":"Enables binary package installations Linux distributions. Provides access RStudio public repositories https://packagemanager.posit.co, transparent management system requirements without administrative privileges. Currently supported distributions CentOS / RHEL 7-9, several RHEL derivatives (Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux), openSUSE / SLES 15.4-5, Debian 11-12, Ubuntu LTS 20-22.","code":""},{"path":"/reference/rspm-package.html","id":"references","dir":"Reference","previous_headings":"","what":"References","title":"rspm: RStudio Package Manager — rspm-package","text":"https://cran4linux.github.io/rspm/","code":""},{"path":[]},{"path":"/reference/rspm-package.html","id":"author","dir":"Reference","previous_headings":"","what":"Author","title":"rspm: RStudio Package Manager — rspm-package","text":"Iñaki Ucar","code":""},{"path":"/news/index.html","id":"rspm-061","dir":"Changelog","previous_headings":"","what":"rspm 0.6.1","title":"rspm 0.6.1","text":"Fix regexp escaping apt-file calls Debian-like systems (#32).","code":""},{"path":"/news/index.html","id":"rspm-060","dir":"Changelog","previous_headings":"","what":"rspm 0.6.0","title":"rspm 0.6.0","text":"CRAN release: 2024-06-21 Add support Pop!_OS (#26 addressing #25). Add support Amazon Linux 2023 (#28 addressing #27).","code":""},{"path":"/news/index.html","id":"rspm-053","dir":"Changelog","previous_headings":"","what":"rspm 0.5.3","title":"rspm 0.5.3","text":"CRAN release: 2024-05-20 Drop test failure avoid test failures CRAN.","code":""},{"path":"/news/index.html","id":"rspm-052","dir":"Changelog","previous_headings":"","what":"rspm 0.5.2","title":"rspm 0.5.2","text":"CRAN release: 2024-05-04 Don’t use expect_match now avoid test failures CRAN.","code":""},{"path":"/news/index.html","id":"rspm-051","dir":"Changelog","previous_headings":"","what":"rspm 0.5.1","title":"rspm 0.5.1","text":"CRAN release: 2024-05-01 Export missing_sysreqs() debugging purposes. Fix call tinytest function namespace. Update supported systems.","code":""},{"path":"/news/index.html","id":"rspm-050","dir":"Changelog","previous_headings":"","what":"rspm 0.5.0","title":"rspm 0.5.0","text":"CRAN release: 2023-11-25 Move cran4linux org GitHub, update URLs. Add support Debian 11 12 (#21).","code":""},{"path":"/news/index.html","id":"rspm-040","dir":"Changelog","previous_headings":"","what":"rspm 0.4.0","title":"rspm 0.4.0","text":"CRAN release: 2023-04-14 Implement root mode improve Docker workflows (#20 addressing #17). Internal refactoring improve extensibility (part #20). Remove libs’ arch subfolder Ubuntu fix relative path issues (#19).","code":""},{"path":"/news/index.html","id":"rspm-031","dir":"Changelog","previous_headings":"","what":"rspm 0.3.1","title":"rspm 0.3.1","text":"CRAN release: 2023-03-26 Fix version detection CentOS (#18 addressing #16). Fix unpacking new rpm versions (part #18).","code":""},{"path":"/news/index.html","id":"rspm-030","dir":"Changelog","previous_headings":"","what":"rspm 0.3.0","title":"rspm 0.3.0","text":"CRAN release: 2022-12-22 Add support CentOS/RHEL 9 derivatives (#13 addressing #12).","code":""},{"path":"/news/index.html","id":"rspm-023","dir":"Changelog","previous_headings":"","what":"rspm 0.2.3","title":"rspm 0.2.3","text":"CRAN release: 2022-11-21 Fix non-root unpacking old rpm/dpkg versions (#11 addressing #9, #10).","code":""},{"path":"/news/index.html","id":"rspm-022","dir":"Changelog","previous_headings":"","what":"rspm 0.2.2","title":"rspm 0.2.2","text":"CRAN release: 2022-09-15 Fix root permission requirement yum-based systems (#9). Clean empty user directory.","code":""},{"path":"/news/index.html","id":"rspm-021","dir":"Changelog","previous_headings":"","what":"rspm 0.2.1","title":"rspm 0.2.1","text":"CRAN release: 2022-08-16 Fix .Rprofile enabling error (#8). fixes requested CRAN.","code":""},{"path":"/news/index.html","id":"rspm-020","dir":"Changelog","previous_headings":"","what":"rspm 0.2.0","title":"rspm 0.2.0","text":"Add support CentOS 7, RHEL 7 8 (#1). Add support several RHEL derivatives: Rocky Linux 8, AlmaLinux 8, Oracle Linux 7 8, Amazon Linux 2 (#2). Add support openSUSE / SLES 15.3 (#3). Add support renv projects via rspm::renv_init() (#5 closing #4).","code":""},{"path":"/news/index.html","id":"rspm-010","dir":"Changelog","previous_headings":"","what":"rspm 0.1.0","title":"rspm 0.1.0","text":"Initial release, support CentOS 8 Ubuntu 18.04, 20.04 22.04.","code":""}] 2 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | /404.html 3 | /LICENSE-text.html 4 | /authors.html 5 | /index.html 6 | /news/index.html 7 | /reference/index.html 8 | /reference/integration.html 9 | /reference/manager.html 10 | /reference/renv_init.html 11 | /reference/rspm-package.html 12 | 13 | 14 | -------------------------------------------------------------------------------- /inst/COPYRIGHTS: -------------------------------------------------------------------------------- 1 | Files: * 2 | Copyright: see file LICENSE 3 | License: MIT 4 | 5 | File: R/userdir.R 6 | Copyright: 2020 R Core Team 7 | License: GPL-2+ 8 | -------------------------------------------------------------------------------- /inst/resources/activate.R: -------------------------------------------------------------------------------- 1 | local({ 2 | try_install_if_not_available <- function(pkg, source) { 3 | if (!requireNamespace(pkg, quietly=TRUE)) 4 | try(renv::install(source), silent=TRUE) 5 | } 6 | 7 | try_install_if_not_available("rspm@VERSION") 8 | try_install_if_not_available("cran4linux/rspm@VERSION") 9 | try_install_if_not_available("cran4linux/rspm") 10 | 11 | try(rspm::enable(), silent=TRUE) 12 | }) 13 | -------------------------------------------------------------------------------- /inst/tinytest/test_integration_ci.R: -------------------------------------------------------------------------------- 1 | if (!at_home()) 2 | exit_file("not in a CI environment") 3 | 4 | supported <- c("debian", "ubuntu", "pop", "centos", "rocky", "almalinux", 5 | "ol", "rhel", "amzn", "sles", "opensuse") 6 | 7 | expect_silent(os <- rspm:::os()) 8 | expect_inherits(os, "list") 9 | expect_true(os$id %in% supported) 10 | message(paste("code:", os$code)) 11 | 12 | # user agent 13 | expect_true(grepl(getRversion(), getOption("HTTPUserAgent"))) 14 | 15 | # user dir 16 | expect_true(dir.exists(rspm:::user_dir())) 17 | 18 | # tracing and repo setting 19 | untrace(utils::install.packages) 20 | expect_false(inherits(utils::install.packages, "functionWithTrace")) 21 | 22 | enable() 23 | expect_true(inherits(utils::install.packages, "functionWithTrace")) 24 | expect_true("RSPM" %in% names(getOption("repos"))) 25 | expect_true(grepl(rspm:::os()$code, getOption("repos")["RSPM"])) 26 | 27 | tracer <- paste(body(utils::install.packages), collapse="") 28 | expect_true(grepl("rspm::install_sysreqs()", tracer, fixed=TRUE)) 29 | 30 | disable() 31 | expect_false(inherits(utils::install.packages, "functionWithTrace")) 32 | expect_false("RSPM" %in% names(getOption("repos"))) 33 | -------------------------------------------------------------------------------- /inst/tinytest/test_manager_ci.R: -------------------------------------------------------------------------------- 1 | if (!at_home()) 2 | exit_file("not in a CI environment") 3 | 4 | # requirements 5 | reqs <- rspm:::check_requirements() 6 | expect_true(all(reqs != "")) 7 | 8 | # installation and loading 9 | expect_false(requireNamespace("units", quietly=TRUE)) 10 | 11 | enable() 12 | install.packages("units") 13 | expect_true(requireNamespace("units", quietly=TRUE)) 14 | 15 | # cleanup 16 | disable() 17 | remove.packages("units") 18 | -------------------------------------------------------------------------------- /inst/tinytest/test_renv.R: -------------------------------------------------------------------------------- 1 | if (!requireNamespace("renv", quietly=TRUE)) 2 | exit_file("renv not available for testing") 3 | 4 | # infrastructure 5 | dir.create(temp <- tempfile()) 6 | old <- setwd(temp) 7 | renv_init() 8 | 9 | expect_true(dir.exists(file.path(renv::paths$library(), "rspm"))) 10 | infra <- readLines(file.path(renv::project(), "renv/activate.R")) 11 | expect_true(any(grepl("rspm::enable()", infra))) 12 | 13 | # cleanup 14 | setwd(old) 15 | unlink(temp, recursive=TRUE, force=TRUE) 16 | -------------------------------------------------------------------------------- /man/integration.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/integration.R 3 | \name{integration} 4 | \alias{integration} 5 | \alias{enable} 6 | \alias{disable} 7 | \title{Enable/Disable RStudio Package Manager} 8 | \usage{ 9 | enable() 10 | 11 | disable() 12 | } 13 | \value{ 14 | No return value, called for side effects. 15 | } 16 | \description{ 17 | Functions to enable or disable RSPM repos as well as the integration of 18 | \code{\link{install_sysreqs}} into \code{install.packages} and 19 | \code{update.packages}. When enabled, binary packages are installed from 20 | RSPM if available, and system requirements are transparently resolved and 21 | installed without root privileges. 22 | } 23 | \details{ 24 | To enable \pkg{rspm} permanently, include the following into your 25 | \code{.Rprofile}: 26 | 27 | \code{suppressMessages(rspm::enable())} 28 | } 29 | \examples{ 30 | \dontrun{ 31 | # install 'units' and all its dependencies from the system repos 32 | rspm::enable() 33 | install.packages("units") 34 | 35 | # install packages again from CRAN 36 | rspm::disable() 37 | install.packages("errors") 38 | } 39 | 40 | } 41 | \seealso{ 42 | \code{\link{renv_init}} for \pkg{renv} projects. 43 | } 44 | -------------------------------------------------------------------------------- /man/manager.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/manager.R 3 | \name{manager} 4 | \alias{manager} 5 | \alias{install_sysreqs} 6 | \alias{missing_sysreqs} 7 | \title{Manage System Requirements} 8 | \usage{ 9 | install_sysreqs() 10 | 11 | missing_sysreqs() 12 | } 13 | \value{ 14 | \code{install_sysreqs}: No return value, called for side effects. 15 | 16 | \code{missing_sysreqs}: A list of missing libraries, for debugging. 17 | } 18 | \description{ 19 | Detect, install and configure system requirements. This function is 20 | automatically called when the package is enabled via \code{\link{enable}}. 21 | It can also be called manually at any time to update the system requirements. 22 | } 23 | \examples{ 24 | \dontrun{ 25 | # install 'units' without enabling the integration 26 | install.packages("units") 27 | # then trigger the installation of system requirements manually 28 | rspm::install_sysreqs() 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /man/renv_init.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/renv.R 3 | \name{renv_init} 4 | \alias{renv_init} 5 | \title{Initialize an \pkg{renv} Project} 6 | \usage{ 7 | renv_init(...) 8 | } 9 | \arguments{ 10 | \item{...}{Arguments to be passed to \code{renv::init()}.} 11 | } 12 | \value{ 13 | The project directory, invisibly. This function is called for its 14 | side effects. 15 | } 16 | \description{ 17 | Substitutes \code{renv::init()} to initialize a new \pkg{renv} project with 18 | \pkg{rspm} enabled. This function sets the appropriate infrastructure to 19 | activate the integration. Then, packages can be installed normally via 20 | \code{install.packages} and \code{update.packages}. 21 | } 22 | \details{ 23 | Note that, if \code{renv::install} or \code{renv::update} are called 24 | directly, then \code{rspm::install_sysreqs()} needs to be called manually. 25 | } 26 | \examples{ 27 | \dontrun{ 28 | # initialize a new project (with an empty R library) 29 | rspm::renv_init() 30 | 31 | # install 'units' and all its dependencies from the system repos 32 | install.packages("units") 33 | 34 | # install a specific version and install dependencies manually 35 | renv::install("units@0.8-0") 36 | rspm::install_sysreqs() 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /man/rspm-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/rspm.R 3 | \docType{package} 4 | \name{rspm-package} 5 | \alias{rspm} 6 | \alias{rspm-package} 7 | \title{\pkg{rspm}: RStudio Package Manager} 8 | \description{ 9 | Enables binary package installations on Linux distributions. 10 | Provides access to RStudio public repositories at 11 | \url{https://packagemanager.posit.co}, and transparent management of 12 | system requirements without administrative privileges. Currently supported 13 | distributions are CentOS / RHEL 7-9, and several RHEL derivatives 14 | (Rocky Linux, AlmaLinux, Oracle Linux, Amazon Linux), 15 | openSUSE / SLES 15.4-5, Debian 11-12, and Ubuntu LTS 20-22. 16 | } 17 | \references{ 18 | \url{https://cran4linux.github.io/rspm/} 19 | } 20 | \seealso{ 21 | \code{\link{manager}}, \code{\link{integration}} 22 | } 23 | \author{ 24 | Iñaki Ucar 25 | } 26 | -------------------------------------------------------------------------------- /rspm.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | AutoAppendNewline: Yes 16 | StripTrailingWhitespace: Yes 17 | 18 | BuildType: Package 19 | PackageUseDevtools: Yes 20 | PackageInstallArgs: --no-multiarch --with-keep.source 21 | -------------------------------------------------------------------------------- /tests/tinytest.R: -------------------------------------------------------------------------------- 1 | tmp_user_dir <- tempdir() 2 | Sys.setenv(RSPM_USER_DIR=tmp_user_dir) 3 | 4 | if (requireNamespace("tinytest", quietly=TRUE)) { 5 | home <- identical(Sys.getenv("CI"), "true") 6 | tinytest::test_package("rspm", at_home=home) 7 | } 8 | 9 | unlink(tmp_user_dir, recursive=TRUE, force=TRUE) 10 | --------------------------------------------------------------------------------