Skip to content
Closed
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
545 changes: 270 additions & 275 deletions R/get_auth_token.R

Large diffs are not rendered by default.

163 changes: 80 additions & 83 deletions R/get_container.R
Original file line number Diff line number Diff line change
@@ -1,83 +1,80 @@
#' Get Azure storage container
#'
#' The environment variable "AZ_STORAGE_EP" should be set. This provides the URL
#' for the default Azure storage endpoint.
#' Use [list_container_names] to get a list of available container names.
#'
#' @param container_name Name of the container as a string. `NULL` by default,
#' which means the function will look instead for a container name stored in
#' the environment variable "AZ_CONTAINER"
#' @param token An Azure authentication token. If left as `NULL`, a token
#' returned by [get_auth_token] will be used
#' @param endpoint_url An Azure endpoint URL. If left as `NULL`, the default,
#' the value of the environment variable "AZ_STORAGE_EP" will be used
#' @param ... arguments to be passed through to [get_auth_token], if a token is
#' not already supplied
#' @returns An Azure blob container (list object of class "blob_container")
#' @export
get_container <- function(
container_name = NULL,
token = NULL,
endpoint_url = NULL,
...
) {
msg1 <- paste0(
"{.var container_name} is empty. ",
"Did you forget to set an environment variable?"
)
msg2 <- paste0(
"{.var endpoint_url} is empty. ",
"Did you forget to set an environment variable?"
)
container_name <- (container_name %||% check_envvar("AZ_CONTAINER")) |>
check_nzchar(msg1)
endpoint_url <- (endpoint_url %||% check_envvar("AZ_STORAGE_EP")) |>
check_nzchar(msg2)
token <- token %||% get_auth_token(...)

get_azure_endpoint(token, endpoint_url) |>
AzureStor::blob_container(container_name)
}


#' Return a list of container names that are found at the endpoint
#'
#' @inheritParams get_container
#' @returns A character vector of all container names found
#' @export
list_container_names <- function(token = NULL, endpoint_url = NULL, ...) {
token <- token %||% get_auth_token(...)
endpoint <- get_azure_endpoint(token, endpoint_url)
container_list <- AzureStor::list_blob_containers(endpoint)
stopifnot("no containers found" = length(container_list) >= 1L)
names(container_list)
}


#' Return an Azure "blob_endpoint"
#'
#' This function will return the endpoint specified in the environment variable
#' "AZ_STORAGE_EP" by default
#'
#' @inheritParams get_container
#' @returns An Azure blob endpoint (object of class "blob_endpoint")
#' @keywords internal
get_azure_endpoint <- function(token = NULL, endpoint_url = NULL, ...) {
token <- token %||% get_auth_token(...)
endpoint_url <- endpoint_url %||% check_envvar("AZ_STORAGE_EP")
AzureStor::blob_endpoint(endpoint_url, token = token)
}


#' Check that an environment variable exists
#'
#' The function prints a helpful error if the variable is not found, else
#' it returns the value of `Sys.getenv(x)`
#'
#' @param x the *name* of the environment variable to be found and checked
#' @returns the value of the environment variable named in `x`
#' @export
check_envvar <- function(x) {
cst_msg <- cst_error_msg("The environment variable {.envvar {x}} is not set")
check_scalar_type(Sys.getenv(x, NA_character_), "string", cst_msg)
}
#' Get Azure storage container
#'
#' The environment variable "AZ_STORAGE_EP" should be set. This provides the URL
#' for the default Azure storage endpoint.
#' Use [list_container_names] to get a list of available container names.
#'
#' @param container_name Name of the container as a string. `NULL` by default,
#' which means the function will look instead for a container name stored in
#' the environment variable "AZ_CONTAINER"
#' @param token An Azure authentication token. If left as `NULL`, a token
#' returned by [get_auth_token] will be used
#' @param endpoint_url An Azure endpoint URL. If left as `NULL`, the default,
#' the value of the environment variable "AZ_STORAGE_EP" will be used
#' @param ... arguments to be passed through to [get_auth_token], if a token is
#' not already supplied
#' @returns An Azure blob container (list object of class "blob_container")
#' @export
get_container <- function(
container_name = NULL,
token = NULL,
endpoint_url = NULL,
...
) {
msg1 <- paste0(
"{.var container_name} is empty. ",
"Did you forget to set an environment variable?"
)
msg2 <- paste0(
"{.var endpoint_url} is empty. ",
"Did you forget to set an environment variable?"
)
container_name <- (container_name %||% check_envvar("AZ_CONTAINER")) |>
check_nzchar(msg1)
endpoint_url <- (endpoint_url %||% check_envvar("AZ_STORAGE_EP")) |>
check_nzchar(msg2)
token <- token %||% get_auth_token(...)

get_azure_endpoint(token, endpoint_url) |>
AzureStor::blob_container(container_name)
}

