Skip to content

Commit

Permalink
Merge pull request #8 from g6t/cran_release
Browse files Browse the repository at this point in the history
Cran release
  • Loading branch information
idmn authored Oct 18, 2023
2 parents 0063dd0 + f11ecd8 commit 9b8afbc
Show file tree
Hide file tree
Showing 64 changed files with 1,037 additions and 846 deletions.
2 changes: 2 additions & 0 deletions .Rbuildignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,5 @@
^docs$
^pkgdown$
^tools$
^cran-comments\.md$
^CRAN-SUBMISSION$
12 changes: 7 additions & 5 deletions DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
Package: cloudfs
Title: Streamlined interface to interact with cloud storage platforms
Version: 0.0.1
Title: Streamlined Interface to Interact with Cloud Storage Platforms
Version: 0.1.2.9000
Authors@R: c(
person("Iaroslav", "Domin", email = "[email protected]", role = c("aut", "cre")),
person("Stefan", "Musch", email = "[email protected]", role = c("aut")),
person("Michal", "Czyz", email = "[email protected]", role = c("aut")),
person("Emmanuel", "Ugochukwu", email = "[email protected]", role = c("aut")),
person("Gradient Metrics", role = c("cph", "fnd"))
)
Description: This package offers a unified interface for simplifying cloud
storage interactions, including uploading, downloading, reading, and writing
files, with functions for both Google Drive and Amazon S3.
Description: A unified interface for simplifying cloud storage interactions,
including uploading, downloading, reading, and writing files, with functions
for both 'Google Drive' (<https://www.google.com/drive/>) and 'Amazon S3'
(<https://aws.amazon.com/s3/>).
License: MIT + file LICENSE
Encoding: UTF-8
Roxygen: list(markdown = TRUE)
Expand Down Expand Up @@ -41,3 +42,4 @@ VignetteBuilder:
knitr
Config/testthat/edition: 3
URL: https://g6t.github.io/cloudfs/, https://github.com/g6t/cloudfs
BugReports: https://github.com/g6t/cloudfs/issues
4 changes: 3 additions & 1 deletion NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
# cloudfs 0.0.1
# cloudfs (development version)

# cloudfs 0.1.2

* Initial version.
105 changes: 6 additions & 99 deletions R/cli.R
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
#' @title User Interface: Ask a Yes/No question
#'
#' @description This function is inspired by (if not mostly copied from)
#' [usethis::ui_yeah] function. It's purpose is to ask user a yes/no question.
#' `usethis::ui_yeah` function. It's purpose is to ask user a yes/no question.
#' The differences are:
#' 1. It is more limited in answer options customization. This is done on
#' purpose to standardize command line dialogues in our code.
Expand All @@ -15,20 +15,14 @@
#' @param x Question to display.
#' @param straight (logical) Ask a straight Yes/No question? By default (when
#' `FALSE`), two different "no" options and one "yes" option are sampled from
#' a pool of variants. In other words it behaves just like [usethis::ui_yeah]
#' a pool of variants. In other words it behaves just like `usethis::ui_yeah`
#' with default parameter setup. When `straight = TRUE`, it only shows "Yes"
#' and "No", literally.
#'
#' @return (logical) Returns `TRUE` when the user selects a "yes" option and
#' `FALSE` otherwise, i.e. when user selects a "no" option or refuses to make
#' a selection (cancels).
#'
#' @examples
#' \dontrun{
#' cli_yeah("Is this {.strong true}?: {.code 2+2 == 4}")
#' cli_yeah("{.field Yes} or {.field No}?", straight = TRUE)
#' }
#'
#' @keywords internal
cli_yeah <- function(x, straight = FALSE, .envir = parent.frame()) {
check_scalar(x, arg_class = "character")
Expand Down Expand Up @@ -68,41 +62,6 @@ cli_yeah <- function(x, straight = FALSE, .envir = parent.frame()) {
#'
#' @return Invisible `NULL` if assertion is `TRUE`, otherwise an error message.
#'
#' @examples
#' # Variables values to test
#' char_s <- "test"
#' char_v <- c("test", "variable")
#' num_s <- 1.5
#' num_v <- c(2, 1.5, 3.33)
#' logical_s <- TRUE
#' logical_v <- c(FALSE, FALSE)
#' int_s <- 1L
#' int_v <- c(3L, 33L)
#' \dontrun{
#' # Assert Scalar Character
#' check_scalar(char_s, arg_class = "character")
#' check_scalar(char_v, arg_class = "character")
#' check_scalar(num_s, arg_class = "character")
#' check_scalar(logical_s, arg_class = "character")
#'
#' # Assert Scalar Numeric
#' check_scalar(num_s, arg_class = "numeric")
#' check_scalar(num_v, arg_class = "numeric")
#' check_scalar(int_s, arg_class = "numeric", alt_null = TRUE)
#' check_scalar(logical_v, arg_class = "numeric")
#'
#' # Assert Scalar Logical
#' check_scalar(logical_s, arg_class = "logical")
#' check_scalar(logical_v, arg_class = "logical")
#' check_scalar(char_s, arg_class = "logical", alt_null = TRUE)
#' check_scalar(int_v, arg_class = "logical")
#'
#' #' # Assert Scalar Integer
#' check_scalar(int_s, arg_class = "integer")
#' check_scalar(int_v, arg_class = "integer", alt_null = TRUE)
#' check_scalar(num_s, arg_class = "integer")
#' check_scalar(logical_v, arg_class = "integer", alt_null = TRUE)
#' }
#' @keywords internal
check_scalar <- function(..., arg_class, alt_null = FALSE) {

Expand Down Expand Up @@ -171,26 +130,6 @@ check_numeric <- function(x) {
#' @return If argument `class` is same as `arg_class` it returns invisible
#' `NULL`. Otherwise the function throws an error.
#'
#' @examples
#' c1 <- c("x", "y")
#' n1 <- c(1,3,4)
#' n2 <- c(1.5, 2.5)
#' i1 <- 1L
#' df1 <- data.frame(x = 1:5, y = 6:10)
#' new_class <- structure("new class", class= c("character", "new class"))
#' nl1 <- NULL
#' \dontrun{
#' check_class(c1, arg_class = "character")
#' check_class(c1, arg_class = "numeric")
#' check_class(df1, arg_class = "data.frame")
#' check_class(
#' new_class, arg_class = "tbl_df",
#' add_msg = "{.arg {x_name}} with {.cls {wrong_class}} not {.cls {arg_class}}"
#' )
#' check_class(nl1, arg_class = "character")
#' check_class(nl1, arg_class = "character", alt_null = TRUE)
#' check_class(n2, arg_class = "character", alt_null = TRUE)
#' }
#' @keywords internal
check_class <- function(x, arg_class, alt_null = FALSE, add_msg = NULL) {
if(!(inherits(arg_class, "character") & length(arg_class) == 1)) {
Expand Down Expand Up @@ -246,24 +185,6 @@ check_class <- function(x, arg_class, alt_null = FALSE, add_msg = NULL) {
#' @return Returns invisible `NULL` when argument is of asserted length,
#' otherwise it will throw an error.
#'
#' @examples
#' x1 <- 2
#' x2 <- c("x", "y")
#' nl1 <- NULL
#' \dontrun{
#' check_length(x1, arg_length = 1L)
#' check_length(x2, arg_length = 1L)
#' check_length(x1, arg_length = 2L)
#' check_length(
#' x1, arg_length = 2L, add_msg = "{.arg {x_name}} should be short"
#' )
#' check_length(
#' x1, arg_length = 2L, alt_null = TRUE, add_msg = "{.arg {x_name}} should be short"
#' )
#' check_length(
#' nl1, arg_length = 2L, alt_null = TRUE, add_msg = "{.arg {x_name}} should be short"
#' )
#' }
#' @keywords internal
check_length <- function(x, arg_length = 1L, alt_null = FALSE, add_msg = NULL) {
if(!inherits(arg_length, "integer") | length(arg_length) != 1) {
Expand Down Expand Up @@ -301,7 +222,8 @@ check_length <- function(x, arg_length = 1L, alt_null = FALSE, add_msg = NULL) {
#'
#' @description Helper to catch arguments.
#'
#' @param ... unqouted arguments names
#' @param ... unquoted arguments names
#' @return List of quosures.
#'
#' @keywords internal
check_args <- function(...) {
Expand All @@ -317,6 +239,8 @@ check_args <- function(...) {
#' @param x Argument to check if is NULL.
#' @param alt_null Logical. If `TRUE` it will check if `x` is `NULL`.
#'
#' @return Either `TRUE` or `FALSE`.
#'
#' @keywords internal
check_null_cond <- function(x, alt_null){
if(!(isTRUE(alt_null) | isFALSE(alt_null) | length(alt_null) != 1)) {
Expand Down Expand Up @@ -350,23 +274,6 @@ check_null_cond <- function(x, alt_null){
#' @return If argument is single `TRUE` or `FALSE` (optionally `NULL`) it
#' returns invisible `NULL`. Otherwise the function throws an error.
#'
#' @examples
#' c1 <- c("x", "y")
#' n1 <- c(1,3,4)
#' n2 <- c(1.5, 2.5)
#' i1 <- 1L
#' nl1 <- NULL
#' l1 <- FALSE
#' l2 <- c(FALSE, TRUE)
#' \dontrun{
#' check_bool(c1)
#' check_bool(nl1)
#' check_bool(nl1, alt_null = TRUE)
#' check_bool(n2, alt_null = TRUE)
#' check_bool(i1)
#' check_bool(l1)
#' check_bool(l2)
#' }
#' @keywords internal
check_bool <- function(x, alt_null = FALSE, add_msg = NULL) {

Expand Down
43 changes: 24 additions & 19 deletions R/cloud_local.R
Original file line number Diff line number Diff line change
@@ -1,30 +1,32 @@
#' @title List Contents of local project folder
#'
#' @description Prints names, timestamps and sizes of files and folders inside
#' local project folder.
#' @description Retrieves names, timestamps, and sizes of files and folders
#' inside local project folder.
#'
#' @inheritParams validate_desc
#' @inheritParams cloud_prep_ls
#'
#' @param path (optional) Path inside local project folder to list contents of
#' a subfolder. By default, when `path = ""`, lists root-level files and
#' folders.
#' @param root Local path relative to which to consider all paths.
#' @param ignore (logical) Currently just ignores the "renv" folder if `TRUE`.
#' The main reason for this parameter is that "renv" folder usually contains
#' thousands of files and it takes a lot of time to calculate its size. But
#' potentially we may use something like global or project-level cloud ignore
#' files akin to .gitignore.
#' @param path (optional) Path, relative to the specified root to list contents
#' of. By default, when `path = ""`, lists root-level files and folders.
#' @param root Local directory path relative to which all other paths are
#' considered.
#' @param ignore Logical flag indicating whether to ignore certain directories.
#' Currently, if set to `TRUE`, the 'renv' folder is ignored due to its
#' typically large size. This parameter may be expanded in the future to
#' support more complex ignore patterns.
#'
#' @return A tibble containing the names, last modification timestamps, and
#' sizes in bytes of files and folders inside the specified local folder.
#'
#' @examples
#' \dontrun{
#' # list only root-level files and folders
#' cloud_local_ls()
#'
#' # list all files in all nested folders
#' cloud_local_ls(recursive = TRUE)
#'
#' # list contents of "plots/barplots" subfolder
#' \dontrun{
#' # list contents of "plots/barplots" subfolder (if it exists)
#' cloud_local_ls("plots/barplots")
#' }
#'
Expand Down Expand Up @@ -89,23 +91,24 @@ cloud_local_ls <- function(path = "", root = ".", recursive = FALSE,
)
}

#' @title Prepare an ls dataframe for a list of objects
#' @title Prepare a dataframe for bulk writing of objects to cloud
#'
#' @description `cloud_*_ls` functions for cloud locations (e.g.
#' [`cloud_s3_ls`]) return content dataframes which can then be passed to
#' `cloud_*_read_bulk` and `cloud_*_download_bulk` functions to read/download
#' multiple files at once. In a similar manner, this function takes a list of
#' objects as an input and produces a dataframe which can then be passed to
#' multiple files at once. In a similar manner, this function accepts a list
#' of objects as an input and produces a dataframe which can then be passed to
#' `cloud_*_write_bulk` functions to write multiple files at once.
#'
#' @param x A **named** list. Names may contain letters, digits, spaces, '.',
#' '-', '_' symbols and cannot contain trailing or leading spaces.
#' @param path A directory to write objects to.
#' @param extension File extension (string).
#' @param path A directory relative to the project root to write objects to.
#' @param extension File extension (string) without the leading dot.
#' @param prefix,suffix (optional) strings to attach at the beginning or at the
#' end of file names.
#'
#' @return A tibble with two columns.
#' @return A tibble in which each row represents an object from the input list,
#' comprising the following columns:
#'
#' - `object` - objects you've provided
#'
Expand Down Expand Up @@ -172,6 +175,8 @@ cloud_object_ls <- function(x, path, extension, prefix = "", suffix = "") {
#' @param content (data.frame) output of `cloud_object_ls()`
#' @param quiet all caution messages may be turned off by setting this parameter
#' to `TRUE`.
#'
#' @return Modified `content` dataframe.
#'
#' @keywords internal
cloud_object_prep_bulk <- function(content, quiet = FALSE) {
Expand Down
49 changes: 38 additions & 11 deletions R/common.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,24 @@
#' DESCRIPTION.
#'
#' @inheritParams validate_desc
#' @return A named list where each element corresponds to a `cloudfs.*` root
#' defined in the project's DESCRIPTION file. The names of the list elements
#' are derived from the `cloudfs.*` fields by removing the `cloudfs.` prefix.
#'
#' @examples
#' # create a temp. folder, and put DESCRIPTION file with cloudfs.* fields into it
#' tmp_project <- file.path(tempdir(), "cloudfs")
#' if (!dir.exists(tmp_project)) dir.create(tmp_project)
#' tmp_project_desc <- file.path(tmp_project, "DESCRIPTION")
#' desc_content <- c(
#' "Package: -",
#' "cloudfs.s3: my_bucket/my_project",
#' "cloudfs.drive: aaaaaa"
#' )
#' writeLines(desc_content, tmp_project_desc)
#'
#' roots <- cloud_get_roots(tmp_project)
#' roots
#'
#' @export
cloud_get_roots <- function(project = ".") {
Expand All @@ -14,11 +32,13 @@ cloud_get_roots <- function(project = ".") {
}


#' @title Extract values from DESCRUPTION file
#' @title Extract values from DESCRIPTION file
#'
#' @inheritParams validate_desc
#' @param key Character. What field to search for in DESCRIPTION file.
#'
#' @return A string value extracted from the DESCRIPTION field.
#'
#' @keywords internal
proj_desc_get <- function(key, project = ".") {
check_string(key)
Expand All @@ -38,22 +58,25 @@ proj_desc_get <- function(key, project = ".") {
#' letters, digits, '-', '_', '.', spaces and '/' symbols.
#' @param error if `TRUE` (default), throws an error if `file` is not a valid
#' file path.
#'
#' @return Either `TRUE` or `FALSE` if `error` is `FALSE`. Either `TRUE` or
#' an error if `error` is `TRUE`.
#'
#' @keywords internal
cloud_validate_file_path <- function(file, error = TRUE) {
check_string(file)
res <- grepl("^([A-Za-z]|[0-9]|-|_|\\.| |/)+$", file)
if (error) {
if (file == "") stop("A valid file name should not be empty.")
if (!res) stop(
"File name '", file, "' is not valid\n\n",
"A valid file name may consist of\n",
" * uppercase/lowercase letters\n",
" * digits\n",
" * spaces",
" * '/' symbols to describe its location inside project's folder\n",
" * '_', '-', '.' symbols"
)
if (file == "") cli::cli_abort("A valid file name should not be empty.")
if (!res) cli_abort(c(
"File name '{file}' is not valid",
"A valid file name may consist of:",
"*" = "uppercase/lowercase letters",
"*" = "digits",
"*" = "spaces",
"*" = "'/' symbols to describe its location inside project's folder",
"*" = "'_', '-', '.' symbols"
))
}
res
}
Expand Down Expand Up @@ -89,6 +112,8 @@ cloud_validate_file_names <- function(x) {
#'
#' @param project Character. Path to a project. By default it is current working
#' directory.
#'
#' @return Either `TRUE` or an error.
#'
#' @keywords internal
validate_desc <- function(project = ".") {
Expand Down Expand Up @@ -160,6 +185,8 @@ init_desc <- function(project = ".") {
#' nested subfolders. Default is `FALSE`.
#' @param full_names (logical) If `TRUE`, folder path is appended to object
#' names to give a relative file path.
#'
#' @return Transformed `data`.
#'
#' @keywords internal
cloud_prep_ls <- function(data, path, recursive, full_names) {
Expand Down
Loading

0 comments on commit 9b8afbc

Please sign in to comment.