-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
load binary packages ahead of use #1275
Comments
I have a proof-of-concept which does not install a package into the primary library if it cannot be loaded, created by code-reading some of the package loading that R performs when installing from source. test_load_package.RR_runR <- function(cmd = NULL, Ropts = "", env = "",
stdout = TRUE, stderr = TRUE, stdin = NULL) {
# from tools/check.R; non-windows.
suppressWarnings(system2(file.path(R.home("bin"), "R"),
c(Ropts),
stdout, stderr, stdin, input = cmd, env = env))
}
setRlibs <- function() {
rlibs <- .libPaths()
rlibs <- paste(rlibs, collapse = .Platform$path.sep)
rlibs <- shQuote(rlibs)
c(paste0("R_LIBS=", rlibs),
"R_ENVIRON_USER=''",
"R_LIBS_USER='NULL'",
"R_LIBS_SITE='NULL'")
}
# This produces a (by default single) quoted string for use in a
# command sent to another R process.
# from tools::install.packages
quote_path <- function(path, quote = "'") {
path <- gsub("\\", "\\\\", path, fixed = TRUE)
path <- gsub(quote, paste0("\\", quote), path, fixed = TRUE)
paste0(quote, path, quote)
}
load_package <- function(pkg_name, tmplib) {
cat(paste0("trying to load: ", pkg_name, " from ", tmplib, "\n"))
# TODO: What versions of R contain this helper? Do we need our own?
cmd <- paste0("tools:::.test_load_package('", pkg_name, "', ", quote_path(tmplib), ")")
opts <- "--no-save --no-restore --no-echo"
env <- setRlibs()
out <- R_runR(cmd, Ropts = opts, env = env)
if (length(out)) {
cat(paste(c(out, ""), collapse = "\n"))
}
if (length(attr(out, "status"))) {
stop("loading failed", call. = FALSE, domain = NA)
}
cat("load successful.\n")
}
safe_install_impl <- function(pkg_name, lib) {
tmplib <- tempfile()
dir.create(tmplib)
on.exit(unlink(tmplib), add = TRUE)
cat(paste0("lib: ", lib, "\n"))
cat(paste0("tmplib: ", tmplib, "\n"))
old_paths <- .libPaths()
on.exit(.libPaths(old_paths), add = TRUE)
.libPaths(c(tmplib, lib, .libPaths()))
install.packages(pkg_name)
load_package(pkg_name, tmplib)
tmp_pkg_path <- file.path(tmplib, pkg_name)
pkg_path <- file.path(lib, pkg_name)
# FIXME: rename only works when within the same file-system.
# FIXME: handle when the target already exists.
cat(paste0("renaming: ", tmp_pkg_path, " => ", pkg_path, "\n"))
file.rename(tmp_pkg_path, pkg_path)
}
safe_install <- function(pkg_name, lib) {
tryCatch(
safe_install_impl(pkg_name, lib),
error = function(e) {
e$message <- paste0(
"Failed to install package ", pkg_name,
" into ", lib, ": ", e$message)
stop(e)
})
}
options(repos = c(CRAN = "https://packagemanager.rstudio.com/cran/__linux__/jammy/latest"))
# FIXME: Determine the target some other way.
lib <- .libPaths()[1L]
safe_install("coda", lib)
safe_install("rjags", lib) A similar FROM rstudio/r-base:4.3-jammy AS without-jags
RUN apt-get update && apt-get -y install pkg-config
FROM without-jags AS installation
COPY test_load_package.R /content/test_load_package.R
WORKDIR /content
RUN R -s -f test_load_package.R When run, the "install" errs, as we want: docker build \
--progress=plain \
--no-cache-filter installation \
-f Dockerfile.load-bad .
|
Re-tested this issue after the resolution of #1611 and the rjags load problem is still detected:
Used a slightly different FROM rstudio/r-base:4.3-jammy
RUN apt-get update && apt-get -y install pkg-config
ARG REPOSITORY=https://packagemanager.rstudio.com/cran/__linux__/jammy/latest
RUN mkdir /content && echo "library(rjags)" > /content/script.R
WORKDIR /content
RUN R -s -e "install.packages('remotes', repos=c(CRAN='${REPOSITORY}'))"
RUN R -s -e "remotes::install_github('rstudio/renv')"
RUN R -s -e "renv::init(bare = TRUE, repos=c(CRAN='${REPOSITORY}'))"
RUN R -s -e "renv::install('rjags', repos=c(CRAN='${REPOSITORY}'))"
RUN R -s -e "renv::snapshot()"
RUN R -s -f "script.R" |
Installing binary packages can often hide problems with an environment until runtime.
Take, for example, the
Dockerfile
:Building this image:
docker build \ --progress=plain \ --no-cache -f Dockerfile.renv .
This example errs because the
library
statement fails to load therjags
package (becausejags
is missing).This same situation can be seen with renv:
The error:
Part of this is rooted in how R handles package installation: The
R CMD install
command installs source and binary packages differently.R CMD install source/binary switch:
https://github.com/wch/r-source/blob/3a15e29d1b5a94e06b99cb9315c562fd8f71bc5b/src/library/tools/R/install.R#L419-L422
R CMD install package load test (inside do_install_source):
https://github.com/wch/r-source/blob/3a15e29d1b5a94e06b99cb9315c562fd8f71bc5b/src/library/tools/R/install.R#L1814-L1852
https://github.com/wch/r-source/blob/3a15e29d1b5a94e06b99cb9315c562fd8f71bc5b/src/library/tools/R/install.R#L1854-L1861
R CMD install do_install_binary does not attempt load:
https://github.com/wch/r-source/blob/3a15e29d1b5a94e06b99cb9315c562fd8f71bc5b/src/library/tools/R/install.R#L480-L502
When first added, only to the source path (and used library, not external process):
wch/r-source@7bc912f
Could renv attempt to validate binary packages by loading them before finalizing the installation? That would let us identify problems at restore-time rather than downstream when running the content.
The text was updated successfully, but these errors were encountered: