Skip to content
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
Expand Up @@ -7,6 +7,11 @@
longer used to detect if these are actually git-like. This prevents
issues if you name a CRAN-like repository something like "GitHub". (#747)

- `restore()` will warn when a package's lockfile hash does not match the hash
computed from the installed DESCRIPTION file, which indicates the lockfile was
generated from inaccurate package metadata and will cause repeated cache
misses. (#750)

# packrat 0.9.3

- Update vendored `renv` with support for additional Linux distributions when
Expand Down
15 changes: 15 additions & 0 deletions R/restore.R
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,21 @@ installPkg <- function(pkgRecord, project, repos, lib = libDir(project)) {
)
} else {
hash <- hash(descPath)
if (!isTRUE(pkgRecord$hash == hash)) {
warning(
"Package '",
pkgRecord$name,
"': expected hash ",
pkgRecord$hash,
" but got ",
hash,
" after installation. The DESCRIPTION fields used for hashing ",
"(Package, Version, Depends, Imports, Suggests, LinkingTo, and ",
"Remote fields such as GithubSHA1, RemoteType, RemoteHost, ",
"RemoteRepo, RemoteUsername, RemoteRef, RemoteSha, RemoteSubdir) ",
Comment on lines +785 to +787
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok to leave this here since it's simpler, though it's a little fragile cause we'll need to update this if the fields change. But that's a pretty low likelihood event anyway?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I think it's ok and that DRYing it up would just make the logic in hash() more complicated unnecessarily.

"may differ from what was recorded in the lockfile."
)
}
moveInstalledPackageToCache(
packagePath = pkgInstallPath,
hash = hash,
Expand Down
51 changes: 50 additions & 1 deletion tests/testthat/test-cache.R
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,49 @@ test_that("package installation when configured with a a cache uses the cache",
expect_true(is.symlink(packageDir), packageDir)
})

test_that("packrat warns when lockfile hash does not match installed hash", {
skip_on_cran()
skip_on_os("windows")

scopeTestContext()

projRoot <- cloneTestProject("healthy")
libRoot <- file.path(projRoot, "packrat", "lib")
srcRoot <- file.path(projRoot, "packrat", "src")

theCache <- tempfile("packrat-cache-")
ensureDirectory(theCache)
Sys.setenv(R_PACKRAT_CACHE_DIR = theCache)
on.exit(
{
Sys.unsetenv("R_PACKRAT_CACHE_DIR")
unlink(theCache, recursive = TRUE)
},
add = TRUE
)
init(projRoot, options = list(local.repos = "packages"), enter = FALSE)

set_opts(project = projRoot, use.cache = TRUE)
on.exit(set_opts(use.cache = FALSE, project = projRoot), add = TRUE)

# Replace one package's hash in the lockfile with a bogus value
lockfilePath <- file.path(projRoot, "packrat", "packrat.lock")
lockfileContent <- readLines(lockfilePath)
hashLines <- grep("^Hash:", lockfileContent)
lockfileContent[hashLines[1]] <- "Hash: 00000000000000000000000000000000"
writeLines(lockfileContent, lockfilePath)

# Remove lib and src so restore must reinstall
unlink(libRoot, recursive = TRUE)
unlink(srcRoot, recursive = TRUE)

# Restore should warn about the hash mismatch
expect_warning(
restore(projRoot, overwrite.dirty = TRUE, prompt = FALSE, restart = FALSE),
"expected hash.*after installation"
)
})

test_that("packrat uses the untrusted cache when instructed", {
skip_on_cran()
skip_on_os("windows")
Expand All @@ -70,7 +113,13 @@ test_that("packrat uses the untrusted cache when instructed", {

# pretend that we're Posit Connect
Sys.setenv(POSIT_CONNECT = 1)
on.exit(Sys.unsetenv("POSIT_CONNECT"), add = TRUE)
on.exit(
{
Sys.unsetenv("POSIT_CONNECT")
options(packrat.untrusted.packages = NULL)
},
add = TRUE
)

projRoot <- cloneTestProject("healthy")
libRoot <- file.path(projRoot, "packrat", "lib")
Expand Down