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

Respect renv lockfiles #791

Merged
merged 57 commits into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
462da70
Sketch out main changes
hadley Mar 20, 2023
8a928ea
Add basic translation code
hadley Mar 21, 2023
3796044
Add renv example
hadley Mar 21, 2023
0928e7a
Improve testing infrastructure
hadley Mar 21, 2023
5dbb07c
Add news bullet
hadley Mar 21, 2023
24fe5ab
More comments
hadley Mar 21, 2023
024be49
Simplify showDcf()
hadley Mar 23, 2023
8c7a828
Restore packrat/renv directory ignoring
hadley Mar 23, 2023
93e6522
Don't need to support packrat lockfiles
hadley Mar 23, 2023
46d3c05
Hack into new shape
hadley Mar 23, 2023
9fe6c68
Standardise repos like packrat snapshot
hadley Mar 23, 2023
88aeced
Delete lockfile when we're done with it
hadley Mar 23, 2023
adb2b84
Improve message
hadley Mar 23, 2023
5dfcb80
Use renv for snapshotting too
hadley Mar 23, 2023
e4fcac7
Clean up tests
hadley Mar 23, 2023
3a60c58
Move packrat functions to own file
hadley Mar 23, 2023
5b8f9b5
Update writeManifest() docs
hadley Mar 23, 2023
ef4e237
Move tests around
hadley Mar 23, 2023
fedb322
Massiaing renv tests
hadley Mar 23, 2023
b93ae24
Trick R CMD check
hadley Mar 23, 2023
3c0f2a6
Update snapshot
hadley Mar 23, 2023
52d5fd9
More info about manifest fields
hadley Mar 23, 2023
1386887
Complete tests of standardizeRenvPackage()
hadley Mar 24, 2023
8129386
Move empty dir test to individual impls
hadley Mar 24, 2023
c29339b
Test bundlePackage() paths
hadley Mar 24, 2023
f7d42fd
Eliminate unused code
hadley Mar 24, 2023
de2efd6
Document rsconnect.packrat option
hadley Mar 24, 2023
d83f36e
Start thinking about DESCRIPTIONs
hadley Mar 24, 2023
156e637
Correct strategy for getting renv library
hadley Mar 24, 2023
f8a7d71
Merge commit '516fb9cad24568ea502af784dad0e670f1f2f78b'
hadley Mar 24, 2023
f868fe3
Remove now unneeded helper
hadley Mar 24, 2023
91c8a24
Fix R CMD check failure
hadley Mar 24, 2023
0f77dd2
Restore original order
hadley Mar 24, 2023
4bee9a5
Linting
hadley Mar 24, 2023
f014634
Merge commit '72bcf625ca0805629838a41755b7fe5bfd8d12e7'
hadley Apr 20, 2023
b667f1f
Compute source/repository in correct order
hadley Apr 20, 2023
3cbe9e0
Repository can be NULL
hadley Apr 20, 2023
ae60d88
Work around renv/pak buglet
hadley Apr 20, 2023
e81c51e
Match existing manifest.json structure
hadley Apr 20, 2023
48c4e6a
Polishing; adding more docs
hadley Apr 20, 2023
08fff5d
Apply same fix to lockfile path
hadley Apr 21, 2023
c6a88cd
Add manual test scripts
hadley Apr 21, 2023
bfaa7ea
Proof reading
hadley Apr 21, 2023
b386d8a
Lazily get default biocRepos, if needed
hadley Apr 22, 2023
1c6cef8
Silence renv output
hadley May 2, 2023
2d4c4d3
Update R/bundlePackagePackrat.R
hadley May 3, 2023
8fe29c6
Apply suggestions from code review
hadley May 3, 2023
957c1a5
Update tests/testthat/test-bundlePackageRenv.R
hadley May 3, 2023
5198d45
Update R/bundlePackageRenv.R
hadley May 3, 2023
36d0d50
Set required versions
hadley May 3, 2023
af72cd0
Match on Packages field rather than rownames
hadley May 3, 2023
d7db6dd
Fix misunderstood fix
hadley May 3, 2023
f53703d
Finish off rowname -> Package col changes
hadley May 3, 2023
3ec221a
Merge commit '25b93da28be464a58aaf3f3ac36d6ca50ece67c9'
hadley May 3, 2023
48ecfa5
Switch to package that's not under active development
hadley May 3, 2023
6e7a8b2
And another test case
hadley May 3, 2023
752857f
Merge branch 'main' into renv-support
hadley May 8, 2023
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,5 +1,10 @@
# rsconnect (development version)

