Skip to content

Commit 7188082

Browse files
Bisaloohadley
andauthored
Move from rappdirs cache dir to tools::R_user_dir() (#800)
--------- Co-authored-by: Hadley Wickham <h.wickham@gmail.com>
1 parent 26fc58a commit 7188082

4 files changed

Lines changed: 81 additions & 7 deletions

File tree

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ Imports:
2323
magrittr,
2424
openssl,
2525
R6,
26-
rappdirs,
2726
rlang (>= 1.3.0),
2827
vctrs (>= 0.6.3),
2928
withr
@@ -44,6 +43,7 @@ Suggests:
4443
otelsdk (>= 0.2.0),
4544
paws.common (>= 0.8.0),
4645
promises,
46+
rappdirs,
4747
rmarkdown,
4848
testthat (>= 3.1.8),
4949
tibble,

NEWS.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
* Fixed OAuth token cache pruning so that it actually matches the encrypted `.rds.enc` files written to disk; previously the pruning pattern only matched an unencrypted `.rds` file that was never created, so cached tokens were never automatically deleted regardless of age.
44
* httr2 now requires rlang >= 1.3.0, which changes the hash used to name files cached by `req_cache()` and on-disk OAuth token caches (e.g. from `req_oauth_auth_code(cache_disk = TRUE)`). Existing cached files won't match the new hash, so they'll be silently ignored (triggering a normal cache miss/re-authentication) and cleaned up over time by the usual pruning rules; you can also delete them manually.
5+
* `oauth_cache_path()` now defaults to a standard R cache directory (via `tools::R_user_dir()`). Because this release also changes the hash used for cache filenames, existing OAuth tokens will generally not be reused and you may need to authenticate once after upgrading. New tokens are written to the new location, and obsolete tokens in both the old and new locations are removed by the usual pruning rules. httr2 no longer requires the rappdirs package (#800).
56
* `req_oauth_*()` gains an `expiry_margin` argument to control how early cached OAuth tokens are treated as expired; the default margin increases from 5 to 30 seconds (@zacdav-db, #860).
67

78
# httr2 1.2.3

R/oauth.R

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -210,9 +210,12 @@ cache_disk <- function(client, key = NULL) {
210210
}
211211

212212
# Update req_oauth_auth_code() docs if change default from 30
213-
cache_disk_prune <- function(days = 30, path = oauth_cache_path()) {
213+
cache_disk_prune <- function(
214+
days = 30,
215+
paths = c(oauth_cache_path(), oauth_cache_path_legacy())
216+
) {
214217
files <- dir(
215-
path,
218+
paths,
216219
recursive = TRUE,
217220
full.names = TRUE,
218221
pattern = "-token\\.rds\\.enc$"
@@ -232,13 +235,35 @@ cache_disk_prune <- function(days = 30, path = oauth_cache_path()) {
232235
#' @export
233236
oauth_cache_path <- function() {
234237
path <- Sys.getenv("HTTR2_OAUTH_CACHE")
235-
if (path != "") {
236-
return(path)
238+
if (nzchar(path)) {
239+
path
240+
} else {
241+
tools::R_user_dir("httr2", which = "cache")
237242
}
238-
239-
rappdirs::user_cache_dir("httr2")
240243
}
244+
# Equivalent to rappdirs::user_cache_dir("httr2"), inlined so httr2 doesn't
245+
# depend on rappdirs solely to find tokens cached by older versions. The
246+
# appname is nested twice and gains a "Cache" subdir on Windows because that's
247+
# what rappdirs did with its default `appauthor` and `opinion` arguments.
248+
oauth_cache_path_legacy <- function() {
249+
base <- Sys.getenv("R_USER_CACHE_DIR")
250+
if (nzchar(base)) {
251+
if (.Platform$OS.type == "windows") {
252+
return(file.path(base, "httr2", "httr2", "Cache"))
253+
} else {
254+
return(file.path(base, "httr2"))
255+
}
256+
}
241257

258+
if (.Platform$OS.type == "windows") {
259+
base <- Sys.getenv("LOCALAPPDATA", Sys.getenv("APPDATA"))
260+
file.path(base, "httr2", "httr2", "Cache")
261+
} else if (Sys.info()[["sysname"]] == "Darwin") {
262+
"~/Library/Caches/httr2"
263+
} else {
264+
file.path(Sys.getenv("XDG_CACHE_HOME", "~/.cache"), "httr2")
265+
}
266+
}
242267

243268
#' Clear OAuth cache
244269
#'

tests/testthat/test-oauth.R

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,9 +216,57 @@ test_that("can prune old files", {
216216
expect_equal(dir(path), "a-token.rds.enc")
217217
})
218218

219+
test_that("prunes old files from both new and legacy locations", {
220+
new_path <- withr::local_tempdir()
221+
legacy_path <- withr::local_tempdir()
222+
local_mocked_bindings(
223+
oauth_cache_path = function() new_path,
224+
oauth_cache_path_legacy = function() legacy_path
225+
)
226+
227+
touch(file.path(new_path, "a-token.rds.enc"), Sys.time() - 86400 * 1)
228+
touch(file.path(new_path, "b-token.rds.enc"), Sys.time() - 86400 * 2)
229+
touch(file.path(legacy_path, "a-token.rds.enc"), Sys.time() - 86400 * 1)
230+
touch(file.path(legacy_path, "b-token.rds.enc"), Sys.time() - 86400 * 2)
231+
232+
cache_disk_prune(2)
233+
234+
expect_equal(dir(new_path), "a-token.rds.enc")
235+
expect_equal(dir(legacy_path), "a-token.rds.enc")
236+
})
237+
219238
# cache_path --------------------------------------------------------------
220239

221240
test_that("can override path with env var", {
222241
withr::local_envvar("HTTR2_OAUTH_CACHE" = "/tmp")
223242
expect_equal(oauth_cache_path(), "/tmp")
224243
})
244+
245+
test_that("inlined legacy path matches rappdirs", {
246+
path <- oauth_cache_path_legacy()
247+
rappdirs_path <- rappdirs::user_cache_dir("httr2")
248+
249+
if (.Platform$OS.type == "windows") {
250+
# rappdirs uses the CSIDL API, which can return an 8.3 short form of
251+
# the user's home directory, while our env-var based path uses the
252+
# long form. Both refer to the same directory, so convert to the
253+
# (existing) directory's canonical short form before comparing.
254+
dir.create(path, recursive = TRUE, showWarnings = FALSE)
255+
withr::defer(unlink(path, recursive = TRUE))
256+
path <- utils::shortPathName(path)
257+
rappdirs_path <- utils::shortPathName(rappdirs_path)
258+
}
259+
260+
expect_equal(
261+
normalizePath(path, mustWork = FALSE),
262+
normalizePath(rappdirs_path, mustWork = FALSE)
263+
)
264+
})
265+
266+
test_that("legacy path respects R_USER_CACHE_DIR", {
267+
path <- withr::local_tempdir()
268+
withr::local_envvar("R_USER_CACHE_DIR" = path)
269+
270+
expected <- rappdirs::user_cache_dir("httr2")
271+
expect_equal(oauth_cache_path_legacy(), expected)
272+
})

0 commit comments

Comments
 (0)