Skip to content
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

tolerate packages requiring newer versions of R #2074

Merged
merged 3 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@

# renv 1.1.0 (UNRELEASED)

* Fixed an issue where R package installation could fail if the project
depended on a package whose current version available from the configured
package repositories required on a newer version of R than what was currently
installed, even if that package need not be updated. (#2071)

* Fixed an issue where `RENV_CONFIG_EXTERNAL_LIBRARIES` was incorrectly
split when using Windows paths. (#2069)

Expand Down
20 changes: 12 additions & 8 deletions R/project.R
Original file line number Diff line number Diff line change
Expand Up @@ -161,15 +161,19 @@ renv_project_remotes <- function(project, filter = NULL, resolve = FALSE) {

# check for explicit version requirement
explicit <- spec[spec$Require == "==", ]
if (nrow(explicit) == 0)
return(renv_remotes_resolve(package))

version <- spec$Version[[1]]
if (!nzchar(version))
return(renv_remotes_resolve(package))
if (nrow(explicit)) {
version <- explicit$Version[[1L]]
if (nzchar(version)) {
entry <- paste(package, version, sep = "@")
return(renv_remotes_resolve(entry))
}
}

entry <- paste(package, version, sep = "@")
renv_remotes_resolve(entry)
# check if we're being invoked during restore or install
# if so, we may want to re-use an already-existing package
# https://github.com/rstudio/renv/issues/2071
packages <- renv_restore_state(key = "packages")
renv_remotes_resolve(package, infer = !package %in% packages)

}

Expand Down
11 changes: 10 additions & 1 deletion R/remotes.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ remote <- function(spec) {

# take a short-form remotes spec, parse that into a remote,
# and generate a corresponding package record
renv_remotes_resolve <- function(spec, latest = FALSE) {
renv_remotes_resolve <- function(spec, latest = FALSE, infer = FALSE) {

# check for already-resolved specs
if (is.null(spec) || is.list(spec))
Expand All @@ -30,6 +30,15 @@ renv_remotes_resolve <- function(spec, latest = FALSE) {
# https://github.com/rstudio/renv/issues/1135
spec <- gsub("/+$", "", spec, perl = TRUE)

# check if we should infer the package version
infer <-
infer &&
grepl(renv_regexps_package_name(), spec) &&
renv_package_installed(spec)

if (infer)
spec <- paste(spec, renv_package_version(spec), sep = "@")

# check for archive URLs -- this is a bit hacky
if (grepl("^(?:file|https?)://", spec)) {
for (suffix in c(".zip", ".tar.gz", ".tgz", "/tarball"))
Expand Down
8 changes: 7 additions & 1 deletion R/retrieve.R
Original file line number Diff line number Diff line change
Expand Up @@ -915,9 +915,15 @@ renv_retrieve_repos_archive <- function(record) {
if (is.null(root))
next

# attempt download
# attempt download; report errors via condition handler
name <- renv_retrieve_repos_archive_name(record, type = "source")
status <- catch(renv_retrieve_repos_impl(record, "source", name, root))
if (inherits(status, "error")) {
attr(status, "record") <- record
renv_condition_signal("renv.retrieve.error", entry)
}

# exit now if we had success
if (identical(status, TRUE))
return(TRUE)

Expand Down
1 change: 1 addition & 0 deletions tests/testthat/helper-aaa.R
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ teardown_env <- function() {
}

the$tests_repopath <- renv_scope_tempfile("renv-repos-", scope = teardown_env())

renv_tests_repopath <- function() {
the$tests_repopath
}
3 changes: 2 additions & 1 deletion tests/testthat/helper-setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ renv_tests_setup_envvars <- function(scope = parent.frame()) {
# set up sandbox directory
sandbox <- file.path(root, "sandbox")
ensure_directory(sandbox)

renv_scope_envvars(
RENV_AUTOLOAD_ENABLED = FALSE,
RENV_CONFIG_LOCKING_ENABLED = FALSE,
Expand Down Expand Up @@ -222,6 +222,7 @@ renv_tests_setup_repos <- function(scope = parent.frame()) {
descpath <- file.path(path, "DESCRIPTION")
desc <- renv_description_read(descpath)
desc$Version <- "0.1.0"
desc$Depends <- gsub("99.99.99", "1.0.0", desc$Depends %||% "", fixed = TRUE)
write.dcf(desc, file = descpath)

# place these packages into the archive
Expand Down
10 changes: 10 additions & 0 deletions tests/testthat/packages/future/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Package: future
Type: Package
Version: 1.0.0
Depends: today
Repository: CRAN
License: GPL
Description: renv test package
Title: renv test package
Author: Anonymous Person <[email protected]>
Maintainer: Anonymous Person <[email protected]>
10 changes: 10 additions & 0 deletions tests/testthat/packages/today/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Package: today
Type: Package
Version: 1.0.0
Depends: R (>= 99.99.99)
Repository: CRAN
License: GPL
Description: renv test package
Title: renv test package
Author: Anonymous Person <[email protected]>
Maintainer: Anonymous Person <[email protected]>
29 changes: 27 additions & 2 deletions tests/testthat/test-install.R
Original file line number Diff line number Diff line change
Expand Up @@ -371,7 +371,7 @@ test_that("packages embedded in the project use a project-local RemoteURL", {
skip_if(is.null(usethis$create_package))
renv_scope_options(usethis.quiet = TRUE)
unlink("example", recursive = TRUE)

fields <- list(
"Authors@R" = utils::person(
"Kevin", "Ushey",
Expand All @@ -380,7 +380,7 @@ test_that("packages embedded in the project use a project-local RemoteURL", {
comment = c(ORCID = "0000-0003-2880-7407")
)
)

usethis$create_package("example", fields = fields, rstudio = FALSE, open = FALSE)

install("./example")
Expand Down Expand Up @@ -767,3 +767,28 @@ test_that("packages installed from r-universe preserve their remote metadata", {
record <- renv_snapshot_description(package = "rlang")
expect_true(is.character(record[["RemoteSha"]]))
})

# https://github.com/rstudio/renv/issues/2071
test_that("irrelevant R version requirements don't prevent package installation", {

renv_tests_scope()
init()

# package in repository not compatible with this version of R
expect_error(install("today"))

# but older version can be successfully installed
install("[email protected]")
expect_true(renv_package_installed("today"))
expect_equal(renv_package_version("today"), "0.1.0")

# other packages can be installed even if this project depends on it
writeLines("Depends: future, today", con = "DESCRIPTION")
install("future")
expect_true(renv_package_installed("future"))
remove("future")

# but installing that package should still fail
expect_error(install("today"))

})
2 changes: 1 addition & 1 deletion tests/testthat/test-repos.R
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
test_that("we can query our local repository during tests", {

expected <- list.files("packages")
drop <- if (.Platform$OS.type == "unix") "windowsonly" else "unixonly"
drop <- c("today", if (.Platform$OS.type == "unix") "windowsonly" else "unixonly")
expected <- setdiff(expected, drop)

renv_tests_scope()
Expand Down
Loading