* `deployApp()` and friends will now respect packrat and renv lock files,
hadley marked this conversation as resolved.
Show resolved Hide resolved
if present. If you don't want to use these lockfiles, and instead return
hadley marked this conversation as resolved.
Show resolved Hide resolved
the previous behaviour of snapshotting on every deploy, add your
lockfiles to `.rscignore` (#671).

* New `rsconnect.http.headers` and `rsconnect.http.cookies` allow you to
set extra arbitrary additional headers/cookies on each request (#405).
Their use is documented in the new `vignette("custom-http")`.
Expand Down
2 changes: 0 additions & 2 deletions R/bundleFiles.R
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,6 @@ ignoreBundleFiles <- function(dir, contents) {
ignore <- c(
# rsconnect packages
"rsconnect", "rsconnect-python", "manifest.json",
# packrat + renv,
"renv", "renv.lock", "packrat",
hadley marked this conversation as resolved.
Show resolved Hide resolved
# version control
".git", ".gitignore", ".svn",
# R/RStudio
Expand Down
22 changes: 14 additions & 8 deletions R/bundlePackage.R
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ bundlePackages <- function(bundleDir,
unclass(utils::packageDescription(nm))
})

# Connect prefers that packrat/packrat.lock file, but will use the manifest
# Connect prefers the packrat/packrat.lock file, but will use the manifest
# if needed. shinyapps.io only uses the manifest, and only supports Github
# remotes, not Bitbucket or Gitlab.
github_cols <- grep("Github", colnames(deps), perl = TRUE, value = TRUE)
Expand Down Expand Up @@ -68,15 +68,21 @@ copyPackageDescriptions <- function(bundleDir, packages) {
invisible()
}

snapshotRDependencies <- function(appDir,
snapshotRDependencies <- function(bundleDir,
implicit_dependencies = c(),
verbose = FALSE) {

# create a packrat "snapshot"
addPackratSnapshot(appDir, implicit_dependencies, verbose = verbose)
if (file.exists(renvLockFile(bundleDir))) {
# Translate renv lock file to packrat lock file
translateRenvToPackrat(bundleDir)
} else if (file.exists(packratLockFile(bundleDir))) {
# Packrat lock file already exists; no action needed
} else {
# Find and snapshot current dependencies
addPackratSnapshot(bundleDir, implicit_dependencies, verbose = verbose)
}

# TODO: should we care about lockfile version or packrat version?
lockFilePath <- snapshotLockFile(appDir)
lockFilePath <- packratLockFile(bundleDir)
df <- as.data.frame(read.dcf(lockFilePath), stringsAsFactors = FALSE)

# get repos defined in the lockfile
Expand Down Expand Up @@ -270,6 +276,6 @@ performPackratSnapshot <- function(bundleDir, verbose = FALSE) {
invisible()
}

snapshotLockFile <- function(appDir) {
file.path(appDir, "packrat", "packrat.lock")
packratLockFile <- function(bundleDir) {
file.path(bundleDir, "packrat", "packrat.lock")
}
86 changes: 86 additions & 0 deletions R/renv.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
translateRenvToPackrat <- function(bundleDir) {
hadley marked this conversation as resolved.
Show resolved Hide resolved
renv <- jsonlite::read_json(renvLockFile(bundleDir))
packrat <- packratFromRenv(renv)

packratPath <- packratLockFile(bundleDir)
dir.create(dirname(packratPath), showWarnings = FALSE)
write.dcf(packrat, packratPath)
}

packratFromRenv <- function(renv) {
meta <- packratMeta(renv)
packages <- packratPackages(renv$Packages)
rbind_fill(list(meta, packages))
}

packratMeta <- function(renv) {
repos <- vapply(
renv$R$Repositories,
function(x) paste0(x$Name, "=", x$URL),
character(1)
)
data.frame(
PackratFormat = NA,
hadley marked this conversation as resolved.
Show resolved Hide resolved
PackratVersion = NA,
RVersion = renv$R$Version,
Repos = paste(repos, collapse = ",")
)
}

packratPackages <- function(packages) {
out <- lapply(packages, packratPackage)
names(out) <- NULL
out <- compact(out)
out <- lapply(out, as.data.frame, stringsAsFactors = FALSE)
rbind_fill(out)
}

packratPackage <- function(pkg) {
# Don't include renv itself
if (identical(pkg$Package, "renv")) {
return(NULL)
}

# Convert renv sources to packrat sources
# https://github.com/rstudio/renv/blob/0.17.2/R/snapshot.R
if (identical(pkg$Repository, "CRAN")) {
pkg$Source <- "CRAN"
} else if (pkg$Source == "unknown") {
pkg$Source <- "source"
}

# Remove Remote fields that renv adds for "standard" installs from CRAN
hadley marked this conversation as resolved.
Show resolved Hide resolved
if (identical(pkg$RemoteType, "standard")) {
pkg <- pkg[!grepl("^Remote", names(pkg))]
}

# Drop hash since packrat hash != renv hash
pkg$Hash <- NULL
hadley marked this conversation as resolved.
Show resolved Hide resolved

# Convert Requirements to Requires, a comma separated list
if (length(pkg$Requirements) > 0) {
pkg$Requires <- paste0(unlist(pkg$Requirements), collapse = ", ")
}
pkg$Requirements <- NULL

pkg
}

renvLockFile <- function(bundleDir) {
file.path(bundleDir, "renv.lock")
}

showPackratTranslation <- function(path) {
renv <- jsonlite::read_json(renvLockFile(path))
packrat <- packratFromRenv(renv)
showDcf(packrat)
}

showDcf <- function(df) {
path <- tempfile()
on.exit(path, add = TRUE)

write.dcf(df, path)
hadley marked this conversation as resolved.
Show resolved Hide resolved
writeLines(readLines(path))
invisible()
}
46 changes: 46 additions & 0 deletions tests/testthat/_snaps/renv.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# generates expected packrat file

Code
showPackratTranslation(test_path("renv-cran"))
Output
RVersion: 4.2.1
Repos: CRAN=https://cran.rstudio.com

Package: cli
Version: 3.6.0
Source: CRAN
Repository: CRAN
Code
showPackratTranslation(test_path("renv-github"))
Output
RVersion: 4.2.1
Repos: CRAN=https://cran.rstudio.com

Package: withr
Version: 2.5.0.9000
Source: GitHub
RemoteType: github
RemoteHost: api.github.com
RemoteUsername: r-lib
RemoteRepo: withr
RemoteRef: main
RemoteSha: 3b01a2bef7b17bf2f82d94be58a2d4287827fa21
Code
showPackratTranslation(test_path("renv-bioc"))
Output
RVersion: 4.2.1
Repos: CRAN=https://cran.rstudio.com

Package: BiocGenerics
Version: 0.44.0
Source: Bioconductor
git_url: https://git.bioconductor.org/packages/BiocGenerics
git_branch: RELEASE_3_16
git_last_commit: d7cd9c1
git_last_commit_date: 2022-11-01

Package: BiocManager
Version: 1.30.20
Source: CRAN
Repository: CRAN

1 change: 1 addition & 0 deletions tests/testthat/renv-bioc/dependences.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
library(bioBase)
46 changes: 46 additions & 0 deletions tests/testthat/renv-bioc/renv.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"R": {
"Version": "4.2.1",
"Repositories": [
{
"Name": "CRAN",
"URL": "https://cran.rstudio.com"
}
]
},
"Packages": {
"BiocGenerics": {
"Package": "BiocGenerics",
"Version": "0.44.0",
"Source": "Bioconductor",
"git_url": "https://git.bioconductor.org/packages/BiocGenerics",
"git_branch": "RELEASE_3_16",
"git_last_commit": "d7cd9c1",
"git_last_commit_date": "2022-11-01",
"Hash": "0de19224c2cd94f48fbc0d0bc663ce3b",
"Requirements": []
},
"BiocManager": {
"Package": "BiocManager",
"Version": "1.30.20",
"Source": "Repository",
"Repository": "CRAN",
"Hash": "a7fca16a50b6ef7771b49d636dd54b57",
"Requirements": []
},
"renv": {
"Package": "renv",
"Version": "0.16.0",
"Source": "Repository",
"Repository": "CRAN",
"RemoteType": "standard",
"RemotePkgRef": "renv",
"RemoteRef": "renv",
"RemoteRepos": "https://cran.rstudio.com",
"RemotePkgPlatform": "aarch64-apple-darwin20",
"RemoteSha": "0.16.0",
"Hash": "c9e8442ab69bc21c9697ecf856c1e6c7",
"Requirements": []
}
}
}
1 change: 1 addition & 0 deletions tests/testthat/renv-cran/dependences.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
library(cli)
41 changes: 41 additions & 0 deletions tests/testthat/renv-cran/renv.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"R": {
"Version": "4.2.1",
"Repositories": [
{
"Name": "CRAN",
"URL": "https://cran.rstudio.com"
}
]
},
"Packages": {
"cli": {
"Package": "cli",
"Version": "3.6.0",
"Source": "Repository",
"Repository": "CRAN",
"RemoteType": "standard",
"RemotePkgRef": "cli",
"RemoteRef": "cli",
"RemoteRepos": "https://cran.rstudio.com",
"RemotePkgPlatform": "aarch64-apple-darwin20",
"RemoteSha": "3.6.0",
"Hash": "3177a5a16c243adc199ba33117bd9657",
"Requirements": []
},
"renv": {
"Package": "renv",
"Version": "0.16.0",
"Source": "Repository",
"Repository": "CRAN",
"RemoteType": "standard",
"RemotePkgRef": "renv",
"RemoteRef": "renv",
"RemoteRepos": "https://cran.rstudio.com",
"RemotePkgPlatform": "aarch64-apple-darwin20",
"RemoteSha": "0.16.0",
"Hash": "c9e8442ab69bc21c9697ecf856c1e6c7",
"Requirements": []
}
}
}
1 change: 1 addition & 0 deletions tests/testthat/renv-github/dependences.R
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
library(withr)
40 changes: 40 additions & 0 deletions tests/testthat/renv-github/renv.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"R": {
"Version": "4.2.1",
"Repositories": [
{
"Name": "CRAN",
"URL": "https://cran.rstudio.com"
}
]
},
"Packages": {
"renv": {
"Package": "renv",
"Version": "0.16.0",
"Source": "Repository",
"Repository": "CRAN",
"RemoteType": "standard",
"RemotePkgRef": "renv",
"RemoteRef": "renv",
"RemoteRepos": "https://cran.rstudio.com",
"RemotePkgPlatform": "aarch64-apple-darwin20",
"RemoteSha": "0.16.0",
"Hash": "c9e8442ab69bc21c9697ecf856c1e6c7",
"Requirements": []
},
"withr": {
"Package": "withr",
"Version": "2.5.0.9000",
"Source": "GitHub",
"RemoteType": "github",
"RemoteHost": "api.github.com",
"RemoteUsername": "r-lib",
"RemoteRepo": "withr",
"RemoteRef": "main",
"RemoteSha": "3b01a2bef7b17bf2f82d94be58a2d4287827fa21",
"Hash": "a5b00ca54909a1dd45d6f6f148887c64",
"Requirements": []
}
}
}
2 changes: 1 addition & 1 deletion tests/testthat/test-bundleFiles.R
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ test_that("ignores knitr cache directories", {
test_that("ignores files anywhere in path", {
dir <- withr::local_tempdir()
dir.create(file.path(dir, "a/b/c"), recursive = TRUE)
file.create(file.path(dir, c("x", "a/renv", "a/b/.gitignore", "a/b/c/.DS_Store")))
file.create(file.path(dir, c("x", "a/b/.gitignore", "a/b/c/.DS_Store")))

expect_equal(bundleFiles(dir), "x")
})
Expand Down
30 changes: 30 additions & 0 deletions tests/testthat/test-renv.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#' @examples
#' makeRenvSnapshot(test_path("renv-cran"), "cli")
#' makeRenvSnapshot(test_path("renv-bioc"), "bioBase", "bioc::Biobase")
#' makeRenvSnapshot(test_path("renv-github"), "withr", "r-lib/withr")
makeRenvSnapshot <- function(path, name, package = name) {
dir.create(path, showWarnings = FALSE)

withr::local_dir(path)
writeLines(paste0("library(", name, ")"), "dependences.R")

callr::r(args = list(package = package), function(package) {
renv::activate()
renv::install(package)
renv::snapshot(prompt = FALSE)
})

unlink(c(".Rprofile", ".gitignore", "renv"), recursive = TRUE)

invisible()
}

# -------------------------------------------------------------------------

test_that("generates expected packrat file", {
expect_snapshot({
showPackratTranslation(test_path("renv-cran"))
showPackratTranslation(test_path("renv-github"))
showPackratTranslation(test_path("renv-bioc"))
})
})