Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
866bd76
add windows toolchain preflight and platform record
kevinushey Oct 10, 2026
a428ed4
equip() installs rtools; report external tools in platform record
kevinushey Oct 10, 2026
147d846
report packages to be compiled from source before installing
kevinushey Oct 11, 2026
e5552ad
scope an empty cache in the preflight classification tests
kevinushey Oct 11, 2026
54f5210
comment the empty window title passed to start
kevinushey Oct 14, 2026
b8de631
run the source-build preflight on the resolved install set
kevinushey Oct 14, 2026
749df75
add equip() to the pkgdown reference index
kevinushey Oct 14, 2026
3a7277c
address review findings for the preflight and rtools changes
kevinushey Oct 14, 2026
50d6397
honor RENV_PATHS_RTOOLS in equip(); harden tool and installer checks
kevinushey Oct 14, 2026
ab67977
don't consult P3M in the source-build preflight
kevinushey Oct 14, 2026
551c71e
Revert "don't consult P3M in the source-build preflight"
kevinushey Oct 14, 2026
59c6233
consult P3M before the source archive in the dependency graph
kevinushey Oct 14, 2026
da82854
skip P3M for records pinned to a repository in strict mode
kevinushey Oct 14, 2026
31e4fe0
use the requested package type in the preflight's P3M check
kevinushey Oct 14, 2026
c3cdadf
mirror the resolver's lookup order in the source-build preflight
kevinushey Oct 14, 2026
1f479fb
classify repository records in the preflight via the resolver
kevinushey Oct 14, 2026
6b92522
compare env var names case-insensitively on windows in test state check
kevinushey Oct 14, 2026
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
27 changes: 27 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,33 @@
whitespace, so tools like pre-commit's `trailing-whitespace` hook no longer
modify it. (#2411)

* Fixed an issue where `renv::restore()` and `renv::install()` would build a
package from its archived sources when the requested version was no longer
available from the configured repositories, even when P3M provided a binary
for that version. The dependency graph now consults P3M before falling back
to the archive, as it did before the graph-based installer (renv 1.2.0).

* `renv::restore()` and `renv::install()` now report, before installing
anything, which of the requested packages are not available as binaries and
so will be compiled from source. On Windows, when no Rtools installation is
found, the report also names the version of Rtools required. Previously,
such installs failed only after reaching the first package needing
compilation.

* On Windows, `renv::equip()` now downloads and runs the installer for the
version of Rtools matching the running version of R, when no Rtools
installation is found. The external libraries previously installed by
`equip()` are now only installed for R (< 4.0.0), as newer versions of
Rtools bundle them.

* `renv::diagnostics()` now reports a description of the platform R is running
on: the R version and platform, the operating system (and Linux
distribution), the BLAS and LAPACK libraries in use, the versions of the
external software R was built against, the collation locale, the Rtools
installation (on Windows), the versions of pandoc, Quarto, Java and TeX
found on the system, and the installed versions of the system packages
required by the packages in the lockfile (on Linux).

* renv now recognizes the custom binary package types introduced with R 4.6.0
(of the form `<system>.binary.<build>`), along with binary packages
distributed as `.tar.bz2`, `.tar.xz`, `.tar.zst` and `.tar.zstd` archives
Expand Down
7 changes: 7 additions & 0 deletions R/diagnostics.R
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ diagnostics <- function(project = NULL) {
renv_diagnostics_status,
renv_diagnostics_packages,
renv_diagnostics_sysreqs,
renv_diagnostics_platform,
renv_diagnostics_r,
renv_diagnostics_abi,
renv_diagnostics_profile,
Expand Down Expand Up @@ -193,6 +194,12 @@ renv_diagnostics_sysreqs <- function(project) {

}

renv_diagnostics_platform <- function(project) {
writef(header("Platform"))
record <- renv_platform_record(project = project)
renv_json_write(record, file = stdout())
}

renv_diagnostics_packages_version <- function(lockfile, all) {

data <- rep.int(NA_character_, length(all))
Expand Down
112 changes: 105 additions & 7 deletions R/equip.R
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@

#' Install required system libraries
#' Install a build toolchain
#'
#' Equip your system with libraries commonly-used during compilation of
#' base and recommended \R packages. This was previously useful with older
#' versions of R on windows, but is no longer terribly helpful.
#' Equip your system with the tools required to build \R packages from
#' source. This is useful when a package recorded in the lockfile is not
#' available as a binary for your version of \R, as can happen when
#' restoring an older project.
#'
#' On Windows, `equip()` downloads and runs the installer for the version of
#' [Rtools](https://cran.r-project.org/bin/windows/Rtools/) matching the
#' running version of \R. The installer may request administrator
#' privileges. (For \R versions older than 4.0.0, `equip()` instead installs
#' the external libraries once used when building packages on Windows.)
#'
#' On macOS, `equip()` ensures the Xcode command line tools are installed.
#'
#' @return This function is normally called for its side effects.
#' @export
#' @keywords internal
#' @examples
Comment thread
kevinushey marked this conversation as resolved.
#' \dontrun{
#'
#' # download useful build tools
#' # install a build toolchain, if one is not already available
#' renv::equip()
#'
#' }
Expand All @@ -30,7 +38,97 @@ equip <- function() {
}

renv_equip_windows <- function() {
invisible(renv_extsoft_install() && renv_extsoft_use())

# Rtools 4.0 and newer bundle the libraries once provided by extsoft
if (getRversion() < "4.0.0")
return(invisible(renv_extsoft_install() && renv_extsoft_use()))

invisible(renv_equip_windows_rtools())

}

renv_equip_windows_rtools <- function() {

# an explicitly-requested Rtools installation needn't be discoverable
root <- renv_paths_override("rtools")
if (!is.null(root) && file.exists(root)) {
writef("- Rtools is already installed at %s.", renv_path_pretty(root))
return(TRUE)
}

spec <- renv_rtools_find()
if (!is.null(spec)) {
fmt <- "- Rtools %s is already installed at %s."
writef(fmt, spec$version, renv_path_pretty(spec$root))
return(TRUE)
}

if (renv_rtools_path_available()) {
writef("- A build toolchain is already available on the PATH.")
return(TRUE)
}

series <- renv_rtools_required(getRversion(), renv_rtools_series_available())
url <- renv_rtools_installer_url(series)

if (interactive()) {

bulletin(
sprintf("Rtools %s will be downloaded and installed from:", series),
url,
"The installer may request administrator privileges."
)

cancel_if(!proceed())

}

destfile <- file.path(tempdir(), basename(url))
download(url, destfile = destfile)
renv_equip_windows_rtools_run(destfile)

# the installer is run via 'start', so check for the installation itself
# rather than relying on the exit status
spec <- renv_rtools_find()
if (is.null(spec)) {

bulletin(
"renv was unable to verify that Rtools was installed. You can run the installer manually:",
renv_path_pretty(destfile),
"Use the default installation location so that R can find it."
)

return(FALSE)

}

fmt <- "- Rtools %s was installed at %s."
writef(fmt, spec$version, renv_path_pretty(spec$root))
TRUE

}

renv_equip_windows_rtools_run <- function(installer) {

# the installer requests elevation, which CreateProcess() (and so system2())
# refuses; launch it through the shell instead so that Windows can prompt.
# note that 'start' treats its first quoted argument as a window title, so
# an empty title ("") is required for the installer path to be run
args <- c(
"/c", "start", "\"\"", "/wait",
shQuote(installer),
"/VERYSILENT", "/SUPPRESSMSGBOXES", "/NORESTART"
)

printf("- Running the Rtools installer ... ")
status <- suppressWarnings(system2("cmd", args, stdout = FALSE, stderr = FALSE))
if (identical(status, 0L))
writef("Done!")
else
writef("FAILED [exit code %s]", status)

invisible(status)

}

renv_equip_linux <- function() {
Expand Down
51 changes: 49 additions & 2 deletions R/graph.R
Original file line number Diff line number Diff line change
Expand Up @@ -1204,8 +1204,15 @@ renv_graph_url_repository <- function(desc) {

}

# the requested version is not in current available packages;
# try the CRAN-style archive (source only)
# the requested version is not in current available packages. P3M may
# still have a binary for it, from the snapshot taken when it was current;
# prefer that over building the archived sources, as sequential retrieval
# does (renv_retrieve_repos())
info <- renv_graph_url_repository_p3m(desc)
if (!is.null(info))
return(info)

# otherwise, try the CRAN-style archive (source only)
baseurl <- renv_repos_baseurl(attr(record, "url", exact = TRUE))
root <- renv_retrieve_repos_archive_root(baseurl, as.list(desc))

Expand All @@ -1230,6 +1237,46 @@ renv_graph_url_repository <- function(desc) {

}

# the P3M binary for this record on the current platform, if P3M is in use
# and its database knows of one
renv_graph_url_repository_p3m <- function(desc) {

if (!renv_p3m_enabled(the$install_pkg_type))
return(NULL)

# in strict mode, records naming a repository are only retrieved from it
if (renv_graph_url_repository_strict(desc))
return(NULL)

# a failure to refresh or read the P3M database shouldn't abort
# resolution; the archive remains available
record <- as.list(desc)
date <- catch(renv_retrieve_repos_p3m_date(record))
if (inherits(date, "error") || is.null(date))
return(NULL)

suffix <- contrib.url("", type = "binary")
base <- renv_p3m_url(date, suffix)
name <- renv_retrieve_name(record, type = "binary")

list(
url = file.path(base, name),
destfile = renv_retrieve_path(record, type = "binary"),
type = "repository",
pkgtype = "binary",
repourl = base,
reponame = "P3M"
)

}

# is this record restricted to the repository it names? see restore(strict = TRUE)
renv_graph_url_repository_strict <- function(desc) {
repository <- desc[["Repository"]]
strict <- renv_restore_state(key = "strict") %||% FALSE
strict && is.character(repository) && grepl("://", repository, fixed = TRUE)
}

# the package types to search, in preference order, when the record we're
# resolving carries no type tag of its own
renv_graph_url_repository_types <- function() {
Expand Down
Loading
Loading