diff --git a/r/R/filesystem.R b/r/R/filesystem.R index d6554239f630..5a1e0eab6066 100644 --- a/r/R/filesystem.R +++ b/r/R/filesystem.R @@ -167,8 +167,9 @@ FileSelector$create <- function(base_dir, allow_not_found = FALSE, recursive = F #' with `expiration` #' - `expiration`: `POSIXct`. optional datetime representing point at which #' `access_token` will expire. -#' - `json_credentials`: optional string for authentication. Point to a JSON -#' credentials file downloaded from GCS. +#' - `json_credentials`: optional string for authentication. Either a string +#' containing JSON credentials or a path to their location on the filesystem. +#' If a path to credentials is given, the file should be UTF-8 encoded. #' - `endpoint_override`: if non-empty, will connect to provided host name / port, #' such as "localhost:9001", instead of default GCS ones. This is primarily useful #' for testing purposes. @@ -572,6 +573,11 @@ GcsFileSystem$create <- function(anonymous = FALSE, retry_limit_seconds = 15, .. options$retry_limit_seconds <- retry_limit_seconds + # Handle reading json_credentials from the filesystem + if ("json_credentials" %in% names(options) && file.exists(options[["json_credentials"]])) { + options[["json_credentials"]] <- paste(read_file_utf8(options[["json_credentials"]]), collapse = "\n") + } + fs___GcsFileSystem__Make(anonymous, options) } @@ -657,3 +663,10 @@ clean_path_rel <- function(path) { path_sep <- ifelse(tolower(Sys.info()[["sysname"]]) == "windows", "\\\\", "/") gsub(path_sep, "/", path) } + +read_file_utf8 <- function(file) { + res <- readBin(file, "raw", n = file.size(file)) + res <- rawToChar(res) + Encoding(res) <- "UTF-8" + res +} diff --git a/r/man/FileSystem.Rd b/r/man/FileSystem.Rd index c9586f70e716..38c694af995c 100644 --- a/r/man/FileSystem.Rd +++ b/r/man/FileSystem.Rd @@ -69,8 +69,9 @@ credentials using standard GCS configuration methods. with \code{expiration} \item \code{expiration}: \code{POSIXct}. optional datetime representing point at which \code{access_token} will expire. -\item \code{json_credentials}: optional string for authentication. Point to a JSON -credentials file downloaded from GCS. +\item \code{json_credentials}: optional string for authentication. Either a string +containing JSON credentials or a path to their location on the filesystem. +If a path to credentials is given, the file should be UTF-8 encoded. \item \code{endpoint_override}: if non-empty, will connect to provided host name / port, such as "localhost:9001", instead of default GCS ones. This is primarily useful for testing purposes. diff --git a/r/tests/testthat/test-gcs.R b/r/tests/testthat/test-gcs.R index e284beb225e2..fd173e923b27 100644 --- a/r/tests/testthat/test-gcs.R +++ b/r/tests/testthat/test-gcs.R @@ -91,6 +91,30 @@ test_that("GcsFileSystem$create() input validation", { ) }) +test_that("GcsFileSystem$create() can read json_credentials", { + # From string + fs <- GcsFileSystem$create(json_credentials = "fromstring") + expect_equal(fs$options$json_credentials, "fromstring") + + # From disk + cred_string <- '{"key" : "valu\u00e9"}' + cred_string_bytes_utf8 <- iconv( + cred_string, + from = Encoding(cred_string), + to = "UTF-8", + toRaw = TRUE + )[[1]] + + cred_path <- tempfile() + on.exit(unlink(cred_path)) + con <- file(cred_path, open = "wb") + writeBin(cred_string_bytes_utf8, con) + close(con) + + fs <- GcsFileSystem$create(json_credentials = cred_path) + expect_equal(fs$options$json_credentials, "{\"key\" : \"valué\"}") +}) + skip_on_cran() skip_if_not(system('python -c "import testbench"') == 0, message = "googleapis-storage-testbench is not installed.") library(dplyr)