Skip to content

Commit

Permalink
init gains load argument (#1593)
Browse files Browse the repository at this point in the history
* init gains load argument

* ensure libpaths aren't mutated
  • Loading branch information
kevinushey authored Jul 26, 2023
1 parent 6eb3eda commit e8ece45
Show file tree
Hide file tree
Showing 11 changed files with 92 additions and 46 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@

# renv 1.1.0 (UNRELEASED)

* `renv::init()` gains the `load` argument, making it possible to initialize
a project without explicitly loading it. (#1583)

* renv now uses a lock when synchronizing installed packages with the cache.
This should help alleviate issues that can arise when multiple R processes
are installing and caching packges concurrently. (#1571)
Expand Down
9 changes: 7 additions & 2 deletions R/activate.R
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ activate <- function(project = NULL, profile = NULL) {
renv_activate_impl <- function(project,
profile,
version = NULL,
load = TRUE,
restart = TRUE)
{
# prepare renv infrastructure
Expand All @@ -85,8 +86,12 @@ renv_activate_impl <- function(project,
renv_rstudio_initialize(project)

# try to load the project
setwd(project)
load(project)
if (load) {
setwd(project)
load(project)
}

invisible(project)

}

Expand Down
6 changes: 6 additions & 0 deletions R/hydrate.R
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
#' @param library The \R library to be hydrated. When `NULL`, the active
#' library as reported by `.libPaths()` is used.
#'
#' @param repos The \R repositories to be used. If the project depends on any
#' \R packages which cannot be found within the user library paths, then
#' those packages will be installed from these repositories instead.
#'
#' @param update Boolean; should `hydrate()` attempt to update already-installed
#' packages if the requested package is already installed in the project
#' library? Set this to `"all"` if you'd like _all_ packages to be refreshed
Expand Down Expand Up @@ -57,6 +61,7 @@
hydrate <- function(packages = NULL,
...,
library = NULL,
repos = getOption("repos"),
update = FALSE,
sources = NULL,
prompt = interactive(),
Expand All @@ -71,6 +76,7 @@ hydrate <- function(packages = NULL,

renv_activate_prompt("hydrate", library, prompt, project)

renv_scope_options(repos = repos)
library <- renv_path_normalize(library %||% renv_libpaths_active())
packages <- packages %||% renv_hydrate_packages(project)

Expand Down
51 changes: 25 additions & 26 deletions R/imbue.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,22 @@ imbue <- function(project = NULL,

}

renv_imbue_impl <- function(project, version = NULL, force = FALSE) {

renv_imbue_impl <- function(project,
library = NULL,
version = NULL,
force = FALSE)
{
# don't imbue during tests unless explicitly requested
if (renv_tests_running() && !force)
return(NULL)

# resolve library path
library <- library %||% renv_paths_library(project = project)
ensure_directory(library)

# NULL version means imbue this version of renv
if (is.null(version))
return(renv_imbue_self(project))
return(renv_imbue_self(project, library = library))

# otherwise, try to download and install the requested version
# of renv from GitHub
Expand All @@ -52,46 +59,38 @@ renv_imbue_impl <- function(project, version = NULL, force = FALSE) {

renv_scope_restore(
project = project,
library = renv_libpaths_active(),
library = library,
records = records,
packages = "renv",
recursive = FALSE
)

# retrieve renv
records <- retrieve("renv")
record <- records[[1]]

# ensure renv is installed into project library
library <- renv_paths_library(project = project)
ensure_directory(library)
renv_scope_libpaths(library)

printf("- Installing renv [%s] ... ", version)
before <- Sys.time()
with(record, r_cmd_install(Package, Path, library))
after <- Sys.time()
elapsed <- difftime(after, before, units = "auto")
writef("OK [built source in %s]", renv_difftime_format(elapsed))
renv_install_impl(records)

record <- records[["renv"]]
invisible(record)

}

renv_imbue_self <- function(project, source = NULL) {

renv_imbue_self <- function(project,
library = NULL,
source = NULL)
{
# construct source, target paths
# (check if 'renv' is loaded to handle embedded case)
source <- source %||% if ("renv" %in% loadedNamespaces()) {
renv_namespace_path("renv")
} else {
renv_package_find("renv")
source <- source %||% {
if ("renv" %in% loadedNamespaces()) {
renv_namespace_path("renv")
} else {
renv_package_find("renv")
}
}

if (!file.exists(source))
stop("internal error: could not find where 'renv' is installed")

target <- renv_paths_library("renv", project = project)
library <- library %||% renv_paths_library(project = project)
target <- file.path(library, "renv")
if (renv_file_same(source, target))
return(TRUE)

Expand Down
24 changes: 13 additions & 11 deletions R/init.R
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ the$init_running <- FALSE
#' to `TRUE` to use the default version of Bioconductor recommended by the
#' BiocManager package.
#'
#' @param load Boolean; should the project be loaded after it is initialized?
#'
#' @param restart Boolean; attempt to restart the \R session after initializing
#' the project? A session restart will be attempted if the `"restart"` \R
#' option is set by the frontend embedding \R.
Expand All @@ -71,6 +73,7 @@ init <- function(project = NULL,
force = FALSE,
repos = NULL,
bioconductor = NULL,
load = TRUE,
restart = interactive())
{
renv_consent_check()
Expand All @@ -88,7 +91,6 @@ init <- function(project = NULL,

# normalize repos
repos <- renv_repos_normalize(repos %||% renv_init_repos())
options(repos = repos)

# form path to lockfile, library
library <- renv_paths_library(project = project)
Expand All @@ -105,8 +107,7 @@ init <- function(project = NULL,
renv_bioconductor_init(library = library)

# retrieve bioconductor repositories appropriate for this project
biocrepos <- renv_bioconductor_repos(project = project, version = biocver)
options(repos = biocrepos)
repos <- renv_bioconductor_repos(project = project, version = biocver)

# notify user
writef("- Using Bioconductor version '%s'.", biocver)
Expand All @@ -121,7 +122,7 @@ init <- function(project = NULL,
# for bare inits, just activate the project
if (bare) {
renv_imbue_impl(project)
return(renv_init_fini(project, profile, restart))
return(renv_init_fini(project, profile, load, restart))
}

# compute and cache dependencies to (a) reveal problems early and (b) compute once
Expand All @@ -131,31 +132,32 @@ init <- function(project = NULL,
action <- renv_init_action(project, library, lockfile, bioconductor)
cancel_if(empty(action) || identical(action, "cancel"))

# activate library paths for this project
libpaths <- renv_libpaths_activate(project = project)
# compute library paths for this project
libpaths <- renv_init_libpaths(project = project)

# perform the action
if (action == "init") {
renv_scope_options(renv.config.dependency.errors = "ignored")
renv_imbue_impl(project)
hydrate(library = library, prompt = FALSE, report = FALSE, project = project)
renv_imbue_impl(project, library = library)
hydrate(library = library, repos = repos, prompt = FALSE, report = FALSE, project = project)
snapshot(library = libpaths, repos = repos, prompt = FALSE, project = project)
} else if (action == "restore") {
ensure_directory(library)
restore(project = project, library = libpaths, prompt = FALSE)
restore(project = project, library = libpaths, repos = repos, prompt = FALSE)
}

# activate the newly-hydrated project
renv_init_fini(project, profile, restart)
renv_init_fini(project, profile, load, restart)

}

renv_init_fini <- function(project, profile, restart) {
renv_init_fini <- function(project, profile, load, restart) {

renv_activate_impl(
project = project,
profile = profile,
version = renv_metadata_version(),
load = load,
restart = restart
)

Expand Down
6 changes: 2 additions & 4 deletions R/libpaths.R
Original file line number Diff line number Diff line change
Expand Up @@ -165,19 +165,17 @@ renv_libpaths_user <- function() {

}

renv_libpaths_activate <- function(project) {
renv_init_libpaths <- function(project) {

projlib <- renv_paths_library(project = project)
extlib <- renv_libpaths_external(project = project)
userlib <- if (config$user.library())
renv_libpaths_user()

libpaths <- c(projlib, extlib, userlib)

lapply(libpaths, ensure_directory)
renv_libpaths_set(libpaths)

.libPaths()
libpaths

}

Expand Down
7 changes: 5 additions & 2 deletions R/load.R
Original file line number Diff line number Diff line change
Expand Up @@ -186,8 +186,10 @@ renv_load_minimal <- function(project) {
renv_load_libpaths(project)

lockfile <- renv_lockfile_load(project)
if (length(lockfile))
if (length(lockfile)) {
renv_load_r(project, lockfile$R)
renv_load_python(project, lockfile$Python)
}

renv_load_finish(project, lockfile)
invisible(project)
Expand Down Expand Up @@ -436,9 +438,10 @@ renv_load_rprofile_impl <- function(profile) {
}

renv_load_libpaths <- function(project = NULL) {
libpaths <- renv_libpaths_activate(project)
libpaths <- renv_init_libpaths(project)
lapply(libpaths, renv_library_diagnose, project = project)
Sys.setenv(R_LIBS_USER = paste(libpaths, collapse = .Platform$path.sep))
renv_libpaths_set(libpaths)
}

renv_load_sandbox <- function(project) {
Expand Down
5 changes: 5 additions & 0 deletions man/hydrate.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions man/init.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion tests/testthat/helper-scope.R
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ renv_tests_scope <- function(packages = character(),
renv_scope_libpaths(library, scope = scope)

# return path to project directory
invisible(project)
invisible(renv_path_normalize(project))
}

renv_tests_scope_repos <- function(scope = parent.frame()) {
Expand Down
22 changes: 22 additions & 0 deletions tests/testthat/test-init.R
Original file line number Diff line number Diff line change
Expand Up @@ -229,3 +229,25 @@ test_that("init() prompts the user for the snapshot type", {
expect_true(renv_package_installed("bread"))

})

test_that("a project can be initialized without loading it", {
skip_on_cran()

project <- renv_tests_scope()
init()
expect_equal(renv_project_get(), project)

oldwd <- getwd()
oldrepos <- getOption("repos")
oldlibs <- .libPaths()

other <- renv_scope_tempfile("renv-project-")
ensure_directory(other)
init(project = other, load = FALSE, restart = FALSE)
expect_equal(renv_project_get(), project)
expect_true(file.exists(file.path(other, "renv.lock")))

expect_equal(oldwd, getwd())
expect_equal(oldrepos, getOption("repos"))
expect_equal(oldlibs, .libPaths())
})

0 comments on commit e8ece45

Please sign in to comment.