#' Return a list of container names that are found at the endpoint
#'
#' @inheritParams get_container
#' @returns A character vector of all container names found
#' @export
list_container_names <- function(token = NULL, endpoint_url = NULL, ...) {
token <- token %||% get_auth_token(...)
endpoint <- get_azure_endpoint(token, endpoint_url)
container_list <- AzureStor::list_blob_containers(endpoint)
stopifnot("no containers found" = length(container_list) >= 1L)
names(container_list)
}

#' Return an Azure "blob_endpoint"
#'
#' This function will return the endpoint specified in the environment variable
#' "AZ_STORAGE_EP" by default
#'
#' @inheritParams get_container
#' @returns An Azure blob endpoint (object of class "blob_endpoint")
#' @keywords internal
get_azure_endpoint <- function(token = NULL, endpoint_url = NULL, ...) {
token <- token %||% get_auth_token(...)
endpoint_url <- endpoint_url %||% check_envvar("AZ_STORAGE_EP")
AzureStor::blob_endpoint(endpoint_url, token = token)
}

#' Check that an environment variable exists
#'
#' The function prints a helpful error if the variable is not found, else
#' it returns the value of `Sys.getenv(x)`
#'
#' @param x the *name* of the environment variable to be found and checked
#' @returns the value of the environment variable named in `x`
#' @export
check_envvar <- function(x) {
cst_msg <- cst_error_msg("The environment variable {.envvar {x}} is not set")
check_scalar_type(Sys.getenv(x, NA_character_), "string", cst_msg)
}
55 changes: 25 additions & 30 deletions R/helpers.R
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,12 @@
#' @export
check_that <- function(x, predicate, message, pf = parent.frame()) {
if (predicate(x)) {
x
x
} else {
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
}
}


#' @export
ct_error_msg <- \(text) paste0("{.fn check_that}: ", text)

Expand Down Expand Up @@ -57,16 +56,15 @@ check_vec <- function(
w <- rlang::arg_match(which)
test_call <- rlang::call2(w, .x = x, .p = predicate, .ns = "purrr")
if (eval(test_call)) {
x
x
} else {
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
}
}

#' @export
cv_error_msg <- \(text) paste0("{.fn check_vec}: ", text)


#' An alternative to stopifnot/assert_that etc
#'
#' This function makes it easy to use the `is_scalar_*` functions from `{rlang}`
Expand All @@ -86,32 +84,31 @@ check_scalar_type <- function(
pf = parent.frame()
) {
opts <- c(
"character",
"logical",
"integer",
"double",
"string",
"bool",
"list",
"bytes",
"raw",
"vector",
"complex"
"character",
"logical",
"integer",
"double",
"string",
"bool",
"list",
"bytes",
"raw",
"vector",
"complex"
)
t <- rlang::arg_match(type, opts)
t <- if (t %in% c("string", "bool")) t else paste0("scalar_", t)
test_call <- rlang::call2(paste0("is_", t), x = x, .ns = "rlang")
if (eval(test_call)) {
x
x
} else {
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
}
}

#' @export
cst_error_msg <- \(text) paste0("{.fn check_scalar_type}: ", text)


#' Check if a supplied non-NULL value is a string with >0 characters
#'
#' Will error if x is equal to `""`, or if it is otherwise missing or invalid.
Expand All @@ -125,19 +122,18 @@ cst_error_msg <- \(text) paste0("{.fn check_scalar_type}: ", text)
#' @export
check_nzchar <- function(x, message, pf = parent.frame()) {
if (is.null(x)) {
NULL
NULL
}
cnz <- "check_nzchar" # nolint
check_scalar_type(x, "string", "{.fn {cnz}}: {.var x} is not a string")
if (nzchar(x)) {
x
x
} else {
message <- paste0("{.fn {cnz}}: ", message)
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
message <- paste0("{.fn {cnz}}: ", message)
cli::cli_abort(message, call = rlang::caller_call(), .envir = pf)
}
}


#' grepl a glued regex
#'
#' Use \{glue\} expressions in grepl (and put the arguments the right way round)
Expand All @@ -151,16 +147,15 @@ check_nzchar <- function(x, message, pf = parent.frame()) {
#' @keywords internal
gregg <- \(x, rx, ..., g = parent.frame()) grepl(glue::glue_data(g, rx), x, ...)


#' Check that a container looks like a real container
#' @inheritParams read_azure_parquet
#' @export
check_container_class <- function(container) {
if (inherits(container, "blob_container")) {
container
container
} else {
ccc <- "check_container_class" # nolint
cc <- rlang::caller_call()
cli::cli_abort("{.fn {ccc}}: This is not a valid blob container", call = cc)
ccc <- "check_container_class" # nolint
cc <- rlang::caller_call()
cli::cli_abort("{.fn {ccc}}: This is not a valid blob container", call = cc)
}
}
Loading
Loading