From b369b4fde85f49ec51c68d0886006316ee3b9b8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 14 Mar 2024 09:30:29 +0100 Subject: [PATCH 01/22] Put all old code files into a single file --- DESCRIPTION | 2 +- R/api.R | 104 -- R/assertions.R | 110 -- R/build.R | 26 - R/check-class.R | 438 ------ R/check-cran.R | 56 - R/check-shortcuts.R | 139 -- R/check.R | 114 -- R/column-dt.R | 13 - R/column-group-id.R | 25 - R/column-id.R | 25 - R/column-result.R | 39 - R/column-status.R | 49 - R/email.R | 236 --- R/env.R | 51 - R/error.R | 50 - R/handle.R | 26 - R/last.R | 19 - R/list.R | 139 -- R/livelog.R | 129 -- R/local.R | 159 -- R/platform.R | 66 - R/print-status.R | 76 - R/print.R | 56 - R/rematch_all.R | 78 - R/rhub-package.R | 8 - R/rhubv1.R | 2394 +++++++++++++++++++++++++++++++ R/submit.R | 46 - R/utils.R | 117 -- man/check.Rd | 2 +- man/check_for_cran.Rd | 4 +- man/check_shortcuts.Rd | 2 +- man/get_check.Rd | 2 +- man/last_check.Rd | 2 +- man/list_my_checks.Rd | 2 +- man/list_package_checks.Rd | 2 +- man/list_validated_emails.Rd | 2 +- man/local_check_linux.Rd | 2 +- man/local_check_linux_images.Rd | 2 +- man/platforms.Rd | 2 +- man/rhub-ids.Rd | 2 +- man/rhub-package.Rd | 2 +- man/rhub_check.Rd | 2 +- man/validate_email.Rd | 2 +- 44 files changed, 2411 insertions(+), 2411 deletions(-) delete mode 100644 R/api.R delete mode 100644 R/assertions.R delete mode 100644 R/build.R delete mode 100644 R/check-class.R delete mode 100644 R/check-cran.R delete mode 100644 R/check-shortcuts.R delete mode 100644 R/check.R delete mode 100644 R/column-dt.R delete mode 100644 R/column-group-id.R delete mode 100644 R/column-id.R delete mode 100644 R/column-result.R delete mode 100644 R/column-status.R delete mode 100644 R/email.R delete mode 100644 R/env.R delete mode 100644 R/error.R delete mode 100644 R/handle.R delete mode 100644 R/last.R delete mode 100644 R/list.R delete mode 100644 R/livelog.R delete mode 100644 R/local.R delete mode 100644 R/platform.R delete mode 100644 R/print-status.R delete mode 100644 R/print.R delete mode 100644 R/rematch_all.R delete mode 100644 R/rhub-package.R create mode 100644 R/rhubv1.R delete mode 100644 R/submit.R delete mode 100644 R/utils.R diff --git a/DESCRIPTION b/DESCRIPTION index c9a2131..088fe6a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -13,7 +13,7 @@ Description: Run 'R CMD check' on any of the 'R-hub' (= 1 && all(x != "") -} - -on_failure(is_check_ids) <- function(call, env) { - paste0(deparse(call$x), " is not a vector of check ids") -} - -is_count <- function(x) { - is.numeric(x) && length(x) == 1 && as.integer(x) == x -} - -on_failure(is_count) <- function(call, env) { - paste0(deparse(call$x), " is not a count (length 1 integer)") -} - -as_timeout <- function(x) { - if (inherits(x, "difftime")) return(x) - as.difftime(as.double(x), units = "secs") -} - -is_timeout <- function(x) { - inherits(x, "difftime") && length(x) == 1 && !is.na(x) -} - -on_failure(is_timeout) <- function(call, env) { - paste0(deparse(call$x), " must be a timeout, a 'difftime' constant") -} diff --git a/R/build.R b/R/build.R deleted file mode 100644 index 18a7739..0000000 --- a/R/build.R +++ /dev/null @@ -1,26 +0,0 @@ - -#' @importFrom withr with_dir -#' @importFrom callr rcmd_safe - -build_package <- function(path, tmpdir) { - - path <- normalizePath(path) - - dir.create(tmpdir) - file.copy(path, tmpdir, recursive = TRUE) - - ## If not a tar.gz, build it. Otherwise just leave it as it is. - if (file.info(path)$isdir) { - build_status <- with_dir( - tmpdir, - rcmd_safe("build", basename(path)) - ) - unlink(file.path(tmpdir, basename(path)), recursive = TRUE) - report_system_error("Build failed", build_status) - } - - file.path( - tmpdir, - list.files(tmpdir, pattern = "\\.tar\\.gz$") - ) -} diff --git a/R/check-class.R b/R/check-class.R deleted file mode 100644 index f755bd4..0000000 --- a/R/check-class.R +++ /dev/null @@ -1,438 +0,0 @@ - -#' @title R-hub check ids -#' @section R-hub ids: -#' -#' Every R-hub check has a unique id, that is constructed from the -#' name of the source package archive, and a random string. For example: -#' ```r -#' devtools_2.0.0.tar.gz-fe53bbba85de4a579f6dc3b852bf76a3 -#' ``` -#' -#' @section R-hub group ids: -#' -#' For every check submission, R-hub also creates a unique check group id. -#' One check group may contain multiple checks. E.g. [check_for_cran()] -#' typically creates three or four check groups. Group ids look the same -#' as individual check ids. -#' -#' @section Abbreviating ids: -#' -#' The rhub package keeps a list of all the checks that it has seen in the -#' current session, and these checks can be also referenced by any unique -#' prefix of the random string part of the id, e.g. in the [get_check()] -#' function. E.g. if rhub already know the devtools check above, then -#' ```r -#' get_check("fe53bbb") -#' ``` -#' works. -#' -#' This is only recommended in interactive mode, and we suggest that you -#' always use the full ids when using rhub programmatically. -#' -#' @name rhub-ids -NULL - -#' An `rhub_check` object holds status and results of rhub checks -#' -#' @section Usage: -#' ``` -#' ch <- rhub_check$new(ids = NULL, status = NULL, group = NULL) -#' ch$get_ids() -#' ch$update() -#' ch$print(...) -#' ch$browse(which = NULL) -#' ch$urls(which = NULL) -#' ch$livelog(which = 1) -#' ch$cran_summary() -#' ``` -#' -#' @section Arguments: -#' * `ch` An rhub check object. It can be created using [`check()`], -#' and other check functions including [`check_for_cran`]. -#' See also [last_check()]. -#' * `ids` Character vector of check ids. -#' * `status` Check status for `ids` or `group`. -#' * `group` Check group id, string scalar. Either `group` or `ids` must -#' be non-`NULL`. -#' * `...` Extra arguments are currently ignored. -#' * `which` Which check to show, if the object contains multiple -#' checks. For `browse` the default is all checks. For `livelog` the -#' default is the first check. A check can be selected via its number -#' or id. -#' -#' @section Details: -#' -#' An `rhub_check` object can be created by [check()], [list_my_checks()], -#' or [list_package_checks()]. [last_check()] returns the last check(s) -#' submitted from the current R session. Do not confuse `rhub_check`/`rhub_check_for_cran` -#' (classes) with [check()] or [check_for_cran()] (functions). -#' -#' `ch$get_ids()` returns the check ids. These can be used to query if a -#' check has finished. -#' -#' `ch$update()` updates the status of the check. Printing the check -#' status to the screen does not perform an update, unless the status of -#' the check(s) is unknown. -#' -#' `ch$print()` prints the status of the check(s) to the screen. -#' -#' `ch$cran_summary()` prints text to be copy-pasted in cran-comments.md, -#' it is especially useful on the output of [`check_for_cran()`]. -#' -#' `ch$browse()` opens a tab or window in the default web browser, that points -#' to the detailed logs of the check(s). -#' -#' `ch$urls()` return a [`tibble::tibble`] with URL to the html log, text log and artifacts -#' of the check(s). -#' -#' For both `ch$browse()` and `ch$urls()`, note that the logs and artifacts -#' are not kept forever, they are accessible for a few days after submission. -#' -#' `ch$livelog()` shows the live log of the check. The live log can be -#' interrupted using the usual interruption keyboard shortcut, usually -#' `CTRL+c` or `ESC`. -#' -#' @name rhub_check -NULL - -#' @importFrom R6 R6Class - -rhub_check <- R6Class( - "rhub_check", - - public = list( - - initialize = function(ids = NULL, status = NULL, group = NULL) - check_init(self, private, ids, status, group), - - get_ids = function() private$ids_, - - update = function() - check_update(self, private), - - print = function(...) - check_print(self, private, ...), - - web = function(which = NULL) - check_web(self, private, which), - - browse = function(which = NULL) - self$web(which), - - urls = function(which = NULL) - check_urls(self, private, which), - - livelog = function(which = 1) - check_livelog(self, private, which), - - cran_summary = function() - check_cran_summary(self, private) - ), - - private = list( - ids_ = NULL, # character vector of ids - group_ = NULL, # group id - status_ = NULL, # list of status objects, as in DB - status_updated_ = NULL # last time status was updated - ) -) - -check_init <- function(self, private, ids, status, group) { - assert_that( - is_check_ids(ids) || is.null(ids), - (is_check_ids(group) && length(group) == 1) || is.null(group), - !is.null(ids) || !is.null(group)) - - private$ids_ <- ids - private$group_ <- group - private$status_ <- status - status_updated_ <- Sys.time() - invisible(self) -} - -check_update <- function(self, private) { - ## If it is a group, we need to get the ids first. This also updates - ## the status of the individual checks - if (!is.null(private$group_) && is.null(private$ids_)) { - grp <- query("GET GROUP STATUS", list(id = private$group_)) - private$ids_ <- map_chr(grp, "[[", "id") - private$status_ <- grp - private$status_updated_ <- Sys.time() - for (i in seq_along(grp)) cache_put(grp[[i]]$id, grp[[i]]) - return(invisible(self)) - } - - ## Check which ones need update. We need to update if we don't know - ## anything about the id, or if it has not finished yet. - cached <- lapply(private$ids_, cache_get) - need_upd <- map_lgl(cached, function(x) { - is.null(x) || x$status %in% c("created", "in-progress") - }) - - if (any(need_upd)) { - ## Update - upd <- query("GET STATUS", data = list(id = private$ids_[need_upd])) - cached[need_upd] <- upd - - ## Update the cache - for (i in seq_along(upd)) cache_put(private$ids_[need_upd][i], upd[[i]]) - } - - ## Update the object, we always do this, in case the object is outdated, - ## but the cache is not - private$status_ <- cached - private$status_updated_ <- Sys.time() - - invisible(self) -} - -#' @importFrom utils browseURL - -check_web <- function(self, private, which) { - - ids <- select_ids(which = which, self = self, - private = private) - - urls <- paste0(sub("/api$", "/status/", baseurl()), ids) - - lapply(urls, browseURL) - invisible(self) -} - -check_urls <- function(self, private, which) { - - ids <- select_ids(which = which, self = self, - private = private) - - tibble::tibble(html = paste0(sub("/api$", "/status/", baseurl()), ids), - text = paste0(sub("/api$", "/status/original/", baseurl()), - ids), - artifacts = paste0("https://artifacts.r-hub.io/", ids), - stringsAsFactors = FALSE) -} - -select_ids <- function(which, self, private){ - ids <- if (is.null(which)) { - private$ids_ - } else if (is.numeric(which)) { - private$ids_[which] - } else if (is.character(which)) { - intersect(private$ids_, which) - } else { - stop("Unknown check selected", - call. = FALSE) - } - - return(ids) -} - -check_cran_summary <- function(self, private) { - - self$update() - - x <- private$status_ - - statuses <- map_chr(x, "[[", "status") - - if (any(statuses %in% c("in-progress", "created"))) { - stop(paste("At least one of the builds has not finished yet.", - "Please wait before calling `cran_summary()` again."), - call. = FALSE) - } - - if (any(statuses %in% problem_statuses())) { - platforms <- lapply(x, "[[", "platform") - platform_names <- map_chr(platforms, "[[", "name") - stop(paste("Build failures on platforms:", - toString(platform_names[statuses %in% problem_statuses()]), - ". \n", - "Read the log(s) to fix and if needed ask for help via ", - "https://docs.r-hub.io/#pkg-dev-help"), - call. = FALSE) - } - - result <- do.call("rbind", - lapply(x, rectangle_status)) - - systems <- paste0("- R-hub ", - vapply(x, function(xx) xx$platform$name, ""), - " (", - vapply(x, function(xx) xx$platform$rversion, ""), - ")") - lines <- paste0(systems, "\n") - - - result <- result[!is.na(result$type),] - - if (nrow(result) > 0){ - message("For a CRAN submission we recommend that you fix all NOTEs, WARNINGs and ERRORs.") - unique_results <- unique(result[, c("type", "hash")]) - - makeshift <- structure( - list( - package = x$package, - version = toString(vapply(x, function(xx) xx$platform$name, "")), - rversion = toString(systems), - output = list(), - platform = toString(systems), - notes = unlist(lapply(unique(unique_results$hash[unique_results$type == "NOTE"]), - combine_message, result = result)), - warnings = unlist(lapply(unique(unique_results$hash[unique_results$type == "WARNING"]), - combine_message, result = result)), - errors = unlist(lapply(unique(unique_results$hash[unique_results$type == "ERROR"]), - combine_message, result = result)) - ), - class = "rcmdcheck" - ) - - } else { - makeshift <- structure( - list( - package = x$package, - version = toString(vapply(x, function(xx) xx$platform$name, "")), - rversion = toString(systems), - output = list(), - platform = toString(systems), - notes = NULL, - warnings = NULL, - errors = NULL - ), - class = "rcmdcheck" - ) - } - - cat("## Test environments\n") - cat(lines, sep = "") - cat("\n") - cat("## R CMD check results\n") - print(makeshift, header = FALSE) - - invisible(self) -} - - -get_status_part <- function(part, x){ - output <- unlist(x[part]) - if(is.null(output)){ - return("") - }else{ - output - } -} - -rectangle_status <- function(x){ - - df <- rbind(data.frame(type = "ERROR", - message = get_status_part("errors", x$result), - stringsAsFactors = FALSE), - data.frame(type = "WARNING", - message = get_status_part("warnings", x$result), - stringsAsFactors = FALSE), - data.frame(type = "NOTE", - message = get_status_part("notes", x$result), - stringsAsFactors = FALSE)) - - df <- df[df$message != "",] - - if(nrow(df) == 0){ - df <- data.frame(package = x$package, - type = NA, - message = NA, - hash = NA) - } else{ - df$hash <- hash_check(df$message) - } - - df$package <- x$package - df$version <- x$version - df$submitted <- x$submitted - df$platform <- paste0(x$platform$name, " (", x$platform$rversion, - ")") - - return(df) -} - -combine_message <- function(hash, result){ - paste0("On ", toString(result$platform[result$hash == hash]), "\n", - result$message[result$hash == hash][1]) -} - -# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/968fd9ba76ee9b7bf65d192568555ab57160165e/R/parse.R#L110 -#' @importFrom digest digest - -hash_check <- function(check) { - cleancheck <- gsub("[^a-zA-Z0-9]", "", first_line(check)) - vapply(cleancheck, digest::digest, "") -} - -# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/afadc6c53310cad2b64e0a58e399efd1ae18d7dd/R/utils.R#L91 -first_line <- function(x) { - l <- strsplit(x, "\n", fixed = TRUE) - vapply(l, "[[", "", 1) -} - -#' Retrieve the result of R-hub checks -#' -#' @param ids One of the following: -#' - A single R-hub check id. -#' - A character vector of check ids. -#' - An R-hub check group id. -#' All ids can be abbreviated, see [R-hub ids][rhub-ids]. -#' @return An [rhub_check] object. -#' -#' @section Examples: -#' ``` -#' chk <- get_check("915ee61") -#' chk -#' chk$update() -#' chk$browse() -#' chk$cran_summary() -#' chk$urls() -#' ``` -#' -#' @export -#' @seealso [list_my_checks()] and [list_package_checks()] to list -#' R-hub checks. - -get_check <- function(ids) { - assert_that(is_check_ids(ids)) - - short <- grep(re_id, ids, invert = TRUE, value = TRUE) - if (length(short) && - length(package_data$ids) == 0 && - length(package_data$groups) == 0) { - stop( - "Short check id '", short[1], "' ", - if (length(short) > 1) paste0("(and ", length(short)-1, " more) "), - "can only be used for cached ids, and no ids are cached yet.\n", - " Try calling `list_my_checks()` or `list_package_checks()` first." - ) - } - - sle <- cache_get_ids(ids) - grp <- cache_get_group_ids(ids) - - err <- NULL - - ## If we are not sure that it is a group id, then query single ids - res <- if (length(ids) > 1 || is.na(grp)) { - ids2 <- ifelse(is.na(sle), ids, sle) - tryCatch( - rhub_check$new(ids2)$update(), - error = function(e) { err <<- e; NULL } - ) - } - - if (!is.null(res)) return(res) - - ## If there is a chance that it is a group, then we try that as well - if (length(ids) == 1 && is.na(sle)) { - ids3 <- if (is.na(grp)) ids else grp - res <- rhub_check$new(group = ids3)$update() - res - } else { - stop(err) - } -} - -re_id <- "-[0-9a-f]{32}$" diff --git a/R/check-cran.R b/R/check-cran.R deleted file mode 100644 index ae6f3f4..0000000 --- a/R/check-cran.R +++ /dev/null @@ -1,56 +0,0 @@ - -#' Check an R-package on R-hub, for a CRAN submission -#' -#' This function calls [check()] with arguments and platforms, that -#' are suggested for a CRAN submission. -#' -#' In particular, if `platforms` is `NULL` (the default), then -#' * It checks the package on Windows, and Linux. -#' * It checks the package on R-release and R-devel. -#' * It uses the `--as-cran` argument to `R CMD check`. -#' * It requires all dependencies, including suggested ones. -#' -#' @details This function is wrapped by `devtools::check_rhub()` which you -#' might find useful if you load `devtools` via your .Rprofile (see `usethis::use_devtools()`). -#' -#' @param check_args Arguments for `R CMD check`. By default `--as-cran` -#' is used. -#' @param env_vars Character vector of environment variables to set on the builder. -#' By default `_R_CHECK_FORCE_SUGGESTS_="true"` is set, to require all packages used. -#' `_R_CHECK_CRAN_INCOMING_USE_ASPELL_="true"` is also set, to use the -#' spell checker. -#' @param ... Additional arguments are passed to [check()]. -#' @inheritParams check -#' @return An [rhub_check] object. -#' -#' @export -#' @examples -#' \dontrun{ -#' ch <- check_for_cran("package", show_status = FALSE) -#' ch$update() -#' ch$livelog(3) -#' } - -check_for_cran <- function( - path = ".", email = NULL, check_args = "--as-cran", - env_vars = c("_R_CHECK_FORCE_SUGGESTS_" = "true", - "_R_CHECK_CRAN_INCOMING_USE_ASPELL_" = "true"), platforms = NULL, - ...) { - - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - - platforms <- platforms %||% default_cran_check_platforms(path) - - check(path = path, platforms = platforms, email = email, - check_args = check_args, env_vars = env_vars, ...) -} - -default_cran_check_platforms <- function(path) { - c( - "windows-x86_64-devel", - "ubuntu-gcc-release", - "fedora-clang-devel", - if (needs_compilation(path)) "linux-x86_64-rocker-gcc-san" - ) -} diff --git a/R/check-shortcuts.R b/R/check-shortcuts.R deleted file mode 100644 index 3f142e1..0000000 --- a/R/check-shortcuts.R +++ /dev/null @@ -1,139 +0,0 @@ - -## Various OSes -------------------------------------------------------- - -#' Check an R package on an R-hub platform -#' -#' These functions provide a quick easy to use interface to check a -#' package on a platform with some particular aspect. Which platform -#' they use might change over time. -#' -#' @param ... Additional arguments are passed to [check()]. -#' @return An [rhub_check] object. -#' @inheritParams check -#' -#' @export -#' @rdname check_shortcuts - -check_on_linux <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$linux, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_windows <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$windows, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_macos <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$macos, ...) -} - -## Various Linux OSes -------------------------------------------------- - -#' @export -#' @rdname check_shortcuts - -check_on_debian <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$debian, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_ubuntu <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$ubuntu, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_fedora <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$fedora, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_solaris <- function(path = ".", check_args = - "'--no-manual --no-build-vignettes'", ...) { - check(path = path, platforms = check_shortcut_platforms$solaris, - check_args = check_args, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_on_centos <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$centos, ...) -} - -## R versions -------------------------------------------------------- - -#' @export -#' @rdname check_shortcuts - -check_with_roldrel <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$roldrel, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_with_rrelease <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rrelease, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_with_rpatched <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rpatched, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_with_rdevel <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rdevel, ...) -} - -## Extra checks -------------------------------------------------------- - -#' @export -#' @rdname check_shortcuts - -check_with_valgrind <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$valgrind, - valgrind = TRUE, ...) -} - -#' @export -#' @rdname check_shortcuts - -check_with_sanitizers <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$sanitizers, ...) -} - -## ------------------------------------------------------------------- - - -check_shortcut_platforms <- list( - "linux" = "debian-gcc-release", - "windows" = "windows-x86_64-release", - "macos" = "macos-highsierra-release", - "valgrind" = "debian-gcc-release", - "sanitizers" = "linux-x86_64-rocker-gcc-san", - "roldrel" = "windows-x86_64-oldrel", - "rrelease" = "debian-gcc-release", - "rpatched" = "debian-gcc-patched", - "rdevel" = "debian-gcc-devel", - "debian" = "debian-gcc-release", - "ubuntu" = "ubuntu-gcc-release", - "fedora" = "fedora-gcc-devel", - "centos" = "linux-x86_64-centos6-epel", - "solaris" = "solaris-x86-patched" -) diff --git a/R/check.R b/R/check.R deleted file mode 100644 index 42fda1d..0000000 --- a/R/check.R +++ /dev/null @@ -1,114 +0,0 @@ - -#' Check an R package on R-hub -#' -#' @param path Path to a directory containing an R package, or path to -#' source R package tarball built with `R CMD build` or -#' `devtools::build()`. -#' @param platforms A character vector of one or more platforms to build/check -#' the package on. See [platforms()] for the available platforms. If this is -#' \code{NULL}, and the R session is interactive, then a menu is shown. If it -#' is \code{NULL}, and the session is not interactive, then the default R-hub -#' platforms are used. A vector of platforms which saves time by building one -#' R package tarball that is used for all the platforms specified. -#' @param email Email address to send notification to about the check. -#' It must be a validated email address, see [validate_email()]. If -#' `NULL`, then the email address of the maintainer is used, as defined -#' in the `DESCRIPTION` file of the package. -#' @param valgrind Whether to run the check in valgrind. Only supported on -#' Linux currently, and ignored on other platforms. -#' @param check_args Extra arguments for the `R CMD check` command. -#' @param env_vars Environment variables to set on the builder machine -#' before the check. A named character vector. -#' @param show_status Whether to show the status of the build and check -#' (live log) as it is happening. -#' @return An [rhub_check] object. -#' -#' @export -#' @examples -#' \dontrun{ -#' check(".") -#' check("mypackage_1.0.0.tar.gz", platforms = "fedora-clang-devel") -#' } - -check <- function(path = ".", platforms = NULL, - email = NULL, valgrind = FALSE, check_args = character(), - env_vars = character(), show_status = interactive()) { - - ## Check that it is a package - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - assert_that(is_flag(valgrind)) - assert_that(is_named(env_vars)) - assert_that(is.character(env_vars)) - - ## Make sure that maintainer email was validated - if (is.null(email)) email <- get_maintainer_email(path) - if (is.na(email)) stop("Cannot get email address from package") - assert_validated_email_for_check(email) - - platforms <- match_platform(platforms) - - ## Build the tar.gz, if needed - if (file.info(path)$isdir) { - header_line("Building package") - pkg_targz <- build_package(path, tmpdir <- tempfile()) - } else { - pkg_targz <- path - } - - ## Add valgrind to check_args - check_args <- c( - check_args, - if (valgrind) "--use-valgrind" - ) - - ## Submit to R-hub - response <- submit_package( - email, - pkg_targz, - platforms = platforms, - check_args = check_args, - env_vars = env_vars - ) - - ids <- vapply(response, "[[", "", "id") - chk <- rhub_check$new(ids = ids) - - package_data$last_handle <- chk - lapply(ids, cache_put, status = NULL) - - ## Show the live status, if requested - if (show_status) chk$livelog() - - invisible(chk) -} - -assert_validated_email_for_check <- function(email) { - - assert_that(is_email(email)) - code <- email_get_token(email) - if (is.null(code)) { - if (is_interactive()) { - cat("\n") - message(paste(collapse = "\n", strwrap(indent = 2, exdent = 2, paste0( - sQuote(crayon::green(email)), " is not validated, or does not match ", - "the package maintainer's email. To validate it now, please enter ", - "the email address below. Note that R-hub will send a token to ", - "this address. If the address does not belong to you, quit now by ", - "pressing ", crayon::yellow("ENTER"), ". You can also specify a ", - "different email by suppling email=." - )))) - cat("\n") - email2 <- readline(" Email address: ") - cat("\n") - if (email2 == "") { - stop("Aborting.", call. = FALSE) - } else if (email != email2) { - stop("Emails don't match, aborting", call. = FALSE) - } - validate_email(email) - } else { - stop(sQuote(email), " is not validated") - } - } -} diff --git a/R/column-dt.R b/R/column-dt.R deleted file mode 100644 index e439221..0000000 --- a/R/column-dt.R +++ /dev/null @@ -1,13 +0,0 @@ - -column_dt <- function(x) { - as.difftime(x / 1000, units = "secs") -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @importFrom prettyunits pretty_dt -#' @export - -pillar_shaft.difftime <- function(x, ...) { - cx <- my_pretty_dt(x) - new_pillar_shaft_simple(cx, ...) -} diff --git a/R/column-group-id.R b/R/column-group-id.R deleted file mode 100644 index b26492b..0000000 --- a/R/column-group-id.R +++ /dev/null @@ -1,25 +0,0 @@ - -column_group_id <- function(x) { - structure(x, class = unique(c("rhub_column_group_id", class(x)))) -} - -#' @export - -`[.rhub_column_group_id` <- function(x, i) { - column_group_id(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @export - -pillar_shaft.rhub_column_group_id <- function(x, ...) { - cx <- shorten_rhub_id(x) - new_pillar_shaft_simple(cx, ...) -} - -#' @importFrom pillar type_sum -#' @export - -type_sum.rhub_column_group_id <- function(x) { - "rhub::group_id" -} diff --git a/R/column-id.R b/R/column-id.R deleted file mode 100644 index 49d3d8c..0000000 --- a/R/column-id.R +++ /dev/null @@ -1,25 +0,0 @@ - -column_id <- function(x) { - structure(x, class = unique(c("rhub_column_id", class(x)))) -} - -#' @export - -`[.rhub_column_id` <- function(x, i) { - column_id(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @export - -pillar_shaft.rhub_column_id <- function(x, ...) { - cx <- shorten_rhub_id(x) - new_pillar_shaft_simple(cx, ...) -} - -#' @importFrom pillar type_sum -#' @export - -type_sum.rhub_column_id <- function(x) { - "rhub::id" -} diff --git a/R/column-result.R b/R/column-result.R deleted file mode 100644 index b4ab819..0000000 --- a/R/column-result.R +++ /dev/null @@ -1,39 +0,0 @@ -column_result <- function(x) { - structure(x, class = unique(c("rhub_column_result", class(x)))) -} - -#' @export - -`[.rhub_column_result` <- function(x, i) { - column_result(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @export - -pillar_shaft.rhub_column_result <- function(x, ...) { - cx <- lapply(x, color_column_result) - new_pillar_shaft_simple(cx, ...) -} - -color_column_result <- function(x) { - if (is.null(x)) return("in-progress") - E <- if (n <- length(x$errors)) status_style_error(strrep("E", n)) - W <- if (n <- length(x$warnings)) status_style_error(strrep("W", n)) - N <- if (n <- length(x$notes)) status_style_note(strrep("N", n)) - - switch( - x$status, - "parseerror" = status_style_error("parseerror"), - "preperror" = status_style_error("preperror"), - "aborted" = status_style_aborted("aborted"), - "ok" = status_style_ok("ok"), - paste0(E, W, N)) -} - -#' @importFrom pillar type_sum -#' @export - -type_sum.rhub_column_result <- function(x) { - "rhub::result" -} diff --git a/R/column-status.R b/R/column-status.R deleted file mode 100644 index 486fc38..0000000 --- a/R/column-status.R +++ /dev/null @@ -1,49 +0,0 @@ - -column_status <- function(x) { - structure(x, class = unique(c("rhub_column_status", class(x)))) -} - -#' @export - -`[.rhub_column_status` <- function(x, i) { - column_status(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @export - -pillar_shaft.rhub_column_status <- function(x, ...) { - ## status can be - ## - created - ## - in-progress - ## - parseerror (the R-hub output parser failed) - ## - preperror (build failed before R CMD check has started - ## - aborted (build was aborted) - ## - error - ## - warning - ## - note - ## - ok - - hst <- c( - "created" = status_style_created("created"), - "in-progress" = status_style_in_progress("in-progress"), - "parseerror" = status_style_error("parseerror"), - "preperror" = status_style_error("preperror"), - "aborted" = status_style_aborted("aborted"), - "error" = status_style_error("error"), - "warning" = status_style_error("warning"), - "note" = status_style_note("note"), - "ok" = status_style_ok("ok")) - - cx <- hst[x] - cx[is.na(cx)] <- x[is.na(cx)] - - new_pillar_shaft_simple(cx, ...) -} - -#' @importFrom pillar type_sum -#' @export - -type_sum.rhub_column_status <- function(x) { - "rhub::status" -} diff --git a/R/email.R b/R/email.R deleted file mode 100644 index e33db4c..0000000 --- a/R/email.R +++ /dev/null @@ -1,236 +0,0 @@ - -#' Validate an email address on R-hub -#' -#' To build and check R packages on R-hub, you need to validate your -#' email address. This is because R-hub sends out emails about check -#' results. -#' -#' The `rhub` package stores validated email addresses in a user -#' configuration file, at a platform-dependent location. -#' On your current platform the file is at -#' \Sexpr[stage=render]{rhub:::email_file()}. -#' -#' To validate a new email address, call this function from an interactive -#' R session, without any arguments. -#' -#' To add an email address that was validated before (probably on another -#' machine), to the configuration file, call this function with the `email` -#' and `token` arguments. -#' -#' @param email The email address to validate. -#' @param token Token obtained from `rhub`, to validate the email address. -#' -#' @family email validation -#' @export -#' @importFrom jsonlite unbox - -validate_email <- function(email = NULL, token = NULL) { - - if (is.null(email) || is.null(token)) { - if (!is_interactive()) { - stop("No email or no token and not in interactive mode") - } - return(validate_email_interactive(email, token)) - } - - assert_that(is_email(email)) - assert_that(is_token(token)) - - email_add_token(email, token) - message("Token added for ", sQuote(email)) - cat("\n") - token_file_msg() - cat("\n") - invisible() -} - -#' @importFrom cli symbol -#' @importFrom utils menu -#' @importFrom whoami email_address - -get_email_to_validate <- function(path) { - - ## Find out email first. List currently validated addresses, - ## Offer address by whoami::email_address(), and also the - ## maintainer address, if any. - - valid <- list_validated_emails2(msg_if_empty = FALSE) - guess <- email_address() - maint <- tryCatch(get_maintainer_email(path), error = function(e) NULL) - - choices <- rbind( - if (nrow(valid)) cbind(valid = TRUE, valid), - if (!is.null(guess) && ! guess %in% valid$email) { - data_frame(valid = FALSE, email = guess, token = NA) - }, - if (!is.null(maint) && ! maint %in% valid$email && maint != guess) { - data_frame(valid = FALSE, email = maint, token = NA) - }, - data_frame(valid = NA, email = "New email address", token = NA) - ) - - ## Only show the menu if there is more than one thing there - if (nrow(choices) != 1) { - choices_str <- paste( - sep = " ", - ifelse( - choices$valid & !is.na(choices$valid), - crayon::green(symbol$tick), - " " - ), - choices$email - ) - - cat("\n") - title <- crayon::yellow(paste0( - symbol$line, symbol$line, - " Choose email address to (re)validate (or 0 to exit)" - )) - ch <- menu(choices_str, title = title) - - if (ch == 0) stop("Cancelled email validation", call. = FALSE) - - } else { - ch <- 1 - } - - ## Get another address if that is selected - if (is.na(choices$valid[ch])) { - cat("\n") - email <- readline("Email address: ") - } else { - email <- choices$email[ch] - } -} - -validate_email_interactive <- function(email, token, path = ".") { - - if (is.null(email)) email <- get_email_to_validate(path) - assert_that(is_email(email)) - - ## Token next. For this we need to make an API query. - if (is.null(token)) { - query("VALIDATE EMAIL", data = list(email = unbox(email))) - message(crayon::yellow( - "Please check your emails for the R-hub access token." - )) - token <- readline("Token: ") - } - assert_that(is_token(token)) - - ## We got everything now - validate_email(email, token) -} - -#' List validated email addresses -#' -#' @description List email addresses validated on R-hub on the current machine. -#' -#' @return A `data.frame` with two columns: `email` and `token`. -#' If in interactive mode, and there are no validated email addresses, -#' then a message is printed and the data frame is returned invisibly. -#' -#' @family email validation -#' @export - -list_validated_emails <- function() { - list_validated_emails2() -} - -list_validated_emails2 <- function(msg_if_empty = TRUE) { - file <- email_file() - res <- if (file.exists(file)) { - if (is_interactive()) { - token_file_msg() - } - - structure( - read.csv(file, stringsAsFactors = FALSE, header = FALSE), - names = c("email", "token") - ) - } else { - data.frame( - email = character(), - token = character(), - stringsAsFactors = FALSE - ) - } - if (is_interactive() && nrow(res) == 0) { - if (msg_if_empty) message("No validated emails found.") - invisible(res) - } else { - res - } -} - -#' @importFrom rappdirs user_data_dir - -email_file <- function() { - rhub_data_dir <- user_data_dir("rhub", "rhub") - file.path(rhub_data_dir, "validated_emails.csv") -} - -#' @importFrom utils read.csv - -email_get_token <- function(email) { - file <- email_file() - if (! file.exists(file)) return(NULL) - - tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) - if (! email %in% tokens[,1]) return(NULL) - - tokens[match(email, tokens[,1]), 2] -} - -## If it exists already, then overwrites - -#' @importFrom utils read.csv write.table - -email_add_token <- function(email, token) { - - assert_that(is_email(email)) - assert_that(is_token(token)) - - file <- email_file() - - if (!file.exists(file)) { - parent <- dirname(file) - if (!file.exists(parent)) dir.create(parent, recursive = TRUE) - tokens <- data.frame( - V1 = character(), - V2 = character(), - stringsAsFactors = FALSE - ) - - } else { - tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) - } - - if (! email %in% tokens[,1]) { - tokens <- rbind(tokens, c(email, token)) - - } else{ - tokens[match(email, tokens[,1]), 2] <- token - } - - write.table( - tokens, - file = file, - sep = ",", - col.names = FALSE, - row.names = FALSE - ) - - invisible() -} - -token_file_msg <- function() { - message( - crayon::green( - paste0( - "For info the token(s) and email(s) are stored at ", - email_file() - ) - ) - ) -} diff --git a/R/env.R b/R/env.R deleted file mode 100644 index 3da0689..0000000 --- a/R/env.R +++ /dev/null @@ -1,51 +0,0 @@ - -package_data <- new.env(parent = emptyenv()) -package_data$status <- new.env(parent = emptyenv()) -package_data$ids <- character() -package_data$groups <- character() - -## Since the status can be NULL, meaning unknown, we put all cache elements -## in a list of length 1. - -cache_get <- function(id) { - e <- package_data$status - if (!is.null(x <- e[[id]][[1]])) return(x) - nms <- ls(e) - sts <- grep(paste0("-", id, "[0-9a-f]*$"), nms) - if (length(sts) == 0) return(NULL) - if (length(sts) == 1) return(e[[ nms[sts] ]][[1]]) - stop("Multiple checks match, please use a more specific id", call. = FALSE) -} - -cache_put <- function(id, status) { - cache_put_ids(id) - cache_put_group_ids(status$group) - package_data$status[[id]] <- list(status) - invisible() -} - -cache_put_ids <- function(id) { - id <- unique(setdiff(id, package_data$ids)) - if (length(id)) package_data$ids <- c(id, package_data$ids) -} - -cache_put_group_ids <- function(id) { - id <- unique(setdiff(id, package_data$groups)) - if (length(id)) package_data$groups <- c(id, package_data$groups) -} - -cache_get_ids <- function(ids) { - w <- match_partial(ids, package_data$ids) - package_data$ids[w] -} - -cache_get_group_ids <- function(ids) { - w <- match_partial(ids, package_data$groups) - package_data$groups[w] -} - -match_partial <- function(x, table) { - hash <- sub("^.*-", "", table) - m <- match(x, table) - ifelse(is.na(m), pmatch(x, hash), m) -} diff --git a/R/error.R b/R/error.R deleted file mode 100644 index 095cb0c..0000000 --- a/R/error.R +++ /dev/null @@ -1,50 +0,0 @@ - -#' @importFrom crayon yellow red underline - -report_system_error <- function(msg, status) { - - if (status$status == 0) return() - - if (status$stderr == "") { - stop( - msg, ", unknown error, standard output:\n", - yellow(status$stdout), - call. = FALSE - ) - - } else { - stop( - underline(yellow(paste0("\n", msg, ", standard output:\n\n"))), - yellow(status$stdout), "\n", - underline(red("Standard error:\n\n")), red(status$stderr), - call. = FALSE - ) - } -} - -#' @importFrom httr status_code - -report_error <- function(response) { - if (status_code(response) < 300) { - invisible(response) - } else { - call <- sys.call(-1) - stop(create_condition(response, "error", call = call)) - } -} - -#' @importFrom httr content - -create_condition <- function(response, - class = c("error", "warning", "message"), - call) { - - class <- match.arg(class) - - message <- content(response)$message %||% "rhub error" - - structure( - list(message = message, call = call), - class = c("rhub_error", class, "condition") - ) -} diff --git a/R/handle.R b/R/handle.R deleted file mode 100644 index 2bc968d..0000000 --- a/R/handle.R +++ /dev/null @@ -1,26 +0,0 @@ - -handle_id <- function(x) { - if (is.character(x)) { - unname(sub("^.*/([^/]+)$", "\\1", x, perl = TRUE)) - } else if (inherits(x, "rhub_handle")) { - unname(vapply(x, "[[", "", "id")) - } else { - stop("Invalid R-hub check id") - } -} - -#' @export - -print.rhub_handle <- function(x, ...) { - id <- handle_id(x) - if (length(id) == 1) { - cat("R-hub check: ", id, "\n", sep = "") - - } else { - cat( - "R-hub checks:\n", - paste(" ", id, collapse = "\n") - ) - } - invisible(x) -} diff --git a/R/last.R b/R/last.R deleted file mode 100644 index 62af220..0000000 --- a/R/last.R +++ /dev/null @@ -1,19 +0,0 @@ - -#' The last rhub check of this R session -#' -#' `rhub` caches the id(s) of the last submission. This can be retrieved -#' with `last_check`. -#' -#' @return An rhub_check object. -#' -#' @export -#' @examples -#' \dontrun{ -#' check("packagedir") -#' last_check() -#' last_check()$livelog() -#' } - -last_check <- function() { - package_data$last_handle -} diff --git a/R/list.R b/R/list.R deleted file mode 100644 index 3a28dfd..0000000 --- a/R/list.R +++ /dev/null @@ -1,139 +0,0 @@ - -#' List all checks for an email address -#' -#' @param email Email address. By default it is guessed with -#' [whoami::email_address()]. The address must be validated, see -#' [validate_email()]. -#' @param package `NULL`, or a character scalar. Can be used to restrict -#' the search for a single package. -#' @param howmany How many check groups (checks submitted simultaneously) -#' to show. The current API limit is 20. -#' @return A [tibble::tibble] with columns: -#' * package Name of the package. -#' * version Package version. -#' * result: More detailed result of the check. Can be `NULL` for errors. -#' This is a list column with members: `status`, `errors`, `warnings`, -#' `notes`. -#' * group: R-hub check group id. -#' * id: `R-hub check id. -#' * platform_name: Name of the check platform. -#' * build_time: Build time, a [difftime] object. -#' * submitted: Time of submission. -#' * started: Time of the check start. -#' * platform: Detailed platform data, a list column. -#' * builder: Name of the builder machine. -#' * status Status of the check. Possible values: -#' - `created`: check job was created, but not running yet. -#' - `in-progress`: check job is running. -#' - `parseerror`: internal R-hub error parsing the check results. -#' - `preperror`: check error, before the package check has started. -#' - `aborted`: aborted by admin or user. -#' - `error`: failed check. (Possibly warnings and notes as well.) -#' - `warning`: `R CMD check` reported warnings. (Possibly notes as well.) -#' - `note`: `R CMD check` reported notes. -#' - `ok`: successful check. -#' * email: Email address of maintainer / submitter. -#' -#' @export -#' @seealso list_package_checks -#' @examples -#' \dontrun{ -#' ch <- list_my_checks() -#' ch -#' ch$details() -#' } - -list_my_checks <- function(email = email_address(), package = NULL, - howmany = 20) { - - assert_that(is_email(email)) - assert_that(is_string_or_null(package)) - assert_that(is_count(howmany)) - - response <- if (is.null(package)) { - query( - "LIST BUILDS EMAIL", - params = list(email = email, token = email_get_token(email))) - } else { - query( - "LIST BUILDS PACKAGE", - params = list(email = email, package = package, - token = email_get_token(email))) - } - - if (length(response) > howmany) response <- response[seq_len(howmany)] - - make_check_list(response) -} - - -#' List checks of a package -#' -#' @param package Directory of an R package, or a package tarball. -#' @param email Email address that was used for the check(s). -#' If `NULL`, then the maintainer address is used. -#' @param howmany How many checks to show. The current maximum of the API -#' is 20. -#' @inherit list_my_checks return -#' -#' @export -#' @importFrom desc desc_get -#' @examples -#' \dontrun{ -#' ch <- list_package_checks() -#' ch -#' ch$details(1) -#' } - -list_package_checks <- function(package = ".", email = NULL, howmany = 20) { - - assert_that(is_pkg_dir_or_tarball(package)) - if (is.null(email)) email <- get_maintainer_email(package) - assert_that(is_email(email)) - assert_that(is_count(howmany)) - - package <- unname(desc_get("Package", file = package)) - - response <- query( - "LIST BUILDS PACKAGE", - params = list(email = email, package = package, - token = email_get_token(email)) - ) - - if (length(response) > howmany) response <- response[seq_len(howmany)] - - make_check_list(response) -} - -make_check_list <- function(response) { - data <- unlist(response, recursive = FALSE) - - df <- tibble::tibble( - package = map_chr(data, "[[", "package"), - version = map_chr(data, "[[", "version"), - result = column_result(map(data, function(x) x$result)), - group = column_group_id(map_chr(data, "[[", "group")), - id = column_id(map_chr(data, "[[", "id")), - platform_name = map_chr(data, function(x) x$platform$name), - build_time = column_dt(map_int(data, function(x) { - suppressWarnings(as.integer(x$build_time %||% NA_integer_)) - })), - submitted = column_time(map_chr(data, "[[", "submitted")), - started = column_time(map_chr(data, function(x) x$started %||% NA_character_)), - platform = map(data, "[[", "platform"), - builder = map_chr(data, function(x) x$builder_machine %||% NA_character_), - status = column_status(map_chr(data, "[[", "status")), - email = map_chr(data, "[[", "email") - ) - - cache_put_ids(df$id) - cache_put_group_ids(df$group) - - df -} - -column_time <- function(x) { - res <- rep(as.POSIXct(NA_character_), length(x)) - res[! is.na(x)] <- parse_iso_8601(x[!is.na(x)]) - res -} diff --git a/R/livelog.R b/R/livelog.R deleted file mode 100644 index a4e3cb9..0000000 --- a/R/livelog.R +++ /dev/null @@ -1,129 +0,0 @@ - -check_livelog <- function(self, private, which) { - assert_that(is_count(which) || is_string(which)) - if (is_count(which) && (which < 1 || which > length(private$ids_))) { - stop("Unknown check selected") - } - if (is.character(which) && ! which %in% private$ids_) { - stop("Unknow check selected") - } - - make_streamer(private$ids_[[which]], make_status_parser) - self$update() - invisible(self) -} - -make_streamer <- function(id, parser_factory) { - - if (length(id) > 1) { - warning("Only first submission is streamed") - id <- id[1] - } - - start <- 0 - parser <- parser_factory() - - spinner <- c("-", "/", "|", "\\") - spin <- function() { - cat("\r", spinner[1], sep = "") - spinner <<- c(spinner[-1], spinner[1]) - } - - errors <- 100 - - repeat { - response <- tryCatch( - query( - "LIVE LOG", - params = list(id = id), - query = list(start = start) - ), - error = function(e) { - if (errors > 0) { - errors <- errors - 1 - list(text = list(), more = TRUE, size = start) - } else { - stop("Internal R-hub error") - list(text = list(), more = FALSE) - } - } - ) - - for (i in response$text) parser(i) - if (!response$more) break; - start <- response$size - for (i in 1:5) { Sys.sleep(0.1); spin() } - } - - cat("\r \n") - - if (grepl( - "^(Finished: ABORTED|Finished: ERROR)$", - response$text[[length(response$text)]] - )) { - cat(response$text[[length(response$text)]], "\n", sep = "") - } -} - -#' @importFrom rcmdcheck rcmdcheck - -make_status_parser <- function() { - - first <- TRUE - checking <- FALSE - - ## This is to make sure that `rhub` works with older and newer - ## rcmdcheck versions as well. Older versions expect a call for each - ## line. Newer versions just take a block of output. - formatter <- try( - ("rcmdcheck" %:::% "check_callback")(top_line = FALSE), - silent = TRUE - ) - if (inherits(formatter, "try-error")) { - cb <- ("rcmdcheck" %:::% "block_callback")(top_line = FALSE) - formatter <- function(x) cb(paste0(x, "\n")) - } - - function(x) { - - ## Make sure we are at the beginning of the line - cat("\r") - - if (first) { - header_line("Build started") - first <<- FALSE - } - - ## Get rid of potential \r characters - x <- gsub("[\r]+", "", x) - - ## Checking (already, and still) - - if (checking) { - if (grepl("^Status: ", x)) { - checking <<- FALSE - return(formatter(x)) - } else { - return(formatter(x)) - } - } - - ## Not checking (yet, or any more) - - if (grepl("^>>>>>=====+ Running R CMD check", x)) { - checking <<- TRUE - x <- sub("^>>>>>=+ ", "", x) - header_line(x) - - } else if (grepl("^>>>>>=====", x)) { - x <- sub("^>>>>>=+ ", "", x) - header_line(x) - - } else if (grepl("^\\+R-HUB-R-HUB-R-HUB", x)) { - x <- sub("^\\+R-HUB-R-HUB-R-HUB", "", x) - - } else { - ## print nothing - } - } -} diff --git a/R/local.R b/R/local.R deleted file mode 100644 index f7faeb3..0000000 --- a/R/local.R +++ /dev/null @@ -1,159 +0,0 @@ - -#' Run a package check locally, in a Docker container -#' -#' @description Run a package check locally, in a Docker container. UNTESTED -#' ON WINDOWS, bug reports welcome. :-) -#' -#' @param quiet Whether to print the check output -#' @param image Docker image to use. If `NULL`, a default image is selected. -#' @param valgrind Whether to run the check with Valgrind. -#' @param timeout Timeout for a check, a `difftime` object or a scalar -#' that will be interpreted as seconds. -#' @param artifacts Where to copy the build artifacts after the build. -#' @inheritParams check -#' @return An `rcmdcheck::rcmdcheck` object, with extra fields: -#' * `all_output`: all output from the check, both standard output and -#' error. -#' * `container_name`: name of the Docker container that performed the -#' build. It is a random name. -#' * `artifacts`: directory of build artifacts. -#' -#' @export -#' @importFrom withr with_dir -#' @importFrom processx run -#' @importFrom utils tail -#' @importFrom uuid UUIDgenerate -#' -#' @details You'll need to have bash and Docker installed. - -local_check_linux <- function(path = ".", quiet = FALSE, image = NULL, - valgrind = FALSE, check_args = character(), - env_vars = character(), timeout = Inf, artifacts = tempfile()) { - - ## Check that it is a package - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - assert_that(is_flag(quiet)) - assert_that(is.null(image) || is.character(image)) - assert_that(is_flag(valgrind)) - assert_that(is_named(env_vars)) - assert_that(is.character(env_vars)) - assert_that(is_timeout(timeout <- as_timeout(timeout))) - assert_that(is.character(artifacts)) - - if ((bash <- Sys.which("bash")) == "" || Sys.which("docker") == "") { - stop("You need bash and Docker to run local Linux checks") - } - - ## Build the tar.gz, if needed - if (file.info(path)$isdir) { - header_line("Building package") - pkg_targz <- build_package(path, tmpdir <- tempfile()) - } else { - pkg_targz <- path - } - - ## Add valgrind to check_args - check_args <- c( - check_args, - if (valgrind) "--use-valgrind" - ) - - dir.create(artifacts, showWarnings = FALSE, recursive = TRUE) - artifacts <- normalizePath(artifacts) - - container_name <- UUIDgenerate() - if (!quiet) { - cat(sep = "", "\nContainer name: ", container_name, "-2", "\n") - cat("It will _not_ be removed after the check.\n\n") - } - - ## Arguments - env_str <- paste(paste0(names(env_vars), "=", env_vars), collapse = "\n") - args <- c( - "-k", - if (!is.null(image)) c("-i", image), - if (length(check_args)) c("-c", paste(check_args, collapse = " ")), - if (length(env_vars)) c("-e", env_str), - c("-a", artifacts), - c("-d", container_name), - pkg_targz) - - output <- character() - callback <- function(x, proc) output <<- c(output, x) - - ## Run it - wd <- system.file(package = .packageName, "bin") - result <- with_dir( - wd, - run(bash, c(file.path(wd, "rhub-linux.sh"), args), echo = TRUE, - stdout_line_callback = callback, stderr_line_callback = callback, - timeout = timeout, spinner = FALSE) - ) - - ## TODO: better error object - if (result$timeout) stop("Check timed out") - - if (!quiet) cat("Artifacts in", artifacts, "\n") - if (!quiet) cat(sep = "", "Container name: ", container_name, "-2", "\n\n") - - ## Try to parse as R CMD check result - check_start <- grep("^>>>>>=====+ Running R CMD check", output)[1] - if (is.na(check_start)) stop("Failed before check started") - check_output <- tail(output, -check_start) - check_result <- tryCatch( - rcmdcheck::parse_check(text = check_output), - error = function(e) NULL) - - result <- list( - check_result = check_result, - output = output, - image = image, - artifacts = artifacts, - container_name = paste0(container_name, "-2")) - class(result) <- "rhub_local_check" - result -} - -#' @importFrom utils head -#' @export - -print.rhub_local_check <- function(x, ...) { - cat0("\n") - if (!is.null(x$image)) cat0(symbol$bullet, " image: ", x$image, "\n") - if (!is.null(x$output)) { - cat0(symbol$bullet, " output:\n") - cat(paste0(" ", c(head(x$output, 5), "...")), sep = "\n") - } - cat0(symbol$bullet, " container_name: ", x$container_name, "\n") - if (!is.null(x$artifacts)) { - cat0(symbol$bullet, " artifacts: \n ", x$artifacts, "\n") - } - if (!is.null(x$check_result)) { - cat0(symbol$bullet, " check_result:\n") - print(x$check_result) - } -} - -#' List R-hub Docker images -#' -#' The images are pretty-printed in a short format. Use -#' `as.data.frame()` to get all available platform metadata. -#' -#' @export - -local_check_linux_images <- function() { - plat <- platforms() - plat <- plat[!is.na(plat$`docker-image`), ] - class(plat) <- c("rhub_docker_images", class(plat)) - plat -} - -#' @export - -print.rhub_docker_images <- function(x, ...) { - res <- paste(cyan(paste0("rhub/", x$`docker-image`)), - green(x$description), sep = ":\n ") - cat(res, sep = "\n") - invisible(x) -} diff --git a/R/platform.R b/R/platform.R deleted file mode 100644 index 9ddfb12..0000000 --- a/R/platform.R +++ /dev/null @@ -1,66 +0,0 @@ - -#' List all R-hub platforms -#' -#' The platforms are pretty-printed in a short format. Use -#' `as.data.frame(platforms())` to get all available platform metadata. -#' -#' @export -#' @importFrom jsonlite fromJSON -#' @importFrom crayon green cyan -#' @examples -#' \dontrun{ -#' platforms() -#' as.data.frame(platforms()) -#' } - -platforms <- function() { - json <- query("GET PLATFORMS", as = "text") - pls <- fromJSON(json, simplifyDataFrame = TRUE) - pls <- pls[order(pls$name), , drop = FALSE] - class(pls) <- c("rhub_platforms", class(pls)) - pls -} - -#' @export - -print.rhub_platforms <- function(x, ...) { - res <- paste(cyan(x$name), green(x$description), sep = ":\n ") - cat(res, sep = "\n") - invisible(x) -} - -match_platform <- function(platform) { - all_platforms <- platforms() - if (is.null(platform)) { - if (is_interactive()) { - select_platform_interactively(all_platforms) - } else { - all_platforms$name[1] - } - - } else { - if (! all(platform %in% all_platforms$name)) { - stop("Unknown R-hub platform, see rhub::platforms() for a list") - } - platform - } -} - -select_platform_interactively <- function(platforms) { - - choices <- paste0( - platforms$description, - crayon::green(" (", platforms$name, ")", sep = "") - ) - - cat("\n") - title <- crayon::yellow(paste0( - symbol$line, symbol$line, - " Choose build platform" - )) - ch <- menu(choices, title = title) - cat("\n") - if (ch == 0) stop("R-hub check aborted", call. = FALSE) - - platforms$name[ch] -} diff --git a/R/print-status.R b/R/print-status.R deleted file mode 100644 index ff2a523..0000000 --- a/R/print-status.R +++ /dev/null @@ -1,76 +0,0 @@ - -check_print <- function(self, private) { - self$update() - for (x in private$status_) check_print2(x) - invisible(self) -} - -#' @importFrom parsedate parse_iso_8601 -#' @importFrom prettyunits pretty_ms -#' @importFrom crayon make_style red yellow - -check_print2 <- function(x) { - - title_line(paste0(x$package, " ", x$version, ": ", toupper(x$status))) - - greyish <- make_style("darkgrey") - - submitted_time <- as.numeric(Sys.time() - parse_iso_8601(x$submitted), units = "secs") - submitted <- if (submitted_time > 0) { - paste(pretty_ms(submitted_time * 1000), "ago") - } else { - "just now" - } - - build_time <- if (!is.null(x$build_time) && x$build_time != 0) { - paste0(greyish(" Build time: "), pretty_ms(x$build_time), "\n") - } - - cat( - sep = "", - greyish(" Build ID: "), x$id, "\n", - greyish(" Platform: "), x$platform$description, "\n", - greyish(" Submitted: "), submitted, "\n", - build_time %||% "", - "\n" - ) - - ## If not done, then this is all we do - if (is.null(build_time)) return(invisible(x)) - - ## R CMD check error - if (tolower(x$status) != "preperror" && tolower(x$status) != "aborted") { - makeshift <- structure( - list( - package = x$package, - version = x$version, - rversion = x$platform$rversion, - output = list(stdout = x$check_output, stderr = "", status = 0), - platform = x$platform$name, - notes = x$result$notes, - warnings = x$result$warnings, - errors = x$result$errors - ), - class = "rcmdcheck" - ) - print(makeshift, header = FALSE) - - ## Or we never got to R CMD check - } else { - clog <- gsub("+R-HUB-R-HUB-R-HUB", "", fixed = TRUE, x$preperror_log) - clog <- gsub("\necho >>>>>=========[^\n]*\n", "\n", clog) - clog <- gsub( - "\n>>>>>=======* (.+)\n", - yellow(sep = "", "\n\n", symbol$line, " \\1\n\n"), - clog, - perl = TRUE - ) - - cat(red(paste0(symbol$pointer, " Build failed during preparation or aborted\n"))) - cat(greyish("\n[...]\n")) - cat(greyish(clog)) - cat("\n") - } - - invisible(x) -} diff --git a/R/print.R b/R/print.R deleted file mode 100644 index 4e31719..0000000 --- a/R/print.R +++ /dev/null @@ -1,56 +0,0 @@ - -#' @importFrom crayon make_style -#' @importFrom cli symbol - -header_line <- function(x) { - - greyish <- make_style("darkgrey") - - cat( - paste0("\r", greyish(symbol$line), " "), - greyish(x), - "\n", - sep = "" - ) -} - -#' @importFrom crayon yellow -#' @importFrom cli symbol - -title_line <- function(x) { - - cat( - sep ="", - "\n", - yellow(paste0(symbol$line, symbol$line, " ", x)), - "\n\n" - ) -} - -#' @importFrom cli make_ansi_style style_bold style_inverse -#' col_red col_blue col_green - -status_style_created <- function(x) { - x -} - -status_style_in_progress <- function(x) { - x -} - -status_style_error <- function(x) { - style_inverse(style_bold(col_red(x))) -} - -status_style_aborted <- function(x) { - style_bold(col_blue(x)) -} - -status_style_note <- function(x) { - orange <- make_ansi_style("orange") - style_bold(orange(x)) -} - -status_style_ok <- function(x) { - style_inverse(style_bold(col_green(x))) -} diff --git a/R/rematch_all.R b/R/rematch_all.R deleted file mode 100644 index 3711881..0000000 --- a/R/rematch_all.R +++ /dev/null @@ -1,78 +0,0 @@ - -re_match_all <- function(text, pattern, ...) { - - text <- as.character(text) - stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) - - ## Need to handle this case separately, as gregexpr effectively - ## does not work for this. - if (length(text) == 0) return(empty_result(text, pattern, ...)) - - match <- gregexpr(pattern, text, perl = TRUE, ...) - - num_groups <- length(attr(match[[1]], "capture.names")) - - ## Non-matching strings have a rather strange special form, - ## so we just treat them differently - non <- vapply(match, function(m) m[1] == -1, TRUE) - yes <- !non - res <- replicate(length(text), list(), simplify = FALSE) - if (any(non)) { - res[non] <- list(replicate(num_groups + 1, character(), simplify = FALSE)) - } - if (any(yes)) { - res[yes] <- mapply(match1, text[yes], match[yes], SIMPLIFY = FALSE) - } - - ## Need to assemble the final data frame "manually". - ## There is apparently no function for this. rbind() is almost - ## good, but simplifies to a matrix if the dimensions allow it.... - res <- lapply(seq_along(res[[1]]), function(i) { - lapply(res, "[[", i) - }) - - structure( - res, - names = c(attr(match[[1]], "capture.names"), ".match"), - row.names = seq_along(text), - class = c("data.frame") - ) -} - -match1 <- function(text1, match1) { - - matchstr <- substring( - text1, - match1, - match1 + attr(match1, "match.length") - 1L - ) - - ## substring fails if the index is length zero, - ## need to handle special case - if (is.null(attr(match1, "capture.start"))) { - list(.match = matchstr) - - } else { - gstart <- attr(match1, "capture.start") - glength <- attr(match1, "capture.length") - gend <- gstart + glength - 1L - - groupstr <- substring(text1, gstart, gend) - dim(groupstr) <- dim(gstart) - - c(lapply(seq_len(ncol(groupstr)), function(i) groupstr[, i]), - list(.match = matchstr) - ) - } -} - -empty_result <- function(text, pattern, ...) { - match <- regexpr(pattern, text, perl = TRUE, ...) - num_groups <- length(attr(match, "capture.names")) - structure( - replicate(num_groups + 1, list(), simplify = FALSE), - names = c(attr(match, "capture.names"), ".match"), - row.names = integer(0), - class = "data.frame" - ) -} diff --git a/R/rhub-package.R b/R/rhub-package.R deleted file mode 100644 index b30bbda..0000000 --- a/R/rhub-package.R +++ /dev/null @@ -1,8 +0,0 @@ -#' @keywords internal -"_PACKAGE" - -# The following block is used by usethis to automatically manage -# roxygen namespace tags. Modify with care! -## usethis namespace: start -## usethis namespace: end -NULL diff --git a/R/rhubv1.R b/R/rhubv1.R new file mode 100644 index 0000000..0366d09 --- /dev/null +++ b/R/rhubv1.R @@ -0,0 +1,2394 @@ + +baseurl <- function() { + paste0(Sys.getenv("RHUB_SERVER", "https://builder.r-hub.io"), "/api") +} + +rhub_server <- baseurl + +endpoints <- list( + c("GET PLATFORMS", "GET", "/platform/list", FALSE), + c("VALIDATE EMAIL", "POST", "/check/validate_email", FALSE), + c("SUBMIT PACKAGE", "POST", "/check/submit", FALSE), + c("GET STATUS", "POST", "/status", FALSE), + c("GET GROUP STATUS", "GET", "/status/group/:id", FALSE), + c("LIST BUILDS EMAIL", "GET", "/list/:email", TRUE), + c("LIST BUILDS PACKAGE", "GET", "/list/:email/:package", TRUE), + c("LIVE LOG", "GET", "/livelog/text/:id", FALSE) +) + +default_headers <- c( + "Accept" = "application/json", + "Content-Type" = "application/json", + "User-Agent" = "R-hub client" +) + +#' @importFrom httr GET POST DELETE add_headers +#' @importFrom jsonlite toJSON + +query <- function(endpoint, params = list(), data = NULL, + query = list(), headers = character(), as = NULL) { + + ep <- get_endpoint(endpoint, params) + headers <- update( + update(default_headers, ep$headers), + as.character(headers)) + + url <- paste0(baseurl(), ep$path) + + json <- if (!is.null(data)) toJSON(data) + + response <- if (ep$method == "GET") { + GET(url, add_headers(.headers = headers), query = query) + + } else if (ep$method == "POST") { + POST(url, add_headers(.headers = headers), body = json, query = query) + + } else if (ep$method == "DELETE") { + DELETE(url, add_headers(.headers = headers), query = query) + + } else { + stop("Unexpected HTTP verb, internal rhub error") + } + + report_error(response) + + parse_response(response, as = as) +} + +get_endpoint <- function(endpoint, params) { + + idx <- match(endpoint, vapply(endpoints, "[[", "", 1)) + if (is.na(idx)) stop("Unknown API endpoint: ", sQuote(endpoint)) + + method <- endpoints[[idx]][2] + path <- endpoints[[idx]][3] + + colons <- re_match_all(path, ":[a-zA-Z0-9_]+")$.match[[1]] + + for (col in colons) { + col1 <- substring(col, 2) + value <- params[[col1]] %||% stop("Unknown API parameter: ", col) + path <- gsub(col, value, path, fixed = TRUE) + } + + headers <- if (endpoints[[idx]][[4]]) { + if (is.null(params$token)) { + stop("Cannot find token, email address is not validated?") + } + c("Authorization" = paste("token", params$token)) + } + + list(method = method, path = path, headers = headers) +} + +#' @importFrom httr headers content +#' @importFrom jsonlite fromJSON + +parse_response <- function(response, as = NULL) { + + content_type <- headers(response)$`content-type` + + if (is.null(content_type) || length(content_type) == 0) { + content(response, as = "text") + + } else if (grepl("^application/json", content_type, ignore.case = TRUE)) { + if (is.null(as)) { + fromJSON(content(response, as = "text"), simplifyVector = FALSE) + } else { + content(response, as = as) + } + + } else { + content(response, as = "text") + } +} + +#' @importFrom assertthat assert_that on_failure<- + +is_pkg_dir <- function(path) { + file.exists(path) && + file.info(path)$isdir && + file.exists(file.path(path, "DESCRIPTION")) +} + +is_pkg_tarball <- function(path) { + file.exists(path) && + grepl("\\.tar\\.gz", path) +} + +is_pkg_dir_or_tarball <- function(path) { + is_pkg_tarball(path) || is_pkg_dir(path) +} + +on_failure(is_pkg_dir_or_tarball) <- function(call, env) { + paste0( + deparse(call$path), + " is not an R package directory or source R package" + ) +} + +is_string <- function(x) { + !is.null(x) && + is.character(x) && + length(x) == 1 && + !is.na(x) +} + +on_failure(is_string) <- function(call, env) { + paste0(deparse(call$x), " is not a string") +} + +is_string_or_null <- function(x) { + is_string(x) || is.null(x) +} + +on_failure(is_string_or_null) <- function(call, env) { + paste0(deparse(call$x), " is not a string and not NULL") +} + +is_email <- function(x) { + assert_that(is_string(x)) + grepl(".@.", x) +} + +on_failure(is_email) <- function(call, env) { + paste0(deparse(call$x), " is not an email address") +} + +is_flag <- function(x) { + !is.null(x) && + is.logical(x) && + length(x) == 1 && + !is.na(x) +} + +on_failure(is_flag) <- function(call, env) { + paste0(deparse(call$x), " is not a flag (length one logical)") +} + +is_named <- function(x) { + length(names(x)) == length(x) && + all(names(x) != "") +} + +on_failure(is_named) <- function(call, env) { + paste0(deparse(call$x), " does not have names") +} + +is_token <- function(x) { + assert_that(is_string(x)) + grepl("[a-zA-Z0-9]{6}", x, perl = TRUE) +} + +on_failure(is_token) <- function(call, env) { + paste0(deparse(call$x), " does not look like an R-hub token") +} + +is_check_ids <- function(x) { + is.character(x) && length(x) >= 1 && all(x != "") +} + +on_failure(is_check_ids) <- function(call, env) { + paste0(deparse(call$x), " is not a vector of check ids") +} + +is_count <- function(x) { + is.numeric(x) && length(x) == 1 && as.integer(x) == x +} + +on_failure(is_count) <- function(call, env) { + paste0(deparse(call$x), " is not a count (length 1 integer)") +} + +as_timeout <- function(x) { + if (inherits(x, "difftime")) return(x) + as.difftime(as.double(x), units = "secs") +} + +is_timeout <- function(x) { + inherits(x, "difftime") && length(x) == 1 && !is.na(x) +} + +on_failure(is_timeout) <- function(call, env) { + paste0(deparse(call$x), " must be a timeout, a 'difftime' constant") +} + +#' @importFrom withr with_dir +#' @importFrom callr rcmd_safe + +build_package <- function(path, tmpdir) { + + path <- normalizePath(path) + + dir.create(tmpdir) + file.copy(path, tmpdir, recursive = TRUE) + + ## If not a tar.gz, build it. Otherwise just leave it as it is. + if (file.info(path)$isdir) { + build_status <- with_dir( + tmpdir, + rcmd_safe("build", basename(path)) + ) + unlink(file.path(tmpdir, basename(path)), recursive = TRUE) + report_system_error("Build failed", build_status) + } + + file.path( + tmpdir, + list.files(tmpdir, pattern = "\\.tar\\.gz$") + ) +} + +#' @title R-hub check ids +#' @section R-hub ids: +#' +#' Every R-hub check has a unique id, that is constructed from the +#' name of the source package archive, and a random string. For example: +#' ```r +#' devtools_2.0.0.tar.gz-fe53bbba85de4a579f6dc3b852bf76a3 +#' ``` +#' +#' @section R-hub group ids: +#' +#' For every check submission, R-hub also creates a unique check group id. +#' One check group may contain multiple checks. E.g. [check_for_cran()] +#' typically creates three or four check groups. Group ids look the same +#' as individual check ids. +#' +#' @section Abbreviating ids: +#' +#' The rhub package keeps a list of all the checks that it has seen in the +#' current session, and these checks can be also referenced by any unique +#' prefix of the random string part of the id, e.g. in the [get_check()] +#' function. E.g. if rhub already know the devtools check above, then +#' ```r +#' get_check("fe53bbb") +#' ``` +#' works. +#' +#' This is only recommended in interactive mode, and we suggest that you +#' always use the full ids when using rhub programmatically. +#' +#' @name rhub-ids +NULL + +#' An `rhub_check` object holds status and results of rhub checks +#' +#' @section Usage: +#' ``` +#' ch <- rhub_check$new(ids = NULL, status = NULL, group = NULL) +#' ch$get_ids() +#' ch$update() +#' ch$print(...) +#' ch$browse(which = NULL) +#' ch$urls(which = NULL) +#' ch$livelog(which = 1) +#' ch$cran_summary() +#' ``` +#' +#' @section Arguments: +#' * `ch` An rhub check object. It can be created using [`check()`], +#' and other check functions including [`check_for_cran`]. +#' See also [last_check()]. +#' * `ids` Character vector of check ids. +#' * `status` Check status for `ids` or `group`. +#' * `group` Check group id, string scalar. Either `group` or `ids` must +#' be non-`NULL`. +#' * `...` Extra arguments are currently ignored. +#' * `which` Which check to show, if the object contains multiple +#' checks. For `browse` the default is all checks. For `livelog` the +#' default is the first check. A check can be selected via its number +#' or id. +#' +#' @section Details: +#' +#' An `rhub_check` object can be created by [check()], [list_my_checks()], +#' or [list_package_checks()]. [last_check()] returns the last check(s) +#' submitted from the current R session. Do not confuse `rhub_check`/`rhub_check_for_cran` +#' (classes) with [check()] or [check_for_cran()] (functions). +#' +#' `ch$get_ids()` returns the check ids. These can be used to query if a +#' check has finished. +#' +#' `ch$update()` updates the status of the check. Printing the check +#' status to the screen does not perform an update, unless the status of +#' the check(s) is unknown. +#' +#' `ch$print()` prints the status of the check(s) to the screen. +#' +#' `ch$cran_summary()` prints text to be copy-pasted in cran-comments.md, +#' it is especially useful on the output of [`check_for_cran()`]. +#' +#' `ch$browse()` opens a tab or window in the default web browser, that points +#' to the detailed logs of the check(s). +#' +#' `ch$urls()` return a [`tibble::tibble`] with URL to the html log, text log and artifacts +#' of the check(s). +#' +#' For both `ch$browse()` and `ch$urls()`, note that the logs and artifacts +#' are not kept forever, they are accessible for a few days after submission. +#' +#' `ch$livelog()` shows the live log of the check. The live log can be +#' interrupted using the usual interruption keyboard shortcut, usually +#' `CTRL+c` or `ESC`. +#' +#' @name rhub_check +NULL + +#' @importFrom R6 R6Class + +rhub_check <- R6Class( + "rhub_check", + + public = list( + + initialize = function(ids = NULL, status = NULL, group = NULL) + check_init(self, private, ids, status, group), + + get_ids = function() private$ids_, + + update = function() + check_update(self, private), + + print = function(...) + check_print(self, private, ...), + + web = function(which = NULL) + check_web(self, private, which), + + browse = function(which = NULL) + self$web(which), + + urls = function(which = NULL) + check_urls(self, private, which), + + livelog = function(which = 1) + check_livelog(self, private, which), + + cran_summary = function() + check_cran_summary(self, private) + ), + + private = list( + ids_ = NULL, # character vector of ids + group_ = NULL, # group id + status_ = NULL, # list of status objects, as in DB + status_updated_ = NULL # last time status was updated + ) +) + +check_init <- function(self, private, ids, status, group) { + assert_that( + is_check_ids(ids) || is.null(ids), + (is_check_ids(group) && length(group) == 1) || is.null(group), + !is.null(ids) || !is.null(group)) + + private$ids_ <- ids + private$group_ <- group + private$status_ <- status + status_updated_ <- Sys.time() + invisible(self) +} + +check_update <- function(self, private) { + ## If it is a group, we need to get the ids first. This also updates + ## the status of the individual checks + if (!is.null(private$group_) && is.null(private$ids_)) { + grp <- query("GET GROUP STATUS", list(id = private$group_)) + private$ids_ <- map_chr(grp, "[[", "id") + private$status_ <- grp + private$status_updated_ <- Sys.time() + for (i in seq_along(grp)) cache_put(grp[[i]]$id, grp[[i]]) + return(invisible(self)) + } + + ## Check which ones need update. We need to update if we don't know + ## anything about the id, or if it has not finished yet. + cached <- lapply(private$ids_, cache_get) + need_upd <- map_lgl(cached, function(x) { + is.null(x) || x$status %in% c("created", "in-progress") + }) + + if (any(need_upd)) { + ## Update + upd <- query("GET STATUS", data = list(id = private$ids_[need_upd])) + cached[need_upd] <- upd + + ## Update the cache + for (i in seq_along(upd)) cache_put(private$ids_[need_upd][i], upd[[i]]) + } + + ## Update the object, we always do this, in case the object is outdated, + ## but the cache is not + private$status_ <- cached + private$status_updated_ <- Sys.time() + + invisible(self) +} + +#' @importFrom utils browseURL + +check_web <- function(self, private, which) { + + ids <- select_ids(which = which, self = self, + private = private) + + urls <- paste0(sub("/api$", "/status/", baseurl()), ids) + + lapply(urls, browseURL) + invisible(self) +} + +check_urls <- function(self, private, which) { + + ids <- select_ids(which = which, self = self, + private = private) + + tibble::tibble(html = paste0(sub("/api$", "/status/", baseurl()), ids), + text = paste0(sub("/api$", "/status/original/", baseurl()), + ids), + artifacts = paste0("https://artifacts.r-hub.io/", ids), + stringsAsFactors = FALSE) +} + +select_ids <- function(which, self, private){ + ids <- if (is.null(which)) { + private$ids_ + } else if (is.numeric(which)) { + private$ids_[which] + } else if (is.character(which)) { + intersect(private$ids_, which) + } else { + stop("Unknown check selected", + call. = FALSE) + } + + return(ids) +} + +check_cran_summary <- function(self, private) { + + self$update() + + x <- private$status_ + + statuses <- map_chr(x, "[[", "status") + + if (any(statuses %in% c("in-progress", "created"))) { + stop(paste("At least one of the builds has not finished yet.", + "Please wait before calling `cran_summary()` again."), + call. = FALSE) + } + + if (any(statuses %in% problem_statuses())) { + platforms <- lapply(x, "[[", "platform") + platform_names <- map_chr(platforms, "[[", "name") + stop(paste("Build failures on platforms:", + toString(platform_names[statuses %in% problem_statuses()]), + ". \n", + "Read the log(s) to fix and if needed ask for help via ", + "https://docs.r-hub.io/#pkg-dev-help"), + call. = FALSE) + } + + result <- do.call("rbind", + lapply(x, rectangle_status)) + + systems <- paste0("- R-hub ", + vapply(x, function(xx) xx$platform$name, ""), + " (", + vapply(x, function(xx) xx$platform$rversion, ""), + ")") + lines <- paste0(systems, "\n") + + + result <- result[!is.na(result$type),] + + if (nrow(result) > 0){ + message("For a CRAN submission we recommend that you fix all NOTEs, WARNINGs and ERRORs.") + unique_results <- unique(result[, c("type", "hash")]) + + makeshift <- structure( + list( + package = x$package, + version = toString(vapply(x, function(xx) xx$platform$name, "")), + rversion = toString(systems), + output = list(), + platform = toString(systems), + notes = unlist(lapply(unique(unique_results$hash[unique_results$type == "NOTE"]), + combine_message, result = result)), + warnings = unlist(lapply(unique(unique_results$hash[unique_results$type == "WARNING"]), + combine_message, result = result)), + errors = unlist(lapply(unique(unique_results$hash[unique_results$type == "ERROR"]), + combine_message, result = result)) + ), + class = "rcmdcheck" + ) + + } else { + makeshift <- structure( + list( + package = x$package, + version = toString(vapply(x, function(xx) xx$platform$name, "")), + rversion = toString(systems), + output = list(), + platform = toString(systems), + notes = NULL, + warnings = NULL, + errors = NULL + ), + class = "rcmdcheck" + ) + } + + cat("## Test environments\n") + cat(lines, sep = "") + cat("\n") + cat("## R CMD check results\n") + print(makeshift, header = FALSE) + + invisible(self) +} + + +get_status_part <- function(part, x){ + output <- unlist(x[part]) + if(is.null(output)){ + return("") + }else{ + output + } +} + +rectangle_status <- function(x){ + + df <- rbind(data.frame(type = "ERROR", + message = get_status_part("errors", x$result), + stringsAsFactors = FALSE), + data.frame(type = "WARNING", + message = get_status_part("warnings", x$result), + stringsAsFactors = FALSE), + data.frame(type = "NOTE", + message = get_status_part("notes", x$result), + stringsAsFactors = FALSE)) + + df <- df[df$message != "",] + + if(nrow(df) == 0){ + df <- data.frame(package = x$package, + type = NA, + message = NA, + hash = NA) + } else{ + df$hash <- hash_check(df$message) + } + + df$package <- x$package + df$version <- x$version + df$submitted <- x$submitted + df$platform <- paste0(x$platform$name, " (", x$platform$rversion, + ")") + + return(df) +} + +combine_message <- function(hash, result){ + paste0("On ", toString(result$platform[result$hash == hash]), "\n", + result$message[result$hash == hash][1]) +} + +# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/968fd9ba76ee9b7bf65d192568555ab57160165e/R/parse.R#L110 +#' @importFrom digest digest + +hash_check <- function(check) { + cleancheck <- gsub("[^a-zA-Z0-9]", "", first_line(check)) + vapply(cleancheck, digest::digest, "") +} + +# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/afadc6c53310cad2b64e0a58e399efd1ae18d7dd/R/utils.R#L91 +first_line <- function(x) { + l <- strsplit(x, "\n", fixed = TRUE) + vapply(l, "[[", "", 1) +} + +#' Retrieve the result of R-hub checks +#' +#' @param ids One of the following: +#' - A single R-hub check id. +#' - A character vector of check ids. +#' - An R-hub check group id. +#' All ids can be abbreviated, see [R-hub ids][rhub-ids]. +#' @return An [rhub_check] object. +#' +#' @section Examples: +#' ``` +#' chk <- get_check("915ee61") +#' chk +#' chk$update() +#' chk$browse() +#' chk$cran_summary() +#' chk$urls() +#' ``` +#' +#' @export +#' @seealso [list_my_checks()] and [list_package_checks()] to list +#' R-hub checks. + +get_check <- function(ids) { + assert_that(is_check_ids(ids)) + + short <- grep(re_id, ids, invert = TRUE, value = TRUE) + if (length(short) && + length(package_data$ids) == 0 && + length(package_data$groups) == 0) { + stop( + "Short check id '", short[1], "' ", + if (length(short) > 1) paste0("(and ", length(short)-1, " more) "), + "can only be used for cached ids, and no ids are cached yet.\n", + " Try calling `list_my_checks()` or `list_package_checks()` first." + ) + } + + sle <- cache_get_ids(ids) + grp <- cache_get_group_ids(ids) + + err <- NULL + + ## If we are not sure that it is a group id, then query single ids + res <- if (length(ids) > 1 || is.na(grp)) { + ids2 <- ifelse(is.na(sle), ids, sle) + tryCatch( + rhub_check$new(ids2)$update(), + error = function(e) { err <<- e; NULL } + ) + } + + if (!is.null(res)) return(res) + + ## If there is a chance that it is a group, then we try that as well + if (length(ids) == 1 && is.na(sle)) { + ids3 <- if (is.na(grp)) ids else grp + res <- rhub_check$new(group = ids3)$update() + res + } else { + stop(err) + } +} + +re_id <- "-[0-9a-f]{32}$" + +#' Check an R-package on R-hub, for a CRAN submission +#' +#' This function calls [check()] with arguments and platforms, that +#' are suggested for a CRAN submission. +#' +#' In particular, if `platforms` is `NULL` (the default), then +#' * It checks the package on Windows, and Linux. +#' * It checks the package on R-release and R-devel. +#' * It uses the `--as-cran` argument to `R CMD check`. +#' * It requires all dependencies, including suggested ones. +#' +#' @details This function is wrapped by `devtools::check_rhub()` which you +#' might find useful if you load `devtools` via your .Rprofile (see `usethis::use_devtools()`). +#' +#' @param check_args Arguments for `R CMD check`. By default `--as-cran` +#' is used. +#' @param env_vars Character vector of environment variables to set on the builder. +#' By default `_R_CHECK_FORCE_SUGGESTS_="true"` is set, to require all packages used. +#' `_R_CHECK_CRAN_INCOMING_USE_ASPELL_="true"` is also set, to use the +#' spell checker. +#' @param ... Additional arguments are passed to [check()]. +#' @inheritParams check +#' @return An [rhub_check] object. +#' +#' @export +#' @examples +#' \dontrun{ +#' ch <- check_for_cran("package", show_status = FALSE) +#' ch$update() +#' ch$livelog(3) +#' } + +check_for_cran <- function( + path = ".", email = NULL, check_args = "--as-cran", + env_vars = c("_R_CHECK_FORCE_SUGGESTS_" = "true", + "_R_CHECK_CRAN_INCOMING_USE_ASPELL_" = "true"), platforms = NULL, + ...) { + + path <- normalizePath(path) + assert_that(is_pkg_dir_or_tarball(path)) + + platforms <- platforms %||% default_cran_check_platforms(path) + + check(path = path, platforms = platforms, email = email, + check_args = check_args, env_vars = env_vars, ...) +} + +default_cran_check_platforms <- function(path) { + c( + "windows-x86_64-devel", + "ubuntu-gcc-release", + "fedora-clang-devel", + if (needs_compilation(path)) "linux-x86_64-rocker-gcc-san" + ) +} + +## Various OSes -------------------------------------------------------- + +#' Check an R package on an R-hub platform +#' +#' These functions provide a quick easy to use interface to check a +#' package on a platform with some particular aspect. Which platform +#' they use might change over time. +#' +#' @param ... Additional arguments are passed to [check()]. +#' @return An [rhub_check] object. +#' @inheritParams check +#' +#' @export +#' @rdname check_shortcuts + +check_on_linux <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$linux, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_windows <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$windows, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_macos <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$macos, ...) +} + +## Various Linux OSes -------------------------------------------------- + +#' @export +#' @rdname check_shortcuts + +check_on_debian <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$debian, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_ubuntu <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$ubuntu, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_fedora <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$fedora, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_solaris <- function(path = ".", check_args = + "'--no-manual --no-build-vignettes'", ...) { + check(path = path, platforms = check_shortcut_platforms$solaris, + check_args = check_args, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_on_centos <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$centos, ...) +} + +## R versions -------------------------------------------------------- + +#' @export +#' @rdname check_shortcuts + +check_with_roldrel <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$roldrel, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_with_rrelease <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$rrelease, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_with_rpatched <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$rpatched, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_with_rdevel <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$rdevel, ...) +} + +## Extra checks -------------------------------------------------------- + +#' @export +#' @rdname check_shortcuts + +check_with_valgrind <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$valgrind, + valgrind = TRUE, ...) +} + +#' @export +#' @rdname check_shortcuts + +check_with_sanitizers <- function(path = ".", ...) { + check(path = path, platforms = check_shortcut_platforms$sanitizers, ...) +} + +## ------------------------------------------------------------------- + + +check_shortcut_platforms <- list( + "linux" = "debian-gcc-release", + "windows" = "windows-x86_64-release", + "macos" = "macos-highsierra-release", + "valgrind" = "debian-gcc-release", + "sanitizers" = "linux-x86_64-rocker-gcc-san", + "roldrel" = "windows-x86_64-oldrel", + "rrelease" = "debian-gcc-release", + "rpatched" = "debian-gcc-patched", + "rdevel" = "debian-gcc-devel", + "debian" = "debian-gcc-release", + "ubuntu" = "ubuntu-gcc-release", + "fedora" = "fedora-gcc-devel", + "centos" = "linux-x86_64-centos6-epel", + "solaris" = "solaris-x86-patched" +) + +#' Check an R package on R-hub +#' +#' @param path Path to a directory containing an R package, or path to +#' source R package tarball built with `R CMD build` or +#' `devtools::build()`. +#' @param platforms A character vector of one or more platforms to build/check +#' the package on. See [platforms()] for the available platforms. If this is +#' \code{NULL}, and the R session is interactive, then a menu is shown. If it +#' is \code{NULL}, and the session is not interactive, then the default R-hub +#' platforms are used. A vector of platforms which saves time by building one +#' R package tarball that is used for all the platforms specified. +#' @param email Email address to send notification to about the check. +#' It must be a validated email address, see [validate_email()]. If +#' `NULL`, then the email address of the maintainer is used, as defined +#' in the `DESCRIPTION` file of the package. +#' @param valgrind Whether to run the check in valgrind. Only supported on +#' Linux currently, and ignored on other platforms. +#' @param check_args Extra arguments for the `R CMD check` command. +#' @param env_vars Environment variables to set on the builder machine +#' before the check. A named character vector. +#' @param show_status Whether to show the status of the build and check +#' (live log) as it is happening. +#' @return An [rhub_check] object. +#' +#' @export +#' @examples +#' \dontrun{ +#' check(".") +#' check("mypackage_1.0.0.tar.gz", platforms = "fedora-clang-devel") +#' } + +check <- function(path = ".", platforms = NULL, + email = NULL, valgrind = FALSE, check_args = character(), + env_vars = character(), show_status = interactive()) { + + ## Check that it is a package + path <- normalizePath(path) + assert_that(is_pkg_dir_or_tarball(path)) + assert_that(is_flag(valgrind)) + assert_that(is_named(env_vars)) + assert_that(is.character(env_vars)) + + ## Make sure that maintainer email was validated + if (is.null(email)) email <- get_maintainer_email(path) + if (is.na(email)) stop("Cannot get email address from package") + assert_validated_email_for_check(email) + + platforms <- match_platform(platforms) + + ## Build the tar.gz, if needed + if (file.info(path)$isdir) { + header_line("Building package") + pkg_targz <- build_package(path, tmpdir <- tempfile()) + } else { + pkg_targz <- path + } + + ## Add valgrind to check_args + check_args <- c( + check_args, + if (valgrind) "--use-valgrind" + ) + + ## Submit to R-hub + response <- submit_package( + email, + pkg_targz, + platforms = platforms, + check_args = check_args, + env_vars = env_vars + ) + + ids <- vapply(response, "[[", "", "id") + chk <- rhub_check$new(ids = ids) + + package_data$last_handle <- chk + lapply(ids, cache_put, status = NULL) + + ## Show the live status, if requested + if (show_status) chk$livelog() + + invisible(chk) +} + +assert_validated_email_for_check <- function(email) { + + assert_that(is_email(email)) + code <- email_get_token(email) + if (is.null(code)) { + if (is_interactive()) { + cat("\n") + message(paste(collapse = "\n", strwrap(indent = 2, exdent = 2, paste0( + sQuote(crayon::green(email)), " is not validated, or does not match ", + "the package maintainer's email. To validate it now, please enter ", + "the email address below. Note that R-hub will send a token to ", + "this address. If the address does not belong to you, quit now by ", + "pressing ", crayon::yellow("ENTER"), ". You can also specify a ", + "different email by suppling email=." + )))) + cat("\n") + email2 <- readline(" Email address: ") + cat("\n") + if (email2 == "") { + stop("Aborting.", call. = FALSE) + } else if (email != email2) { + stop("Emails don't match, aborting", call. = FALSE) + } + validate_email(email) + } else { + stop(sQuote(email), " is not validated") + } + } +} + +column_dt <- function(x) { + as.difftime(x / 1000, units = "secs") +} + +#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @importFrom prettyunits pretty_dt +#' @export + +pillar_shaft.difftime <- function(x, ...) { + cx <- my_pretty_dt(x) + new_pillar_shaft_simple(cx, ...) +} + +column_group_id <- function(x) { + structure(x, class = unique(c("rhub_column_group_id", class(x)))) +} + +#' @export + +`[.rhub_column_group_id` <- function(x, i) { + column_group_id(NextMethod("[")) +} + +#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @export + +pillar_shaft.rhub_column_group_id <- function(x, ...) { + cx <- shorten_rhub_id(x) + new_pillar_shaft_simple(cx, ...) +} + +#' @importFrom pillar type_sum +#' @export + +type_sum.rhub_column_group_id <- function(x) { + "rhub::group_id" +} + +column_id <- function(x) { + structure(x, class = unique(c("rhub_column_id", class(x)))) +} + +#' @export + +`[.rhub_column_id` <- function(x, i) { + column_id(NextMethod("[")) +} + +#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @export + +pillar_shaft.rhub_column_id <- function(x, ...) { + cx <- shorten_rhub_id(x) + new_pillar_shaft_simple(cx, ...) +} + +#' @importFrom pillar type_sum +#' @export + +type_sum.rhub_column_id <- function(x) { + "rhub::id" +} +column_result <- function(x) { + structure(x, class = unique(c("rhub_column_result", class(x)))) +} + +#' @export + +`[.rhub_column_result` <- function(x, i) { + column_result(NextMethod("[")) +} + +#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @export + +pillar_shaft.rhub_column_result <- function(x, ...) { + cx <- lapply(x, color_column_result) + new_pillar_shaft_simple(cx, ...) +} + +color_column_result <- function(x) { + if (is.null(x)) return("in-progress") + E <- if (n <- length(x$errors)) status_style_error(strrep("E", n)) + W <- if (n <- length(x$warnings)) status_style_error(strrep("W", n)) + N <- if (n <- length(x$notes)) status_style_note(strrep("N", n)) + + switch( + x$status, + "parseerror" = status_style_error("parseerror"), + "preperror" = status_style_error("preperror"), + "aborted" = status_style_aborted("aborted"), + "ok" = status_style_ok("ok"), + paste0(E, W, N)) +} + +#' @importFrom pillar type_sum +#' @export + +type_sum.rhub_column_result <- function(x) { + "rhub::result" +} + +column_status <- function(x) { + structure(x, class = unique(c("rhub_column_status", class(x)))) +} + +#' @export + +`[.rhub_column_status` <- function(x, i) { + column_status(NextMethod("[")) +} + +#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @export + +pillar_shaft.rhub_column_status <- function(x, ...) { + ## status can be + ## - created + ## - in-progress + ## - parseerror (the R-hub output parser failed) + ## - preperror (build failed before R CMD check has started + ## - aborted (build was aborted) + ## - error + ## - warning + ## - note + ## - ok + + hst <- c( + "created" = status_style_created("created"), + "in-progress" = status_style_in_progress("in-progress"), + "parseerror" = status_style_error("parseerror"), + "preperror" = status_style_error("preperror"), + "aborted" = status_style_aborted("aborted"), + "error" = status_style_error("error"), + "warning" = status_style_error("warning"), + "note" = status_style_note("note"), + "ok" = status_style_ok("ok")) + + cx <- hst[x] + cx[is.na(cx)] <- x[is.na(cx)] + + new_pillar_shaft_simple(cx, ...) +} + +#' @importFrom pillar type_sum +#' @export + +type_sum.rhub_column_status <- function(x) { + "rhub::status" +} + +#' Validate an email address on R-hub +#' +#' To build and check R packages on R-hub, you need to validate your +#' email address. This is because R-hub sends out emails about check +#' results. +#' +#' The `rhub` package stores validated email addresses in a user +#' configuration file, at a platform-dependent location. +#' On your current platform the file is at +#' \Sexpr[stage=render]{rhub:::email_file()}. +#' +#' To validate a new email address, call this function from an interactive +#' R session, without any arguments. +#' +#' To add an email address that was validated before (probably on another +#' machine), to the configuration file, call this function with the `email` +#' and `token` arguments. +#' +#' @param email The email address to validate. +#' @param token Token obtained from `rhub`, to validate the email address. +#' +#' @family email validation +#' @export +#' @importFrom jsonlite unbox + +validate_email <- function(email = NULL, token = NULL) { + + if (is.null(email) || is.null(token)) { + if (!is_interactive()) { + stop("No email or no token and not in interactive mode") + } + return(validate_email_interactive(email, token)) + } + + assert_that(is_email(email)) + assert_that(is_token(token)) + + email_add_token(email, token) + message("Token added for ", sQuote(email)) + cat("\n") + token_file_msg() + cat("\n") + invisible() +} + +#' @importFrom cli symbol +#' @importFrom utils menu +#' @importFrom whoami email_address + +get_email_to_validate <- function(path) { + + ## Find out email first. List currently validated addresses, + ## Offer address by whoami::email_address(), and also the + ## maintainer address, if any. + + valid <- list_validated_emails2(msg_if_empty = FALSE) + guess <- email_address() + maint <- tryCatch(get_maintainer_email(path), error = function(e) NULL) + + choices <- rbind( + if (nrow(valid)) cbind(valid = TRUE, valid), + if (!is.null(guess) && ! guess %in% valid$email) { + data_frame(valid = FALSE, email = guess, token = NA) + }, + if (!is.null(maint) && ! maint %in% valid$email && maint != guess) { + data_frame(valid = FALSE, email = maint, token = NA) + }, + data_frame(valid = NA, email = "New email address", token = NA) + ) + + ## Only show the menu if there is more than one thing there + if (nrow(choices) != 1) { + choices_str <- paste( + sep = " ", + ifelse( + choices$valid & !is.na(choices$valid), + crayon::green(symbol$tick), + " " + ), + choices$email + ) + + cat("\n") + title <- crayon::yellow(paste0( + symbol$line, symbol$line, + " Choose email address to (re)validate (or 0 to exit)" + )) + ch <- menu(choices_str, title = title) + + if (ch == 0) stop("Cancelled email validation", call. = FALSE) + + } else { + ch <- 1 + } + + ## Get another address if that is selected + if (is.na(choices$valid[ch])) { + cat("\n") + email <- readline("Email address: ") + } else { + email <- choices$email[ch] + } +} + +validate_email_interactive <- function(email, token, path = ".") { + + if (is.null(email)) email <- get_email_to_validate(path) + assert_that(is_email(email)) + + ## Token next. For this we need to make an API query. + if (is.null(token)) { + query("VALIDATE EMAIL", data = list(email = unbox(email))) + message(crayon::yellow( + "Please check your emails for the R-hub access token." + )) + token <- readline("Token: ") + } + assert_that(is_token(token)) + + ## We got everything now + validate_email(email, token) +} + +#' List validated email addresses +#' +#' @description List email addresses validated on R-hub on the current machine. +#' +#' @return A `data.frame` with two columns: `email` and `token`. +#' If in interactive mode, and there are no validated email addresses, +#' then a message is printed and the data frame is returned invisibly. +#' +#' @family email validation +#' @export + +list_validated_emails <- function() { + list_validated_emails2() +} + +list_validated_emails2 <- function(msg_if_empty = TRUE) { + file <- email_file() + res <- if (file.exists(file)) { + if (is_interactive()) { + token_file_msg() + } + + structure( + read.csv(file, stringsAsFactors = FALSE, header = FALSE), + names = c("email", "token") + ) + } else { + data.frame( + email = character(), + token = character(), + stringsAsFactors = FALSE + ) + } + if (is_interactive() && nrow(res) == 0) { + if (msg_if_empty) message("No validated emails found.") + invisible(res) + } else { + res + } +} + +#' @importFrom rappdirs user_data_dir + +email_file <- function() { + rhub_data_dir <- user_data_dir("rhub", "rhub") + file.path(rhub_data_dir, "validated_emails.csv") +} + +#' @importFrom utils read.csv + +email_get_token <- function(email) { + file <- email_file() + if (! file.exists(file)) return(NULL) + + tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) + if (! email %in% tokens[,1]) return(NULL) + + tokens[match(email, tokens[,1]), 2] +} + +## If it exists already, then overwrites + +#' @importFrom utils read.csv write.table + +email_add_token <- function(email, token) { + + assert_that(is_email(email)) + assert_that(is_token(token)) + + file <- email_file() + + if (!file.exists(file)) { + parent <- dirname(file) + if (!file.exists(parent)) dir.create(parent, recursive = TRUE) + tokens <- data.frame( + V1 = character(), + V2 = character(), + stringsAsFactors = FALSE + ) + + } else { + tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) + } + + if (! email %in% tokens[,1]) { + tokens <- rbind(tokens, c(email, token)) + + } else{ + tokens[match(email, tokens[,1]), 2] <- token + } + + write.table( + tokens, + file = file, + sep = ",", + col.names = FALSE, + row.names = FALSE + ) + + invisible() +} + +token_file_msg <- function() { + message( + crayon::green( + paste0( + "For info the token(s) and email(s) are stored at ", + email_file() + ) + ) + ) +} + +package_data <- new.env(parent = emptyenv()) +package_data$status <- new.env(parent = emptyenv()) +package_data$ids <- character() +package_data$groups <- character() + +## Since the status can be NULL, meaning unknown, we put all cache elements +## in a list of length 1. + +cache_get <- function(id) { + e <- package_data$status + if (!is.null(x <- e[[id]][[1]])) return(x) + nms <- ls(e) + sts <- grep(paste0("-", id, "[0-9a-f]*$"), nms) + if (length(sts) == 0) return(NULL) + if (length(sts) == 1) return(e[[ nms[sts] ]][[1]]) + stop("Multiple checks match, please use a more specific id", call. = FALSE) +} + +cache_put <- function(id, status) { + cache_put_ids(id) + cache_put_group_ids(status$group) + package_data$status[[id]] <- list(status) + invisible() +} + +cache_put_ids <- function(id) { + id <- unique(setdiff(id, package_data$ids)) + if (length(id)) package_data$ids <- c(id, package_data$ids) +} + +cache_put_group_ids <- function(id) { + id <- unique(setdiff(id, package_data$groups)) + if (length(id)) package_data$groups <- c(id, package_data$groups) +} + +cache_get_ids <- function(ids) { + w <- match_partial(ids, package_data$ids) + package_data$ids[w] +} + +cache_get_group_ids <- function(ids) { + w <- match_partial(ids, package_data$groups) + package_data$groups[w] +} + +match_partial <- function(x, table) { + hash <- sub("^.*-", "", table) + m <- match(x, table) + ifelse(is.na(m), pmatch(x, hash), m) +} + +#' @importFrom crayon yellow red underline + +report_system_error <- function(msg, status) { + + if (status$status == 0) return() + + if (status$stderr == "") { + stop( + msg, ", unknown error, standard output:\n", + yellow(status$stdout), + call. = FALSE + ) + + } else { + stop( + underline(yellow(paste0("\n", msg, ", standard output:\n\n"))), + yellow(status$stdout), "\n", + underline(red("Standard error:\n\n")), red(status$stderr), + call. = FALSE + ) + } +} + +#' @importFrom httr status_code + +report_error <- function(response) { + if (status_code(response) < 300) { + invisible(response) + } else { + call <- sys.call(-1) + stop(create_condition(response, "error", call = call)) + } +} + +#' @importFrom httr content + +create_condition <- function(response, + class = c("error", "warning", "message"), + call) { + + class <- match.arg(class) + + message <- content(response)$message %||% "rhub error" + + structure( + list(message = message, call = call), + class = c("rhub_error", class, "condition") + ) +} + +handle_id <- function(x) { + if (is.character(x)) { + unname(sub("^.*/([^/]+)$", "\\1", x, perl = TRUE)) + } else if (inherits(x, "rhub_handle")) { + unname(vapply(x, "[[", "", "id")) + } else { + stop("Invalid R-hub check id") + } +} + +#' @export + +print.rhub_handle <- function(x, ...) { + id <- handle_id(x) + if (length(id) == 1) { + cat("R-hub check: ", id, "\n", sep = "") + + } else { + cat( + "R-hub checks:\n", + paste(" ", id, collapse = "\n") + ) + } + invisible(x) +} + +#' The last rhub check of this R session +#' +#' `rhub` caches the id(s) of the last submission. This can be retrieved +#' with `last_check`. +#' +#' @return An rhub_check object. +#' +#' @export +#' @examples +#' \dontrun{ +#' check("packagedir") +#' last_check() +#' last_check()$livelog() +#' } + +last_check <- function() { + package_data$last_handle +} + +#' List all checks for an email address +#' +#' @param email Email address. By default it is guessed with +#' [whoami::email_address()]. The address must be validated, see +#' [validate_email()]. +#' @param package `NULL`, or a character scalar. Can be used to restrict +#' the search for a single package. +#' @param howmany How many check groups (checks submitted simultaneously) +#' to show. The current API limit is 20. +#' @return A [tibble::tibble] with columns: +#' * package Name of the package. +#' * version Package version. +#' * result: More detailed result of the check. Can be `NULL` for errors. +#' This is a list column with members: `status`, `errors`, `warnings`, +#' `notes`. +#' * group: R-hub check group id. +#' * id: `R-hub check id. +#' * platform_name: Name of the check platform. +#' * build_time: Build time, a [difftime] object. +#' * submitted: Time of submission. +#' * started: Time of the check start. +#' * platform: Detailed platform data, a list column. +#' * builder: Name of the builder machine. +#' * status Status of the check. Possible values: +#' - `created`: check job was created, but not running yet. +#' - `in-progress`: check job is running. +#' - `parseerror`: internal R-hub error parsing the check results. +#' - `preperror`: check error, before the package check has started. +#' - `aborted`: aborted by admin or user. +#' - `error`: failed check. (Possibly warnings and notes as well.) +#' - `warning`: `R CMD check` reported warnings. (Possibly notes as well.) +#' - `note`: `R CMD check` reported notes. +#' - `ok`: successful check. +#' * email: Email address of maintainer / submitter. +#' +#' @export +#' @seealso list_package_checks +#' @examples +#' \dontrun{ +#' ch <- list_my_checks() +#' ch +#' ch$details() +#' } + +list_my_checks <- function(email = email_address(), package = NULL, + howmany = 20) { + + assert_that(is_email(email)) + assert_that(is_string_or_null(package)) + assert_that(is_count(howmany)) + + response <- if (is.null(package)) { + query( + "LIST BUILDS EMAIL", + params = list(email = email, token = email_get_token(email))) + } else { + query( + "LIST BUILDS PACKAGE", + params = list(email = email, package = package, + token = email_get_token(email))) + } + + if (length(response) > howmany) response <- response[seq_len(howmany)] + + make_check_list(response) +} + + +#' List checks of a package +#' +#' @param package Directory of an R package, or a package tarball. +#' @param email Email address that was used for the check(s). +#' If `NULL`, then the maintainer address is used. +#' @param howmany How many checks to show. The current maximum of the API +#' is 20. +#' @inherit list_my_checks return +#' +#' @export +#' @importFrom desc desc_get +#' @examples +#' \dontrun{ +#' ch <- list_package_checks() +#' ch +#' ch$details(1) +#' } + +list_package_checks <- function(package = ".", email = NULL, howmany = 20) { + + assert_that(is_pkg_dir_or_tarball(package)) + if (is.null(email)) email <- get_maintainer_email(package) + assert_that(is_email(email)) + assert_that(is_count(howmany)) + + package <- unname(desc_get("Package", file = package)) + + response <- query( + "LIST BUILDS PACKAGE", + params = list(email = email, package = package, + token = email_get_token(email)) + ) + + if (length(response) > howmany) response <- response[seq_len(howmany)] + + make_check_list(response) +} + +make_check_list <- function(response) { + data <- unlist(response, recursive = FALSE) + + df <- tibble::tibble( + package = map_chr(data, "[[", "package"), + version = map_chr(data, "[[", "version"), + result = column_result(map(data, function(x) x$result)), + group = column_group_id(map_chr(data, "[[", "group")), + id = column_id(map_chr(data, "[[", "id")), + platform_name = map_chr(data, function(x) x$platform$name), + build_time = column_dt(map_int(data, function(x) { + suppressWarnings(as.integer(x$build_time %||% NA_integer_)) + })), + submitted = column_time(map_chr(data, "[[", "submitted")), + started = column_time(map_chr(data, function(x) x$started %||% NA_character_)), + platform = map(data, "[[", "platform"), + builder = map_chr(data, function(x) x$builder_machine %||% NA_character_), + status = column_status(map_chr(data, "[[", "status")), + email = map_chr(data, "[[", "email") + ) + + cache_put_ids(df$id) + cache_put_group_ids(df$group) + + df +} + +column_time <- function(x) { + res <- rep(as.POSIXct(NA_character_), length(x)) + res[! is.na(x)] <- parse_iso_8601(x[!is.na(x)]) + res +} + +check_livelog <- function(self, private, which) { + assert_that(is_count(which) || is_string(which)) + if (is_count(which) && (which < 1 || which > length(private$ids_))) { + stop("Unknown check selected") + } + if (is.character(which) && ! which %in% private$ids_) { + stop("Unknow check selected") + } + + make_streamer(private$ids_[[which]], make_status_parser) + self$update() + invisible(self) +} + +make_streamer <- function(id, parser_factory) { + + if (length(id) > 1) { + warning("Only first submission is streamed") + id <- id[1] + } + + start <- 0 + parser <- parser_factory() + + spinner <- c("-", "/", "|", "\\") + spin <- function() { + cat("\r", spinner[1], sep = "") + spinner <<- c(spinner[-1], spinner[1]) + } + + errors <- 100 + + repeat { + response <- tryCatch( + query( + "LIVE LOG", + params = list(id = id), + query = list(start = start) + ), + error = function(e) { + if (errors > 0) { + errors <- errors - 1 + list(text = list(), more = TRUE, size = start) + } else { + stop("Internal R-hub error") + list(text = list(), more = FALSE) + } + } + ) + + for (i in response$text) parser(i) + if (!response$more) break; + start <- response$size + for (i in 1:5) { Sys.sleep(0.1); spin() } + } + + cat("\r \n") + + if (grepl( + "^(Finished: ABORTED|Finished: ERROR)$", + response$text[[length(response$text)]] + )) { + cat(response$text[[length(response$text)]], "\n", sep = "") + } +} + +#' @importFrom rcmdcheck rcmdcheck + +make_status_parser <- function() { + + first <- TRUE + checking <- FALSE + + ## This is to make sure that `rhub` works with older and newer + ## rcmdcheck versions as well. Older versions expect a call for each + ## line. Newer versions just take a block of output. + formatter <- try( + ("rcmdcheck" %:::% "check_callback")(top_line = FALSE), + silent = TRUE + ) + if (inherits(formatter, "try-error")) { + cb <- ("rcmdcheck" %:::% "block_callback")(top_line = FALSE) + formatter <- function(x) cb(paste0(x, "\n")) + } + + function(x) { + + ## Make sure we are at the beginning of the line + cat("\r") + + if (first) { + header_line("Build started") + first <<- FALSE + } + + ## Get rid of potential \r characters + x <- gsub("[\r]+", "", x) + + ## Checking (already, and still) + + if (checking) { + if (grepl("^Status: ", x)) { + checking <<- FALSE + return(formatter(x)) + } else { + return(formatter(x)) + } + } + + ## Not checking (yet, or any more) + + if (grepl("^>>>>>=====+ Running R CMD check", x)) { + checking <<- TRUE + x <- sub("^>>>>>=+ ", "", x) + header_line(x) + + } else if (grepl("^>>>>>=====", x)) { + x <- sub("^>>>>>=+ ", "", x) + header_line(x) + + } else if (grepl("^\\+R-HUB-R-HUB-R-HUB", x)) { + x <- sub("^\\+R-HUB-R-HUB-R-HUB", "", x) + + } else { + ## print nothing + } + } +} + +#' Run a package check locally, in a Docker container +#' +#' @description Run a package check locally, in a Docker container. UNTESTED +#' ON WINDOWS, bug reports welcome. :-) +#' +#' @param quiet Whether to print the check output +#' @param image Docker image to use. If `NULL`, a default image is selected. +#' @param valgrind Whether to run the check with Valgrind. +#' @param timeout Timeout for a check, a `difftime` object or a scalar +#' that will be interpreted as seconds. +#' @param artifacts Where to copy the build artifacts after the build. +#' @inheritParams check +#' @return An `rcmdcheck::rcmdcheck` object, with extra fields: +#' * `all_output`: all output from the check, both standard output and +#' error. +#' * `container_name`: name of the Docker container that performed the +#' build. It is a random name. +#' * `artifacts`: directory of build artifacts. +#' +#' @export +#' @importFrom withr with_dir +#' @importFrom processx run +#' @importFrom utils tail +#' @importFrom uuid UUIDgenerate +#' +#' @details You'll need to have bash and Docker installed. + +local_check_linux <- function(path = ".", quiet = FALSE, image = NULL, + valgrind = FALSE, check_args = character(), + env_vars = character(), timeout = Inf, artifacts = tempfile()) { + + ## Check that it is a package + path <- normalizePath(path) + assert_that(is_pkg_dir_or_tarball(path)) + assert_that(is_flag(quiet)) + assert_that(is.null(image) || is.character(image)) + assert_that(is_flag(valgrind)) + assert_that(is_named(env_vars)) + assert_that(is.character(env_vars)) + assert_that(is_timeout(timeout <- as_timeout(timeout))) + assert_that(is.character(artifacts)) + + if ((bash <- Sys.which("bash")) == "" || Sys.which("docker") == "") { + stop("You need bash and Docker to run local Linux checks") + } + + ## Build the tar.gz, if needed + if (file.info(path)$isdir) { + header_line("Building package") + pkg_targz <- build_package(path, tmpdir <- tempfile()) + } else { + pkg_targz <- path + } + + ## Add valgrind to check_args + check_args <- c( + check_args, + if (valgrind) "--use-valgrind" + ) + + dir.create(artifacts, showWarnings = FALSE, recursive = TRUE) + artifacts <- normalizePath(artifacts) + + container_name <- UUIDgenerate() + if (!quiet) { + cat(sep = "", "\nContainer name: ", container_name, "-2", "\n") + cat("It will _not_ be removed after the check.\n\n") + } + + ## Arguments + env_str <- paste(paste0(names(env_vars), "=", env_vars), collapse = "\n") + args <- c( + "-k", + if (!is.null(image)) c("-i", image), + if (length(check_args)) c("-c", paste(check_args, collapse = " ")), + if (length(env_vars)) c("-e", env_str), + c("-a", artifacts), + c("-d", container_name), + pkg_targz) + + output <- character() + callback <- function(x, proc) output <<- c(output, x) + + ## Run it + wd <- system.file(package = .packageName, "bin") + result <- with_dir( + wd, + run(bash, c(file.path(wd, "rhub-linux.sh"), args), echo = TRUE, + stdout_line_callback = callback, stderr_line_callback = callback, + timeout = timeout, spinner = FALSE) + ) + + ## TODO: better error object + if (result$timeout) stop("Check timed out") + + if (!quiet) cat("Artifacts in", artifacts, "\n") + if (!quiet) cat(sep = "", "Container name: ", container_name, "-2", "\n\n") + + ## Try to parse as R CMD check result + check_start <- grep("^>>>>>=====+ Running R CMD check", output)[1] + if (is.na(check_start)) stop("Failed before check started") + check_output <- tail(output, -check_start) + check_result <- tryCatch( + rcmdcheck::parse_check(text = check_output), + error = function(e) NULL) + + result <- list( + check_result = check_result, + output = output, + image = image, + artifacts = artifacts, + container_name = paste0(container_name, "-2")) + class(result) <- "rhub_local_check" + result +} + +#' @importFrom utils head +#' @export + +print.rhub_local_check <- function(x, ...) { + cat0("\n") + if (!is.null(x$image)) cat0(symbol$bullet, " image: ", x$image, "\n") + if (!is.null(x$output)) { + cat0(symbol$bullet, " output:\n") + cat(paste0(" ", c(head(x$output, 5), "...")), sep = "\n") + } + cat0(symbol$bullet, " container_name: ", x$container_name, "\n") + if (!is.null(x$artifacts)) { + cat0(symbol$bullet, " artifacts: \n ", x$artifacts, "\n") + } + if (!is.null(x$check_result)) { + cat0(symbol$bullet, " check_result:\n") + print(x$check_result) + } +} + +#' List R-hub Docker images +#' +#' The images are pretty-printed in a short format. Use +#' `as.data.frame()` to get all available platform metadata. +#' +#' @export + +local_check_linux_images <- function() { + plat <- platforms() + plat <- plat[!is.na(plat$`docker-image`), ] + class(plat) <- c("rhub_docker_images", class(plat)) + plat +} + +#' @export + +print.rhub_docker_images <- function(x, ...) { + res <- paste(cyan(paste0("rhub/", x$`docker-image`)), + green(x$description), sep = ":\n ") + cat(res, sep = "\n") + invisible(x) +} + +#' List all R-hub platforms +#' +#' The platforms are pretty-printed in a short format. Use +#' `as.data.frame(platforms())` to get all available platform metadata. +#' +#' @export +#' @importFrom jsonlite fromJSON +#' @importFrom crayon green cyan +#' @examples +#' \dontrun{ +#' platforms() +#' as.data.frame(platforms()) +#' } + +platforms <- function() { + json <- query("GET PLATFORMS", as = "text") + pls <- fromJSON(json, simplifyDataFrame = TRUE) + pls <- pls[order(pls$name), , drop = FALSE] + class(pls) <- c("rhub_platforms", class(pls)) + pls +} + +#' @export + +print.rhub_platforms <- function(x, ...) { + res <- paste(cyan(x$name), green(x$description), sep = ":\n ") + cat(res, sep = "\n") + invisible(x) +} + +match_platform <- function(platform) { + all_platforms <- platforms() + if (is.null(platform)) { + if (is_interactive()) { + select_platform_interactively(all_platforms) + } else { + all_platforms$name[1] + } + + } else { + if (! all(platform %in% all_platforms$name)) { + stop("Unknown R-hub platform, see rhub::platforms() for a list") + } + platform + } +} + +select_platform_interactively <- function(platforms) { + + choices <- paste0( + platforms$description, + crayon::green(" (", platforms$name, ")", sep = "") + ) + + cat("\n") + title <- crayon::yellow(paste0( + symbol$line, symbol$line, + " Choose build platform" + )) + ch <- menu(choices, title = title) + cat("\n") + if (ch == 0) stop("R-hub check aborted", call. = FALSE) + + platforms$name[ch] +} + +check_print <- function(self, private) { + self$update() + for (x in private$status_) check_print2(x) + invisible(self) +} + +#' @importFrom parsedate parse_iso_8601 +#' @importFrom prettyunits pretty_ms +#' @importFrom crayon make_style red yellow + +check_print2 <- function(x) { + + title_line(paste0(x$package, " ", x$version, ": ", toupper(x$status))) + + greyish <- make_style("darkgrey") + + submitted_time <- as.numeric(Sys.time() - parse_iso_8601(x$submitted), units = "secs") + submitted <- if (submitted_time > 0) { + paste(pretty_ms(submitted_time * 1000), "ago") + } else { + "just now" + } + + build_time <- if (!is.null(x$build_time) && x$build_time != 0) { + paste0(greyish(" Build time: "), pretty_ms(x$build_time), "\n") + } + + cat( + sep = "", + greyish(" Build ID: "), x$id, "\n", + greyish(" Platform: "), x$platform$description, "\n", + greyish(" Submitted: "), submitted, "\n", + build_time %||% "", + "\n" + ) + + ## If not done, then this is all we do + if (is.null(build_time)) return(invisible(x)) + + ## R CMD check error + if (tolower(x$status) != "preperror" && tolower(x$status) != "aborted") { + makeshift <- structure( + list( + package = x$package, + version = x$version, + rversion = x$platform$rversion, + output = list(stdout = x$check_output, stderr = "", status = 0), + platform = x$platform$name, + notes = x$result$notes, + warnings = x$result$warnings, + errors = x$result$errors + ), + class = "rcmdcheck" + ) + print(makeshift, header = FALSE) + + ## Or we never got to R CMD check + } else { + clog <- gsub("+R-HUB-R-HUB-R-HUB", "", fixed = TRUE, x$preperror_log) + clog <- gsub("\necho >>>>>=========[^\n]*\n", "\n", clog) + clog <- gsub( + "\n>>>>>=======* (.+)\n", + yellow(sep = "", "\n\n", symbol$line, " \\1\n\n"), + clog, + perl = TRUE + ) + + cat(red(paste0(symbol$pointer, " Build failed during preparation or aborted\n"))) + cat(greyish("\n[...]\n")) + cat(greyish(clog)) + cat("\n") + } + + invisible(x) +} + +#' @importFrom crayon make_style +#' @importFrom cli symbol + +header_line <- function(x) { + + greyish <- make_style("darkgrey") + + cat( + paste0("\r", greyish(symbol$line), " "), + greyish(x), + "\n", + sep = "" + ) +} + +#' @importFrom crayon yellow +#' @importFrom cli symbol + +title_line <- function(x) { + + cat( + sep ="", + "\n", + yellow(paste0(symbol$line, symbol$line, " ", x)), + "\n\n" + ) +} + +#' @importFrom cli make_ansi_style style_bold style_inverse +#' col_red col_blue col_green + +status_style_created <- function(x) { + x +} + +status_style_in_progress <- function(x) { + x +} + +status_style_error <- function(x) { + style_inverse(style_bold(col_red(x))) +} + +status_style_aborted <- function(x) { + style_bold(col_blue(x)) +} + +status_style_note <- function(x) { + orange <- make_ansi_style("orange") + style_bold(orange(x)) +} + +status_style_ok <- function(x) { + style_inverse(style_bold(col_green(x))) +} + +re_match_all <- function(text, pattern, ...) { + + text <- as.character(text) + stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) + + ## Need to handle this case separately, as gregexpr effectively + ## does not work for this. + if (length(text) == 0) return(empty_result(text, pattern, ...)) + + match <- gregexpr(pattern, text, perl = TRUE, ...) + + num_groups <- length(attr(match[[1]], "capture.names")) + + ## Non-matching strings have a rather strange special form, + ## so we just treat them differently + non <- vapply(match, function(m) m[1] == -1, TRUE) + yes <- !non + res <- replicate(length(text), list(), simplify = FALSE) + if (any(non)) { + res[non] <- list(replicate(num_groups + 1, character(), simplify = FALSE)) + } + if (any(yes)) { + res[yes] <- mapply(match1, text[yes], match[yes], SIMPLIFY = FALSE) + } + + ## Need to assemble the final data frame "manually". + ## There is apparently no function for this. rbind() is almost + ## good, but simplifies to a matrix if the dimensions allow it.... + res <- lapply(seq_along(res[[1]]), function(i) { + lapply(res, "[[", i) + }) + + structure( + res, + names = c(attr(match[[1]], "capture.names"), ".match"), + row.names = seq_along(text), + class = c("data.frame") + ) +} + +match1 <- function(text1, match1) { + + matchstr <- substring( + text1, + match1, + match1 + attr(match1, "match.length") - 1L + ) + + ## substring fails if the index is length zero, + ## need to handle special case + if (is.null(attr(match1, "capture.start"))) { + list(.match = matchstr) + + } else { + gstart <- attr(match1, "capture.start") + glength <- attr(match1, "capture.length") + gend <- gstart + glength - 1L + + groupstr <- substring(text1, gstart, gend) + dim(groupstr) <- dim(gstart) + + c(lapply(seq_len(ncol(groupstr)), function(i) groupstr[, i]), + list(.match = matchstr) + ) + } +} + +empty_result <- function(text, pattern, ...) { + match <- regexpr(pattern, text, perl = TRUE, ...) + num_groups <- length(attr(match, "capture.names")) + structure( + replicate(num_groups + 1, list(), simplify = FALSE), + names = c(attr(match, "capture.names"), ".match"), + row.names = integer(0), + class = "data.frame" + ) +} +#' @keywords internal +"_PACKAGE" + +# The following block is used by usethis to automatically manage +# roxygen namespace tags. Modify with care! +## usethis namespace: start +## usethis namespace: end +NULL + +#' @importFrom rematch re_match +#' @importFrom jsonlite base64_enc +#' @importFrom crayon blue + +submit_package <- function(email, pkg_targz, platforms, check_args, + env_vars) { + + assert_that(is_email(email)) + assert_that( + is.character(platforms), + length(platforms) >= 1 + ) + + m <- re_match( + pattern = "^(?.+)_(?.+)\\.tar\\.gz", + basename(pkg_targz) + ) + + header_line("Uploading package") + buf <- readBin(pkg_targz, raw(), file.info(pkg_targz)$size) + response <- query( + "SUBMIT PACKAGE", + data = list( + email = unbox(email), + token = unbox(email_get_token(email)), + package = unbox(unname(m[, "package"])), + version = unbox(unname(m[, "version"])), + platform = platforms, + env = as.list(env_vars), + check_args = unbox(paste(check_args, collapse = " ")), + file = unbox(base64_enc(buf)) + ) + ) + + header_line(paste0( + "Preparing build, see status at\n", + blue(paste( + " ", + vapply(response, "[[", "", "status-url"), + collapse = "\n" + )) + )) + + response +} + +update <- function(original, new) { + + if (length(new)) { + if (length(original)) assert_that(is_named(original)) + assert_that(is_named(new)) + original[names(new)] <- new + } + + original +} + +#' @importFrom rematch re_match + +parse_email <- function(x) { + unname( + re_match(pattern = "<(?[^>]+)>", x)[, "email"] + ) +} + +`%||%` <- function(l, r) if (is.null(l)) r else l + +#' @importFrom desc desc_get_maintainer +#' @importFrom utils untar + +get_maintainer_email <- function(path) { + path <- normalizePath(path) + if (is_dir(path)) { + if (!file.exists(file.path(path, "DESCRIPTION"))) { + stop("No 'DESCRIPTION' file found") + } + parse_email(desc_get_maintainer(path)) + } else { + dir.create(tmp <- tempfile()) + files <- untar(path, list = TRUE, tar = "internal") + desc <- grep("^[^/]+/DESCRIPTION$", files, value = TRUE) + if (length(desc) < 1) stop("No 'DESCRIPTION' file in package") + untar(path, desc, exdir = tmp, tar = "internal") + parse_email(desc_get_maintainer(file.path(tmp, desc))) + } +} + +needs_compilation <- function(path) { + path <- normalizePath(path) + if (is_dir(path)) { + file.exists(file.path(path, "src")) + } else { + dir.create(tmp <- tempfile()) + files <- untar(path, list = TRUE, tar = "internal") + any(grepl("^[^/]+/src/?$", files)) + } +} + +`%:::%` <- function(p, f) { + get(f, envir = asNamespace(p)) +} + +is_interactive <- function() { + interactive() +} + +is_dir <- function(x) { + file.info(x)$isdir +} + +data_frame <- function(...) { + data.frame(stringsAsFactors = FALSE, ...) +} + +drop_nulls <- function(x) { + x [ ! vapply(x, is.null, TRUE) ] +} + +get_group <- function(l){ + if (! "group" %in% names(l)){ + "" + } else { + l[["group"]] + } +} + +cat0 <- function(..., sep = "") { + cat(..., sep = sep) +} + +map <- function(.x, .f, ...) { + lapply(.x, .f, ...) +} + +map_lgl <- function(.x, .f, ...) { + vapply(.x, .f, logical(1), ...) +} + +map_chr <- function(.x, .f, ...) { + vapply(.x, .f, character(1), ...) +} + +map_int <- function(.x, .f, ...) { + vapply(.x, .f, integer(1), ...) +} + +shorten_rhub_id <- function(x) { + sx <- strsplit(x, "-", fixed = TRUE) + substr(map_chr(sx, tail, 1), 1, 7) +} + +## This is a workaround to handle NAs + +my_pretty_dt <- function(x, compact = TRUE) { + res <- rep("?", length(x)) + res[!is.na(x)] <- pretty_dt(x[!is.na(x)], compact = compact) + res +} + +problem_statuses <- function(){ + c("parseerror", "preperror", "aborted") +} diff --git a/R/submit.R b/R/submit.R deleted file mode 100644 index 737d1af..0000000 --- a/R/submit.R +++ /dev/null @@ -1,46 +0,0 @@ - -#' @importFrom rematch re_match -#' @importFrom jsonlite base64_enc -#' @importFrom crayon blue - -submit_package <- function(email, pkg_targz, platforms, check_args, - env_vars) { - - assert_that(is_email(email)) - assert_that( - is.character(platforms), - length(platforms) >= 1 - ) - - m <- re_match( - pattern = "^(?.+)_(?.+)\\.tar\\.gz", - basename(pkg_targz) - ) - - header_line("Uploading package") - buf <- readBin(pkg_targz, raw(), file.info(pkg_targz)$size) - response <- query( - "SUBMIT PACKAGE", - data = list( - email = unbox(email), - token = unbox(email_get_token(email)), - package = unbox(unname(m[, "package"])), - version = unbox(unname(m[, "version"])), - platform = platforms, - env = as.list(env_vars), - check_args = unbox(paste(check_args, collapse = " ")), - file = unbox(base64_enc(buf)) - ) - ) - - header_line(paste0( - "Preparing build, see status at\n", - blue(paste( - " ", - vapply(response, "[[", "", "status-url"), - collapse = "\n" - )) - )) - - response -} diff --git a/R/utils.R b/R/utils.R deleted file mode 100644 index b83cf89..0000000 --- a/R/utils.R +++ /dev/null @@ -1,117 +0,0 @@ - -update <- function(original, new) { - - if (length(new)) { - if (length(original)) assert_that(is_named(original)) - assert_that(is_named(new)) - original[names(new)] <- new - } - - original -} - -#' @importFrom rematch re_match - -parse_email <- function(x) { - unname( - re_match(pattern = "<(?[^>]+)>", x)[, "email"] - ) -} - -`%||%` <- function(l, r) if (is.null(l)) r else l - -#' @importFrom desc desc_get_maintainer -#' @importFrom utils untar - -get_maintainer_email <- function(path) { - path <- normalizePath(path) - if (is_dir(path)) { - if (!file.exists(file.path(path, "DESCRIPTION"))) { - stop("No 'DESCRIPTION' file found") - } - parse_email(desc_get_maintainer(path)) - } else { - dir.create(tmp <- tempfile()) - files <- untar(path, list = TRUE, tar = "internal") - desc <- grep("^[^/]+/DESCRIPTION$", files, value = TRUE) - if (length(desc) < 1) stop("No 'DESCRIPTION' file in package") - untar(path, desc, exdir = tmp, tar = "internal") - parse_email(desc_get_maintainer(file.path(tmp, desc))) - } -} - -needs_compilation <- function(path) { - path <- normalizePath(path) - if (is_dir(path)) { - file.exists(file.path(path, "src")) - } else { - dir.create(tmp <- tempfile()) - files <- untar(path, list = TRUE, tar = "internal") - any(grepl("^[^/]+/src/?$", files)) - } -} - -`%:::%` <- function(p, f) { - get(f, envir = asNamespace(p)) -} - -is_interactive <- function() { - interactive() -} - -is_dir <- function(x) { - file.info(x)$isdir -} - -data_frame <- function(...) { - data.frame(stringsAsFactors = FALSE, ...) -} - -drop_nulls <- function(x) { - x [ ! vapply(x, is.null, TRUE) ] -} - -get_group <- function(l){ - if (! "group" %in% names(l)){ - "" - } else { - l[["group"]] - } -} - -cat0 <- function(..., sep = "") { - cat(..., sep = sep) -} - -map <- function(.x, .f, ...) { - lapply(.x, .f, ...) -} - -map_lgl <- function(.x, .f, ...) { - vapply(.x, .f, logical(1), ...) -} - -map_chr <- function(.x, .f, ...) { - vapply(.x, .f, character(1), ...) -} - -map_int <- function(.x, .f, ...) { - vapply(.x, .f, integer(1), ...) -} - -shorten_rhub_id <- function(x) { - sx <- strsplit(x, "-", fixed = TRUE) - substr(map_chr(sx, tail, 1), 1, 7) -} - -## This is a workaround to handle NAs - -my_pretty_dt <- function(x, compact = TRUE) { - res <- rep("?", length(x)) - res[!is.na(x)] <- pretty_dt(x[!is.na(x)], compact = compact) - res -} - -problem_statuses <- function(){ - c("parseerror", "preperror", "aborted") -} diff --git a/man/check.Rd b/man/check.Rd index cbf4d0b..7d9fbd1 100644 --- a/man/check.Rd +++ b/man/check.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check.R +% Please edit documentation in R/rhubv1.R \name{check} \alias{check} \title{Check an R package on R-hub} diff --git a/man/check_for_cran.Rd b/man/check_for_cran.Rd index 5b2ea74..374d883 100644 --- a/man/check_for_cran.Rd +++ b/man/check_for_cran.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check-cran.R +% Please edit documentation in R/rhubv1.R \name{check_for_cran} \alias{check_for_cran} \title{Check an R-package on R-hub, for a CRAN submission} @@ -27,7 +27,7 @@ in the \code{DESCRIPTION} file of the package.} \item{check_args}{Arguments for \verb{R CMD check}. By default \code{--as-cran} is used.} -\item{env_vars}{Character vecctor of environment variables to set on the builder. +\item{env_vars}{Character vector of environment variables to set on the builder. By default \verb{_R_CHECK_FORCE_SUGGESTS_="true"} is set, to require all packages used. \verb{_R_CHECK_CRAN_INCOMING_USE_ASPELL_="true"} is also set, to use the spell checker.} diff --git a/man/check_shortcuts.Rd b/man/check_shortcuts.Rd index dca41b0..e13b60a 100644 --- a/man/check_shortcuts.Rd +++ b/man/check_shortcuts.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check-shortcuts.R +% Please edit documentation in R/rhubv1.R \name{check_on_linux} \alias{check_on_linux} \alias{check_on_windows} diff --git a/man/get_check.Rd b/man/get_check.Rd index 2490d37..e6a8172 100644 --- a/man/get_check.Rd +++ b/man/get_check.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check-class.R +% Please edit documentation in R/rhubv1.R \name{get_check} \alias{get_check} \title{Retrieve the result of R-hub checks} diff --git a/man/last_check.Rd b/man/last_check.Rd index 30de104..817b442 100644 --- a/man/last_check.Rd +++ b/man/last_check.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/last.R +% Please edit documentation in R/rhubv1.R \name{last_check} \alias{last_check} \title{The last rhub check of this R session} diff --git a/man/list_my_checks.Rd b/man/list_my_checks.Rd index 6022e51..07aa205 100644 --- a/man/list_my_checks.Rd +++ b/man/list_my_checks.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/list.R +% Please edit documentation in R/rhubv1.R \name{list_my_checks} \alias{list_my_checks} \title{List all checks for an email address} diff --git a/man/list_package_checks.Rd b/man/list_package_checks.Rd index 16e10ad..6344d32 100644 --- a/man/list_package_checks.Rd +++ b/man/list_package_checks.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/list.R +% Please edit documentation in R/rhubv1.R \name{list_package_checks} \alias{list_package_checks} \title{List checks of a package} diff --git a/man/list_validated_emails.Rd b/man/list_validated_emails.Rd index 53d4659..bea8172 100644 --- a/man/list_validated_emails.Rd +++ b/man/list_validated_emails.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/email.R +% Please edit documentation in R/rhubv1.R \name{list_validated_emails} \alias{list_validated_emails} \title{List validated email addresses} diff --git a/man/local_check_linux.Rd b/man/local_check_linux.Rd index 770b393..deb1da7 100644 --- a/man/local_check_linux.Rd +++ b/man/local_check_linux.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/local.R +% Please edit documentation in R/rhubv1.R \name{local_check_linux} \alias{local_check_linux} \title{Run a package check locally, in a Docker container} diff --git a/man/local_check_linux_images.Rd b/man/local_check_linux_images.Rd index faf28f4..2fe6d28 100644 --- a/man/local_check_linux_images.Rd +++ b/man/local_check_linux_images.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/local.R +% Please edit documentation in R/rhubv1.R \name{local_check_linux_images} \alias{local_check_linux_images} \title{List R-hub Docker images} diff --git a/man/platforms.Rd b/man/platforms.Rd index 71a1fe0..dee8e38 100644 --- a/man/platforms.Rd +++ b/man/platforms.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/platform.R +% Please edit documentation in R/rhubv1.R \name{platforms} \alias{platforms} \title{List all R-hub platforms} diff --git a/man/rhub-ids.Rd b/man/rhub-ids.Rd index d7f3af2..0751aab 100644 --- a/man/rhub-ids.Rd +++ b/man/rhub-ids.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check-class.R +% Please edit documentation in R/rhubv1.R \name{rhub-ids} \alias{rhub-ids} \title{R-hub check ids} diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index c3208ca..8534a72 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rhub-package.R +% Please edit documentation in R/rhubv1.R \docType{package} \name{rhub-package} \alias{rhub} diff --git a/man/rhub_check.Rd b/man/rhub_check.Rd index 52a07c9..a381511 100644 --- a/man/rhub_check.Rd +++ b/man/rhub_check.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/check-class.R +% Please edit documentation in R/rhubv1.R \name{rhub_check} \alias{rhub_check} \title{An \code{rhub_check} object holds status and results of rhub checks} diff --git a/man/validate_email.Rd b/man/validate_email.Rd index 747b6e9..0d46707 100644 --- a/man/validate_email.Rd +++ b/man/validate_email.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/email.R +% Please edit documentation in R/rhubv1.R \name{validate_email} \alias{validate_email} \title{Validate an email address on R-hub} From fc7417414b6eb9ac33c5c98e69d4e2e32341513d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 14 Mar 2024 11:51:23 +0100 Subject: [PATCH 02/22] Deprecate old, add new --- .Rbuildignore | 2 + .gitignore | 1 + DESCRIPTION | 38 +- NAMESPACE | 99 +- R/a-rstudio-detect.R | 177 + R/aa-assertthat.R | 91 + R/aaa-async.R | 4507 ++++++++++++++++++++++++ R/assertions.R | 68 + R/assertthat.R | 183 + R/check.R | 127 + R/cli.R | 11 + R/compat-vctrs.R | 640 ++++ R/doctor.R | 276 ++ R/errors.R | 1198 +++++++ R/gh.R | 75 + R/http-cache.R | 18 + R/platforms.R | 200 ++ R/rematch.R | 36 + R/rhubv1.R | 2362 +------------ R/rhubv2.R | 17 + R/setup.R | 146 + R/utils.R | 109 + README.Rmd | 116 + README.md | 119 +- man/check.Rd | 50 +- man/check_for_cran.Rd | 63 +- man/check_shortcuts.Rd | 49 +- man/get_check.Rd | 33 +- man/last_check.Rd | 18 +- man/list_my_checks.Rd | 57 +- man/list_package_checks.Rd | 52 +- man/list_validated_emails.Rd | 17 +- man/local_check_linux.Rd | 49 +- man/local_check_linux_images.Rd | 10 +- man/platforms.Rd | 16 +- man/rhub-ids.Rd | 44 - man/rhub-package.Rd | 214 +- man/rhub_check.Rd | 82 +- man/rhub_doctor.Rd | 17 + man/rhub_platforms.Rd | 29 + man/rhub_setup.Rd | 19 + man/rhubv2.Rd | 8 + man/roxygen/meta.R | 24 + man/validate_email.Rd | 30 +- tests/testthat/helpers.R | 24 - tests/testthat/test-api.R | 60 - tests/testthat/test-assertions.R | 90 - tests/testthat/test-build.R | 19 - tests/testthat/test-check.R | 67 - tests/testthat/test-email.R | 43 - tests/testthat/test-error.R | 41 - tests/testthat/test-platforms.R | 171 - tests/testthat/test-print.R | 9 - tests/testthat/test-submit.R | 38 - tests/testthat/test-utils.R | 66 - tests/testthat/test.R | 3 + vignettes/.gitignore | 2 - vignettes/figures/check-output.gif | Bin 642364 -> 0 bytes vignettes/figures/email-validation.png | Bin 112491 -> 0 bytes vignettes/local-debugging.Rmd | 140 - vignettes/rhub.Rmd | 362 -- vignettes/rhubv2.Rmd | 1 + 62 files changed, 8605 insertions(+), 4028 deletions(-) create mode 100644 R/a-rstudio-detect.R create mode 100644 R/aa-assertthat.R create mode 100644 R/aaa-async.R create mode 100644 R/assertions.R create mode 100644 R/assertthat.R create mode 100644 R/check.R create mode 100644 R/cli.R create mode 100644 R/compat-vctrs.R create mode 100644 R/doctor.R create mode 100644 R/errors.R create mode 100644 R/gh.R create mode 100644 R/http-cache.R create mode 100644 R/platforms.R create mode 100644 R/rematch.R create mode 100644 R/rhubv2.R create mode 100644 R/setup.R create mode 100644 R/utils.R create mode 100644 README.Rmd delete mode 100644 man/rhub-ids.Rd create mode 100644 man/rhub_doctor.Rd create mode 100644 man/rhub_platforms.Rd create mode 100644 man/rhub_setup.Rd create mode 100644 man/rhubv2.Rd create mode 100644 man/roxygen/meta.R delete mode 100644 tests/testthat/helpers.R delete mode 100644 tests/testthat/test-api.R delete mode 100644 tests/testthat/test-assertions.R delete mode 100644 tests/testthat/test-build.R delete mode 100644 tests/testthat/test-check.R delete mode 100644 tests/testthat/test-email.R delete mode 100644 tests/testthat/test-error.R delete mode 100644 tests/testthat/test-platforms.R delete mode 100644 tests/testthat/test-print.R delete mode 100644 tests/testthat/test-submit.R delete mode 100644 tests/testthat/test-utils.R create mode 100644 tests/testthat/test.R delete mode 100644 vignettes/.gitignore delete mode 100644 vignettes/figures/check-output.gif delete mode 100644 vignettes/figures/email-validation.png delete mode 100644 vignettes/local-debugging.Rmd delete mode 100644 vignettes/rhub.Rmd create mode 100644 vignettes/rhubv2.Rmd diff --git a/.Rbuildignore b/.Rbuildignore index 55871de..e084894 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -11,3 +11,5 @@ ^revdep$ ^codecov\.yml$ ^\.github$ +^vignettes$ +^man/_cache$ diff --git a/.gitignore b/.gitignore index 54834f8..776e299 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ inst/doc .RData rhub.Rproj /revdep +/man/_cache diff --git a/DESCRIPTION b/DESCRIPTION index 088fe6a..31b475e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -3,7 +3,7 @@ Title: Connect to 'R-hub' Version: 1.1.2.9000 Authors@R: c( person("Gábor", "Csárdi",, "csardi.gabor@gmail.com", role = c("aut", "cre")), - person("Maëlle", "Salmon", role = "aut", + person("Maëlle", "Salmon", role = "aut", email = "maelle.salmon@yahoo.se", comment = c(ORCID = "0000-0002-2815-0399")), person("R Consortium", role = c("fnd"))) @@ -13,34 +13,22 @@ Description: Run 'R CMD check' on any of the 'R-hub' (= 1.1.0), - crayon, - desc, - digest, - httr, + cli, + curl, + gert, + glue, + gitcreds, jsonlite, - parsedate, - pillar, - prettyunits, processx, R6, - rappdirs, - rcmdcheck (>= 1.2.1), - rematch, - tibble, - utils, - uuid, - whoami, - withr -Suggests: - covr, - testthat, - knitr, - rmarkdown + rprojroot +Suggests: + asciicast, + debugme, + pillar, + testthat (>= 3.0.0) Encoding: UTF-8 -VignetteBuilder: knitr, rmarkdown diff --git a/NAMESPACE b/NAMESPACE index ad60cb2..8800019 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,22 +1,11 @@ # Generated by roxygen2: do not edit by hand -S3method("[",rhub_column_group_id) -S3method("[",rhub_column_id) -S3method("[",rhub_column_result) -S3method("[",rhub_column_status) -S3method(pillar_shaft,difftime) -S3method(pillar_shaft,rhub_column_group_id) -S3method(pillar_shaft,rhub_column_id) -S3method(pillar_shaft,rhub_column_result) -S3method(pillar_shaft,rhub_column_status) -S3method(print,rhub_docker_images) -S3method(print,rhub_handle) -S3method(print,rhub_local_check) -S3method(print,rhub_platforms) -S3method(type_sum,rhub_column_group_id) -S3method(type_sum,rhub_column_id) -S3method(type_sum,rhub_column_result) -S3method(type_sum,rhub_column_status) +S3method("[",rhub2_platforms) +S3method(format,rhub2_platforms) +S3method(format,rhub2_platforms_summary) +S3method(print,rhub2_platforms) +S3method(print,rhub2_platforms_summary) +S3method(summary,rhub2_platforms) export(check) export(check_for_cran) export(check_on_centos) @@ -41,56 +30,32 @@ export(list_validated_emails) export(local_check_linux) export(local_check_linux_images) export(platforms) +export(rhub_check) +export(rhub_doctor) +export(rhub_platforms) +export(rhub_setup) export(validate_email) importFrom(R6,R6Class) -importFrom(assertthat,"on_failure<-") -importFrom(assertthat,assert_that) -importFrom(callr,rcmd_safe) -importFrom(cli,col_blue) -importFrom(cli,col_green) -importFrom(cli,col_red) -importFrom(cli,make_ansi_style) -importFrom(cli,style_bold) -importFrom(cli,style_inverse) -importFrom(cli,symbol) -importFrom(crayon,blue) -importFrom(crayon,cyan) -importFrom(crayon,green) -importFrom(crayon,make_style) -importFrom(crayon,red) -importFrom(crayon,underline) -importFrom(crayon,yellow) -importFrom(desc,desc_get) -importFrom(desc,desc_get_maintainer) -importFrom(digest,digest) -importFrom(httr,DELETE) -importFrom(httr,GET) -importFrom(httr,POST) -importFrom(httr,add_headers) -importFrom(httr,content) -importFrom(httr,headers) -importFrom(httr,status_code) -importFrom(jsonlite,base64_enc) -importFrom(jsonlite,fromJSON) -importFrom(jsonlite,toJSON) -importFrom(jsonlite,unbox) -importFrom(parsedate,parse_iso_8601) -importFrom(pillar,new_pillar_shaft_simple) -importFrom(pillar,pillar_shaft) -importFrom(pillar,type_sum) -importFrom(prettyunits,pretty_dt) -importFrom(prettyunits,pretty_ms) -importFrom(processx,run) -importFrom(rappdirs,user_data_dir) -importFrom(rcmdcheck,rcmdcheck) -importFrom(rematch,re_match) -importFrom(utils,browseURL) +importFrom(callr,r_process) +importFrom(callr,r_process_options) +importFrom(callr,r_session) +importFrom(callr,rcmd_safe_env) +importFrom(curl,handle_data) +importFrom(curl,handle_setheaders) +importFrom(curl,handle_setopt) +importFrom(curl,multi_add) +importFrom(curl,multi_cancel) +importFrom(curl,multi_fdset) +importFrom(curl,multi_list) +importFrom(curl,multi_run) +importFrom(curl,multi_set) +importFrom(curl,new_handle) +importFrom(curl,new_pool) +importFrom(curl,parse_headers_list) +importFrom(processx,conn_get_fileno) +importFrom(processx,process) +importFrom(utils,getSrcDirectory) +importFrom(utils,getSrcFilename) +importFrom(utils,getSrcLocation) importFrom(utils,head) -importFrom(utils,menu) -importFrom(utils,read.csv) -importFrom(utils,tail) -importFrom(utils,untar) -importFrom(utils,write.table) -importFrom(uuid,UUIDgenerate) -importFrom(whoami,email_address) -importFrom(withr,with_dir) +importFrom(utils,modifyList) diff --git a/R/a-rstudio-detect.R b/R/a-rstudio-detect.R new file mode 100644 index 0000000..6a2800d --- /dev/null +++ b/R/a-rstudio-detect.R @@ -0,0 +1,177 @@ + +rstudio <- local({ + + standalone_env <- environment() + parent.env(standalone_env) <- baseenv() + + # -- Collect data ------------------------------------------------------ + + data <- NULL + + get_data <- function() { + envs <- c( + "R_BROWSER", + "R_PDFVIEWER", + "RSTUDIO", + "RSTUDIO_TERM", + "RSTUDIO_CONSOLE_COLOR", + "ASCIICAST") + + d <- list( + pid = Sys.getpid(), + envs = Sys.getenv(envs), + api = tryCatch( + asNamespace("rstudioapi")$isAvailable(), + error = function(err) FALSE + ), + tty = isatty(stdin()), + gui = .Platform$GUI, + args = commandArgs(), + search = search() + ) + d$ver <- if (d$api) asNamespace("rstudioapi")$getVersion() + d$desktop <- if (d$api) asNamespace("rstudioapi")$versionInfo()$mode + + d + } + + # -- Auto-detect environment ------------------------------------------- + + is_rstudio <- function() { + Sys.getenv("RSTUDIO") == "1" + } + + detect <- function(clear_cache = FALSE) { + # Cached? + if (clear_cache) data <<- list() + if (!is.null(data)) return(get_caps(data)) + + # Otherwise get data + new <- get_data() + + # Cache unless told otherwise + cache <- TRUE + + new$type <- if (new$envs[["RSTUDIO"]] != "1") { + # 1. Not RStudio at all + "not_rstudio" + + } else if (new$gui == "RStudio" && new$api) { + # 2. RStudio console, properly initialized + "rstudio_console" + + } else if (new$gui == "RStudio" && ! new$api) { + # 3. RStudio console, initilizing + cache <- FALSE + "rstudio_console_starting" + + } else if (new$tty && new$envs[["ASCIICAST"]] != "true") { + # 4. R in the RStudio terminal + # This could also be a subprocess of the console or build pane + # with a pseudo-terminal. There isn't really a way to rule that + # out, without inspecting some process data with ps::ps_*(). + # At least we rule out asciicast + "rstudio_terminal" + + } else if (! new$tty && + new$envs[["RSTUDIO_TERM"]] == "" && + new$envs[["R_BROWSER"]] == "false" && + new$envs[["R_PDFVIEWER"]] == "false" && + is_build_pane_command(new$args)) { + # 5. R in the RStudio build pane + # https://github.com/rstudio/rstudio/blob/master/src/cpp/session/ + # modules/build/SessionBuild.cpp#L231-L240 + "rstudio_build_pane" + + } else { + # Otherwise it is a subprocess of the console, terminal or + # build pane, and it is hard to say which, so we do not try. + "rstudio_subprocess" + } + + if (cache) data <<- new + + get_caps(new) + } + + is_build_pane_command <- function(args) { + cmd <- gsub("[\"']", "", args[[length(args)]]) + rcmd <- sub("[(].*$", "", cmd) + rcmd %in% c("devtools::build", "devtools::test", "devtools::check") + } + + # -- Capabilities ------------------------------------------------------ + + caps <- list() + + caps$not_rstudio <- function(data) { + list( + type = "not_rstudio", + dynamic_tty = FALSE, + ansi_tty = FALSE, + ansi_color = FALSE, + num_colors = 1L + ) + } + + caps$rstudio_console <- function(data) { + list( + type = "rstudio_console", + dynamic_tty = TRUE, + ansi_tty = FALSE, + ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", + num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]) + ) + } + + caps$rstudio_console_starting <- function(data) { + res <- caps$rstudio_console(data) + res$type <- "rstudio_console_starting" + res + } + + caps$rstudio_terminal <- function(data) { + list( + type = "rstudio_terminal", + dynamic_tty = TRUE, + ansi_tty = TRUE, + ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", + num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]) + ) + } + + caps$rstudio_build_pane <- function(data) { + list( + type = "rstudio_build_pane", + dynamic_tty = TRUE, + ansi_tty = FALSE, + ansi_color = data$envs[["RSTUDIO_CONSOLE_COLOR"]] != "", + num_colors = as.integer(data$envs[["RSTUDIO_CONSOLE_COLOR"]]) + ) + } + + caps$rstudio_subprocess <- function(data) { + list( + type = "rstudio_subprocess", + dynamic_tty = FALSE, + ansi_tty = FALSE, + ansi_color = FALSE, + num_colors = 1L + ) + } + + get_caps <- function(data, type = data$type) { + ret <- caps[[type]](data) + ret$version <- data$ver + ret + } + + structure( + list( + .internal = standalone_env, + is_rstudio = is_rstudio, + detect = detect + ), + class = c("standalone_rstudio_detect", "standalone") + ) +}) diff --git a/R/aa-assertthat.R b/R/aa-assertthat.R new file mode 100644 index 0000000..2a7679f --- /dev/null +++ b/R/aa-assertthat.R @@ -0,0 +1,91 @@ + +assert_that <- function(..., env = parent.frame(), msg = NULL) { + res <- see_if(..., env = env, msg = msg) + if (res) return(TRUE) + + throw(new_assert_error(attr(res, "msg"))) +} + +new_assert_error <- function (message, call = NULL) { + cond <- new_error(message, call. = call) + class(cond) <- c("assert_error", class(cond)) + cond +} + +see_if <- function(..., env = parent.frame(), msg = NULL) { + asserts <- eval(substitute(alist(...))) + + for (assertion in asserts) { + res <- tryCatch({ + eval(assertion, env) + }, error = function(e) { + structure(FALSE, msg = e$message) + }) + check_result(res) + + # Failed, so figure out message to produce + if (!res) { + if (is.null(msg)) + msg <- get_message(res, assertion, env) + return(structure(FALSE, msg = msg)) + } + } + + res +} + +check_result <- function(x) { + if (!is.logical(x)) + throw(new_assert_error("assert_that: assertion must return a logical value")) + if (any(is.na(x))) + throw(new_assert_error("assert_that: missing values present in assertion")) + if (length(x) != 1) { + throw(new_assert_error("assert_that: length of assertion is not 1")) + } + + TRUE +} + +get_message <- function(res, call, env = parent.frame()) { + stopifnot(is.call(call), length(call) >= 1) + + if (has_attr(res, "msg")) { + return(attr(res, "msg")) + } + + f <- eval(call[[1]], env) + if (!is.primitive(f)) call <- match.call(f, call) + fname <- deparse(call[[1]]) + + fail <- on_failure(f) %||% base_fs[[fname]] %||% fail_default + fail(call, env) +} + +# The default failure message works in the same way as stopifnot, so you can +# continue to use any function that returns a logical value: you just won't +# get a friendly error message. +# The code below says you get the first 60 characters plus a ... +fail_default <- function(call, env) { + call_string <- deparse(call, width.cutoff = 60L) + if (length(call_string) > 1L) { + call_string <- paste0(call_string[1L], "...") + } + + paste0(call_string, " is not TRUE") +} + +on_failure <- function(x) attr(x, "fail") + +"on_failure<-" <- function(x, value) { + stopifnot(is.function(x), identical(names(formals(value)), c("call", "env"))) + attr(x, "fail") <- value + x +} + +has_attr <- function(x, which) !is.null(attr(x, which, exact = TRUE)) +on_failure(has_attr) <- function(call, env) { + paste0(deparse(call$x), " does not have attribute ", eval(call$which, env)) +} +"%has_attr%" <- has_attr + +base_fs <- new.env(parent = emptyenv()) diff --git a/R/aaa-async.R b/R/aaa-async.R new file mode 100644 index 0000000..7736865 --- /dev/null +++ b/R/aaa-async.R @@ -0,0 +1,4507 @@ + +#' Create an async function +#' +#' Create an async function, that returns a deferred value, from a +#' regular function. If `fun` is already an async function, then it does +#' nothing, just returns it. +#' +#' The result function will have the same arguments, with the same default +#' values, and the same environment as the original input function. +#' +#' @param fun Original function. +#' @return Async version of the original function. +#' +#' @noRd +#' @examples +#' f <- function(x) 42 +#' af <- async(f) +#' is_async(f) +#' is_async(af) +#' f() +#' synchronise(dx <- af()) +#' dx + +async <- function(fun) { + fun <- as.function(fun) + if (is_async(fun)) return(fun) + + async_fun <- fun + body(async_fun) <- bquote({ + mget(ls(environment(), all.names = TRUE), environment()) + fun2 <- function() { + evalq( + .(body(fun)), + envir = parent.env(environment()) + ) + } + + deferred$new( + type = "async", + action = function(resolve) resolve(fun2()) + ) + }) + + # This is needed, otherwise async_fun might not find 'deferred' + async_env <- new.env(parent = environment(async_fun)) + async_env$deferred <- deferred + environment(async_fun) <- async_env + + mark_as_async(async_fun) +} + +mark_as_async <- function(fun) { + attr(body(fun), "async")$async <- TRUE + + ## These are not valid any more, anyway + attr(fun, "srcref") <- NULL + attr(body(fun), "srcref") <- NULL + + fun +} + +#' Checks if a function is async +#' +#' If `fun` is not a function, an error is thrown. +#' +#' Currently, it checks for the `async` attribute, which is set by +#' [async()]. +#' +#' @param fun Function. +#' @return Logical scalar, whether `fun` is async. +#' +#' @noRd +#' @examples +#' f <- function(x) 42 +#' af <- async(f) +#' is_async(f) +#' is_async(af) +#' f() +#' synchronise(dx <- af()) +#' dx + +is_async <- function(fun) { + assert_that(is.function(fun)) + is.list(a <- attr(body(fun), "async")) && identical(a$async, TRUE) +} + +is_string <- function(x) { + is.character(x) && length(x) == 1 && !is.na(x) +} + +on_failure(is_string) <- function(call, env) { + paste0(deparse(call$x), " is not a string (length 1 character)") +} + +is_flag <- function(x) { + is.logical(x) && length(x) == 1 && !is.na(x) +} + +on_failure(is_flag) <- function(call, env) { + paste0(deparse(call$x), " is not a flag (length 1 logical)") +} + +is_action_function <- function(x) { + is.function(x) && length(formals(x)) %in% 1:2 +} + +on_failure(is_action_function) <- function(call, env) { + paste0(deparse(call$x), " is not a function with two arguments") +} + +is_time_interval <- function(x) { + inherits(x, "difftime") || + (is.numeric(x) && length(x) == 1 && !is.na(x) && x >= 0) +} + +on_failure(is_time_interval) <- function(call, env) { + paste0(deparse(call$x), " is not a valid time interval") +} + +is_count <- function(x) { + is.numeric(x) && length(x) == 1 && !is.na(x) && as.integer(x) == x +} + +on_failure(is_count) <- function(call, env) { + paste0(deparse(call$x), " is not a count (non-negative integer)") +} + +is_flag <- function(x) { + is.logical(x) && length(x) == 1 && !is.na(x) +} + +on_failure(is_flag) <- function(call, env) { + paste0(deparse(call$x), " must be a flag (length 1 logical)") +} + +#' Retry an asynchronous function with exponential backoff +#' +#' Keeps trying until the function's deferred value resolves without +#' error, or `times` tries have been performed, or `time_limit` seconds +#' have passed since the start of the first try. +#' +#' Note that all unnamed arguments are passed to `task`. +#' +#' @param task An asynchronous function. +#' @param ... Arguments to pass to `task`. +#' @param .args More arguments to pass to `task`. +#' @param times Maximum number of tries. +#' @param time_limit Maximum number of seconds to try. +#' @param custom_backoff If not `NULL` then a callback function to +#' calculate waiting time, after the `i`the try. `i` is passed as an +#' argument. If `NULL`, then the default is used, which is a uniform +#' random number of seconds between 1 and 2^i. +#' @param on_progress Callback function for a progress bar. Retries are +#' announced here, if not `NULL`. `on_progress` is called with two +#' arguments. The first is a named list with entries: +#' * `event`: string that is either `"retry"` or `"givenup"`, +#' * `tries`: number of tried so far, +#' * `spent`: number of seconds spent trying so far, +#' * `error`: the error object for the last failure, +#' * `retry_in`: number of seconds before the next try. +#' The second argument is `progress_data`. +#' @param progress_data `async_backoff()` will pass this object to +#' `on_progress` as the second argument. +#' @return Deferred value for the operation with retries. +#' +#' @family async control flow +#' @noRd +#' @examples +#' \donttest{ +#' afun <- function() { +#' wait_100_ms <- function(i) 0.1 +#' async_backoff( +#' function() if (runif(1) < 0.8) stop("nope") else "yes!", +#' times = 5, +#' custom_backoff = wait_100_ms +#' ) +#' } +#' +#' # There is a slight chance that it fails +#' tryCatch(synchronise(afun()), error = function(e) e) +#' } + +async_backoff <- function(task, ..., .args = list(), times = Inf, + time_limit = Inf, custom_backoff = NULL, + on_progress = NULL, progress_data = NULL) { + + task <- async(task) + args <- c(list(...), .args) + times <- times + time_limit <- time_limit + custom_backoff <- custom_backoff %||% default_backoff + on_progress <- on_progress + progress_data <- progress_data + + did <- 0L + started <- NULL + limit <- NULL + + self <- deferred$new( + type = "backoff", call = sys.call(), + action = function(resolve) { + started <<- Sys.time() + limit <<- started + time_limit + do.call(task, args)$then(self) + }, + parent_reject = function(value, resolve) { + did <<- did + 1L + now <- Sys.time() + if (did < times && now < limit) { + wait <- custom_backoff(did) + if (!is.null(on_progress)) { + on_progress(list( + event = "retry", + tries = did, + spent = now - started, + error = value, + retry_in = wait + ), progress_data) + } + delay(wait)$ + then(function() do.call(task, args))$ + then(self) + } else { + if (!is.null(on_progress)) { + on_progress(list( + event = "givenup", + tries = did, + spent = now - started, + error = value, + retry_in = NA_real_ + ), progress_data) + } + stop(value) + } + } + ) +} + +async_backoff <- mark_as_async(async_backoff) + +default_backoff <- function(i) { + as.integer(stats::runif(1, min = 1, max = 2^i) * 1000) / 1000 +} + +#' Asynchronous function call, in a worker pool +#' +#' The function will be called on another process, very much like +#' [callr::r()]. +#' +#' @param func Function to call. See also the notes at [callr::r()]. +#' @param args Arguments to pass to the function. They will be copied +#' to the worker process. +#' @return Deferred object. +#' +#' @noRd + +call_function <- function(func, args = list()) { + func; args + + id <- NULL + + deferred$new( + type = "pool-task", call = sys.call(), + action = function(resolve) { + resolve + reject <- environment(resolve)$private$reject + id <<- get_default_event_loop()$add_pool_task( + function(err, res) if (is.null(err)) resolve(res) else reject(err), + list(func = func, args = args)) + }, + on_cancel = function(reason) { + if (!is.null(id)) { + get_default_event_loop()$cancel(id) + } + } + ) +} + +call_function <- mark_as_async(call_function) + +#' Make a minimal deferred that resolves to the specified value +#' +#' This is sometimes useful to start a deferred chain. +#' +#' Note that the evaluation of `value` is forced when the deferred value +#' is created. +#' +#' @param value The value to resolve to. +#' @return A deferred value. +#' +#' @noRd +#' @examples +#' afun <- async(function() { +#' async_constant(1/100)$ +#' then(function(x) delay(x))$ +#' then(function(x) print(x)) +#' }) +#' synchronise(afun()) + +async_constant <- function(value = NULL) { + force(value) + deferred$new( + type = "constant", call = sys.call(), + function(resolve) resolve(value)) +} + +async_constant <- mark_as_async(async_constant) + +async_env <- new.env(parent = emptyenv()) +async_env$loops <- list() + +get_default_event_loop <- function() { + num_loops <- length(async_env$loops) + if (num_loops == 0) { + err <- make_error( + "You can only call async functions from an async context", + class = "async_synchronization_barrier_error" + ) + stop(err) + } + + async_env$loops[[num_loops]] +} + +push_event_loop <- function() { + num_loops <- length(async_env$loops) + if (num_loops > 0) async_env$loops[[num_loops]]$suspend() + new_el <- event_loop$new() + async_env$loops <- c(async_env$loops, list(new_el)) + new_el +} + +pop_event_loop <- function() { + num_loops <- length(async_env$loops) + async_env$loops[[num_loops]] <- NULL + if (num_loops > 1) async_env$loops[[num_loops - 1]]$wakeup() +} + +#' Async debugging utilities +#' +#' Helper function to help with the non-trivial debugging of async code. +#' +#' Async debugging can be turned on by setting the `async_debug` global +#' option to `TRUE`: +#' ``` +#' options(async_debug = TRUE) +#' ``` +#' Setting this value to `FALSE` will turn off debugging. +#' +#' If debugging is on, a [synchronise()] call will stop at the beginning +#' of the event loop. No deferred actions of other callbacks have run at +#' this point. [synchronise()] stops by calling [base::browser()]. All the +#' usual [browser()] commands (see its manual) can be used here, plus some +#' extra commands to help async debugging. The extra commands: +#' +#' `async_debug_shortcuts()` adds handy shortcuts to most of the helper +#' functions. E.g. `async_next()` can be invoked as `.an` (without the +#' parens). You only need to run it once per R session. Note that it adds +#' the shortcuts to the global environment. +#' +#' `async_debug_remove_shortcuts()` removes the shortcuts from the global +#' environment. +#' +#' `.an` (or `async_next()`) runs the next iteration of the event loop. +#' Note that it does not return until _something_ happens in the event loop: +#' an action or a parent callback is executed, or HTTP or other I/O is +#' performed. Also note, that a single iteration of the event loop typically +#' runs multiple action, parent or other callbacks. Once the iteration is +#' done, the control is returned to the browser. +#' +#' `.as` (or `async_step()`) is similar to `.an`, but it also starts the +#' debugging of the action or parent callbacks. I.e. another [browser()] is +#' called at the beginning of _all_ callbacks in the next iteration of the +#' event loop. +#' +#' `.asb` (or `async_step_back()`) stops the debugging of the callbacks. +#' It does not actually exdecutes anything from the event loop, so to go +#' back to the main async browser, you also need to execute `c` (continue). +#' +#' `.al` (or `async_list()`) lists all deferred values in the current async +#' phase. (Only the ones that already exist, some may be created in the +#' future.) It returns a data frame with columns: +#' +#' * `id`: The integer id of the deferred value. +#' * `parents`: Integer vector, the parents of the deferred value. +#' * `label`: A character label, that is used by `async_tree()` to nicely +#' format information about a deferred value. +#' * `call`: The call (language object) that created the deferred value. +#' * `children`: The list of children, an integer vector. A deferred value +#' can only have one child, unless it is shared. +#' * `type`: The type of the deferred value. This is an arbitrary label, +#' specified when the deferred value was created. +#' * `running`: Whether the deferred value is already running. +#' * `state`: The state of the deferred value, `"pending"`, `"fulfilled"` or +#' `"rejected"`. This is typically pending, since resolved deferred +#' values are removed from the async DAG (in the next event loop +#' iteration.) +#' * `cancelled`: Whether the deferred value was cancelled. +#' * `shared`: Whether the deferred value is shared. +#' * `filename`: The file name for the source code that created the +#' deferred value. Only present if this code was parsed with source +#' references enabled. +#' * `position`: The start file position, in line:column format, as a +#' string. Only present if this code was parsed with source references +#' enabled. +#' +#' `.at` (or `async_tree()`) prints the DAG of the deferred values. +#' +#' `async_debug()` can be used to debug the action and/or parent callbacks +#' of the specified deferred value. +#' +#' `async_wait_for()` runs the event loop until the specified deferred +#' value is resolved (i.e. fulfilled or rejected). +#' +#' `.aw` (or `async_where()`) prints a call stack and marks the frame the +#' corresponds to an action or parent callback. +#' +#' @param el Event loop, defaults to the current event loop. +#' @param def Deferred value that is used at the root of the DAG. Defaults +#' to the deferred value corresponding to the result of the async phase. +#' @param id Integer scalar, the if of the deferred to debug or to wait for. +#' @param action Whether to debug the action callback. +#' @param parent Whether to debug the parent callbacks. +#' @param calls The calls to print, result of `sys.calls()`. Defaults to +#' the current call stack. +#' @param parents The parent frames in the call stack, result of +#' `sys.parents()`. Defaults to the current parents. +#' @param frm The async frame to mark. Defaults to the most recent async +#' frame in the stack. +#' +#' @name async_debug +#' @noRd +NULL + +#' @noRd +#' @aliases .an +#' @rdname async_debug + +async_next <- function(el = NULL) { + el <- el %||% find_sync_frame()$new_el + if (is.null(el)) stop("No async context") + ## TODO: some visual indication that something has happened? + if (! el$run("once")) message("[ASYNC] async phase complete") +} + +# nocov start + +#' @noRd +#' @aliases .as +#' @rdname async_debug + +async_step <- function() { + el <- find_sync_frame()$new_el + if (is.null(el)) stop("No async context") + ## TODO: some visual indication that something has happened? + old <- options(async_debug_steps = TRUE) + on.exit(options(old)) + if (! el$run("once")) { + message("[ASYNC] async phase complete") + } +} + +#' @noRd +#' @aliases .asb +#' @rdname async_debug + +async_step_back <- function() { + options(async_debug_steps = FALSE) + message("[ASYNC] step back, you still need to 'c'ontinue") +} + +# nocov end + +#' @noRd +#' @aliases .al +#' @rdname async_debug + +async_list <- function(def = NULL) { + def <- def %||% find_sync_frame()$res + if (is.null(def)) stop("No async context") + info <- list() + find_parents <- function(def) { + info <<- c(info, list(get_private(def)$get_info())) + prn <- get_private(def)$parents + lapply(prn, find_parents) + } + find_parents(def) + + do.call(rbind, info) +} + +#' @noRd +#' @aliases .at +#' @rdname async_debug + +async_tree <- function(def = NULL) { + def <- def %||% find_sync_frame()$res + data <- async_list(def) + root <- as.character(get_private(def)$id) + cli::tree(data, root = root) +} + +#' @noRd +#' @rdname async_debug + +async_debug <- function(id, action = TRUE, parent = TRUE) { + def <- find_deferred(id) + if (is.null(def)) stop("Cannot find deferred `", id, "`") + prv <- get_private(def) + + if (prv$state != "pending") { + message("[ASYNC] ", id, " already resolved") + return(invisible()) + } + + what <- character() + if (action) { + if (prv$running) { + message("[ASYNC] ", id, " action already running") + } else if (is.null(prv$action)) { + message("[ASYNC] ", id, " has no action") + } else { + ## TODO: make a copy? Or should the deferred make a copy? + debug1(prv$action) + what <- "action" + } + } + + if (parent) { + ## TODO: make copies? + debug_all(prv$parent_resolve) + debug_all(prv$parent_reject) + what <- c(what, "parent callbacks") + } + + if (length(what) == 1) { + message("[ASYNC] ", id, " debugging ", what) + } + if (length(what) == 2) { + message("[ASYNC] ", id, " debugging ", what[1], " and ", what[2]) + } + + invisible(def) +} + +#' @noRd +#' @rdname async_debug + +async_wait_for <- function(id) { + el <- find_sync_frame()$new_el + if (is.null(el)) stop("No async context") + def <- find_deferred(id) + if (is.null(def)) stop("Cannot find deferred `", id, "`") + priv <- get_private(def) + while (priv$state == "pending") el$run("once") + message("[ASYNC] ", id, " resolved") +} + +#' @noRd +#' @aliases .aw +#' @rdname async_debug + +async_where <- function(calls = sys.calls(), parents = sys.parents(), + frm = get_async_frames()) { + afrm <- viapply(frm, "[[", "frame") + num <- seq_along(calls) + + src <- lapply(calls, get_source_position) + + res <- data.frame( + stringsAsFactors = FALSE, + call = I(calls), + parent = parents, + filename = vcapply(src, "[[", "filename"), + position = vcapply(src, "[[", "position"), + async = num %in% afrm + ) + + res$def_id <- NA_integer_ + res$def_id[afrm] <- viapply(frm, function(x) x$deferred) + res$def_cb_type <- NA_character_ + res$def_cb_type[afrm] <- vcapply(frm, function(x) x$type) + res$def_call <- I(list(NULL)) + res$def_call[afrm] <- lapply(frm, "[[", "call") + + def_src <- lapply(res$def_call[afrm], get_source_position) + res$def_filename <- NA_character_ + res$def_filename[afrm] <- vcapply(def_src, "[[", "filename") + res$def_position <- NA_character_ + res$def_position[afrm] <- vcapply(def_src, "[[", "position") + + class(res) <- c("async_where", class(res)) + res +} + +# nocov start + +#' @noRd + +print.async_where <- function(x, ...) { + cat(format(x, ...)) + invisible(x) +} + +# nocov end + +#' @noRd + +format.async_where <- function(x, ...) { + paste0(paste( + formatC(seq_len(nrow(x)), width = 3), + vcapply(x$call, expr_name), + paste0(" ", x$filename, ":", x$position), + ifelse (! x$async, "", + paste0("\n ", x$def_id, " ", x$def_cb_type, " ", + x$def_call, " ", x$def_filename, ":", x$def_position)), + collapse = "\n" + ), "\n") +} + +get_async_frames <- function() { + drop_nulls(lapply(seq_along(sys.frames()), function(i) { + if (! is.null(data <- sys.frame(i)$`__async_data__`)) { + list(frame = i + data$skip %||% 1L, deferred = data[[1]], type = data[[2]], + call = get_private(data[[3]])$mycall) + } + })) +} + +find_sync_frame <- function() { + for (i in seq_along(sys.frames())) { + cand <- sys.frame(-i) + if (isTRUE(cand$`__async_synchronise_frame__`)) return(cand) + } +} + +find_async_data_frame <- function() { + frames <- sys.frames() + for (i in seq_along(frames)) { + cand <- sys.frame(-i) + if (!is.null(data <- cand$`__async_data__`)) { + return(list(frame = length(frames) - i + 1L, data = data)) + } + } +} + +find_deferred <- function(id, def = NULL) { + def <- def %||% find_sync_frame()$res + if (is.null(def)) stop("No async context") + search_parents <- function(def) { + if (get_private(def)$id == id) return(def) + prn <- get_private(def)$parents + for (p in lapply(prn, search_parents)) { + if (!is.null(p)) return(p) + } + } + search_parents(def) +} + +# nocov start + +debug1 <- function(fun) { + debugonce(fun) +} + +#' @noRd +#' @rdname async_debug + +async_debug_shortcuts <- function() { + as <- function(name, fun) { + makeActiveBinding(name, fun, .GlobalEnv) + } + as(".an", async_next) + as(".as", async_step) + as(".asb", async_step_back) + as(".al", async_list) + as(".at", async_tree) + as(".aw", async_where) +} + +#' @noRd +#' @rdname async_debug + +async_debug_remove_shortcuts <- function() { + tryCatch( + rm(list = c(".an", ".as", ".asb", ".al", ".at", ".aw"), + envir = .GlobalEnv), + error = function(x) x) +} + +# nocov end + +debug_all <- function(fun) { + debug(fun) +} + +#' Deferred value +#' +#' @section Usage: +#' ``` +#' dx <- deferred$new(action = NULL, on_progress = NULL, on_cancel = NULL, +#' parents = NULL, parent_resolve = NULL, parent_reject = NULL, +#' type = NULL) +#' dx$then(on_fulfilled) +#' dx$catch(...) +#' dx$finally(on_finally) +#' dx$cancel(reason = "Cancelled") +#' dx$share() +#' ``` +#' +#' @section Arguments: +#' * `action`: Function to call when the deferred value starts running. +#' it needs to have at least two arguments: `resolve` and `reject`, +#' and the third `progress` argument is optional. See details below. +#' * `on_progress`: A function to call to report progress. See details +#' below. +#' * `on_cancel`: A function to call when the deferred is cancelled. See +#' details below. +#' * `parents`: A list of deferred values that will be the parents of the +#' deferred value being created. If some of them are already owned, +#' an error is thrown. +#' * `parent_resolve`: A function to call when a parent is resolved. +#' See details below. +#' * `parent_reject`: A function to call when a parent throws an error. +#' See details below. +#' * `type`: A label that can be used to indicate the type of the deferred +#' value to create. This might be useful for debugging, but otherwise +#' it is not used. +#' * `on_fulfilled`: Function to call when the parent deferred is resolved. +#' Essentially this is the `parent_resolve` function of the `then()` +#' deferred. +#' * `...` Error handlers, as in `tryCatch()`, see details below. +#' * `on_finally`: Function to call, after the deferred value is resolved +#' or after it has thrown an error. It will be called without arguments. +#' * `reason` Error message or error object that will be used to cancel the +#' deferred. +#' +#' @section Deferred values: +#' +#' Asynchronous computation is represented by deferred values. +#' A deferred value is an [R6](https://github.com/wch/R6) object. +#' +#' ``` +#' deferred$new(action = NULL, on_progress = NULL, on_cancel = NULL, +#' parents = NULL, parent_resolve = NULL, parent_reject = NULL, +#' type = NULL) +#' ``` +#' +#' Creates a new deferred value. `action` is a function that is called +#' once the deferred value is _started_ (i.e. _not_ when `dx` is created). +#' It must have one or two arguments: `resolve`, or `resolve` and `progress` +#' It should call `resolve` when it is done, with the final value of the +#' deferred as the argument. (See examples below.) If it has two arguments, +#' then the second one is a callback function for creating progress bars. +#' The deferred value may report its progress through this function. +#' See details in the _Progress bars_ section below. +#' +#' `action` is called when the evaluation of the deferred value is started. +#' Only deferred values that are needed to calculate the value of the +#' async phase, are evaluated. (See also _Lazy Evaluation_ below.) +#' +#' Note that `action` is optional, for some deferred values, no action is +#' takes when they are started. (These typically depend on their parent +#' nodes.) +#' +#' `on_cancel` is a function that is called without arguments when a +#' deferred value is cancelled. This includes explicit cancellation by +#' calling its `$cancel()` method, or auto-cancellation (see below). +#' +#' `parents` is a list of deferred values that need to be computed before +#' the current deferred value. When a parent deferred is resolved, the +#' `parent_resolve` function is called. When a parent referred throws an +#' error, the parent_reject` function is called. +#' +#' `parent_resolve` is a function with (up to) two arguments: +#' `value` and `resolve`. It will be called with the value of the +#' parent, the `resolve` callback of the deferred. +#' `parent_resolve` can resolve the deferred by calling the supplied `resolve` +#' callback, or it can keep waiting on other parents and/or external +#' computation. It may throw an error to fail the deferred. +#' +#' `parent_resolve` allows some shorthands as well: +#' * `NULL`: the deferred is resolved with the value of the parent. +#' * A function with no arguments: this function is called, and the deferred +#' resolves to its return value. +#' * A function with one argument: this function is called with the value +#' of the parent as the argument, and the deferred is resolved to its +#' return value. +#' * A function with arguments `value` and `resolve`. This function is +#' called with the value of the parent, and the resolve callback of the +#' deferred. +#' +#' `parent_reject` is a function with (up to) two arguments: +#' `value`, `resolve`. It will be called with the error object +#' thrown by the parent. +#' +#' `parent_resolve` can resolve the deferred by calling the supplied +#' `resolve` callback, or it can keep waiting on other parents and/or +#' external computation. It may throw an error to fail the deferred. It may +#' also re-throw the error received from the parent, if it does not wish +#' to handle it. +#' +#' `parent_reject` also accepts some shorthands as well: +#' * `NULL`: the deferred throws the same error as the parent. +#' * A function with no arguments: this function is called, and the deferred +#' resolves to its return value. +#' * A function with one argument: this function is called with the value +#' of the parent as the argument, and the deferred is resolved to its +#' return value. +#' * A function with arguments `value` and `resolve`. This function is +#' called with the value of the parent, and the resolve callback of the +#' deferred. + +#' * A list of named error handlers, corresponding to the error handlers +#' of `$catch()` (and `tryCatch()`). If these error handlers handle the +#' parent's error, the deferred is resolved with the result of the +#' handlers. Otherwise the deferred will be failed with the parent's +#' error. The error handlers may also throw a new error. +#' +#' @section Error handling: +#' +#' The action function of the deferred, and also the `parent_resolve` and +#' `parent_reject` handlers may throw errors if the deferred cannot be +#' computed. Errors can be handled wit the `$catch()` member function: +#' +#' ``` +#' dx$catch(...) +#' ``` +#' +#' It takes the same named error handler arguments as `tryCatch()`. +#' +#' Technically, `$catch()` creates a new deferred value, and this new +#' deferred value is resolved to the result of the error handlers. Of the +#' handlers do not handle the error, then the new deferred will fail +#' with the same error. +#' +#' The `$finally()` method can be used to run create finalizer code that +#' runs when a deferred is resolved or when it fails. It can be used to +#' close database connections or other resources: +#' +#' ``` +#' dx$finally(on_finally) +#' ``` +#' +#' Technically, `$finally()` creates a new deferred, which will resolve +#' or fail the same way as the original one, but before doing that it will +#' call the `on_finally` function with no arguments. +#' +#' @section Builtin async functions: +#' +#' The async package comes with some basic async functions: +#' * [delay()] sets a timer and then resolves to `TRUE`. +#' * [async_constant()] resolves successfully to its argument. +#' * [http_get()] and [http_head()] make HTTP GET and HEAD requests. +#' +#' @section Combining async values: +#' +#' Async computation (just like ordinary sync computation) usually +#' consists of several steps that needs to be performed in the specified +#' order. The `$then()` method specifies that a step of computation needs +#' to be performed after the deferred value is known: +#' +#' ``` +#' dx$then(on_fulfilled) +#' ``` +#' +#' `on_fulfilled` is a function with zero or one formal arguments. +#' It will be called once the result of the deferred is known, with its +#' result. (The result is omitted if it has no arguments). +#' +#' `$then()` creates another deferred value, that will resolve to the +#' result of the `on_fulfilled` callback. Should this callback return +#' with a deferred value, then `$then()` the deferred value will be a +#' child of this newly creted deferred, and only resolve after that. +#' +#' See also [when_all()], [when_some()] and [when_any()], which can combine +#' multiple deferred values into one. +#' +#' You cannot call `$then()` (or [when_any()], [when_all()], etc. on the +#' same deferred value multiple times, unless it is a shared deferred +#' value. See _Ownership_ below. +#' +#' The [async_reflect()], [async_retry()], [async_sequence()], +#' [async_timeout()], [async_until()] and [async_whilst()] functions are +#' helpers for more complex async control flow. +#' +#' @section Ownership: +#' +#' async follows a strong ownership model. Each deferred value must be +#' owned by exactly one other deferred value (unless they are shared, see +#' below). +#' +#' After a `dx2 <- dx$then()` call, the `dx` deferred is _owned_ by the +#' newly created deferred value. (The same applied to [when_any()], etc.) +#' This means that it is not possible to call `$then()` on the same +#' deferred value multiple times. The deferred value that is synchronized +#' by calling [synchronise()] on it, is owned by [synchronise()], see +#' _Synchronization_ below. +#' +#' The deferred values of an async phase form a directed graph, which we +#' call the async DAG (directed, acyclic graph). Usually (when no deferred +#' is shared, see below), this DAG is a rooted tree, the root of the tree +#' is the synchronised deferred, the final result of the async phase. +#' +#' @section Shared Deferred Values: +#' +#' In the rare cases when the strong ownership model is too restrictive, +#' a deferred value can be marked as _shared_: +#' +#' ``` +#' dx$share() +#' ``` +#' +#' This has the following implications: +#' * A shared deferred value can have multiple children (owners) in the +#' async DAG. +#' * A shared deferred value is started after its first child is started. +#' * A shared deferred value is not auto-cancelled when all of its children +#' are finished. (Because it might have more children in the future.) +#' * A shared deferred value is still auto-cancelled at the end of the +#' event loop. +#' +#' Use shared deferred values sparingly, only when they are really needed, +#' as they forbid auto-cancellation, so deferred values will hold on to +#' resources longer, until the async phase is finished. +#' +#' @section Synchronization: +#' +#' async allows embedding asynchronous computation in synchronous code. +#' The execution of such a program has a sync phase and async phases. When the +#' program starts, it is in the sync phase. In the sync phase you cannot +#' create deferred values. (But you can still define (async) functions, that +#' will create deferred values when called.) +#' +#' To enter into an async phase, call [synchronise()] on an expression that +#' evaluates to a deferred value. The async phase will last until this +#' deferred value is computed or an error is thrown (and the error reaches +#' [synchronise()]). +#' +#' [synchronise()] creates an event loop, which manages the computation of +#' the deferred values in this particular async phase. +#' +#' Async phases can be embedded into each other. I.e. a program may call +#' [synchronise()] while in the async phase. The outer async phase's event +#' loop then stops until the inner async phase terminates. Deferred values +#' cannot be passed through a `synchronise()` barrier, to anoter (sync or +#' async phase). Should this happen, an error is reported on the first +#' operation on the leaked deferred value. +#' +#' In a typical application, a function is implemented asynchronously, and +#' then used synchronously by the interactive user, or another piece of +#' synchronous code, via [synchronise()] calls. The following example makes +#' three HTTP requests in parallel: +#' +#' ``` +#' http_status3 <- function() { +#' http_status <- function(url) { +#' http_get(url)$then(function(response) response$status_code) +#' } +#' r1 <- http_status("https://eu.httpbin.org/status/403") +#' r2 <- http_status("https://eu.httpbin.org/status/404") +#' r3 <- http_status("https://eu.httpbin.org/status/200") +#' when_all(r1, r2, r3) +#' } +#' synchronise(http_status3()) +#' ``` +#' +#' This async function can also be used asychronously, as a parent of +#' another deferred value, in an async phase. +#' +#' @section Lazy evaluation: +#' +#' async does not evaluate deferred values that are not part of the async +#' DAG of the async phase. These are clearly not needed to compute the +#' result of the async phase, so it would be a waste of resources working on +#' them. (It is also unclear how their errors should be handled.) +#' +#' In the following example, `d1` and `d2` are created, but they are not +#' part of the async DAG, so they are never evaluated. +#' +#' ``` +#' do <- function() { +#' d1 <- delay(1/100)$then(function() print("d1")) +#' d2 <- d1$then(function() print("d2")) +#' d3 <- delay(1/100)$then(function() print("d3")) +#' d4 <- d3$then(function() print("d4")) +#' d4 +#' } +#' invisible(synchronise(do())) +#' ``` +#' +#' @section Cancellation: +#' +#' The computation of a deferred can be cancelled when it is not needed +#' any more: +#' +#' ``` +#' dx$cancel(reason = "Cancelled") +#' ``` +#' +#' This will _fail_ the children of the deferred, unless they have been +#' completed already. It will also auto-cancel the parent DAG of the +#' deferred, unless they are shared deferreds, see the next Section. +#' +#' @section Auto-cancellation: +#' +#' In an async phase, it might happen that parts of the async DAG are not +#' needed for the final result any more. E.g. if a parent of a `when_all()` +#' node throws an error, then the other parents don't have to be computed. +#' In this case the event loop of the phase automatically cancels these +#' deferred values. Similarly, if a single parent of a [when_any()] node is +#' resolved, the other parents can be cancelled. +#' +#' In general, if a node of the async DAG is resolved, the whole directed +#' DAG, rooted at that node, can be cancelled (except for nodes that were +#' already resolved and nodes that have already failed). +#' +#' Auto-cancellation is very convenient, as you can be sure that resources +#' are free as soon as they are not needed. Some practical examples: +#' +#' * Making HTTP requests to many mirror web sites, to check their response +#' time. As soon as the first reply is in, the rest of the HTTP requests +#' are cancelled. +#' * In multi-process computation, as soon as one process fails, the rest are +#' automatically cancelled. (Unless the failure is handled, of course.) +#' +#' async also has another type of cancellation, when [synchronise()] is +#' interrupted externally, either by the user or some system error. In this +#' case all processes and resources that were created in the event loop, +#' are cancelled and freed. +#' +#' Shared deferred values (see `$share()`) are not auto-cancelled when their +#' children are resolved or errored, but they are always cancelled at the +#' end of the async phase. +#' +#' @section Progress bars: +#' +#' A deferred value may report on its progress, if its action has a progress +#' callback. The progress callback is called with a list that describes +#' and event. We suggest that it always has an `event` entry, which is a +#' simple string. The rest of the list entries can be defined as needed, +#' but typically there will be a counter counting ticks, or a ratio +#' describing what part of the computation is already. See [http_get()] +#' for an async function that reports progress. +#' +#' @section Collections helper functions: +#' +#' async provides some utilities that make it easier to deal with +#' collections of deferred values: +#' +#' The current iterators: +#' * [async_map()] applies an async function to all elements of a vector or +#' list (collection). +#' * [async_detect()] finds an element of a collection that passed an async +#' truth test. +#' * [async_every()] checks if every element of a collection satisfies an +#' async predicate. [async_some()] checks if any element does that. +#' * [async_filter()] keeps elements that pass an async truth test. +#' +#' @section Control flow helper functions: +#' +#' Control flow with deferred values can be challenging. Some helpers: +#' * [async_reflect()] creates an async function that always succeeds. +#' This is useful if you want to apply it to a collection, and don't +#' want to stop at the first error. +#' * [async_retry()] tries an async function a number of times. +#' [async_retryable()] turns a regular function into a retryable one. +#' * [async_sequence()] chains two async functions. Calling their sequence +#' is equivalent calling '$then()` on them, but [async_sequence()] is +#' easier to use programmatically. +#' * [async_until()] and [async_whilst()] let you call an async function +#' repeatedly, until or while a (syncronous) condition holds. +#' * [async_timeout()] runs an async function with a timeout. +#' +#' @section Examples: +#' Please see the README and the vignettes for examples. +#' @name deferred +#' @noRd +NULL + +#' @importFrom R6 R6Class +#' @noRd + +deferred <- R6Class( + "deferred", + public = list( + initialize = function(action = NULL, on_progress = NULL, on_cancel = NULL, + parents = NULL, parent_resolve = NULL, + parent_reject = NULL, type = NULL, + call = sys.call(-1)) + async_def_init(self, private, action, on_progress, on_cancel, + parents, parent_resolve, parent_reject, type, call), + then = function(on_fulfilled) + def_then(self, private, on_fulfilled), + catch = function(...) + def_catch(self, private, ...), + finally = function(on_finally) + def_finally(self, private, on_finally), + cancel = function(reason = "Cancelled") + def_cancel(self, private, reason), + share = function() { private$shared <<- TRUE; invisible(self) } + ), + + private = list( + action = NULL, + running = FALSE, + id = NULL, + type = NULL, + state = c("pending", "fulfilled", "rejected")[1], + event_loop = NULL, + value = NULL, + children = list(), + progress_callback = NULL, + cancel_callback = NULL, + cancelled = FALSE, + dead_end = FALSE, + parents = NULL, + parent_resolve = NULL, + parent_reject = NULL, + shared = FALSE, + mycall = NULL, + + run_action = function() + def__run_action(self, private), + + null = function() + def__null(self, private), + + resolve = function(value) + def__resolve(self, private, value), + reject = function(reason) + def__reject(self, private, reason), + progress = function(data) + def__progress(self, private, data), + + make_error_object = function(err) + def__make_error_object(self, private, err), + + maybe_cancel_parents = function(reason) + def__maybe_cancel_parents(self, private, reason), + add_as_parent = function(child) + def__add_as_parent(self, private, child), + update_parent = function(old, new) + def__update_parent(self, private, old, new), + + get_info = function() + def__get_info(self, private) + ) +) + +async_def_init <- function(self, private, action, on_progress, + on_cancel, parents, parent_resolve, + parent_reject, type, call) { + + private$type <- type + private$id <- get_id() + private$event_loop <- get_default_event_loop() + private$parents <- parents + private$action <- action + private$mycall <- call + + "!DEBUG NEW `private$id` (`type`)" + + assert_that(is.null(on_progress) || is.function(on_progress)) + private$progress_callback <- on_progress + assert_that(is.null(on_cancel) || is.function(on_cancel)) + private$cancel_callback <- on_cancel + + ## Handle the parents + + private$parent_resolve <- def__make_parent_resolve(parent_resolve) + private$parent_reject <- def__make_parent_reject(parent_reject) + + for (prt in parents) { + prt_pvt <- get_private(prt) + prt_pvt$add_as_parent(self) + } + + invisible(self) +} + +def__run_action <- function(self, private) { + if (private$running) return() + action <- private$action + private$running <- TRUE + private$action <- NULL + "!DEBUG ACTION `private$type` `private$id`" + + if (!is.null(action)) { + if (!is.function(action)) { + action <- as.function(action) + formals(action) <- alist(resolve = NULL, progress = NULL) + } + assert_that(is_action_function(action)) + + action_args <- names(formals(action)) + args <- list(private$resolve) + if (!is.na(pr_arg <- match("progress", action_args))) { + args$progress <- private$progress + } + + private$event_loop$add_next_tick( + function() { + if (isTRUE(getOption("async_debug_steps", FALSE))) debug1(action) + `__async_data__` <- list(private$id, "action", self, skip = 2L) + do.call(action, args) }, + function(err, res) if (!is.null(err)) private$reject(err)) + } + + ## If some parents are done, we want them to notify us. + ## We also start the ones that are not running yet + for (prt in private$parents) { + prt_priv <- get_private(prt) + if (prt_priv$state != "pending") { + def__call_then( + if (prt_priv$state == "fulfilled") "parent_resolve" else "parent_reject", + self, prt_priv$value) + } + prt_priv$run_action() + } +} + +def_then <- function(self, private, on_fulfilled = NULL, + on_rejected = NULL) { + force(self) + force(private) + + if (! identical(private$event_loop, get_default_event_loop())) { + err <- make_error( + "Cannot create deferred chain across synchronization barrier", + class = "async_synchronization_barrier_error") + stop(err) + } + + if (!is_deferred(on_fulfilled)) { + parent_resolve <- def__make_parent_resolve(on_fulfilled) + parent_reject <- def__make_parent_reject(on_rejected) + + deferred$new(parents = list(self), + type = paste0("then-", private$id), + parent_resolve = parent_resolve, + parent_reject = parent_reject, + call = sys.call(-1)) + + } else { + private$add_as_parent(on_fulfilled) + child_private <- get_private(on_fulfilled) + child_private$parents <- c(child_private$parents, self) + self + } +} + +def_catch <- function(self, private, ...) { + def_then(self, private, on_rejected = list(...)) +} + +def_finally <- function(self, private, on_finally) { + force(on_finally) + def_then( + self, + private, + on_fulfilled = function(value) { + on_finally() + value + }, + on_rejected = function(reason) { + on_finally() + stop(reason) + } + ) +} + +def_cancel <- function(self, private, reason) { + if (private$state != "pending") return() + cancel_cond <- structure( + list(message = reason %||% "Deferred computation cancelled", call = NULL), + class = c("async_cancelled", "error", "condition") + ) + private$reject(cancel_cond) + invisible(self) +} + +def__null <- function(self, private) { + self$.__enclos_env__$private$dead_end <- TRUE + invisible(self) +} + +def__resolve <- function(self, private, value) { + if (private$cancelled) return() + if (private$state != "pending") return() + + if (is_deferred(value)) { + private$parent_resolve <- def__make_parent_resolve(NULL) + private$parent_reject <- def__make_parent_reject(NULL) + + # we need this in case self was shared and had multiple children + val_pvt <- get_private(value) + val_pvt$id <- private$id + val_pvt$shared <- private$shared + val_pvt$dead_end <- private$dead_end # This should not happen, though + + for (child in private$children) { + ch_pvt <- get_private(child) + ch_pvt$update_parent(self, value) + } + + val_pvt$run_action() + + } else { + if (!private$dead_end && !length(private$children) && + !private$shared) { + ## This cannot happen currently + "!DEBUG ??? DEAD END `private$id`" # nocov + warning("Computation going nowhere...") # nocov + } + + "!DEBUG +++ RESOLVE `private$id`" + private$state <- "fulfilled" + private$value <- value + for (child in private$children) { + def__call_then("parent_resolve", child, value) + } + private$maybe_cancel_parents(private$value) + private$parents <- NULL + } +} + +#' Create an error object for a rejected deferred computation +#' +#' * Make sure that the error is an error object. +#' * Make sure that the error has the correct classes. +#' +#' @param self self +#' @param private private self +#' @return error object +#' +#' @noRd + +def__make_error_object <- function(self, private, err) { + class(err) <- unique(c("async_rejected", class(err))) + err +} + +def__make_parent_resolve <- function(fun) { + if (is.null(fun)) { + function(value, resolve) resolve(value) + } else if (!is.function(fun)) { + fun <- as.function(fun) + function(value, resolve) resolve(fun(value)) + } else if (num_args(fun) == 0) { + function(value, resolve) resolve(fun()) + } else if (num_args(fun) == 1) { + function(value, resolve) resolve(fun(value)) + } else if (identical(names(formals(fun)), + c("value", "resolve"))) { + fun + } else { + stop("Invalid parent_resolve callback") + } +} + +def__make_parent_reject <- function(fun) { + if (is.null(fun)) { + function(value, resolve) stop(value) + } else if (is.list(fun)) { + def__make_parent_reject_catch(fun) + } else if (!is.function(fun)) { + fun <- as.function(fun) + function(value, resolve) resolve(fun(value)) + } else if (num_args(fun) == 0) { + function(value, resolve) resolve(fun()) + } else if (num_args(fun) == 1) { + function(value, resolve) resolve(fun(value)) + } else if (identical(names(formals(fun)), + c("value", "resolve"))) { + fun + } else { + stop("Invalid parent_reject callback") + } +} + +def__make_parent_reject_catch <- function(handlers) { + handlers <- lapply(handlers, as.function) + function(value, resolve) { + ok <- FALSE + ret <- tryCatch({ + quo <- as.call(c(list(quote(tryCatch), quote(stop(value))), handlers)) + ret <- eval(quo) + ok <- TRUE + ret + }, error = function(x) x) + + if (ok) resolve(ret) else stop(ret) + } +} + +def__reject <- function(self, private, reason) { + if (private$cancelled) return() + if (private$state != "pending") return() + + ## 'reason' cannot be a deferred here + + "!DEBUG !!! REJECT `private$id`" + private$state <- "rejected" + private$value <- private$make_error_object(reason) + if (inherits(private$value, "async_cancelled")) { + private$cancelled <- TRUE + } + if (!is.null(private$cancel_callback)) { + private$cancel_callback(conditionMessage(private$value)) + } + for (child in private$children) { + def__call_then("parent_reject", child, private$value) + } + private$maybe_cancel_parents(private$value) + private$parents <- NULL +} + +def__maybe_cancel_parents <- function(self, private, reason) { + for (parent in private$parents) { + if (is.null(parent)) next + + parent_priv <- get_private(parent) + if (parent_priv$state != "pending") next + if (parent_priv$shared) next + parent$cancel(reason) + } +} + +def__call_then <- function(which, x, value) { + force(value); + private <- get_private(x) + if (!private$running) return() + if (private$state != "pending") return() + + cb <- private[[which]] + private$event_loop$add_next_tick( + function() { + if (isTRUE(getOption("async_debug_steps", FALSE))) { + debug1(private[[which]]) # nocov + } + `__async_data__` <- list(private$id, "parent", x) + private[[which]](value, private$resolve) + }, + function(err, res) if (!is.null(err)) private$reject(err)) +} + +def__add_as_parent <- function(self, private, child) { + "!DEBUG EDGE [`private$id` -> `get_private(child)$id`]" + + if (! identical(private$event_loop, get_private(child)$event_loop)) { + err <- make_error( + "Cannot create deferred chain across synchronization barrier", + class = "async_synchronization_barrier_error") + stop(err) + } + if (length(private$children) && !private$shared) { + stop("Deferred value is already owned") + } + + private$children <- c(private$children, child) + + if (get_private(child)$running) private$run_action() + if (private$state == "pending") { + ## Nothing to do + + } else if (private$state == "fulfilled") { + def__call_then("parent_resolve", child, private$value) + + } else { + def__call_then("parent_reject", child, private$value) + } +} + +def__update_parent <- function(self, private, old, new) { + for (i in seq_along(private$parents)) { + if (identical(private$parents[[i]], old)) { + private$parents[[i]] <- new + } + } + + new_pvt <- get_private(new) + new_pvt$add_as_parent(self) +} + +def__progress <- function(self, private, data) { + if (private$state != "pending") return() + if (is.null(private$progress_callback)) return() + private$progress_callback(data) +} + +def__get_info <- function(self, private) { + res <- data.frame( + stringsAsFactors = FALSE, + id = private$id, + parents = I(list(viapply(private$parents, function(x) get_private(x)$id))), + label = as.character(private$id), + call = I(list(private$mycall)), + children = I(list(viapply(private$children, function(x) get_private(x)$id))), + type = private$type %||% "unknown", + running = private$running, + state = private$state, + cancelled = private$cancelled, + shared = private$shared + ) + src <- get_source_position(private$mycall) + res$filename <- src$filename + res$position <- src$position + res$label <- paste0( + res$id, " ", + if (private$state == "fulfilled") paste0(cli::symbol$tick, " "), + if (private$state == "rejected") paste0(cli::symbol$cross, " "), + deparse(private$mycall)[1], " @ ", + res$filename, ":", res$position) + + res +} + +#' Is object a deferred value? +#' +#' @param x object +#' @return Whether it is a deferred value. +#' +#' @noRd +#' @examples +#' is_deferred(1:10) +#' afun <- function() { +#' print(is_deferred(dx <- delay(1/100))) +#' dx +#' } +#' synchronise(afun()) + +is_deferred <- function(x) { + inherits(x, "deferred") +} + +#' Delay async computation for the specified time +#' +#' Since R is single-threaded, the deferred value might be resolved (much) +#' later than the specified time period. +#' +#' @param delay Time interval in seconds, the amount of time to delay +#' to delay the execution. It can be a fraction of a second. +#' @return A deferred object. +#' +#' @noRd +#' @examples +#' \donttest{ +#' ## Two HEAD requests with 1/2 sec delay between them +#' resp <- list() +#' afun <- async(function() { +#' http_head("https://eu.httpbin.org?q=2")$ +#' then(function(value) resp[[1]] <<- value$status_code)$ +#' then(function(...) delay(1/2))$ +#' then(function(...) http_head("https://eu.httpbin.org?q=2"))$ +#' then(function(value) resp[[2]] <<- value$status_code) +#' }) +#' synchronise(afun()) +#' resp +#' } + +delay <- function(delay) { + force(delay) + id <- NULL + deferred$new( + type = "delay", call = sys.call(), + action = function(resolve) { + assert_that(is_time_interval(delay)) + force(resolve) + id <<- get_default_event_loop()$add_delayed( + delay, + function() TRUE, + function(err, res) resolve(TRUE) + ) + }, + on_cancel = function(reason) { + if (!is.null(id)) get_default_event_loop()$cancel(id) + } + ) +} + +delay <- mark_as_async(delay) + +#' Find the value of a match, asynchronously +#' +#' All predicates are running in parallel, and the returned match +#' is not guaranteed to be the first one. +#' +#' @param .x A list or atomic vector. +#' @param .p An asynchronous predicate function. +#' @param ... Additional arguments to the predicate function. +#' @param .limit Number of elements to process simulateneously. +#' If it is 1, then the predicate is applied sequentially. +#' @return A deferred value for the result. +#' +#' @family async iterators +#' @noRd +#' @examples +#' \donttest{ +#' synchronise(async_detect( +#' c("https://eu.httpbin.org/status/404", "https://eu.httpbin.org", +#' "https://eu.httpbin.org/status/403"), +#' async_sequence(http_head, function(x) x$status_code == 200) +#' )) +#' } + +async_detect <- function(.x, .p, ..., .limit = Inf) { + if (.limit < length(.x)) { + async_detect_limit(.x, .p, ..., .limit = .limit) + } else { + async_detect_nolimit(.x, .p, ...) + } +} + +async_detect <- mark_as_async(async_detect) + +async_detect_nolimit <- function(.x, .p, ...) { + defs <- lapply(.x, async(.p), ...) + nx <- length(defs) + done <- FALSE + + self <- deferred$new( + type = "async_detect", call = sys.call(), + action = function(resolve) { + lapply(seq_along(defs), function(idx) { + defs[[idx]]$then(function(val) if (isTRUE(val)) idx)$then(self) + }) + if (nx == 0) resolve(NULL) + }, + parent_resolve = function(value, resolve) { + if (!done && !is.null(value)) { + done <<- TRUE + resolve(.x[[value]]) + } else if (!done) { + nx <<- nx - 1L + if (nx == 0) resolve(NULL) + } + } + ) +} + +async_detect_limit <- function(.x, .p, ..., .limit = .limit) { + len <- length(.x) + nx <- len + .p <- async(.p) + args <- list(...) + + done <- FALSE + nextone <- .limit + 1L + firsts <- lapply(.x[seq_len(.limit)], .p, ...) + + self <- deferred$new( + type = "async_detect (limit)", call = sys.call(), + action = function(resolve) { + lapply(seq_along(firsts), function(idx) { + firsts[[idx]]$then(function(val) if (isTRUE(val)) idx)$then(self) + }) + if (nx == 0) resolve(NULL) + }, + parent_resolve = function(value, resolve) { + if (!done && !is.null(value)) { + done <<- TRUE + resolve(.x[[value]]) + } else if (!done) { + nx <<- nx - 1L + if (nx == 0) { + resolve(NULL) + } else if (nextone <= len) { + idx <- nextone + dx <- .p(.x[[nextone]], ...) + dx$then(function(val) if (isTRUE(val)) idx)$then(self) + nextone <<- nextone + 1L + } + } + } + ) + + self +} + +#' @importFrom R6 R6Class + +event_loop <- R6Class( + "event_loop", + public = list( + initialize = function() + el_init(self, private), + + add_http = function(handle, callback, file = NULL, progress = NULL, + data = NULL) + el_add_http(self, private, handle, callback, file, progress, data), + http_setopt = function(total_con = NULL, host_con = NULL, multiplex = NULL) + el_http_setopt(self, private, total_con, host_con, multiplex), + + add_process = function(conns, callback, data) + el_add_process(self, private, conns, callback, data), + add_r_process = function(conns, callback, data) + el_add_r_process(self, private, conns, callback, data), + add_pool_task = function(callback, data) + el_add_pool_task(self, private, callback, data), + add_delayed = function(delay, func, callback, rep = FALSE) + el_add_delayed(self, private, delay, func, callback, rep), + add_next_tick = function(func, callback, data = NULL) + el_add_next_tick(self, private, func, callback, data), + + cancel = function(id) + el_cancel(self, private, id), + cancel_all = function() + el_cancel_all(self, private), + + run = function(mode = c("default", "nowait", "once")) + el_run(self, private, mode = match.arg(mode)), + + suspend = function() + el_suspend(self, private), + wakeup = function() + el_wakeup(self, private) + ), + + private = list( + create_task = function(callback, ..., id = NULL, type = "foobar") + el__create_task(self, private, callback, ..., id = id, type = type), + ensure_pool = function() + el__ensure_pool(self, private), + get_poll_timeout = function() + el__get_poll_timeout(self, private), + run_pending = function() + el__run_pending(self, private), + run_timers = function() + el__run_timers(self, private), + is_alive = function() + el__is_alive(self, private), + update_time = function() + el__update_time(self, private), + io_poll = function(timeout) + el__io_poll(self, private, timeout), + update_curl_data = function() + el__update_curl_data(self, private), + + id = NULL, + time = Sys.time(), + stop_flag = FALSE, + tasks = list(), + timers = Sys.time()[numeric()], + pool = NULL, + curl_fdset = NULL, # return value of multi_fdset() + curl_poll = TRUE, # should we poll for curl sockets? + curl_timer = NULL, # call multi_run() before this + next_ticks = character(), + worker_pool = NULL, + http_opts = NULL + ) +) + +el_init <- function(self, private) { + private$id <- new_event_loop_id() + invisible(self) +} + +#' @importFrom curl multi_add parse_headers_list handle_data + +el_add_http <- function(self, private, handle, callback, progress, file, + data) { + self; private; handle; callback; progress; outfile <- file; data + + id <- private$create_task(callback, list(handle = handle, data = data), + type = "http") + private$ensure_pool() + if (!is.null(outfile)) cat("", file = outfile) + + content <- NULL + + multi_add( + handle = handle, + pool = private$pool, + done = function(response) { + task <- private$tasks[[id]] + private$tasks[[id]] <- NULL + response$content <- do.call(c, as.list(content)) + response$file <- outfile + task$callback(NULL, response) + }, + data = function(bytes, ...) { + if (!is.null(outfile)) { + ## R runs out of connections very quickly, especially because they + ## are not removed until a gc(). However, calling gc() is + ## expensive, so we only do it if we have to. This is a temporary + ## solution until we can use our own connections, that are not + ## so limited in their numbers. + con <- tryCatch( + file(outfile, open = "ab"), + error = function(e) { gc(); file(outfile, open = "ab") } # nocov + ) + writeBin(bytes, con) + close(con) + } else { + content <<- c(content, list(bytes)) + } + }, + fail = function(error) { + task <- private$tasks[[id]] + private$tasks[[id]] <- NULL + error <- make_error(message = error) + class(error) <- unique(c("async_rejected", "async_http_error", + class(error))) + task$callback(error, NULL) + } + ) + id +} + +el_add_process <- function(self, private, conns, callback, data) { + self; private; conns; callback; data + data$conns <- conns + private$create_task(callback, data, type = "process") +} + +el_add_r_process <- function(self, private, conns, callback, data) { + self; private; conns; callback; data + data$conns <- conns + private$create_task(callback, data, type = "r-process") +} + +el_add_pool_task <- function(self, private, callback, data) { + self; private; callback; data + id <- private$create_task(callback, data, type = "pool-task") + if (is.null(async_env$worker_pool)) { + async_env$worker_pool <- worker_pool$new() + } + async_env$worker_pool$add_task(data$func, data$args, id, private$id) + id +} + +el_add_delayed <- function(self, private, delay, func, callback, rep) { + force(self); force(private); force(delay); force(func); force(callback) + force(rep) + id <- private$create_task( + callback, + data = list(delay = delay, func = func, rep = rep), + type = "delayed" + ) + # This has to be real time, because our event loop time might + # be very much in the past when his is called. + private$timers[id] <- Sys.time() + as.difftime(delay, units = "secs") + id +} + +el_add_next_tick <- function(self, private, func, callback, data) { + force(self) ; force(private) ; force(callback); force(data) + data$func <- func + id <- private$create_task(callback, data = data, type = "nexttick") + private$next_ticks <- c(private$next_ticks, id) +} + +#' @importFrom curl multi_cancel + +el_cancel <- function(self, private, id) { + private$next_ticks <- setdiff(private$next_ticks, id) + private$timers <- private$timers[setdiff(names(private$timers), id)] + if (id %in% names(private$tasks) && private$tasks[[id]]$type == "http") { + multi_cancel(private$tasks[[id]]$data$handle) + } else if (id %in% names(private$tasks) && + private$tasks[[id]]$type %in% c("process", "r-process")) { + private$tasks[[id]]$data$process$kill() + } else if (id %in% names(private$tasks) && + private$tasks[[id]]$type == "pool-task") { + async_env$worker_pool$cancel_task(id) + } + private$tasks[[id]] <- NULL + invisible(self) +} + +#' @importFrom curl multi_cancel multi_list + +el_cancel_all <- function(self, private) { + http <- multi_list(pool = private$pool) + lapply(http, multi_cancel) + private$next_ticks <- character() + private$timers <- Sys.time()[numeric()] + + ## Need to cancel pool tasks, these are interrupts for the workers + types <- vcapply(private$tasks, "[[", "type") + ids <- vcapply(private$tasks, "[[", "id") + for (id in ids[types == "pool-task"]) { + self$cancel(id) + } + + private$tasks <- list() + invisible(self) +} + +el_run <- function(self, private, mode) { + + ## This is closely modeled after the libuv event loop, on purpose, + ## because some time we might switch to that. + + alive <- private$is_alive() + if (! alive) private$update_time() + + while (alive && !private$stop_flag) { + private$update_time() + private$update_curl_data() + private$run_timers() + ran_pending <- private$run_pending() + ## private$run_idle() + ## private$run_prepare() + + timeout <- 0 + if ((mode == "once" && !ran_pending) || mode == "default") { + timeout <- private$get_poll_timeout() + } + + private$io_poll(timeout) + ## private$run_check() + ## private$run_closing_handles() + + if (mode == "once") { + ## If io_poll returned without doing anything, that means that + ## we have some timers that are due, so run those. + ## At this point we have surely made progress + private$update_time() + private$run_timers() + } + + alive <- private$is_alive() + if (mode == "once" || mode == "nowait") break + } + + private$stop_flag <- FALSE + + alive +} + +el_suspend <- function(self, private) { + ## TODO +} + +el_wakeup <- function(self, private) { + ## TODO +} + +el__run_pending <- function(self, private) { + next_ticks <- private$next_ticks + private$next_ticks <- character() + for (id in next_ticks) { + task <- private$tasks[[id]] + private$tasks[[id]] <- NULL + call_with_callback(task$data$func, task$callback, + info = task$data$error_info) + } + + ## Check for workers from the pool finished before, while another + ## event loop was active + finished_pool <- FALSE + pool <- async_env$worker_pool + if (!is.null(pool)) { + done_pool <- pool$list_tasks(event_loop = private$id, status = "done") + finished_pool <- nrow(done_pool) > 0 + for (tid in done_pool$id) { + task <- private$tasks[[tid]] + private$tasks[[tid]] <- NULL + res <- pool$get_result(tid) + err <- res$error + res <- res[c("result", "stdout", "stderr")] + task$callback(err, res) + } + } + + length(next_ticks) > 0 || finished_pool +} + +#' @importFrom curl multi_run multi_fdset + +el__io_poll <- function(self, private, timeout) { + + types <- vcapply(private$tasks, "[[", "type") + + ## The things we need to poll, and their types + ## We put the result here as well + pollables <- data.frame( + stringsAsFactors = FALSE, + id = character(), + pollable = I(list()), + type = character(), + ready = character() + ) + + ## HTTP. + if (private$curl_poll) { + curl_pollables <- data.frame( + stringsAsFactors = FALSE, + id = "curl", + pollable = I(list(processx::curl_fds(private$curl_fdset))), + type = "curl", + ready = "silent") + pollables <- rbind(pollables, curl_pollables) + } + + ## Processes + proc <- types %in% c("process", "r-process") + if (sum(proc)) { + conns <- unlist(lapply( + private$tasks[proc], function(t) t$data$conns), + recursive = FALSE) + proc_pollables <- data.frame( + stringsAsFactors = FALSE, + id = names(private$tasks)[proc], + pollable = I(conns), + type = types[proc], + ready = rep("silent", sum(proc))) + pollables <- rbind(pollables, proc_pollables) + } + + ## Pool + px_pool <- if (!is.null(async_env$worker_pool)) { + async_env$worker_pool$get_poll_connections() + } + if (length(px_pool)) { + pool_pollables <- data.frame( + stringsAsFactors = FALSE, + id = names(px_pool), + pollable = I(px_pool), + type = rep("pool", length(px_pool)), + ready = rep("silent", length(px_pool))) + pollables <- rbind(pollables, pool_pollables) + } + + if (!is.null(private$curl_timer) && private$curl_timer <= private$time) { + multi_run(timeout = 0L, poll = TRUE, pool = private$pool) + private$curl_timer <- NULL + } + + if (nrow(pollables)) { + + ## OK, ready to poll + pollables$ready <- unlist(processx::poll(pollables$pollable, timeout)) + + ## Any HTTP? + if (private$curl_poll && + pollables$ready[match("curl", pollables$type)] == "event") { + multi_run(timeout = 0L, poll = TRUE, pool = private$pool) + } + + ## Any processes + proc_ready <- pollables$type %in% c("process", "r-process") & + pollables$ready == "ready" + for (id in pollables$id[proc_ready]) { + p <- private$tasks[[id]] + private$tasks[[id]] <- NULL + ## TODO: this should be async + p$data$process$wait(1000) + p$data$process$kill() + res <- list( + status = p$data$process$get_exit_status(), + stdout = read_all(p$data$stdout, p$data$encoding), + stderr = read_all(p$data$stderr, p$data$encoding), + timeout = FALSE + ) + + error <- FALSE + if (p$type == "r-process") { + res$result <- tryCatch({ + p$data$process$get_result() + }, error = function(e) { error <<- TRUE; e }) + } + + unlink(c(p$data$stdout, p$data$stderr)) + + if (p$data$error_on_status && (error || res$status != 0)) { + err <- make_error("process exited with non-zero status") + err$data <- res + res <- NULL + } else { + err <- NULL + } + p$callback(err, res) + } + + ## Worker pool + pool_ready <- pollables$type == "pool" & pollables$ready == "ready" + if (sum(pool_ready)) { + pool <- async_env$worker_pool + done <- pool$notify_event(as.integer(pollables$id[pool_ready]), + event_loop = private$id) + mine <- intersect(done, names(private$tasks)) + for (tid in mine) { + task <- private$tasks[[tid]] + private$tasks[[tid]] <- NULL + res <- pool$get_result(tid) + err <- res$error + res <- res[c("result", "stdout", "stderr")] + task$callback(err, res) + } + } + + } else if (length(private$timers) || !is.null(private$curl_timer)) { + Sys.sleep(timeout / 1000) + } +} + +el__create_task <- function(self, private, callback, data, ..., id, type) { + id <- id %||% get_uuid() + private$tasks[[id]] <- list( + type = type, + id = id, + callback = callback, + data = data, + error = NULL, + result = NULL + ) + id +} + +#' @importFrom curl new_pool + +el__ensure_pool <- function(self, private) { + getopt <- function(nm) { + anm <- paste0("async_http_", nm) + if (!is.null(v <- getOption(anm))) return(v) + if (!is.na(v <- Sys.getenv(toupper(anm), NA_character_))) return(v) + NULL + } + if (is.null(private$pool)) { + private$http_opts <- list( + total_con = getopt("total_con") %||% 100, + host_con = getopt("host_con") %||% 6, + multiplex = getopt("multiplex") %||% TRUE + ) + private$pool <- new_pool( + total_con = private$http_opts$total_con, + host_con = private$http_opts$host_con, + multiplex = private$http_opts$multiplex + ) + } +} + +#' @importFrom curl multi_set + +el_http_setopt <- function(self, private, total_con, host_con, multiplex) { + private$ensure_pool() + if (!is.null(total_con)) private$http_opts$total_con <- total_con + if (!is.null(host_con)) private$http_opts$host_con <- host_con + if (!is.null(multiplex)) private$http_opts$multiplex <- multiplex + multi_set( + pool = private$pool, + total_con = private$http_opts$total_con, + host_con = private$http_opts$host_con, + multiplex = private$http_opts$multiplex + ) +} + +el__get_poll_timeout <- function(self, private) { + t <- if (length(private$next_ticks)) { + ## TODO: can this happen at all? Probably not, but it does not hurt... + 0 # nocov + } else { + max(0, min(Inf, private$timers - private$time)) + } + + if (!is.null(private$curl_timer)) { + t <- min(t, private$curl_timer - private$time) + } + + t <- max(t, 0) + + if (is.finite(t)) as.integer(t * 1000) else -1L +} + +el__run_timers <- function(self, private) { + + expired <- names(private$timers)[private$timers <= private$time] + expired <- expired[order(private$timers[expired])] + for (id in expired) { + task <- private$tasks[[id]] + if (private$tasks[[id]]$data$rep) { + ## If it is repeated, then re-init + private$timers[id] <- + private$time + as.difftime(task$data$delay, units = "secs") + } else { + ## Otherwise remove + private$tasks[[id]] <- NULL + private$timers <- private$timers[setdiff(names(private$timers), id)] + } + call_with_callback(task$data$func, task$callback) + } +} + +el__is_alive <- function(self, private) { + length(private$tasks) > 0 || + length(private$timers) > 0 || + length(private$next_ticks) > 0 +} + +el__update_time <- function(self, private) { + private$time <- Sys.time() +} + +#' @importFrom curl multi_fdset +#' +el__update_curl_data <- function(self, private) { + private$curl_fdset <- multi_fdset(private$pool) + num_fds <- length(unique(unlist(private$curl_fdset[1:3]))) + private$curl_poll <- num_fds > 0 + private$curl_timer <- if ((t <- private$curl_fdset$timeout) != -1) { + private$time + as.difftime(t / 1000.0, units = "secs") + } +} + +#' Generic Event Emitter +#' +#' This is a generic class that can be used to create event emitters. +#' It is mostly modelled after the 'node.js' `EventEmitter` class +#' +#' @section Usage: +#' ``` +#' ee <- event_emitter$new(async = TRUE) +#' ee$listen_on(event, callback) +#' ee$listen_off(event, callback) +#' ee$listen_once(event, callback) +#' ee$emit(event, ...) +#' ee$get_event_names() +#' ee$get_listener_count(event) +#' ee$remove_all_listeners(event) +#' ``` +#' +#' @section Arguments: +#' * `async`: Whether to call listeners asynchronously, i.e. in the next +#' tick of the event loop. +#' * `event`: String, name of the event. +#' * `callback`: Function, listener to call when the event is emitted. +#' Its arguments must match the arguments passed to the `$emit()` +#' method. It is possible to add the same callback function multiple +#' times as a listener. It will be called as many times, as many times +#' it was added. +#' * `...`: Arguments to pass to the listeners. They can be named or +#' unnnamed. +#' +#' @section Details: +#' +#' `ee$listen_on()` adds `callback` as a new listener for `event`. It is +#' always added to the end of the listener list. Listeners will be called in +#' the order they were added. It returns a reference to the `event_emitter` +#' object, so calls can be chained. +#' +#' `ee$listen_off()` removes the first instance of `callback` from the +#' listener list of `event`. It uses [base::identical()] to find the +#' listener to remove. If `callback` is not among the listeners, nothing +#' happens. Note that if you call this method from an event handler, that +#' does not affect the already emitted events. It returns a reference to +#' the `event_emitter` object, so calls can be chained. +#' +#' `ee$listen_once` is similar to `ee$listen_on()`, but the callback will +#' be only called for a single event, and then it will be removed. +#' (Technically, the listener is removed before the callback is called.) +#' It returns a reference to the `event_emitter` object, so calls can be +#' chained. +#' +#' `ee$emit()` emits an event. All listeners in its listener list will be +#' called, in the order they were added. The arguments are passed to the +#' listeners, so they have to be compatible with them. +#' +#' `ee$get_event_names()` returns the names of the active events, +#' in a character vector. An event is active if it has at least one +#' listener. +#' +#' `ee$get_listener_count()` returns the number of listeners for an event. +#' +#' `ee$remove_all_listener()` removes all listeners for an an event. +#' +#' @section Error handling: +#' Errors are handled by special `error` events. If a listener errors, +#' and the event emitter has an active `error` event (i.e. some listeners +#' exist for `error`, then _all_ listeners are called, in the order they +#' were specified. They receive the originally thrown error object as the +#' single argument. The error object has an `event` entry, which contains +#' the event name the failed listener was called on. +#' +#' If the event emitter does not have any listeners for the `error` event, +#' then it throws an error. This error propagates to the next +#' synchronization barrier, i.e. the last `synchronise()` or +#' `run_event_loop()` call, which fails. +#' +#' In an error happen within an `error` listener, then the same happens, +#' the last `synchronise()` or `run_event_loop()` call fails. You can +#' want to wrap the body of the error listeners in a `tryCatch()` call, +#' if you want to avoid this. +#' +#' @noRd +#' @importFrom R6 R6Class + +event_emitter <- R6Class( + "event_emitter", + public = list( + initialize = function(async = TRUE) + ee_init(self, private, async), + + listen_on = function(event, callback) + ee_listen_on(self, private, event, callback), + + listen_off = function(event, callback) + ee_listen_off(self, private, event, callback), + + listen_once = function(event, callback) + ee_listen_once(self, private, event, callback), + + emit = function(event, ...) + ee_emit(self, private, event, ...), + + get_event_names = function() + ee_get_event_names(self, private), + + get_listener_count = function(event) + ee_get_listener_count(self, private, event), + + remove_all_listeners = function(event) + ee_remove_all_listeners(self, private, event) + ), + + private = list( + lsts = NULL, + async = NULL, + + cleanup_events = function() + ee__cleanup_events(self, private), + error_callback = function(err, res) + ee__error_callback(self, private, err, res) + ) +) + +ee_init <- function(self, private, async) { + assert_that(is_flag(async)) + private$lsts <- structure(list(), names = character()) + private$async <- async + invisible(self) +} + +ee_listen_on <- function(self, private, event, callback) { + assert_that(is_string(event), is.function(callback)) + private$lsts[[event]] <- + c(private$lsts[[event]], list(list(cb = callback, once = FALSE))) + invisible(self) +} + +ee_listen_off <- function(self, private, event, callback) { + assert_that(is_string(event), is.function(callback)) + for (idx in seq_along(private$lsts[[event]])) { + if (identical(private$lsts[[event]][[idx]]$cb, callback)) { + private$lsts[[event]] <- private$lsts[[event]][-idx] + break + } + } + invisible(self) +} + +ee_listen_once <- function(self, private, event, callback) { + assert_that(is_string(event), is.function(callback)) + private$lsts[[event]] <- + c(private$lsts[[event]], list(list(cb = callback, once = TRUE))) + invisible(self) +} + +ee_emit <- function(self, private, event, ...) { + assert_that(is_string(event)) + list(...) + tocall <- private$lsts[[event]] + once <- vlapply(tocall, "[[", "once") + if (any(once)) private$lsts[[event]] <- tocall[!once] + + ## a for loop is not good here, because it does not create + ## a closure for lst + lapply(tocall, function(lst) { + lst + if (private$async) { + get_default_event_loop()$add_next_tick( + function() lst$cb(...), + private$error_callback, + data = list(error_info = list(event = event))) + + } else { + call_with_callback( + function() lst$cb(...), + private$error_callback, + info = list(event = event)) + } + }) + + invisible(self) +} + +ee_get_event_names <- function(self, private) { + private$cleanup_events() + names(private$lsts) +} + +ee_get_listener_count <- function(self, private, event) { + assert_that(is_string(event)) + length(private$lsts[[event]]) +} + +ee_remove_all_listeners <- function(self, private, event) { + assert_that(is_string(event)) + private$lsts[[event]] <- NULL + invisible(self) +} + +ee__cleanup_events <- function(self, private) { + len <- viapply(private$lsts, length) + private$lsts <- private$lsts[len > 0] +} + +ee__error_callback <- function(self, private, err, res) { + if (is.null(err)) return() + tocall <- private$lsts[["error"]] + once <- vlapply(tocall, "[[", "once") + if (any(once)) private$lsts[["error"]] <- tocall[!once] + + if (length(tocall)) { + for (lst in tocall) lst$cb(err) + } else { + stop(err) + } +} + +#' Do every or some elements of a list satisfy an asynchronous predicate? +#' +#' @param .x A list or atomic vector. +#' @param .p An asynchronous predicate function. +#' @param ... Additional arguments to the predicate function. +#' @return A deferred value for the result. +#' +#' @family async iterators +#' @noRd +#' @examples +#' # Check if all numbers are odd +#' # Note the use of force() here. Otherwise x will be evaluated later, +#' # and by then its value might change. +#' is_odd <- async(function(x) { +#' force(x) +#' delay(1/1000)$then(function() as.logical(x %% 2)) +#' }) +#' synchronise(async_every(c(1,3,5,7,10,11), is_odd)) +#' synchronise(async_every(c(1,3,5,7,11), is_odd)) + +async_every <- function(.x, .p, ...) { + defs <- lapply(.x, async(.p), ...) + nx <- length(defs) + done <- FALSE + + deferred$new( + type = "async_every", call = sys.call(), + parents = defs, + action = function(resolve) if (nx == 0) resolve(TRUE), + parent_resolve = function(value, resolve) { + if (!done && !isTRUE(value)) { + done <<- TRUE + resolve(FALSE) + } else if (!done) { + nx <<- nx - 1L + if (nx == 0) resolve(TRUE) + } + } + ) +} + +async_every <- mark_as_async(async_every) + +#' Keep or drop elements using an asyncronous predicate function +#' +#' `async_filter` keep the elements for which `.p` is true. (Tested +#' via `isTRUE()`. `async_reject` is the opposite, it drops them. +#' +#' @param .x A list or atomic vector. +#' @param .p An asynchronous predicate function. +#' @param ... Additional arguments to the predicate function. +#' @return A deferred value for the result. +#' +#' @family async iterators +#' @noRd +#' @examples +#' \donttest{ +#' ## Filter out non-working URLs +#' afun <- async(function(urls) { +#' test_url <- async_sequence( +#' http_head, function(x) identical(x$status_code, 200L)) +#' async_filter(urls, test_url) +#' }) +#' urls <- c("https://eu.httpbin.org/get", +#' "https://eu.httpbin.org/status/404") +#' synchronise(afun(urls)) +#' } + +async_filter <- function(.x, .p, ...) { + when_all(.list = lapply(.x, async(.p), ...))$ + then(function(res) .x[vlapply(res, isTRUE)]) +} + +async_filter <- mark_as_async(async_filter) + +#' @rdname async_filter +#' @noRd + +async_reject <- function(.x, .p, ...) { + when_all(.list = lapply(.x, async(.p), ...))$ + then(function(res) .x[! vlapply(res, isTRUE)]) +} + +async_reject <- mark_as_async(async_reject) + +#' Asynchronous HTTP GET request +#' +#' Start an HTTP GET request in the background, and report its completion +#' via a deferred. +#' +#' @param url URL to connect to. +#' @param headers HTTP headers to send. +#' @param file If not `NULL`, it must be a string, specifying a file. +#' The body of the response is written to this file. +#' @param options Options to set on the handle. Passed to +#' [curl::handle_setopt()]. +#' @param on_progress Progress handler function. It is only used if the +#' response body is written to a file. See details below. +#' @return Deferred object. +#' +#' @section Progress bars: +#' +#' `http_get` can report on the progress of the download, via the +#' `on_progress` argument. This is called with a list, with entries: +#' * `url`: the specified url to download +#' * `handle`: the curl handle of the request. This can be queried using +#' [curl::handle_data()] to get the response status_code, the final +#' URL (after redirections), timings, etc. +#' * `file`: the `file` argument. +#' * `total`: total bytes of the response. If this is unknown, it is set +#' to zero. +#' * `current`: already received bytes of the response. +#' +#' @family asyncronous HTTP calls +#' @noRd +#' @importFrom curl new_handle handle_setheaders +#' @examples +#' \donttest{ +#' afun <- async(function() { +#' http_get("https://eu.httpbin.org/status/200")$ +#' then(function(x) x$status_code) +#' }) +#' synchronise(afun()) +#' } + +http_get <- function(url, headers = character(), file = NULL, + options = list(), on_progress = NULL) { + + url; headers; file; options; on_progress + options <- get_default_curl_options(options) + + make_deferred_http( + function() { + assert_that(is_string(url)) + handle <- new_handle(url = url) + handle_setheaders(handle, .list = headers) + + if (!is.null(on_progress)) { + options$noprogress <- FALSE + fun <- options$progressfunction <- function(down, up) { + on_progress(list( + url = url, + handle = handle, + file = file, + total = down[[1]], + current = down[[2]] + )) + TRUE + } + ## This is a workaround for curl not PROTECT-ing the progress + ## callback function + reg.finalizer(handle, function(...) fun, onexit = TRUE) + } + + handle_setopt(handle, .list = options) + list(handle = handle, options = options) + }, + file + ) +} + +http_get <- mark_as_async(http_get) + +#' Asynchronous HTTP HEAD request +#' +#' @inheritParams http_get +#' @return Deferred object. +#' +#' @family asyncronous HTTP calls +#' @noRd +#' @importFrom curl handle_setopt +#' @examples +#' \donttest{ +#' afun <- async(function() { +#' dx <- http_head("https://eu.httpbin.org/status/200")$ +#' then(function(x) x$status_code) +#' }) +#' synchronise(afun()) +#' +#' # Check a list of URLs in parallel +#' afun <- function(urls) { +#' when_all(.list = lapply(urls, http_head))$ +#' then(function(x) lapply(x, "[[", "status_code")) +#' } +#' urls <- c("https://google.com", "https://eu.httpbin.org") +#' synchronise(afun(urls)) +#' } + +http_head <- function(url, headers = character(), file = NULL, + options = list(), on_progress = NULL) { + + url; headers; file; options; on_progress + options <- get_default_curl_options(options) + + make_deferred_http( + function() { + assert_that(is_string(url)) + handle <- new_handle(url = url) + handle_setheaders(handle, .list = headers) + handle_setopt(handle, customrequest = "HEAD", nobody = TRUE, + .list = options) + list(handle = handle, options = options) + }, + file + ) +} + +http_head <- mark_as_async(http_head) + +#' Asynchronous HTTP POST request +#' +#' Start an HTTP POST request in the background, and report its completion +#' via a deferred value. +#' +#' @inheritParams http_get +#' @param data Data to send. Either a raw vector, or a character string +#' that will be converted to raw with [base::charToRaw]. +#' @param on_progress Progress handler function. It is only used if the +#' response body is written to a file. See details at [http_get()]. +#' +#' @noRd +#' @examples +#' json <- jsonlite::toJSON(list(baz = 100, foo = "bar")) +#' +#' do <- function() { +#' headers <- c("content-type" = "application/json") +#' http_post("https://eu.httpbin.org/post", data = json, headers = headers)$ +#' then(http_stop_for_status)$ +#' then(function(x) { +#' jsonlite::fromJSON(rawToChar(x$content))$json +#' }) +#' } +#' +#' synchronise(do()) + +http_post <- function(url, data, headers = character(), file = NULL, + options = list(), on_progress = NULL) { + + url; data; headers; file; options; on_progress + if (!is.raw(data)) data <- charToRaw(data) + options <- get_default_curl_options(options) + + make_deferred_http( + function() { + assert_that(is_string(url)) + handle <- new_handle(url = url) + handle_setheaders(handle, .list = headers) + handle_setopt(handle, customrequest = "POST", + postfieldsize = length(data), postfields = data, + .list = options) + list(handle = handle, options = options) + }, + file + ) +} + +http_post <- mark_as_async(http_post) + +#' @importFrom utils modifyList + +get_default_curl_options <- function(options) { + getopt <- function(nm) { + if (!is.null(v <- options[[nm]])) return(v) + anm <- paste0("async_http_", nm) + if (!is.null(v <- getOption(anm))) return(v) + if (!is.na(v <- Sys.getenv(toupper(anm), NA_character_))) return (v) + } + modifyList( + options, + drop_nulls(list( + timeout = as.integer(getopt("timeout") %||% 0), + connecttimeout = as.integer(getopt("connecttimeout") %||% 300), + low_speed_time = as.integer(getopt("low_speed_time") %||% 0), + low_speed_limit = as.integer(getopt("low_speed_limit") %||% 0), + cainfo = getopt("cainfo") + )) + ) +} + +make_deferred_http <- function(cb, file) { + cb; file + id <- NULL + deferred$new( + type = "http", call = sys.call(), + action = function(resolve, progress) { + resolve; progress + ## This is a temporary hack until we have proper pollables + ## Then the deferred will have a "work" callback, which will + ## be able to throw. + reject <- environment(resolve)$private$reject + ho <- cb() + id <<- get_default_event_loop()$add_http( + ho$handle, + function(err, res) if (is.null(err)) resolve(res) else reject(err), + progress, + file, + data = ho$options) + }, + on_cancel = function(reason) { + if (!is.null(id)) get_default_event_loop()$cancel(id) + } + ) +} + +#' Throw R errors for HTTP errors +#' +#' Status codes below 400 are considered successful, others will trigger +#' errors. Note that this is different from the `httr` package, which +#' considers the 3xx status code errors as well. +#' +#' @param resp HTTP response from [http_get()], [http_head()], etc. +#' @return The HTTP response invisibly, if it is considered successful. +#' Otherwise an error is thrown. +#' +#' @noRd +#' @examples +#' \donttest{ +#' afun <- async(function() { +#' http_get("https://eu.httpbin.org/status/404")$ +#' then(http_stop_for_status) +#' }) +#' +#' tryCatch(synchronise(afun()), error = function(e) e) +#' } + +http_stop_for_status <- function(resp) { + if (!is.integer(resp$status_code)) stop("Not an HTTP response") + if (resp$status_code < 400) return(invisible(resp)) + stop(http_error(resp)) +} + +http_error <- function(resp, call = sys.call(-1)) { + status <- resp$status_code + reason <- http_status(status)$reason + message <- sprintf("%s (HTTP %d).", reason, status) + status_type <- (status %/% 100) * 100 + if (length(resp[["content"]]) == 0 && !is.null(resp$file) && + file.exists(resp$file)) { + tryCatch({ + n <- file.info(resp$file, extra_cols = FALSE)$size + resp$content <- readBin(resp$file, what = raw(), n = n) + }, error = identity) + } + http_class <- paste0("async_http_", unique(c(status, status_type, "error"))) + structure( + list(message = message, call = call, response = resp), + class = c(http_class, "error", "condition") + ) +} + +http_status <- function(status) { + status_desc <- http_statuses[as.character(status)] + if (is.na(status_desc)) { + stop("Unknown http status code: ", status, call. = FALSE) + } + + status_types <- c("Information", "Success", "Redirection", "Client error", + "Server error") + status_type <- status_types[[status %/% 100]] + + # create the final information message + message <- paste(status_type, ": (", status, ") ", status_desc, sep = "") + + list( + category = status_type, + reason = status_desc, + message = message + ) +} + +http_statuses <- c( + "100" = "Continue", + "101" = "Switching Protocols", + "102" = "Processing (WebDAV; RFC 2518)", + "200" = "OK", + "201" = "Created", + "202" = "Accepted", + "203" = "Non-Authoritative Information", + "204" = "No Content", + "205" = "Reset Content", + "206" = "Partial Content", + "207" = "Multi-Status (WebDAV; RFC 4918)", + "208" = "Already Reported (WebDAV; RFC 5842)", + "226" = "IM Used (RFC 3229)", + "300" = "Multiple Choices", + "301" = "Moved Permanently", + "302" = "Found", + "303" = "See Other", + "304" = "Not Modified", + "305" = "Use Proxy", + "306" = "Switch Proxy", + "307" = "Temporary Redirect", + "308" = "Permanent Redirect (experimental Internet-Draft)", + "400" = "Bad Request", + "401" = "Unauthorized", + "402" = "Payment Required", + "403" = "Forbidden", + "404" = "Not Found", + "405" = "Method Not Allowed", + "406" = "Not Acceptable", + "407" = "Proxy Authentication Required", + "408" = "Request Timeout", + "409" = "Conflict", + "410" = "Gone", + "411" = "Length Required", + "412" = "Precondition Failed", + "413" = "Request Entity Too Large", + "414" = "Request-URI Too Long", + "415" = "Unsupported Media Type", + "416" = "Requested Range Not Satisfiable", + "417" = "Expectation Failed", + "418" = "I'm a teapot (RFC 2324)", + "420" = "Enhance Your Calm (Twitter)", + "422" = "Unprocessable Entity (WebDAV; RFC 4918)", + "423" = "Locked (WebDAV; RFC 4918)", + "424" = "Failed Dependency (WebDAV; RFC 4918)", + "424" = "Method Failure (WebDAV)", + "425" = "Unordered Collection (Internet draft)", + "426" = "Upgrade Required (RFC 2817)", + "428" = "Precondition Required (RFC 6585)", + "429" = "Too Many Requests (RFC 6585)", + "431" = "Request Header Fields Too Large (RFC 6585)", + "444" = "No Response (Nginx)", + "449" = "Retry With (Microsoft)", + "450" = "Blocked by Windows Parental Controls (Microsoft)", + "451" = "Unavailable For Legal Reasons (Internet draft)", + "499" = "Client Closed Request (Nginx)", + "500" = "Internal Server Error", + "501" = "Not Implemented", + "502" = "Bad Gateway", + "503" = "Service Unavailable", + "504" = "Gateway Timeout", + "505" = "HTTP Version Not Supported", + "506" = "Variant Also Negotiates (RFC 2295)", + "507" = "Insufficient Storage (WebDAV; RFC 4918)", + "508" = "Loop Detected (WebDAV; RFC 5842)", + "509" = "Bandwidth Limit Exceeded (Apache bw/limited extension)", + "510" = "Not Extended (RFC 2774)", + "511" = "Network Authentication Required (RFC 6585)", + "598" = "Network read timeout error (Unknown)", + "599" = "Network connect timeout error (Unknown)" +) + +#' Set curl HTTP options in an event loop +#' +#' The event loop must be already running. In other words, you can only +#' call this function from async functions. +#' +#' The default values are set when the first deferred HTTP operation of the +#' event loop is created, and they are taken from the `async_http_total_con`, +#' `async_http_host_con` and `async_http_multiplex` options. +#' +#' @param total_con,host_con,multiplex They are passed to +#' [curl::multi_set()]. If an argument is `NULL` (the default) then it is +#' ignored. +#' @noRd +#' @family asyncronous HTTP calls + +http_setopt <- function(total_con = NULL, host_con = NULL, multiplex = NULL) { + get_default_event_loop()$http_setopt(total_con, host_con, multiplex) + invisible() +} + +#' Apply an asynchronous function to each element of a vector +#' +#' @param .x A list or atomic vector. +#' @param .f Asynchronous function to apply. +#' @param ... Additional arguments to `.f`. +#' @param .args More additional arguments to `.f`. +#' @param .limit Number of elements to process simulateneously. +#' @return Deferred value that is resolved after all deferred values +#' from the application of `.f` are resolved. +#' +#' @family async iterators +#' @noRd +#' @examples +#' synchronise(async_map( +#' seq(10, 100, by = 10) / 100, +#' function(wait) delay(wait)$then(function() "OK") +#' )) + +async_map <- function(.x, .f, ..., .args = list(), .limit = Inf) { + if (.limit < length(.x)) { + async_map_limit(.x, .f, ..., .args = .args, .limit = .limit) + } else { + defs <- do.call(lapply, c(list(.x, async(.f), ...), .args)) + when_all(.list = defs) + } +} + +async_map <- mark_as_async(async_map) + +async_map_limit <- function(.x, .f, ..., .args = list(), .limit = Inf) { + len <- length(.x) + nx <- len + .f <- async(.f) + args <- c(list(...), .args) + + nextone <- .limit + 1L + firsts <- lapply_args(.x[seq_len(.limit)], .f, .args = args) + + result <- structure( + vector(mode = "list", length = len), + names = names(.x) + ) + + self <- deferred$new( + type = "async_map (limit)", call = sys.call(), + action = function(resolve) { + self; nx; firsts + lapply(seq_along(firsts), function(idx) { + firsts[[idx]]$then(function(val) list(idx, val))$then(self) + }) + if (nx == 0) resolve(result) + }, + parent_resolve = function(value, resolve) { + self; nx; nextone; result; .f + nx <<- nx - 1L + result[ value[[1]] ] <<- value[2] + if (nx == 0) { + resolve(result) + } else if (nextone <= len) { + idx <- nextone + dx <- do.call(".f", c(list(.x[[nextone]]), args)) + dx$then(function(val) list(idx, val))$then(self) + nextone <<- nextone + 1L + } + } + ) + + self +} + +## nocov start + +.onLoad <- function(libname, pkgname) { + if (requireNamespace("debugme", quietly = TRUE)) debugme::debugme() +} + +## nocov end + +#' Asynchronous external process execution +#' +#' Start an external process in the background, and report its completion +#' via a deferred. +#' +#' @inheritParams processx::run +#' @param error_on_status Whether to reject the referred value if the +#' program exits with a non-zero status. +#' @return Deferred object. +#' +#' @family asynchronous external processes +#' @noRd +#' @importFrom processx process +#' @examples +#' \dontrun{ +#' afun <- function() { +#' run_process("ls", "-l")$ +#' then(function(x) strsplit(x$stdout, "\r?\n")[[1]]) +#' } +#' synchronise(afun()) +#' } + +run_process <- function(command = NULL, args = character(), + error_on_status = TRUE, wd = NULL, env = NULL, + windows_verbatim_args = FALSE, windows_hide_window = FALSE, + encoding = "", ...) { + + command; args; error_on_status; wd; env; windows_verbatim_args; + windows_hide_window; encoding; list(...) + + id <- NULL + + deferred$new( + type = "process", call = sys.call(), + action = function(resolve) { + resolve + reject <- environment(resolve)$private$reject + stdout <- tempfile() + stderr <- tempfile() + px <- process$new(command, args = args, + stdout = stdout, stderr = stderr, poll_connection = TRUE, + env = env, cleanup = TRUE, wd = wd, encoding = encoding, ...) + pipe <- px$get_poll_connection() + id <<- get_default_event_loop()$add_process( + list(pipe), + function(err, res) if (is.null(err)) resolve(res) else reject(err), + list(process = px, stdout = stdout, stderr = stderr, + error_on_status = error_on_status, encoding = encoding)) + }, + on_cancel = function(reason) { + if (!is.null(id)) get_default_event_loop()$cancel(id) + } + ) +} + +run_process <- mark_as_async(run_process) + +#' Asynchronous call to an R function, in a background R process +#' +#' Start a background R process and evaluate a function call in it. +#' It uses [callr::r_process] internally. +#' +#' @inheritParams callr::r_bg +#' @noRd +#' @importFrom callr r_process_options r_process rcmd_safe_env +#' +#' @examples +#' \dontrun{ +#' afun <- function() { +#' run_r_process(function() Sys.getpid()) +#' } +#' synchronise(afun()) +#' } + +run_r_process <- function(func, args = list(), libpath = .libPaths(), + repos = c(getOption("repos"), c(CRAN = "https://cloud.r-project.org")), + cmdargs = c("--no-site-file", "--slave", "--no-save", "--no-restore"), + system_profile = FALSE, user_profile = FALSE, env = rcmd_safe_env()) { + + func; args; libpath; repos; cmdargs; system_profile; user_profile; env + + id <- NULL + + deferred$new( + type = "r-process", call = sys.calls(), + action = function(resolve) { + resolve + reject <- environment(resolve)$private$reject + stdout <- tempfile() + stderr <- tempfile() + opts <- r_process_options( + func = func, args = args, libpath = libpath, repos = repos, + cmdargs = cmdargs, system_profile = system_profile, + user_profile = user_profile, env = env, stdout = stdout, + stderr = stderr) + rx <- r_process$new(opts) + pipe <- rx$get_poll_connection() + id <<- get_default_event_loop()$add_r_process( + list(pipe), + function(err, res) if (is.null(err)) resolve(res) else reject(err), + list(process = rx, stdout = stdout, stderr = stderr, + error_on_status = TRUE, encoding = "")) + }, + on_cancel = function(reason) { + if (!is.null(id)) get_default_event_loop()$cancel(id) + } + ) +} + +run_r_process <- mark_as_async(run_r_process) + +#' Make an asynchronous function that always succeeds +#' +#' This is sometimes useful, if the function is applied to entries in +#' a vector or list. +#' +#' @param task Function to transform. +#' @return Async function returning a deferred value that is never +#' rejected. Instead its value is a list with entries `error` and +#' `result`. If the original deferred was resolved, then `error` is +#' `NULL`. If the original deferred was rejected, then `result` is +#' `NULL`. +#' +#' @family async control flow +#' @noRd +#' @examples +#' badfun <- async(function() stop("oh no!")) +#' safefun <- async_reflect(badfun) +#' synchronise(when_all(safefun(), "good")) + +async_reflect <- function(task) { + task <- async(task) + function(...) { + task(...)$ + then(function(value) list(error = NULL, result = value))$ + catch(error = function(reason) list(error = reason, result = NULL)) + } +} + +async_reflect <- mark_as_async(async_reflect) + +#' Replicate an async function a number of times +#' +#' Similar to [base::replicate()], with some differences: +#' * it takes an async function, instead of an expression, and +#' * it always returns a list. +#' +#' @param n Number of replications. +#' @param task Async function to call. +#' @param ... Additional arguments to `task`. +#' @param .limit Number of concurrent async processes to create. +#' @return Resolves to a list of the results of the `n` `task` calls. +#' +#' @noRd +#' @examples +#' \donttest{ +#' ## perform an HTTP request three times, and list the reponse times +#' do <- function() { +#' async_replicate(3, +#' function() http_get("https://eu.httpbin.org")$then(function(x) x$times)) +#' } +#' synchronise(do()) +#' } + +async_replicate <- function(n, task, ..., .limit = Inf) { + assert_that( + is_count(n), + .limit == Inf || is_count(.limit), .limit >= 1L) + + force(list(...)) + task <- async(task) + + if (n == 0) { + async_constant(list()) + } else if (n <= .limit) { + async_replicate_nolimit(n, task, ...) + } else { + async_replicate_limit(n, task, ..., .limit = .limit) + } +} + +async_replicate_nolimit <- function(n, task, ...) { + defs <- lapply(seq_len(n), function(i) task(...)) + when_all(.list = defs) +} + +async_replicate_limit <- function(n, task, ..., .limit = .limit) { + n; .limit + + defs <- nextone <- result <- NULL + + self <- deferred$new( + type = "async_replicate", call = sys.call(), + action = function(resolve) { + defs <<- lapply(seq_len(n), function(i) task(...)) + result <<- vector(n, mode = "list") + lapply(seq_len(.limit), function(idx) { + defs[[idx]]$then(function(val) list(idx, val))$then(self) + }) + nextone <<- .limit + 1L + }, + parent_resolve = function(value, resolve) { + result[ value[[1]] ] <<- value[2] + if (nextone > n) { + resolve(result) + } else { + idx <- nextone + defs[[nextone]]$then(function(val) list(idx, val))$then(self) + nextone <<- nextone + 1L + } + } + ) + + self +} + +#' Retry an asynchronous function a number of times +#' +#' Keeps trying until the function's deferred value resolves without +#' error, or `times` tries have been performed. +#' +#' @param task An asynchronous function. +#' @param times Number of tries. +#' @param ... Arguments to pass to `task`. +#' @return Deferred value for the operation with retries. +#' +#' @family async control flow +#' @noRd +#' @examples +#' \donttest{ +#' ## Try a download at most 5 times +#' afun <- async(function() { +#' async_retry( +#' function() http_get("https://eu.httpbin.org"), +#' times = 5 +#' )$then(function(x) x$status_code) +#' }) +#' +#' synchronise(afun()) +#' } + +async_retry <- function(task, times, ...) { + task <- async(task) + times <- times + force(list(...)) + + self <- deferred$new( + type = "retry", call = sys.call(), + parents = list(task(...)), + parent_reject = function(value, resolve) { + times <<- times - 1L + if (times > 0) { + task(...)$then(self) + } else { + stop(value) + } + } + ) +} + +async_retry <- mark_as_async(async_retry) + +#' Make an asynchronous funcion retryable +#' +#' @param task An asynchronous function. +#' @param times Number of tries. +#' @return Asynchronous retryable function. +#' +#' @family async control flow +#' @noRd +#' @examples +#' \donttest{ +#' ## Create a downloader that retries five times +#' http_get_5 <- async_retryable(http_get, times = 5) +#' ret <- synchronise( +#' http_get_5("https://eu.httpbin.org/get?q=1")$ +#' then(function(x) rawToChar(x$content)) +#' ) +#' cat(ret) +#' } + +async_retryable <- function(task, times) { + task <- async(task) + force(times) + function(...) { + async_retry(task, times, ...) + } +} + +#' Compose asynchronous functions +#' +#' This is equivalent to using the `$then()` method of a deferred, but +#' it is easier to use programmatically. +#' +#' @param ... Asynchronous functions to compose. +#' @param .list Mose asynchronous functions to compose. +#' @return Asynchronous function, the composition of all input functions. +#' They are performed left to right, the ones in `.list` are the last +#' ones. +#' +#' @family async control flow +#' @noRd +#' @examples +#' \donttest{ +#' check_url <- async_sequence( +#' http_head, function(x) identical(x$status_code, 200L)) +#' synchronise(check_url("https://eu.httpbin.org/status/404")) +#' synchronise(check_url("https://eu.httpbin.org/status/200")) +#' } + +async_sequence <- function(..., .list = NULL) { + funcs <- c(list(...), .list) + if (length(funcs) == 0) stop("Function list empty in `async_sequence`") + + function(...) { + dx <- async(funcs[[1]])(...) + for (i in seq_along(funcs)[-1]) dx <- dx$then(funcs[[i]]) + dx + } +} + +async_sequence <- mark_as_async(async_sequence) + +#' @noRd +#' @rdname async_every + +async_some <- function(.x, .p, ...) { + defs <- lapply(.x, async(.p), ...) + nx <- length(defs) + done <- FALSE + + deferred$new( + type = "async_some", call = sys.call(), + parents = defs, + action = function(resolve) if (nx == 0) resolve(FALSE), + parent_resolve = function(value, resolve) { + if (!done && isTRUE(value)) { + done <<- TRUE + resolve(TRUE) + } else if (!done) { + nx <<- nx - 1L + if (nx == 0) resolve(FALSE) + } + } + ) +} + +async_some <- mark_as_async(async_some) + +#' Synchronously wrap asynchronous code +#' +#' Evaluate an expression in an async phase. It creates an event loop, +#' then evaluates the supplied expression. If its result is a deferred +#' value, it keeps running the event loop, until the deferred value is +#' resolved, and returns its resolved value. +#' +#' If an error is not handled in the async phase, `synchronise()` will +#' re-throw that error. +#' +#' `synchronise()` cancels all async processes on interrupt or external +#' error. +#' +#' @param expr Async function call expression. If it does not evaluate +#' to a deferred value, then it is just returned. +#' +#' @noRd +#' @examples +#' \donttest{ +#' http_status <- function(url, ...) { +#' http_get(url, ...)$ +#' then(function(x) x$status_code) +#' } +#' +#' synchronise(http_status("https://eu.httpbin.org/status/418")) +#' } + +synchronise <- function(expr) { + new_el <- push_event_loop() + on.exit({ new_el$cancel_all(); pop_event_loop() }, add = TRUE) + + ## Mark this frame as a synchronization point, for debugging + `__async_synchronise_frame__` <- TRUE + + ## This is to allow `expr` to contain `async_list()` etc + ## calls that look for the top promise. Without this there + ## is no top promise. This is a temporary top promise that + ## is never started. + res <- async_constant(NULL) + + res <- expr + + if (!is_deferred(res)) return(res) + + ## We need an extra final promise that cannot be replaced, + ## so priv stays the same. + res <- res$then(function(x) x) + + priv <- get_private(res) + if (! identical(priv$event_loop, new_el)) { + err <- make_error( + "Cannot create deferred chain across synchronization barrier", + class = "async_synchronization_barrier_error") + stop(err) + } + + priv$null() + priv$run_action() + + if (isTRUE(getOption("async_debug"))) start_browser() + while (priv$state == "pending") new_el$run("once") + + if (priv$state == "fulfilled") priv$value else stop(priv$value) +} + +start_browser <- function() { + async_debug_shortcuts() + on.exit(async_debug_remove_shortcuts(), add = TRUE) + cat("This is a standard `browser()` call, but you can also use the\n") + cat("following extra commands:\n") + cat("- .an / async_next(): next event loop iteration.\n") + cat("- .as / async_step(): next event loop, debug next action or parent callback.\n") + cat("- .asb / async_step_back(): stop debugging of callbacks.\n") + cat("- .al / async_list(): deferred values in the current async phase.\n") + cat("- .at / async_tree(): DAG of the deferred values.\n") + cat("- .aw / async_where(): print call stack, mark async callback.\n") + cat("- async_wait_for(): run until deferred is resolved.\n") + cat("- async_debug(): debug action and/or parent callbacks of deferred.\n") + cat("\n") + browser(skipCalls = 1) +} + +#' Run event loop to completion +#' +#' Creates a new event loop, evaluates `expr` in it, and then runs the +#' event loop to completion. It stops when the event loop does not have +#' any tasks. +#' +#' The expression typically creates event loop tasks. It should not create +#' deferred values, though, because those will never be evaluated. +#' +#' Unhandled errors propagate to the `run_event_loop()` call, which fails. +#' +#' In case of an (unhandled) error, all event loop tasks will be cancelled. +#' +#' @param expr Expression to run after creating a new event loop. +#' @return `NULL`, always. If the event loop is to return some value, +#' you can use lexical scoping, see the example below. +#' +#' @noRd +#' @examples +#' counter <- 0L +#' do <- function() { +#' callback <- function() { +#' counter <<- counter + 1L +#' if (runif(1) < 1/10) t$cancel() +#' } +#' t <- async_timer$new(1/1000, callback) +#' } +#' run_event_loop(do()) +#' counter + +run_event_loop <- function(expr) { + new_el <- push_event_loop() + on.exit({ new_el$cancel_all(); pop_event_loop() }, add = TRUE) + + ## Mark this frame as a synchronization point, for debugging + `__async_synchronise_frame__` <- TRUE + + expr + new_el$run() + + invisible() +} + +distill_error <- function(err) { + if (is.null(err$aframe)) return(err) + err$aframe <- list( + frame = err$aframe$frame, + deferred = err$aframe$data[[1]], + type = err$aframe$data[[2]], + call = get_private(err$aframe$data[[3]])$mycall + ) + err +} + +# nocov start +#' @noRd + +print.async_rejected <- function(x, ...) { + cat(format(x, ...)) + invisible(x) +} + +# nocov end + +#' @noRd + +format.async_rejected <- function(x, ...) { + x <- distill_error(x) + src <- get_source_position(x$aframe$call) + paste0( + "" + ) +} + +#' @noRd + +summary.async_rejected <- function(object, ...) { + x <- distill_error(object) + fmt_out <- format(object, ...) + stack <- async_where(calls = x$calls, parents = x$parents, + frm = list(x$aframe)) + stack_out <- format(stack) + structure( + paste0(fmt_out, "\n\n", stack_out), + class = "async_rejected_summary") +} + +# nocov start + +#' @noRd + +print.async_rejected_summary <- function(x, ...) { + cat(x) + invisible(x) +} + +# nocov end + +#' Asynchronous function call with a timeout +#' +#' If the deferred value is not resolved before the timeout expires, +#' `async_timeout()` throws an `async_timeout` error. +#' +#' @param task Asynchronous function. +#' @param timeout Timeout as a `difftime` object, or number of seconds. +#' @param ... Additional arguments to `task`. +#' @return A deferred value. An `async_timeout` error is thrown if it is +#' not resolved within the specified timeout. +#' +#' @family async utilities +#' @noRd +#' @examples +#' ## You can catch the error, asynchronously +#' synchronise( +#' async_timeout(function() delay(1/10)$then(function() "OK"), 1/1000)$ +#' catch(async_timeout = function(e) "Timed out", +#' error = function(e) "Other error") +#' ) +#' +#' ## Or synchronously +#' tryCatch( +#' synchronise( +#' async_timeout(function() delay(1/10)$then(function() "OK"), 1/1000) +#' ), +#' async_timeout = function(e) "Timed out. :(", +#' error = function(e) paste("Other error:", e$message) +#' ) + +async_timeout <- function(task, timeout, ...) { + task <- async(task) + force(timeout) + list(...) + done <- FALSE + + self <- deferred$new( + type = "timeout", call = sys.call(), + action = function(resolve) { + task(...)$then(function(x) list("ok", x))$then(self) + delay(timeout)$then(function() list("timeout"))$then(self) + }, + parent_resolve = function(value, resolve) { + if (!done) { + done <<- TRUE + if (value[[1]] == "ok") { + resolve(value[[2]]) + } else { + cnd <- structure( + list(message = "Aync operation timed out"), + class = c("async_timeout", "error", "condition") + ) + stop(cnd) + } + } + } + ) +} + +async_timeout <- mark_as_async(async_timeout) + +#' Repeated timer +#' +#' The supplied callback function will be called by the event loop +#' every `delay` seconds. +#' +#' @section Usage: +#' ``` +#' t <- async_timer$new(delay, callback) +#' t$cancel() +#' ``` +#' +#' @section Arguments: +#' * `delay`: Time interval in seconds, the amount of time to delay +#' to delay the execution. It can be a fraction of a second. +#' * `callback`: Callback function without arguments. It will be called +#' from the event loop every `delay` seconds. +#' +#' @section Details: +#' +#' An `async_timer` is an `[event_emitter]` object with a `timeout` event. +#' It is possible to add multiple listeners to this event, once the timer +#' is created. Note, however, that removing all listeners does not cancel +#' the timer, `timeout` events will be still emitted as usual. +#' For proper cancellation you'll need to call the `cancel()` method. +#' +#' It is only possible to create `async_timer` objects in an asynchronous +#' context, i.e. within a `synchronise()` or `run_event_loop()` call. +#' A `synchronise()` call finishes as soon as its returned deferred value +#' is resolved (or rejected), even if some timers are still active. The +#' active timers will be automatically cancelled in this case. +#' +#' @section Errors: +#' Errors are handled the same way as for generic event emitters. I.e. to +#' catch errors thrown in the `callback` function, you need to add a +#' listener to the `error` event, see the example below. +#' +#' @section Congestion: +#' `async_timer` is _not_ a real-time timer. In particular, if `callback` +#' does not return in time, before the next timer event, then all future +#' timer events will be delayed. Even if `callback` returns promptly, the +#' event loop might be busy with other events, and then the next timer +#' event is not emitted in time. In general there is no guarantee about +#' the timing of the timer events. +#' +#' @importFrom R6 R6Class +#' @noRd +#' @examples +#' ## Call 10 times a second, cancel with 1/10 probability +#' counter <- 0L +#' do <- function() { +#' cb <- function() { +#' cat("called\n") +#' counter <<- counter + 1L +#' if (runif(1) < 0.1) t$cancel() +#' } +#' t <- async_timer$new(1/10, cb) +#' } +#' +#' run_event_loop(do()) +#' counter +#' +#' ## Error handling +#' counter <- 0L +#' do <- function() { +#' cb <- function() { +#' cat("called\n") +#' counter <<- counter + 1L +#' if (counter == 2L) stop("foobar") +#' if (counter == 3L) t$cancel() +#' } +#' t <- async_timer$new(1/10, cb) +#' handler <- function(err) { +#' cat("Got error:", sQuote(conditionMessage(err)), ", handled\n") +#' } +#' t$listen_on("error", handler) +#' } +#' +#' run_event_loop(do()) +#' counter +#' +#' ## Error handling at the synchonization point +#' counter <- 0L +#' do <- function() { +#' cb <- function() { +#' cat("called\n") +#' counter <<- counter + 1L +#' if (counter == 2L) stop("foobar") +#' if (counter == 3L) t$cancel() +#' } +#' t <- async_timer$new(1/10, cb) +#' } +#' +#' tryCatch(run_event_loop(do()), error = function(x) x) +#' counter + +async_timer <- R6Class( + "async_timer", + inherit = event_emitter, + public = list( + initialize = function(delay, callback) + async_timer_init(self, private, super, delay, callback), + cancel = function() + async_timer_cancel(self, private) + ), + + private = list( + id = NULL + ) +) + +async_timer_init <- function(self, private, super, delay, callback) { + assert_that( + is_time_interval(delay), + is.function(callback) && length(formals(callback)) == 0) + + ## event emitter + super$initialize() + + private$id <- get_default_event_loop()$add_delayed( + delay, + function() self$emit("timeout"), + function(err, res) { + if (!is.null(err)) self$emit("error", err) # nocov + }, + rep = TRUE) + + self$listen_on("timeout", callback) + + invisible(self) +} + +async_timer_cancel <- function(self, private) { + self; private + self$remove_all_listeners("timeout") + get_default_event_loop()$cancel(private$id) + invisible(self) +} + +#' It runs each task in series but stops whenever any of the functions were +#' successful. If one of the tasks were successful, the callback will be +#' passed the result of the successful task. If all tasks fail, the +#' callback will be passed the error and result (if any) of the final +#' attempt. +#' @param ... Deferred values to run in series. +#' @param .list More deferred values to run, `.list` is easier to use +#' programmatically. +#' @return Resolves to the result of the first successful deferred. +#' Otherwise throws an error. The error objects of all failed deferreds +#' will be in the `errors` member of the error object. +#' +#' @family async control flow +#' @noRd +#' @examples +#' do <- function() { +#' async_try_each( +#' async(function() stop("doh"))(), +#' async(function() "cool")(), +#' async(function() stop("doh2"))(), +#' async(function() "cool2")() +#' ) +#' } +#' synchronise(do()) + +async_try_each <- function(..., .list = list()) { + defs <- c(list(...), .list) + wh <- nx <- NULL + errors <- list() + + self <- deferred$new( + type = "async_try_each", call = sys.call(), + action = function(resolve) { + nx <<- length(defs) + if (nx == 0) resolve(NULL) + wh <<- 1L + defs[[wh]]$then(self) + }, + parent_resolve = function(value, resolve) { + resolve(value) + }, + parent_reject = function(value, resolve) { + errors <<- c(errors, list(value)) + if (wh == nx) { + err <- structure( + list(errors = errors, message = "async_try_each failed"), + class = c("async_rejected", "error", "condition")) + stop(err) + } else { + wh <<- wh + 1 + defs[[wh]]$then(self) + } + } + ) + + self +} + +async_try_each <- mark_as_async(async_try_each) + +#' Repeatedly call task until it its test function returns `TRUE` +#' +#' @param test Synchronous test function. +#' @param task Asynchronous function to call repeatedly. +#' @param ... Arguments to pass to `task`. +#' @return Deferred value, that is resolved when the iteration is done. +#' +#' @family async control flow +#' @noRd +#' @examples +#' ## Keep calling until it "returns" a number less than < 0.1 +#' calls <- 0 +#' number <- Inf +#' synchronise(async_until( +#' function() number < 0.1, +#' function() { +#' calls <<- calls + 1 +#' number <<- runif(1) +#' } +#' )) +#' calls + +async_until <- function(test, task, ...) { + force(test) + task <- async(task) + + self <- deferred$new( + type = "async_until", call = sys.call(), + parents = list(task(...)), + parent_resolve = function(value, resolve) { + if (test()) { + resolve(value) + } else { + task(...)$then(self) + } + } + ) + + self +} + +async_until <- mark_as_async(async_until) + +`%||%` <- function(l, r) if (is.null(l)) r else l + +vlapply <- function(X, FUN, ..., FUN.VALUE = logical(1)) { + vapply(X, FUN, FUN.VALUE = FUN.VALUE, ...) +} + +viapply <- function(X, FUN, ..., FUN.VALUE = integer(1)) { + vapply(X, FUN, FUN.VALUE = FUN.VALUE, ...) +} + +vcapply <- function(X, FUN, ..., FUN.VALUE = character(1)) { + vapply(X, FUN, FUN.VALUE = FUN.VALUE, ...) +} + +make_error <- function(message, class = "simpleError", call = NULL) { + class <- c(class, "error", "condition") + structure( + list(message = as.character(message), call = call), + class = class + ) +} + +num_args <- function(fun) { + length(formals(fun)) +} + +get_private <- function(x) { + x$.__enclos_env__$private +} + +#' Call `func` and then call `callback` with the result +#' +#' `callback` will be called with two arguments, the first one will the +#' error object if `func()` threw an error, or `NULL` otherwise. The second +#' argument is `NULL` on error, and the result of `func()` otherwise. +#' +#' @param func Function to call. +#' @param callback Callback to call with the result of `func()`, +#' or the error thrown. +#' @param info Extra info to add to the error object. Must be a named list. +#' +#' @noRd + +call_with_callback <- function(func, callback, info = NULL) { + recerror <- NULL + result <- NULL + tryCatch( + withCallingHandlers( + result <- func(), + error = function(e) { + recerror <<- e + recerror$aframe <<- recerror$aframe %||% find_async_data_frame() + recerror$calls <<- recerror$calls %||% sys.calls() + if (is.null(recerror[["call"]])) recerror[["call"]] <<- sys.call() + recerror$parents <<- recerror$parents %||% sys.parents() + recerror[names(info)] <<- info + handler <- getOption("async.error") + if (is.function(handler)) handler() + } + ), + error = identity + ) + callback(recerror, result) +} + +get_id <- local({ + id <- 0L + function() { + id <<- id + 1L + id + } +}) + +new_event_loop_id <- local({ + id <- 0L + function() { + id <<- id + 1L + id + } +}) + +lapply_args <- function(X, FUN, ..., .args = list()) { + do.call("lapply", c(list(X = X, FUN = FUN), list(...), .args)) +} + +drop_nulls <- function(x) { + x[!vlapply(x, is.null)] +} + +#' @importFrom utils getSrcDirectory getSrcFilename getSrcLocation + +get_source_position <- function(call) { + list( + filename = file.path( + c(getSrcDirectory(call), "?")[1], + c(getSrcFilename(call), "?")[1]), + position = paste0( + getSrcLocation(call, "line", TRUE) %||% "?", ":", + getSrcLocation(call, "column", TRUE) %||% "?") + ) +} + +file_size <- function(...) { + file.info(..., extra_cols = FALSE)$size +} + +read_all <- function(filename, encoding) { + if (is.null(filename)) return(NULL) + r <- readBin(filename, what = raw(0), n = file_size(filename)) + s <- rawToChar(r) + Encoding(s) <- encoding + s +} + +crash <- function () { + get("attach")(structure(list(), class = "UserDefinedDatabase")) +} + +str_trim <- function(x) { + sub("\\s+$", "", sub("^\\s+", "", x)) +} + +expr_name <- function(expr) { + if (is.null(expr)) { + return("NULL") + } + + if (is.symbol(expr)) { + return(as.character(expr)) + } + + if (is.call(expr)) { + cl <- as.list(expr)[[1]] + if (is.symbol(cl)) { + return(as.character(cl)) + } else { + return(paste0(format(cl), collapse = "")) + } + } + + if (is.atomic(expr) && length(expr) == 1) { + return(as.character(expr)) + } + + gsub("\n.*$", "...", as.character(expr)) +} + +get_uuid <- function() { + async_env$pid <- async_env$pid %||% Sys.getpid() + async_env$counter <- async_env$counter %||% 0 + async_env$counter <- async_env$counter + 1L + paste0(async_env$pid, "-", async_env$counter) +} + +#' Deferred value for a set of deferred values +#' +#' Create a deferred value that is resolved when all listed deferred values +#' are resolved. Note that the error of an input deferred value +#' triggers the error `when_all` as well. +#' +#' async has auto-cancellation, so if one deferred value errors, the rest +#' of them will be automatically cancelled. +#' +#' @param ... Deferred values. +#' @param .list More deferred values. +#' @return A deferred value, that is conditioned on all deferred values +#' in `...` and `.list`. +#' +#' @seealso [when_any()], [when_some()] +#' @noRd +#' @examples +#' \donttest{ +#' ## Check that the contents of two URLs are the same +#' afun <- async(function() { +#' u1 <- http_get("https://eu.httpbin.org") +#' u2 <- http_get("https://eu.httpbin.org/get") +#' when_all(u1, u2)$ +#' then(function(x) identical(x[[1]]$content, x[[2]]$content)) +#' }) +#' synchronise(afun()) +#' } + +when_all <- function(..., .list = list()) { + + defs <- c(list(...), .list) + nx <- 0L + + self <- deferred$new( + type = "when_all", + call = sys.call(), + action = function(resolve) { + self; nx; defs + lapply(seq_along(defs), function(idx) { + idx + if (is_deferred(defs[[idx]])) { + nx <<- nx + 1L + defs[[idx]]$then(function(val) list(idx, val))$then(self) + } + }) + if (nx == 0) resolve(defs) + }, + parent_resolve = function(value, resolve) { + defs[ value[[1]] ] <<- value[2] + nx <<- nx - 1L + if (nx == 0L) resolve(defs) + } + ) +} + +when_all <- mark_as_async(when_all) + +#' Resolve a deferred as soon as some deferred from a list resolve +#' +#' `when_some` creates a deferred value that is resolved as soon as the +#' specified number of deferred values resolve. +#' +#' `when_any` is a special case for a single. +#' +#' If the specified number of deferred values cannot be resolved, then +#' `when_any` throws an error. +#' +#' async has auto-cancellation, so if the required number of deferred values +#' are resolved, or too many of them throw error, the rest of the are +#' cancelled. +#' +#' If `when_any` throws an error, then all the underlying error objects +#' are returned in the `errors` member of the error object thrown by +#' `when_any`. +#' +#' @param count Number of deferred values that need to resolve. +#' @param ... Deferred values. +#' @param .list More deferred values. +#' @return A deferred value, that is conditioned on all deferred values +#' in `...` and `.list`. +#' +#' @seealso [when_all()] +#' @noRd +#' @examples +#' \donttest{ +#' ## Use the URL that returns first +#' afun <- function() { +#' u1 <- http_get("https://eu.httpbin.org") +#' u2 <- http_get("https://eu.httpbin.org/get") +#' when_any(u1, u2)$then(function(x) x$url) +#' } +#' synchronise(afun()) +#' } + +when_some <- function(count, ..., .list = list()) { + force(count) + defs <- c(list(...), .list) + num_defs <- length(defs) + num_failed <- 0L + ifdef <- vlapply(defs, is_deferred) + resolved <- defs[!ifdef] + errors <- list() + + cancel_all <- function() lapply(defs[ifdef], function(x) x$cancel()) + + deferred$new( + type = "when_some", call = sys.call(), + parents = defs[ifdef], + action = function(resolve) { + if (num_defs < count) { + stop("Cannot resolve enough deferred values") + } else if (length(resolved) >= count) { + resolve(resolved[seq_len(count)]) + } + }, + parent_resolve = function(value, resolve) { + resolved <<- c(resolved, list(value)) + if (length(resolved) == count) { + resolve(resolved) + } + }, + parent_reject = function(value, resolve) { + num_failed <<- num_failed + 1L + errors <<- c(errors, list(value)) + if (num_failed + count == num_defs + 1L) { + err <- structure( + list(errors = errors, message = "when_some / when_any failed"), + class = c("async_rejected", "error", "condition")) + stop(err) + } + } + ) +} + +when_some <- mark_as_async(when_some) + +#' @noRd +#' @rdname when_some + +when_any <- function(..., .list = list()) { + when_some(1, ..., .list = .list)$then(function(x) x[[1]]) +} + +when_any <- mark_as_async(when_any) + +#' Repeatedly call task, while test returns true +#' +#' @param test Synchronous test function. +#' @param task Asynchronous function to call repeatedly. +#' @param ... Arguments to pass to `task`. +#' @return Deferred value, that is resolved when the iteration is done. +#' +#' @family async control flow +#' @noRd +#' @examples +#' ## Keep calling while result is bigger than 0.1 +#' calls <- 0 +#' number <- Inf +#' synchronise(async_whilst( +#' function() number >= 0.1, +#' function() { +#' calls <<- calls + 1 +#' number <<- runif(1) +#' } +#' )) +#' calls + +async_whilst <- function(test, task, ...) { + force(test) + task <- async(task) + + self <- deferred$new( + type = "async_whilst", call = sys.call(), + action = function(resolve) { + if (!test()) { + resolve(NULL) + } else { + task(...)$then(self) + } + }, + parent_resolve = function(value, resolve) { + if (!test()) { + resolve(value) + } else { + task(...)$then(self) + } + } + ) + + self +} + +async_whilst <- mark_as_async(async_whilst) + +#' Worker pool +#' +#' The worker pool functions are independent of the event loop, to allow +#' independent testing. +#' +#' @family worker pool functions +#' @name worker_pool +#' @noRd +#' @keywords internal +#' @importFrom R6 R6Class +NULL + +worker_pool <- R6Class( + public = list( + initialize = function() + wp_init(self, private), + add_task = function(func, args, id, event_loop) + wp_add_task(self, private, func, args, id, event_loop), + get_fds = function() + wp_get_fds(self, private), + get_pids = function() + wp_get_pids(self, private), + get_poll_connections = function() + wp_get_poll_connections(self, private), + notify_event = function(pids, event_loop) + wp_notify_event(self, private, pids, event_loop), + start_workers = function() + wp_start_workers(self, private), + kill_workers = function() + wp_kill_workers(self, private), + cancel_task = function(id) + wp_cancel_task(self, private, id), + cancel_all_tasks = function() + wp_cancel_all_tasks(self, private), + get_result = function(id) + wp_get_result(self, private, id), + list_workers = function() + wp_list_workers(self, private), + list_tasks = function(event_loop = NULL, status = NULL) + wp_list_tasks(self, private, event_loop, status), + finalize = function() self$kill_workers() + ), + + private = list( + workers = list(), + tasks = list(), + + try_start = function() + wp__try_start(self, private), + interrupt_worker = function(pid) + wp__interrupt_worker(self, private, pid) + ) +) + +wp_init <- function(self, private) { + self$start_workers() + invisible(self) +} + +#' @importFrom callr r_session +#' @importFrom processx conn_get_fileno + +wp_start_workers <- function(self, private) { + num <- worker_pool_size() + + ## See if we need to start more + if (NROW(private$workers) >= num) return(invisible()) + + ## Yeah, start some more + to_start <- num - NROW(private$workers) + sess <- lapply(1:to_start, function(x) r_session$new(wait = FALSE)) + fd <- viapply(sess, function(x) conn_get_fileno(x$get_poll_connection())) + new_workers <- data.frame( + stringsAsFactors = FALSE, + session = I(sess), + task = NA_character_, + pid = viapply(sess, function(x) x$get_pid()), + fd = fd, + event_loop = NA_integer_ + ) + + private$workers <- rbind(private$workers, new_workers) + invisible() +} + +wp_add_task <- function(self, private, func, args, id, event_loop) { + private$tasks <- rbind( + private$tasks, + data.frame( + stringsAsFactors = FALSE, + event_loop = event_loop, id = id, func = I(list(func)), + args = I(list(args)), status = "waiting", result = I(list(NULL))) + ) + + private$try_start() + invisible() +} + +## We only need to poll the sessions that actually do something... + +wp_get_fds <- function(self, private) { + sts <- vcapply(private$workers$session, function(x) x$get_state()) + private$workers$fd[sts %in% c("starting", "busy")] +} + +wp_get_pids <- function(self, private) { + sts <- vcapply(private$workers$session, function(x) x$get_state()) + private$workers$pid[sts %in% c("starting", "busy")] +} + +wp_get_poll_connections <- function(self, private) { + sts <- vcapply(private$workers$session, function(x) x$get_state()) + busy <- sts %in% c("starting", "busy") + structure( + lapply(private$workers$session[busy], + function(x) x$get_poll_connection()), + names = private$workers$pid[busy]) +} + +wp_notify_event <- function(self, private, pids, event_loop) { + done <- NULL + dead <- integer() + which <- match(pids, private$workers$pid) + for (w in which) { + msg <- private$workers$session[[w]]$read() + if (is.null(msg)) next + if (msg$code == 200 || (msg$code >= 500 && msg$code < 600)) { + if (msg$code >= 500 && msg$code < 600) dead <- c(dead, w) + wt <- match(private$workers$task[[w]], private$tasks$id) + if (is.na(wt)) stop("Internal error, no such task") + private$tasks$result[[wt]] <- msg + private$tasks$status[[wt]] <- "done" + private$workers$task[[w]] <- NA_character_ + done <- c(done, private$tasks$id[[wt]]) + } + } + if (length(dead)) { + private$workers <- private$workers[-dead,] + self$start_workers() + } + + private$try_start() + + done +} + +worker_pool_size <- function() { + getOption("async.worker_pool_size") %||% + as.integer(Sys.getenv("ASYNC_WORKER_POOL_SIZE", 4)) +} + +wp_kill_workers <- function(self, private) { + lapply(private$workers$session, function(x) x$kill()) + private$workers <- NULL + invisible() +} + +wp_cancel_task <- function(self, private, id) { + wt <- match(id, private$tasks$id) + if (is.na(wt)) stop("Unknown task") + + if (private$tasks$status[[wt]] == "running") { + wk <- match(id, private$workers$task) + if (!is.na(wk)) private$interrupt_worker(private$workers$pid[wk]) + } + private$tasks <- private$tasks[-wt, ] + invisible() +} + +wp_cancel_all_tasks <- function(self, private) { + stop("`cancel_all_tasks` method is not implemented yet") +} + +wp_get_result <- function(self, private, id) { + wt <- match(id, private$tasks$id) + if (is.na(wt)) stop("Unknown task") + + if (private$tasks$status[[wt]] != "done") stop("Task not done yet") + result <- private$tasks$result[[wt]] + private$tasks <- private$tasks[-wt, ] + result +} + +wp_list_workers <- function(self, private) { + private$workers[, setdiff(colnames(private$workers), "session")] +} + +wp_list_tasks <- function(self, private, event_loop, status) { + dont_show <- c("func", "args", "result") + ret <- private$tasks + if (!is.null(event_loop)) ret <- ret[ret$event_loop %in% event_loop, ] + if (!is.null(status)) ret <- ret[ret$status %in% status, ] + ret[, setdiff(colnames(private$tasks), dont_show)] +} + +## Internals ------------------------------------------------------------- + +#' @importFrom utils head + +wp__try_start <- function(self, private) { + sts <- vcapply(private$workers$session, function(x) x$get_state()) + if (all(sts != "idle")) return() + can_work <- sts == "idle" + + can_run <- private$tasks$status == "waiting" + num_start <- min(sum(can_work), sum(can_run)) + will_run <- head(which(can_run), num_start) + will_work <- head(which(can_work), num_start) + + for (i in seq_along(will_run)) { + wt <- will_run[[i]] + ww <- will_work[[i]] + func <- private$tasks$func[[wt]] + args <- private$tasks$args[[wt]] + private$workers$session[[ww]]$call(func, args) + private$tasks$status[[wt]] <- "running" + private$workers$task[[ww]] <- private$tasks$id[[wt]] + } + + invisible() +} + +#' Interrupt a worker process +#' +#' We need to make sure that the worker is in a usable state after this. +#' +#' For speed, we try to interrupt with a SIGINT first, and if that does +#' not work, then we kill the worker and start a new one. +#' +#' When we interrupt with a SIGINT a number of things can happen: +#' 1. we successfully interrupted a computation, then +#' we'll just poll_io(), and read() and we'll get back an +#' interrupt error. +#' 2. The computation has finished, so we did not interrupt it. +#' In this case the background R process will apply the interrupt +#' to the next computation (at least on Unix) so the bg process +#' needs to run a quick harmless call to absorb the interrupt. +#' We can use `Sys.sleep()` for this, and `write_input()` directly +#' for speed and simplicity. +#' 3. The process has crashed already, in this case `interrupt()` will +#' return `FALSE`. `poll_io()` will return with "ready" immediately, +#' `read()` will return with an error, and `write_input()` throws +#' an error. +#' 4. We could not interrupt the process, because it was in a +#' non-interruptable state. In this case we kill it, and start a +#' new process. `poll_io()` will not return with "ready" in this case. +#' +#' @param self self +#' @param private private self +#' @param pid pid of process +#' @noRd + +wp__interrupt_worker <- function(self, private, pid) { + ww <- match(pid, private$workers$pid) + if (is.na(ww)) stop("Unknown task in interrupt_worker() method") + + kill <- FALSE + sess <- private$workers$session[[ww]] + int <- sess$interrupt() + pr <- sess$poll_io(100)["process"] + + if (pr == "ready") { + msg <- sess$read() + if (! inherits(msg, "interrupt")) { + tryCatch({ + sess$write_input("base::Sys.sleep(0)\n") + sess$read_output() + sess$read_error() + }, error = function(e) kill <<- TRUE) + } + private$workers$task[[ww]] <- NA_character_ + } else { + kill <- TRUE + } + + if (kill) { + sess$close() + private$workers <- private$workers[-ww, ] + ## Make sure that we have enough workers running + self$start_workers() + } + + invisible() +} + +#' External process via a process generator +#' +#' Wrap any [processx::process] object into a deferred value. The +#' process is created by a generator function. +#' +#' @param process_generator Function that returns a [processx::process] +#' object. See details below about the current requirements for the +#' returned process. +#' @param error_on_status Whether to fail if the process terminates +#' with a non-zero exit status. +#' @param ... Extra arguments, passed to `process_generator`. +#' @return Deferred object. +#' +#' Current requirements for `process_generator`: +#' * It must take a `...` argument, and pass it to +#' `processx::process$new()`. +#' * It must use the `poll_connection = TRUE` argument. +#' These requirements might be relaxed in the future. +#' +#' If you want to obtain the standard output and/or error of the +#' process, then `process_generator` must redirect them to files. +#' If you want to discard them, `process_generator` can set them to +#' `NULL`. +#' +#' `process_generator` should not use pipes (`"|"`) for the standard +#' output or error, because the process will stop running if the +#' pipe buffer gets full. We currently never read out the pipe buffer. +#' +#' @noRd +#' @examples +#' \dontrun{ +#' lsgen <- function(dir = ".", ...) { +#' processx::process$new( +#' "ls", +#' dir, +#' poll_connection = TRUE, +#' stdout = tempfile(), +#' stderr = tempfile(), +#' ... +#' ) +#' } +#' afun <- function() { +#' external_process(lsgen) +#' } +#' synchronise(afun()) +#' } + +external_process <- function(process_generator, error_on_status = TRUE, + ...) { + + process_generator; error_on_status; args <- list(...) + args$encoding <- args$encoding %||% "" + + id <- NULL + + deferred$new( + type = "external_process", call = sys.call(), + action = function(resolve) { + resolve + reject <- environment(resolve)$private$reject + px <- do.call(process_generator, args) + stdout <- px$get_output_file() + stderr <- px$get_error_file() + pipe <- px$get_poll_connection() + id <<- get_default_event_loop()$add_process( + list(pipe), + function(err, res) if (is.null(err)) resolve(res) else reject(err), + list(process = px, stdout = stdout, stderr = stderr, + error_on_status = TRUE, encoding = args$encoding) + ) + }, + on_cancel = function(reason) { + if (!is.null(id)) get_default_event_loop()$cancel(id) + } + ) +} diff --git a/R/assertions.R b/R/assertions.R new file mode 100644 index 0000000..f4bbb57 --- /dev/null +++ b/R/assertions.R @@ -0,0 +1,68 @@ + +is_character <- function(x) { + if (!is.character(x)) { + structure( + FALSE, + msg = "{.arg {(.arg)}} must be a character vector without {.code NA}, + but it is {.type {x}}", + env = environment() + ) + } else if (anyNA(x)) { + structure( + FALSE, + msg = "{.arg {(.arg)}} must be a character vector without {.code NA}, + but it has {sum(is.na(x))} {.code NA} value{?s}.", + env = environment() + ) + } else { + TRUE + } +} + +is_string <- function(x) { + if (is.character(x) && length(x) == 1 && !is.na(x)) return(TRUE) + if (is.character(x) && length(x) == 1 && is.na(x)) { + structure( + FALSE, + msg = "{.arg {(.arg)}} must not be {.code NA}.", + env = environment() + ) + } else { + structure( + FALSE, + msg = "{.arg {(.arg)}} must be a string (character scalar), + but it is {.type {x}}.", + env = environment() + ) + } +} + +is_optional_string <- function(x) { + if (is.null(x) || is_string(x)) return(TRUE) + structure( + FALSE, + msg = "{.arg {(.arg)}} must be a path (character scalar), + but it is {.type {x}}.", + env = environment() + ) +} + +is_optional_gh_url <- function(x) { + if (is.null(x)) return(TRUE) + + if (!is_string(x)) { + structure( + FALSE, + msg = "{.arg gh_url} must be a character string. + You supplied {.type {x}}." + ) + } else if (!grepl("^https?://", x)) { + structure( + FALSE, + msg = "{.arg gh_url} must be an HTTP or HTTPS URL. + You supplied: {.val {x}}." + ) + } else { + TRUE + } +} diff --git a/R/assertthat.R b/R/assertthat.R new file mode 100644 index 0000000..c24b704 --- /dev/null +++ b/R/assertthat.R @@ -0,0 +1,183 @@ + +assert_that <- function(..., env = parent.frame(), msg = NULL) { + asserts <- eval(substitute(alist(...))) + + for (assertion in asserts) { + res <- tryCatch({ + eval(assertion, env) + }, assertError = function(e) { + structure(FALSE, msg = e$message) + }) + check_result(res) + if (res) next + + if (is.null(msg)) { + msg <- get_message(res, assertion, env) + evalenv <- attr(res, "env") %||% env + } else { + evalenv <- env + } + throw(assert_error( + assertion, + res, + msg, + call. = sys.call(-1), + .envir = evalenv, + ), frame = env) + } + + invisible(TRUE) +} + +assert_error <- function(assertion, result, msg, .data = NULL, .class = NULL, + .envir = parent.frame(), call. = TRUE) { + + myenv <- new.env(parent = .envir) + myenv$.arg <- if (length(assertion) >= 2) deparse(assertion[[2]]) + myenv$.arg2 <- if (length(assertion) >= 3) deparse(assertion[[3]]) + .hide_from_trace <- TRUE + cnd <- new_error( + call. = call., + cli::format_error( + .envir = myenv, + msg + ) + ) + + if (length(.data)) cnd[names(.data)] <- .data + if (length(class)) class(cnd) <- unique(c(.class, "assertError", class(cnd))) + + cnd +} +check_result <- function(x) { + if (!is.logical(x)) { + throw(pkg_error( + "{.fun assert_that}: assertion must return a logical value.", + "i" = "it returned {.type {x}} instead." + )) + } + + if (length(x) != 1) { + throw(pkg_error( + "{.fun assert_that}: assertion must return a scalar.", + "i" = "it returned a vector of length {length(x)}." + )) + } + + if (any(is.na(x))) { + throw(pkg_error( + "{.fun assert_that}: assertion must not return {.code NA}." + )) + } + + TRUE +} + +get_message <- function(res, call, env = parent.frame()) { + if (has_attr(res, "msg")) { + return(attr(res, "msg")) + } + + f <- eval(call[[1]], env) + if (is.call(call) && !is.primitive(f)) call <- match.call(f, call) + fname <- deparse(call[[1]]) + + base_fs[[fname]] %||% fail_default(call, env) +} + +# The default failure message works in the same way as stopifnot, so you can +# continue to use any function that returns a logical value: you just won't +# get a friendly error message. +# The code below says you get the first 60 characters plus a ... +fail_default <- function(call, env) { + call_string <- deparse(call, width.cutoff = 60L) + if (length(call_string) > 1L) { + call_string <- paste0(call_string[1L], "...") + } + + paste0(call_string, " is not true") +} + +has_attr <- function(x, which) { + if (!is.null(attr(x, which, exact = TRUE))) return(TRUE) + structure( + FALSE, + msg = "{.arg {(.arg)}} must have attribute {.code {which}}.", + env = environment() + ) +} +"%has_attr%" <- has_attr + +base_fs <- new.env(parent = emptyenv()) + +# nocov start + +logical_is_not <- function(failed) { + paste0("{.arg {(.arg)}} must ", failed, " {.arg {(.arg2)}}.") +} + +base_fs$"==" <- logical_is_not("equal") +base_fs$"<" <- logical_is_not("be less than") +base_fs$">" <- logical_is_not("be greater than") +base_fs$">=" <- logical_is_not("be greater than or equal to") +base_fs$"<=" <- logical_is_not("be less than or equal to") +base_fs$"!=" <- logical_is_not("not be equal to") + +is_not <- function(thing) { + paste0("{.arg {(.arg)}} must be ", thing, ".") +} + +# nocov end + +# Vectors +base_fs$is.atomic <- is_not("an atomic vector") +base_fs$is.character <- is_not("a character vector") +base_fs$is.complex <- is_not("a complex vector") +base_fs$is.double <- is_not("a numeric vector") +base_fs$is.integer <- is_not("an integer vector") +base_fs$is.numeric <- is_not("a numeric or integer vector") +base_fs$is.raw <- is_not("a raw vector") +base_fs$is.vector <- is_not("an atomic vector without attributes") + +# Factors +base_fs$is.factor <- is_not("a factor") +base_fs$is.ordered <- is_not("an ordered factor") + +# More complicated data structures +base_fs$is.array <- is_not("an array") +base_fs$is.data.frame <- is_not("a data frame") +base_fs$is.list <- is_not("a list") +base_fs$is.matrix <- is_not("a matrix") +base_fs$is.null <- is_not("{.code NULL}") + +# Functions and environments +base_fs$is.environment <- is_not("an environment") +base_fs$is.function <- is_not("a function") +base_fs$is.primitive <- is_not("a primitive function") + +# Computing on the language +base_fs$is.call <- is_not("a quoted call") +base_fs$is.expression <- is_not("an expression object") +base_fs$is.name <- is_not("a name") +base_fs$is.pairlist <- is_not("a pairlist") +base_fs$is.recursive <- is_not("a recursive object") +base_fs$is.symbol <- is_not("a name") + +# Catch all +base_fs$"&&" <- + "{.arg {(.arg)}} and {.arg {(.arg2)}} must both be true." + +base_fs$"||" <- + "One of {.arg {(.arg)}} and {.arg {(.arg2)}} must be true." + +base_fs$any <- + "At least one of {.arg {(.arg)}} must be true." + +base_fs$all <- + "All of {.arg {(.arg)}} must be true." + +base_fs$file.exists <- + "Path {.arg {(.arg)}} must exist." + +base_fs$identical <- + "{.arg {(.arg)}} must be identical to {.arg {(.arg2)}}." diff --git a/R/check.R b/R/check.R new file mode 100644 index 0000000..1fd83e5 --- /dev/null +++ b/R/check.R @@ -0,0 +1,127 @@ + +#' Check a package on R-hub +#' +#' @param gh_url GitHub URL of a package to check, or `NULL` to check +#' the package in the current directory. +#' @param platforms Platforms to use, a character vector. Use `NULL` to +#' select from a list in interactive sessions. See [rhub_platforms()]. +#' @param r_versions Which R version(s) to use for the platforms that +#' supports multiple R versions. This arguemnt is not implemented yet. +#' @param branch Branch to use to run R-hub. Defaults to the current +#' branch if `gh_url` is `NULL`. Otherwise defaults to `"main"`. Note that +#' this branch also need to include the `rhub.yaml` workflow file. +#' @return TODO +#' +#' @export + +rhub_check <- function(gh_url = NULL, platforms = NULL, r_versions = NULL, + branch = NULL) { + assert_that( + is_optional_gh_url(gh_url), + is.null(platforms) || is_character(platforms), + is_optional_string(branch) + ) + + git_root <- if (is.null(gh_url)) setup_find_git_root() + pat_url <- gh_url %||% "https://github.com" + pat <- doctor_find_pat(pat_url) + gh_url <- gh_url %||% doctor_find_gh_url(repo = git_root) + + if (is.null(branch)) { + if (!is.null(git_root)) { + branch <- gert::git_branch(repo = git_root) + } else { + branch <- "main" + } + } + + tryCatch( + plat <- rhub_platforms(), + error = function(e) { + throw(parent = e, pkg_error( + "Failed to download the list of R-hub platforms.", + i = "Make sure that you are online and Github is also online." + )) + } + ) + + if (is.null(platforms)) { + if (!interactive()) { + throw(pkg_error( + "{.arg platforms} argument is missing for {.fun rhub_check}.", + i = "You need to specify {.arg platforms} in non-interactive + sessions" + )) + } + cli::cli_text() + cli::cli_text( + "Available platforms + (see {.code rhub2::rhub_platforms()} for details):" + ) + cli::cli_text() + cli::cli_verbatim(paste( + cli::ansi_strtrim(format(summary(plat))), + collapse = "\n" + )) + pnums <- trimws(readline( + prompt = "\nSelection (comma separated numbers, 0 to cancel): " + )) + if (pnums == "" || pnums == "0") { + throw(pkg_error("R-hub check cancelled")) + } + pnums <- unique(trimws(strsplit(pnums, ",", fixed = TRUE)[[1]])) + pnums2 <- suppressWarnings(as.integer(pnums)) + bad <- is.na(pnums2) | pnums2 < 1 | pnums2 > nrow(plat) + if (any(bad)) { + throw(pkg_error( + "Invalid platform number{?s}: {.val {pnums[bad]}}." + )) + } + platforms <- plat$name[pnums2] + + } else { + platforms <- unique(platforms) + bad <- !platforms %in% unlist(plat$name, plat$aliaeses) + if (any(bad)) { + throw(pkg_error( + "Unknown platform{?s}: {.val {platforms[bad]}}.", + i = "See {.run rhub::rhub_platforms()} for the list of platforms" + )) + } + } + + url <- parse_gh_url(gh_url) + ep <- glue::glue("/repos/{url$user}/{url$repo}/actions/workflows/rhub.yaml/dispatches") + config <- list(platforms = platforms) + name <- paste(platforms, collapse = ", ") + id <- random_id() + data <- list( + ref = branch, + inputs = list( + config = jsonlite::toJSON(config, auto_unbox = TRUE), + name = name, + id = id + ) + ) + jsondata <- jsonlite::toJSON(data, auto_unbox = TRUE) + + resp <- gh_rest_post(url$api, ep, token = pat, data = jsondata) + + if (resp$status_code != 204) { + throw(pkg_error( + ":( Failed to start check: {resp$content$message}.", + i = "If you think this is a bug in the {.pkg rhub2} package, please + open an issues at {.url https://github.com/r-hub/rhub/issues}." + )) + } + + aurl <- paste0("https://", url$host, "/", url$user, "/", url$repo, "/actions") + cli::cli_text() + cli::cli_bullets(c( + "v" = "Check started: {name} ({id}).", + " " = "See {.url {aurl}} for live output!" + )) + + + invisible(NULL) +} diff --git a/R/cli.R b/R/cli.R new file mode 100644 index 0000000..ea10084 --- /dev/null +++ b/R/cli.R @@ -0,0 +1,11 @@ + +cli_status <- function(msg, ..., .auto_close = FALSE) { + msg + cli::cli_status( + msg = "{.alert {msg}}", + msg_done = "{.alert-success {msg}}", + msg_failed = "{.alert-danger {msg}}", + .auto_close = .auto_close, + ... + ) +} diff --git a/R/compat-vctrs.R b/R/compat-vctrs.R new file mode 100644 index 0000000..3f07fb4 --- /dev/null +++ b/R/compat-vctrs.R @@ -0,0 +1,640 @@ + +# nocov start + +compat_vctrs <- local({ + +# Modified from https://github.com/r-lib/rlang/blob/master/R/compat-vctrs.R + +# Construction ------------------------------------------------------------ + +# Constructs data frames inheriting from `"tbl"`. This allows the +# pillar package to take over printing as soon as it is loaded. +# The data frame otherwise behaves like a base data frame. +data_frame <- function(...) { + new_data_frame(df_list(...), .class = "tbl") +} + +new_data_frame <- function(.x = list(), + ..., + .size = NULL, + .class = NULL) { + n_cols <- length(.x) + if (n_cols != 0 && is.null(names(.x))) { + stop("Columns must be named.", call. = FALSE) + } + + if (is.null(.size)) { + if (n_cols == 0) { + .size <- 0 + } else { + .size <- vec_size(.x[[1]]) + } + } + + structure( + .x, + class = c(.class, "data.frame"), + row.names = .set_row_names(.size), + ... + ) +} + +df_list <- function(..., .size = NULL) { + vec_recycle_common(list(...), size = .size) +} + + +# Binding ----------------------------------------------------------------- + +vec_rbind <- function(...) { + xs <- vec_cast_common(list(...)) + do.call(base::rbind, xs) +} + +vec_cbind <- function(...) { + xs <- list(...) + + ptype <- vec_ptype_common(lapply(xs, `[`, 0)) + class <- setdiff(class(ptype), "data.frame") + + xs <- vec_recycle_common(xs) + out <- do.call(base::cbind, xs) + new_data_frame(out, .class = class) +} + + +# Slicing ----------------------------------------------------------------- + +vec_size <- function(x) { + if (is.data.frame(x)) { + nrow(x) + } else { + length(x) + } +} + +vec_rep <- function(x, times) { + i <- rep.int(seq_len(vec_size(x)), times) + vec_slice(x, i) +} + +vec_recycle_common <- function(xs, size = NULL) { + sizes <- vapply(xs, vec_size, integer(1)) + + n <- unique(sizes) + + if (length(n) == 1 && is.null(size)) { + return(xs) + } + n <- setdiff(n, 1L) + + ns <- length(n) + + if (ns == 0) { + if (is.null(size)) { + return(xs) + } + } else if (ns == 1) { + if (is.null(size)) { + size <- n + } else if (ns != size) { + stop("Inputs can't be recycled to `size`.", call. = FALSE) + } + } else { + stop("Inputs can't be recycled to a common size.", call. = FALSE) + } + + to_recycle <- sizes == 1L + xs[to_recycle] <- lapply(xs[to_recycle], vec_rep, size) + + xs +} + +vec_slice <- function(x, i) { + if (is.logical(i)) { + i <- which(i) + } + stopifnot(is.numeric(i) || is.character(i)) + + if (is.null(x)) { + return(NULL) + } + + if (is.data.frame(x)) { + # We need to be a bit careful to be generic. First empty all + # columns and expand the df to final size. + out <- x[i, 0, drop = FALSE] + + # Then fill in with sliced columns + out[seq_along(x)] <- lapply(x, vec_slice, i) + + # Reset automatic row names to work around `[` weirdness + if (is.numeric(attr(x, "row.names"))) { + row_names <- .set_row_names(nrow(out)) + } else { + row_names <- attr(out, "row.names") + } + + return(out) + } + + d <- vec_dims(x) + if (d == 1) { + if (is.object(x)) { + out <- x[i] + } else { + out <- x[i, drop = FALSE] + } + } else if (d == 2) { + out <- x[i, , drop = FALSE] + } else { + j <- rep(list(quote(expr = )), d - 1) + out <- eval(as.call(list(quote(`[`), quote(x), quote(i), j, drop = FALSE))) + } + + out +} +vec_dims <- function(x) { + d <- dim(x) + if (is.null(d)) { + 1L + } else { + length(d) + } +} + +vec_as_location <- function(i, n, names = NULL) { + out <- seq_len(n) + names(out) <- names + + # Special-case recycling to size 0 + if (is_logical(i, n = 1) && !length(out)) { + return(out) + } + + unname(out[i]) +} + +vec_init <- function(x, n = 1L) { + vec_slice(x, rep_len(NA_integer_, n)) +} + +vec_assign <- function(x, i, value) { + if (is.null(x)) { + return(NULL) + } + + if (is.logical(i)) { + i <- which(i) + } + stopifnot( + is.numeric(i) || is.character(i) + ) + + value <- vec_recycle(value, vec_size(i)) + value <- vec_cast(value, to = x) + + d <- vec_dims(x) + + if (d == 1) { + x[i] <- value + } else if (d == 2) { + x[i, ] <- value + } else { + stop("Can't slice-assign arrays.", call. = FALSE) + } + + x +} + +vec_recycle <- function(x, size) { + if (is.null(x) || is.null(size)) { + return(NULL) + } + + n_x <- vec_size(x) + + if (n_x == size) { + x + } else if (size == 0L) { + vec_slice(x, 0L) + } else if (n_x == 1L) { + vec_slice(x, rep(1L, size)) + } else { + stop("Incompatible lengths: ", n_x, ", ", size, call. = FALSE) + } +} + + +# Coercion ---------------------------------------------------------------- + +vec_cast_common <- function(xs, to = NULL) { + ptype <- vec_ptype_common(xs, ptype = to) + lapply(xs, vec_cast, to = ptype) +} + +vec_cast <- function(x, to) { + if (is.null(x)) { + return(NULL) + } + if (is.null(to)) { + return(x) + } + + if (vec_is_unspecified(x)) { + return(vec_init(to, vec_size(x))) + } + + stop_incompatible_cast <- function(x, to) { + stop( + sprintf("Can't convert <%s> to <%s>.", + .rlang_vctrs_typeof(x), + .rlang_vctrs_typeof(to) + ), + call. = FALSE + ) + } + + lgl_cast <- function(x, to) { + lgl_cast_from_num <- function(x) { + if (any(!x %in% c(0L, 1L))) { + stop_incompatible_cast(x, to) + } + as.logical(x) + } + + switch( + .rlang_vctrs_typeof(x), + logical = x, + integer = , + double = lgl_cast_from_num(x), + stop_incompatible_cast(x, to) + ) + } + + int_cast <- function(x, to) { + int_cast_from_dbl <- function(x) { + out <- suppressWarnings(as.integer(x)) + if (any((out != x) | xor(is.na(x), is.na(out)))) { + stop_incompatible_cast(x, to) + } else { + out + } + } + + switch( + .rlang_vctrs_typeof(x), + logical = as.integer(x), + integer = x, + double = int_cast_from_dbl(x), + stop_incompatible_cast(x, to) + ) + } + + dbl_cast <- function(x, to) { + switch( + .rlang_vctrs_typeof(x), + logical = , + integer = as.double(x), + double = x, + stop_incompatible_cast(x, to) + ) + } + + chr_cast <- function(x, to) { + switch( + .rlang_vctrs_typeof(x), + character = x, + stop_incompatible_cast(x, to) + ) + } + + list_cast <- function(x, to) { + switch( + .rlang_vctrs_typeof(x), + list = x, + stop_incompatible_cast(x, to) + ) + } + + df_cast <- function(x, to) { + # Check for extra columns + if (length(setdiff(names(x), names(to))) > 0 ) { + stop("Can't convert data frame because of missing columns.", call. = FALSE) + } + + # Avoid expensive [.data.frame method + out <- as.list(x) + + # Coerce common columns + common <- intersect(names(x), names(to)) + out[common] <- Map(vec_cast, out[common], to[common]) + + # Add new columns + from_type <- setdiff(names(to), names(x)) + out[from_type] <- lapply(to[from_type], vec_init, n = vec_size(x)) + + # Ensure columns are ordered according to `to` + out <- out[names(to)] + + new_data_frame(out) + } + + rlib_df_cast <- function(x, to) { + new_data_frame(df_cast(x, to), .class = "tbl") + } + tib_cast <- function(x, to) { + new_data_frame(df_cast(x, to), .class = c("tbl_df", "tbl")) + } + + switch( + .rlang_vctrs_typeof(to), + logical = lgl_cast(x, to), + integer = int_cast(x, to), + double = dbl_cast(x, to), + character = chr_cast(x, to), + list = list_cast(x, to), + + base_data_frame = df_cast(x, to), + rlib_data_frame = rlib_df_cast(x, to), + tibble = tib_cast(x, to), + + stop_incompatible_cast(x, to) + ) +} + +vec_ptype_common <- function(xs, ptype = NULL) { + if (!is.null(ptype)) { + return(vec_ptype(ptype)) + } + + xs <- Filter(function(x) !is.null(x), xs) + + if (length(xs) == 0) { + return(NULL) + } + + if (length(xs) == 1) { + out <- vec_ptype(xs[[1]]) + } else { + xs <- map(xs, vec_ptype) + out <- Reduce(vec_ptype2, xs) + } + + vec_ptype_finalise(out) +} + +vec_ptype_finalise <- function(x) { + if (is.data.frame(x)) { + x[] <- lapply(x, vec_ptype_finalise) + return(x) + } + + if (inherits(x, "rlang_unspecified")) { + logical() + } else { + x + } +} + +vec_ptype <- function(x) { + if (vec_is_unspecified(x)) { + return(.rlang_vctrs_unspecified()) + } + + if (is.data.frame(x)) { + out <- new_data_frame(lapply(x, vec_ptype)) + + attrib <- attributes(x) + attrib$row.names <- attr(out, "row.names") + attributes(out) <- attrib + + return(out) + } + + vec_slice(x, 0) +} + +vec_ptype2 <- function(x, y) { + stop_incompatible_type <- function(x, y) { + stop( + sprintf("Can't combine types <%s> and <%s>.", + .rlang_vctrs_typeof(x), + .rlang_vctrs_typeof(y)), + call. = FALSE + ) + } + + x_type <- .rlang_vctrs_typeof(x) + y_type <- .rlang_vctrs_typeof(y) + + if (x_type == "unspecified" && y_type == "unspecified") { + return(.rlang_vctrs_unspecified()) + } + if (x_type == "unspecified") { + return(y) + } + if (y_type == "unspecified") { + return(x) + } + + df_ptype2 <- function(x, y) { + set_partition <- function(x, y) { + list( + both = intersect(x, y), + only_x = setdiff(x, y), + only_y = setdiff(y, x) + ) + } + + # Avoid expensive [.data.frame + x <- as.list(vec_slice(x, 0)) + y <- as.list(vec_slice(y, 0)) + + # Find column types + names <- set_partition(names(x), names(y)) + if (length(names$both) > 0) { + common_types <- Map(vec_ptype2, x[names$both], y[names$both]) + } else { + common_types <- list() + } + only_x_types <- x[names$only_x] + only_y_types <- y[names$only_y] + + # Combine and construct + out <- c(common_types, only_x_types, only_y_types) + out <- out[c(names(x), names$only_y)] + new_data_frame(out) + } + + rlib_df_ptype2 <- function(x, y) { + new_data_frame(df_ptype2(x, y), .class = "tbl") + } + tib_ptype2 <- function(x, y) { + new_data_frame(df_ptype2(x, y), .class = c("tbl_df", "tbl")) + } + + ptype <- switch( + x_type, + + logical = switch( + y_type, + logical = x, + integer = y, + double = y, + stop_incompatible_type(x, y) + ), + + integer = switch( + .rlang_vctrs_typeof(y), + logical = x, + integer = x, + double = y, + stop_incompatible_type(x, y) + ), + + double = switch( + .rlang_vctrs_typeof(y), + logical = x, + integer = x, + double = x, + stop_incompatible_type(x, y) + ), + + character = switch( + .rlang_vctrs_typeof(y), + character = x, + stop_incompatible_type(x, y) + ), + + list = switch( + .rlang_vctrs_typeof(y), + list = x, + stop_incompatible_type(x, y) + ), + + base_data_frame = switch( + .rlang_vctrs_typeof(y), + base_data_frame = , + s3_data_frame = df_ptype2(x, y), + rlib_data_frame = rlib_df_ptype2(x, y), + tibble = tib_ptype2(x, y), + stop_incompatible_type(x, y) + ), + + rlib_data_frame = switch( + .rlang_vctrs_typeof(y), + base_data_frame = , + rlib_data_frame = , + s3_data_frame = rlib_df_ptype2(x, y), + tibble = tib_ptype2(x, y), + stop_incompatible_type(x, y) + ), + + tibble = switch( + .rlang_vctrs_typeof(y), + base_data_frame = , + rlib_data_frame = , + tibble = , + s3_data_frame = tib_ptype2(x, y), + stop_incompatible_type(x, y) + ), + + stop_incompatible_type(x, y) + ) + + vec_slice(ptype, 0) +} + +.rlang_vctrs_typeof <- function(x) { + if (is.object(x)) { + class <- class(x) + + if (identical(class, "rlang_unspecified")) { + return("unspecified") + } + if (identical(class, "data.frame")) { + return("base_data_frame") + } + if (identical(class, c("tbl", "data.frame"))) { + return("rlib_data_frame") + } + if (identical(class, c("tbl_df", "tbl", "data.frame"))) { + return("tibble") + } + if (inherits(x, "data.frame")) { + return("s3_data_frame") + } + + class <- paste0(class, collapse = "/") + stop(sprintf("Unimplemented class <%s>.", class), call. = FALSE) + } + + type <- typeof(x) + switch( + type, + NULL = return("null"), + logical = if (vec_is_unspecified(x)) { + return("unspecified") + } else { + return(type) + }, + integer = , + double = , + character = , + raw = , + list = return(type) + ) + + stop(sprintf("Unimplemented type <%s>.", type), call. = FALSE) +} + +vec_is_unspecified <- function(x) { + !is.object(x) && + typeof(x) == "logical" && + length(x) && + all(vapply(x, identical, logical(1), NA)) +} + +.rlang_vctrs_unspecified <- function(x = NULL) { + structure( + rep(NA, length(x)), + class = "rlang_unspecified" + ) +} + +.rlang_vctrs_s3_method <- function(generic, class, env = parent.frame()) { + fn <- get(generic, envir = env) + + ns <- asNamespace(topenv(fn)) + tbl <- ns$.__S3MethodsTable__. + + for (c in class) { + name <- paste0(generic, ".", c) + if (exists(name, envir = tbl, inherits = FALSE)) { + return(get(name, envir = tbl)) + } + if (exists(name, envir = globalenv(), inherits = FALSE)) { + return(get(name, envir = globalenv())) + } + } + + NULL +} + +environment() + +}) + +data_frame <- compat_vctrs$data_frame + +as_data_frame <- function(x) { + if (is.matrix(x)) { + x <- as.data.frame(x, stringsAsFactors = FALSE) + } else { + x <- compat_vctrs$vec_recycle_common(x) + } + compat_vctrs$new_data_frame(x, .class = "tbl") +} + +# nocov end diff --git a/R/doctor.R b/R/doctor.R new file mode 100644 index 0000000..9eb4fbf --- /dev/null +++ b/R/doctor.R @@ -0,0 +1,276 @@ + +#' Check if the current or the specified package is ready to use with R-hub +#' +#' Errors if the package or repository is not set up correctly, and +#' advises on possible solutions. +#' +#' @param gh_url Use `NULL` for the package in the current working +#' directory. Alternatively, use the URL of a GitHub repository that +#' contains an R package that was set up to use with R-hub. +#' +#' @export + +rhub_doctor <- function(gh_url = NULL) { + assert_that( + is_optional_gh_url(gh_url) + ) + + rpkg_root <- if (is.null(gh_url)) setup_find_r_package() + git_root <- if (is.null(gh_url)) setup_find_git_root() + if (is.null(gh_url)) check_rpkg_root(rpkg_root, git_root) + + pat_url <- gh_url %||% "https://github.com" + pat <- doctor_find_pat(pat_url) + gh_url <- gh_url %||% doctor_find_gh_url(repo = git_root) + + # ----------------------------------------------------------------------- + # Do these up front, concurrently + # We need the following pieces: + # 1 check if we are indeed talking to GitHub + # 2 check that the token is valid, and we have access to the repo + # 3 check that the token has the right scopes + # 4 check that the workflow file exists on the default branch + # 5 check that the workflow exists (e.g. not a fork with disabled actions) + # 6 check that the workflow is enabled + # 7 check that the workflow file is the latest version + # + # Unfortunately we cannot do all this with a single graphql query, because + # (AFAICT) you cannot currently query the workflows of a repository with + # GraphQL. + # + # So we'll have + # - a graphql query for (1), (2), (3), (4), (7) + # - a REST query for (%) and (6) + + resp <- synchronise(when_all( + gql = doctor_async_gql(gh_url, token = pat), + wfl = doctor_async_rest(gh_url, token = pat) + )) + + doctor_check_github(gh_url, resp$gql) + doctor_check_pat_scopes(resp$gql) + doctor_check_workflow(gh_url, resp$gql, resp$wfl) + + cli::cli_alert( + "WOOT! You are ready to run {.run rhub2::rhub_check()} on this package.", + wrap = TRUE + ) + + invisible(NULL) +} + +# TODO: multiple remotes, what if it is not origin? +# TODO: what if there is a remote, but it does not have a URL? + +doctor_find_gh_url <- function(repo) { + remote <- gert::git_info(repo)$remote + if (is.na(remote)) { + throw(pkg_error( + call. = FALSE, + "Cannot determine GitHub URL from git remote in repository at + {.file {repo}}. Is your repository on GitHub?", + i = "If this repository is on GitHub, call + {.code git remote add origin } to add GitHub as a + remote.", + i = "Alternatively, specify the GitHub URL of the repository in + the {.arg gh_url} argument.", + i = "If it is not on GitHub, then you'll need to put it there. + Create a new repository at {.url https://github.com/new}." + )) + } + gert::git_remote_info(repo = repo)$url +} + +doctor_find_pat <- function(pat_url) { + pid <- cli_status("Do you have a GitHub personal access token (PAT)?") + # TODO: get GH URL from git remote, if any + tryCatch( + pat <- gitcreds::gitcreds_get(url = pat_url)$password, + gitcreds_nogit_error = function(e) { + cli::cli_status_clear(pid, result = "failed") + env <- gitcreds::gitcreds_cache_envvar(pat_url) + throw(pkg_error( + call. = FALSE, + "Could not find a GitHub personal access token (PAT) for {.url {pat_url}}.", + i = "I also could not find a working git installation. If you + don't want to install git, but you have a PAT, you can set the + {.env {env}} environment variable to the PAT.", + i = "You can read more about PATs at + {.url https://usethis.r-lib.org/articles/git-credentials.html}." + )) + }, + gitcreds_no_credentials = function(e) { + cli::cli_status_clear(pid, result = "failed") + env <- gitcreds::gitcreds_cache_envvar(pat_url) + throw(pkg_error( + call. = FALSE, + "Could not find a GitHub personal access token (PAT) for {.url {pat_url}}.", + i = "If you have a GitHub PAT, you can use {.run gitcreds::gitcreds_set()} + to add it to the git credential store, so R-hub can use it.", + i = "If you don't have a PAT, you can create one by running + {.run usethis::create_github_token()}.", + i = "You can read more about PATs at + {.url https://usethis.r-lib.org/articles/git-credentials.html}." + )) + }, + error = function(e) { + cli::cli_status_clear(pid, result = "failed") + throw(e) + } + ) + cli::cli_status_clear(pid, result = "clear") + cli::cli_alert_success("Found GitHub PAT.") + + pat +} + +doctor_check_github <- function(gh_url, resp) { + pid <- cli_status(cli::format_inline("Is the package on GitHub at {.url {gh_url}}?")) + if (!"x-ratelimit-limit" %in% names(resp$headers)) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "Remote repository at {.url {gh_url}} does not seem like a GitHub + repository.", + i = "R-hub only supports GitHub packages in GitHub repositories + currently.", + i = "If you think that this is a bug in the {pkg rhub2} package, + please let us know!" + )) + } + cli::cli_status_clear(pid, result = "clear") + cli::cli_alert_success( + "Found repository on GitHub at {.url {gh_url}}.", + wrap = TRUE + ) +} + +# we can assume a GH response at this point + +doctor_check_pat_scopes <- function(resp) { + pid <- cli_status("Does your GitHub PAT have the right scopes?") + scopes <- trimws(strsplit( + resp[["headers"]][["x-oauth-scopes"]] %||% "NOPE", + ",", + fixed = TRUE + )[[1]]) + + if (identical(scopes, "NOPE")) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "Could not use the PAT to authenticate to GitHub", + i = "Make sure that the URL and your PAT are correct." + )) + } + + if (!"repo" %in% scopes) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "Your PAT does not have a {.code repo} scope.", + i = "Withoput a {.code repo} scope R-hub cannot start jobs on GitHub.", + i = "Change the scoped of the PAT on the GitHub web page, or create + a new PAT." + )) + } + cli::cli_status_clear(pid, result = "clear") + cli::cli_alert_success("GitHub PAT has the right scopes.") +} + +doctor_check_workflow <- function(gh_url, gql, rest) { + pid <- cli_status( + "Does the default branch of your git repo have the R-hub workflow file?" + ) + + if (is.null(gql$workflow)) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "Could not find R-hub's workflow file in the repository at + {.url {gh_url}}.", + i = "The workflow file must be at {.path .github/workflows/rhub.yaml}.", + i = "If you have added and committed the workflow file, you need to + push the commit to GitHub with {.code git push}.", + i = if (isTRUE(gql$is_forked)) + "This repository is a fork. Make sure you enabled GitHub Actions + on it, in the {.emph Actions} tab of the repository web page." + )) + } + + if (rest$workflow$state != "active") { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "The workflow is disabled.", + i = "You need to enable it, click on the {.code ...} button at the + top right corner of the web page of the workflow." + )) + } + + cli::cli_status_clear(pid, result = "clear") + cli::cli_alert_success( + "Found R-hub workflow in default branch, and it is active." + ) +} + +# We need the following pieces: +# - check if we are indeed talking to GitHub +# - check that the token is valid, and we have access to the repo +# - check that the token has the right scopes +# - check that the workflow file exists on the default branch +# - check that the workflow file is the latest version + +doctor_async_gql <- function(gh_url, token) { + url <- parse_gh_url(gh_url) + query <- glue::glue("{ + repository(owner: \"\", name: \"\") { + workflow_file: object(expression: \"HEAD:.github/workflows/rhub.yaml\") { + ... on Blob { + isBinary + text + } + } + sha: object(expression: \"HEAD\") { + oid + } + branch: defaultBranchRef { + name + } + isFork + } + }", .open = "<", .close = ">") + async_gh_gql_get(url$graphql, query, token)$ + then(function(resp) { + data <- resp$content$data + list( + status_code = resp$status_code, + headers = resp$headers, + is_repo = !is.null(data$repository), + workflow_binary = data$repository$workflow_file$isBinary, + workflow = data$repository$workflow_file$text, + sha = data$repository$sha$oid, + branch = data$repository$branch$name, + is_fork = data$repository$isFork, + errors = resp$content$errors + ) + }) +} + +# Goal is to +# - check if workflow exist (e.g. not a form with disabled actions) +# - check that workflow is enabled + +doctor_async_rest <- function(gh_url, token) { + url <- parse_gh_url(gh_url) + ep <- glue::glue("/repos/{url$user}/{url$repo}/actions/workflows/rhub.yaml") + async_gh_rest_get(url$api, ep, token)$ + then(function(resp) { + list( + status_code = resp$status_code, + headers = resp$headers, + workflow = resp$content, + errors = resp$content$errors + ) + }) +} diff --git a/R/errors.R b/R/errors.R new file mode 100644 index 0000000..3f10eda --- /dev/null +++ b/R/errors.R @@ -0,0 +1,1198 @@ + +# nocov start + +# # Standalone file for better error handling ---------------------------- +# +# If can allow package dependencies, then you are probably better off +# using rlang's functions for errors. +# +# The canonical location of this file is in the processx package: +# https://github.com/r-lib/processx/blob/main/R/errors.R +# +# ## Dependencies +# - rstudio-detect.R for better printing in RStudio +# +# ## Features +# +# - Throw conditions and errors with the same API. +# - Automatically captures the right calls and adds them to the conditions. +# - Sets `.Last.error`, so you can easily inspect the errors, even if they +# were not caught. +# - It only sets `.Last.error` for the errors that are not caught. +# - Hierarchical errors, to allow higher level error messages, that are +# more meaningful for the users, while also keeping the lower level +# details in the error object. (So in `.Last.error` as well.) +# - `.Last.error` always includes a stack trace. (The stack trace is +# common for the whole error hierarchy.) The trace is accessible within +# the error, e.g. `.Last.error$trace`. The trace of the last error is +# also at `.Last.error.trace`. +# - Can merge errors and traces across multiple processes. +# - Pretty-print errors and traces, if the cli package is loaded. +# - Automatically hides uninformative parts of the stack trace when +# printing. +# +# ## API +# +# ``` +# new_cond(..., call. = TRUE, srcref = NULL, domain = NA) +# new_error(..., call. = TRUE, srcref = NULL, domain = NA) +# throw(cond, parent = NULL, frame = environment()) +# throw_error(cond, parent = NULL, frame = environment()) +# chain_error(expr, err, call = sys.call(-1)) +# chain_call(.NAME, ...) +# chain_clean_call(.NAME, ...) +# onload_hook() +# add_trace_back(cond, frame = NULL) +# format$advice(x) +# format$call(call) +# format$class(x) +# format$error(x, trace = FALSE, class = FALSE, advice = !trace, ...) +# format$error_heading(x, prefix = NULL) +# format$header_line(x, prefix = NULL) +# format$srcref(call, srcref = NULL) +# format$trace(x, ...) +# ``` +# +# ## Roadmap: +# - better printing of anonymous function in the trace +# +# ## NEWS: +# +# ### 1.0.0 -- 2019-06-18 +# +# * First release. +# +# ### 1.0.1 -- 2019-06-20 +# +# * Add `rlib_error_always_trace` option to always add a trace +# +# ### 1.0.2 -- 2019-06-27 +# +# * Internal change: change topenv of the functions to baseenv() +# +# ### 1.1.0 -- 2019-10-26 +# +# * Register print methods via onload_hook() function, call from .onLoad() +# * Print the error manually, and the trace in non-interactive sessions +# +# ### 1.1.1 -- 2019-11-10 +# +# * Only use `trace` in parent errors if they are `rlib_error`s. +# Because e.g. `rlang_error`s also have a trace, with a slightly +# different format. +# +# ### 1.2.0 -- 2019-11-13 +# +# * Fix the trace if a non-thrown error is re-thrown. +# * Provide print_this() and print_parents() to make it easier to define +# custom print methods. +# * Fix annotating our throw() methods with the incorrect `base::`. +# +# ### 1.2.1 -- 2020-01-30 +# +# * Update wording of error printout to be less intimidating, avoid jargon +# * Use default printing in interactive mode, so RStudio can detect the +# error and highlight it. +# * Add the rethrow_call_with_cleanup function, to work with embedded +# cleancall. +# +# ### 1.2.2 -- 2020-11-19 +# +# * Add the `call` argument to `catch_rethrow()` and `rethrow()`, to be +# able to omit calls. +# +# ### 1.2.3 -- 2021-03-06 +# +# * Use cli instead of crayon +# +# ### 1.2.4 -- 2021-04-01 +# +# * Allow omitting the call with call. = FALSE in `new_cond()`, etc. +# +# ### 1.3.0 -- 2021-04-19 +# +# * Avoid embedding calls in trace with embed = FALSE. +# +# ### 2.0.0 -- 2021-04-19 +# +# * Versioned classes and print methods +# +# ### 2.0.1 -- 2021-06-29 +# +# * Do not convert error messages to native encoding before printing, +# to be able to print UTF-8 error messages on Windows. +# +# ### 2.0.2 -- 2021-09-07 +# +# * Do not translate error messages, as this converts them to the native +# encoding. We keep messages in UTF-8 now. +# +# ### 3.0.0 -- 2022-04-19 +# +# * Major rewrite, use rlang compatible error objects. New API. +# +# ### 3.0.1 -- 2022-06-17 +# +# * Remove the `rlang_error` and `rlang_trace` classes, because our new +# deparsed `call` column in the trace is not compatible with rlang. +# +# ### 3.0.2 -- 2022-08-01 +# +# * Use a `procsrcref` column for processed source references. +# Otherwise testthat (and probably other rlang based packages), will +# pick up the `srcref` column, and they expect an `srcref` object there. +# +# ### 3.1.0 -- 2022-10-04 +# +# * Add ANSI hyperlinks to stack traces, if we have a recent enough +# cli package that supports this. +# +# ### 3.1.1 -- 2022-11-17 +# +# * Use `[[` instead of `$` to fix some partial matches. +# * Use fully qualified `base::stop()` to enable overriding `stop()` +# in a package. (Makes sense if compat files use `stop()`. +# * The `is_interactive()` function is now exported. +# +# ### 3.1.2 -- 2022-11-18 +# +# * The `parent` condition can now be an interrupt. + +err <- local({ + + # -- dependencies ----------------------------------------------------- + rstudio_detect <- rstudio$detect + + # -- condition constructors ------------------------------------------- + + #' Create a new condition + #' + #' @noRd + #' @param ... Parts of the error message, they will be converted to + #' character and then concatenated, like in [stop()]. + #' @param call. A call object to include in the condition, or `TRUE` + #' or `NULL`, meaning that [throw()] should add a call object + #' automatically. If `FALSE`, then no call is added. + #' @param srcref Alternative source reference object to use instead of + #' the one of `call.`. + #' @param domain Translation domain, see [stop()]. We set this to + #' `NA` by default, which means that no translation occurs. This + #' has the benefit that the error message is not re-encoded into + #' the native locale. + #' @return Condition object. Currently a list, but you should not rely + #' on that. + + new_cond <- function(..., call. = TRUE, srcref = NULL, domain = NA) { + message <- .makeMessage(..., domain = domain) + structure( + list(message = message, call = call., srcref = srcref), + class = c("condition")) + } + + #' Create a new error condition + #' + #' It also adds the `rlib_error` class. + #' + #' @noRd + #' @param ... Passed to [new_cond()]. + #' @param call. Passed to [new_cond()]. + #' @param srcref Passed tp [new_cond()]. + #' @param domain Passed to [new_cond()]. + #' @return Error condition object with classes `rlib_error`, `error` + #' and `condition`. + + new_error <- function(..., call. = TRUE, srcref = NULL, domain = NA) { + cond <- new_cond(..., call. = call., domain = domain, srcref = srcref) + class(cond) <- c("rlib_error_3_0", "rlib_error", "error", "condition") + cond + } + + # -- throwing conditions ---------------------------------------------- + + #' Throw a condition + #' + #' If the condition is an error, it will also call [stop()], after + #' signalling the condition first. This means that if the condition is + #' caught by an exiting handler, then [stop()] is not called. + #' + #' @noRd + #' @param cond Condition object to throw. If it is an error condition, + #' then it calls [stop()]. + #' @param parent Parent condition. + #' @param frame The throwing context. Can be used to hide frames from + #' the backtrace. + + throw <- throw_error <- function(cond, parent = NULL, frame = environment()) { + if (!inherits(cond, "condition")) { + cond <- new_error(cond) + } + if (!is.null(parent) && !inherits(parent, "condition")) { + throw(new_error("Parent condition must be a condition object")) + } + + if (isTRUE(cond[["call"]])) { + cond[["call"]] <- sys.call(-1) %||% sys.call() + } else if (identical(cond[["call"]], FALSE)) { + cond[["call"]] <- NULL + } + + cond <- process_call(cond) + + if (!is.null(parent)) { + cond$parent <- process_call(parent) + } + + # We can set an option to always add the trace to the thrown + # conditions. This is useful for example in context that always catch + # errors, e.g. in testthat tests or knitr. This options is usually not + # set and we signal the condition here + always_trace <- isTRUE(getOption("rlib_error_always_trace")) + .hide_from_trace <- 1L + # .error_frame <- cond + if (!always_trace) signalCondition(cond) + + if (is.null(cond$`_pid`)) cond$`_pid` <- Sys.getpid() + if (is.null(cond$`_timestamp`)) cond$`_timestamp` <- Sys.time() + + # If we get here that means that the condition was not caught by + # an exiting handler. That means that we need to create a trace. + # If there is a hand-constructed trace already in the error object, + # then we'll just leave it there. + if (is.null(cond$trace)) cond <- add_trace_back(cond, frame = frame) + + # Set up environment to store .Last.error, it will be just before + # baseenv(), so it is almost as if it was in baseenv() itself, like + # .Last.value. We save the print methods here as well, and then they + # will be found automatically. + if (! "org:r-lib" %in% search()) { + do.call("attach", list(new.env(), pos = length(search()), + name = "org:r-lib")) + } + env <- as.environment("org:r-lib") + env$.Last.error <- cond + env$.Last.error.trace <- cond$trace + + # If we always wanted a trace, then we signal the condition here + if (always_trace) signalCondition(cond) + + # If this is not an error, then we'll just return here. This allows + # throwing interrupt conditions for example, with the same UI. + if (! inherits(cond, "error")) return(invisible()) + .hide_from_trace <- NULL + + # Top-level handler, this is intended for testing only for now, + # and its design might change. + if (!is.null(th <- getOption("rlib_error_handler")) && + is.function(th)) { + return(th(cond)) + } + + # In non-interactive mode, we print the error + the traceback + # manually, to make sure that it won't be truncated by R's error + # message length limit. + out <- format( + cond, + trace = !is_interactive(), + class = FALSE, + full = !is_interactive() + ) + writeLines(out, con = default_output()) + + # Dropping the classes and adding "duplicate_condition" is a workaround + # for the case when we have non-exiting handlers on throw()-n + # conditions. These would get the condition twice, because stop() + # will also signal it. If we drop the classes, then only handlers + # on "condition" objects (i.e. all conditions) get duplicate signals. + # This is probably quite rare, but for this rare case they can also + # recognize the duplicates from the "duplicate_condition" extra class. + class(cond) <- c("duplicate_condition", "condition") + + # Turn off the regular error printing to avoid printing + # the error twice. + opts <- options(show.error.messages = FALSE) + on.exit(options(opts), add = TRUE) + + base::stop(cond) + } + + # -- rethrow with parent ----------------------------------------------- + + #' Re-throw an error with a better error message + #' + #' Evaluate `expr` and if it errors, then throw a new error `err`, + #' with the original error set as its parent. + #' + #' @noRd + #' @param expr Expression to evaluate. + #' @param err Error object or message to use for the child error. + #' @param call Call to use in the re-thrown error. See [throw()]. + + chain_error <- function(expr, err, call = sys.call(-1), srcref = NULL) { + .hide_from_trace <- 1 + force(call) + srcref <- srcref %||% utils::getSrcref(sys.call()) + withCallingHandlers({ + expr + }, error = function(e) { + .hide_from_trace <- 0:1 + e$srcref <- srcref + e$procsrcref <- NULL + if (!inherits(err, "condition")) { + err <- new_error(err, call. = call) + } + throw_error(err, parent = e) + }) + } + + # -- rethrowing conditions from C code --------------------------------- + + #' Version of .Call that throw()s errors + #' + #' It re-throws error from compiled code. If the error had class + #' `simpleError`, like all errors, thrown via `error()` in C do, it also + #' adds the `c_error` class. + #' + #' @noRd + #' @param .NAME Compiled function to call, see [.Call()]. + #' @param ... Function arguments, see [.Call()]. + #' @return Result of the call. + + chain_call <- function(.NAME, ...) { + .hide_from_trace <- 1:3 # withCallingHandlers + do.call + .handleSimpleError (?) + call <- sys.call() + call1 <- sys.call(-1) + srcref <- utils::getSrcref(call) + withCallingHandlers( + do.call(".Call", list(.NAME, ...)), + error = function(e) { + .hide_from_trace <- 0:1 + e$srcref <- srcref + e$procsrcref <- NULL + e[["call"]] <- call + name <- native_name(.NAME) + err <- new_error("Native call to `", name, "` failed", call. = call1) + cerror <- if (inherits(e, "simpleError")) "c_error" + class(err) <- c(cerror, "rlib_error_3_0", "rlib_error", "error", "condition") + throw_error(err, parent = e) + } + ) + } + + package_env <- topenv() + + #' Version of entrace_call that supports cleancall + #' + #' This function is the same as [entrace_call()], except that it + #' uses cleancall's [.Call()] wrapper, to enable resource cleanup. + #' See https://github.com/r-lib/cleancall#readme for more about + #' resource cleanup. + #' + #' @noRd + #' @param .NAME Compiled function to call, see [.Call()]. + #' @param ... Function arguments, see [.Call()]. + #' @return Result of the call. + + chain_clean_call <- function(.NAME, ...) { + .hide_from_trace <- 1:3 + call <- sys.call() + call1 <- sys.call(-1) + srcref <- utils::getSrcref(call) + withCallingHandlers( + package_env$call_with_cleanup(.NAME, ...), + error = function(e) { + .hide_from_trace <- 0:1 + e$srcref <- srcref + e$procsrcref <- NULL + e[["call"]] <- call + name <- native_name(.NAME) + err <- new_error("Native call to `", name, "` failed", call. = call1) + cerror <- if (inherits(e, "simpleError")) "c_error" + class(err) <- c(cerror, "rlib_error_3_0", "rlib_error", "error", "condition") + throw_error(err, parent = e) + } + ) + } + + # -- create traceback ------------------------------------------------- + + #' Create a traceback + #' + #' [throw()] calls this function automatically if an error is not caught, + #' so there is currently not much use to call it directly. + #' + #' @param cond Condition to add the trace to + #' @param frame Use this context to hide some frames from the traceback. + #' + #' @return A condition object, with the trace added. + + add_trace_back <- function(cond, frame = NULL) { + + idx <- seq_len(sys.parent(1L)) + frames <- sys.frames()[idx] + + # TODO: remove embedded objects from calls + calls <- as.list(sys.calls()[idx]) + parents <- sys.parents()[idx] + namespaces <- unlist(lapply( + seq_along(frames), + function(i) { + if (is_operator(calls[[i]])) { + "o" + } else { + env_label(topenvx(environment(sys.function(i)))) + } + } + )) + pids <- rep(cond$`_pid` %||% Sys.getpid(), length(calls)) + + mch <- match(format(frame), sapply(frames, format)) + if (is.na(mch)) { + visibles <- TRUE + } else { + visibles <- c(rep(TRUE, mch), rep(FALSE, length(frames) - mch)) + } + + scopes <- vapply(idx, FUN.VALUE = character(1), function(i) { + tryCatch( + get_call_scope(calls[[i]], namespaces[[i]]), + error = function(e) "" + ) + }) + + namespaces <- ifelse(scopes %in% c("::", ":::"), namespaces, NA_character_) + funs <- ifelse( + is.na(namespaces), + ifelse(scopes != "", paste0(scopes, " "), ""), + paste0(namespaces, scopes) + ) + funs <- paste0( + funs, + vapply(calls, function(x) format_name(x[[1]])[1], character(1)) + ) + visibles <- visibles & mark_invisible_frames(funs, frames) + + pcs <- lapply(calls, function(c) process_call(list(call = c))) + calls <- lapply(pcs, "[[", "call") + srcrefs <- I(lapply(pcs, "[[", "srcref")) + procsrcrefs <- I(lapply(pcs, "[[", "procsrcref")) + + cond$trace <- new_trace( + calls, + parents, + visibles = visibles, + namespaces = namespaces, + scopes = scopes, + srcrefs = srcrefs, + procsrcrefs = procsrcrefs, + pids + ) + + cond + } + + is_operator <- function(cl) { + is.call(cl) && length(cl) >= 1 && is.symbol(cl[[1]]) && + grepl("^[^.a-zA-Z]", as.character(cl[[1]])) + } + + mark_invisible_frames <- function(funs, frames) { + visibles <- rep(TRUE, length(frames)) + hide <- lapply(frames, "[[", ".hide_from_trace") + w_hide <- unlist(mapply(seq_along(hide), hide, FUN = function(i, w) { + i + w + }, SIMPLIFY = FALSE)) + w_hide <- w_hide[w_hide <= length(frames)] + visibles[w_hide] <- FALSE + + hide_from <- which(funs %in% names(invisible_frames)) + for (start in hide_from) { + hide_this <- invisible_frames[[ funs[start] ]] + for (i in seq_along(hide_this)) { + if (start + i > length(funs)) break + if (funs[start + i] != hide_this[i]) break + visibles[start + i] <- FALSE + } + } + + visibles + } + + invisible_frames <- list( + "base::source" = c("base::withVisible", "base::eval", "base::eval"), + "base::stop" = "base::.handleSimpleError", + "cli::cli_abort" = c( + "rlang::abort", + "rlang:::signal_abort", + "base::signalCondition"), + "rlang::abort" = c("rlang:::signal_abort", "base::signalCondition") + ) + + call_name <- function(x) { + if (is.call(x)) { + if (is.symbol(x[[1]])) { + as.character(x[[1]]) + } else if (x[[1]][[1]] == quote(`::`) || x[[1]][[1]] == quote(`:::`)) { + as.character(x[[1]][[2]]) + } else { + NULL + } + } else { + NULL + } + } + + get_call_scope <- function(call, ns) { + if (is.na(ns)) return("global") + if (!is.call(call)) return("") + if (is.call(call[[1]]) && + (call[[1]][[1]] == quote(`::`) || call[[1]][[1]] == quote(`:::`))) return("") + if (ns == "base") return("::") + if (! ns %in% loadedNamespaces()) return("") + name <- call_name(call) + nsenv <- asNamespace(ns)$.__NAMESPACE__. + if (is.null(nsenv)) return("::") + if (is.null(nsenv$exports)) return(":::") + if (exists(name, envir = nsenv$exports, inherits = FALSE)) { + "::" + } else if (exists(name, envir = asNamespace(ns), inherits = FALSE)) { + ":::" + } else { + "local" + } + } + + topenvx <- function(x) { + topenv(x, matchThisEnv = err_env) + } + + new_trace <- function (calls, parents, visibles, namespaces, scopes, srcrefs, procsrcrefs, pids) { + trace <- data.frame( + stringsAsFactors = FALSE, + parent = parents, + visible = visibles, + namespace = namespaces, + scope = scopes, + srcref = srcrefs, + procsrcref = procsrcrefs, + pid = pids + ) + trace[["call"]] <- calls + + class(trace) <- c("rlib_trace_3_0", "rlib_trace", "tbl", "data.frame") + trace + } + + env_label <- function(env) { + nm <- env_name(env) + if (nzchar(nm)) { + nm + } else { + env_address(env) + } + } + + env_address <- function(env) { + class(env) <- "environment" + sub("^.*(0x[0-9a-f]+)>$", "\\1", format(env), perl = TRUE) + } + + env_name <- function(env) { + if (identical(env, err_env)) { + return(env_name(package_env)) + } + if (identical(env, globalenv())) { + return(NA_character_) + } + if (identical(env, baseenv())) { + return("base") + } + if (identical(env, emptyenv())) { + return("empty") + } + nm <- environmentName(env) + if (isNamespace(env)) { + return(nm) + } + nm + } + + # -- S3 methods ------------------------------------------------------- + + format_error <- function(x, trace = FALSE, class = FALSE, + advice = !trace, full = trace, header = TRUE, + ...) { + if (has_cli()) { + format_error_cli(x, trace, class, advice, full, header, ...) + } else { + format_error_plain(x, trace, class, advice, full, header, ...) + } + } + + print_error <- function(x, trace = TRUE, class = TRUE, + advice = !trace, ...) { + writeLines(format_error(x, trace, class, advice, ...)) + } + + format_trace <- function(x, ...) { + if (has_cli()) { + format_trace_cli(x, ...) + } else { + format_trace_plain(x, ...) + } + } + + print_trace <- function(x, ...) { + writeLines(format_trace(x, ...)) + } + + cnd_message <- function(cond) { + paste(cnd_message_(cond, full = FALSE), collapse = "\n") + } + + cnd_message_ <- function(cond, full = FALSE) { + if (has_cli()) { + cnd_message_cli(cond, full) + } else { + cnd_message_plain(cond, full) + } + } + + # -- format API ------------------------------------------------------- + + format_advice <- function(x) { + if (has_cli()) { + format_advice_cli(x) + } else { + format_advice_plain(x) + } + } + + format_call <- function(call) { + if (has_cli()) { + format_call_cli(call) + } else { + format_call_plain(call) + } + } + + format_class <- function(x) { + if (has_cli()) { + format_class_cli(x) + } else { + format_class_plain(x) + } + } + + format_error_heading <- function(x, prefix = NULL) { + if (has_cli()) { + format_error_heading_cli(x, prefix) + } else { + format_error_heading_plain(x, prefix) + } + } + + format_header_line <- function(x, prefix = NULL) { + if (has_cli()) { + format_header_line_cli(x, prefix) + } else { + format_header_line_plain(x, prefix) + } + } + + format_srcref <- function(call, srcref = NULL) { + if (has_cli()) { + format_srcref_cli(call, srcref) + } else { + format_srcref_plain(call, srcref) + } + } + + # -- condition message with cli --------------------------------------- + + cnd_message_robust <- function(cond) { + class(cond) <- setdiff(class(cond), "rlib_error_3_0") + conditionMessage(cond) %||% + (if (inherits(cond, "interrupt")) "interrupt") %||% + "" + } + + cnd_message_cli <- function(cond, full = FALSE) { + exp <- paste0(cli::col_yellow("!"), " ") + add_exp <- is.null(names(cond$message)) + msg <- cnd_message_robust(cond) + + c( + paste0(if (add_exp) exp, msg), + if (inherits(cond$parent, "condition")) { + msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { + format(cond$parent, + trace = FALSE, + full = TRUE, + class = FALSE, + header = FALSE, + advice = FALSE + ) + } else if (inherits(cond$parent, "interrupt")) { + "interrupt" + } else { + conditionMessage(cond$parent) + } + add_exp <- substr(cli::ansi_strip(msg[1]), 1, 1) != "!" + if (add_exp) msg[1] <- paste0(exp, msg[1]) + c(format_header_line_cli(cond$parent, prefix = "Caused by error"), + msg + ) + } + ) + } + + # -- condition message w/o cli ---------------------------------------- + + cnd_message_plain <- function(cond, full = FALSE) { + exp <- "! " + add_exp <- is.null(names(cond$message)) + c( + paste0(if (add_exp) exp, cnd_message_robust(cond)), + if (inherits(cond$parent, "condition")) { + msg <- if (full && inherits(cond$parent, "rlib_error_3_0")) { + format(cond$parent, + trace = FALSE, + full = TRUE, + class = FALSE, + header = FALSE, + advice = FALSE + ) + } else if (inherits(cond$parent, "interrupt")) { + "interrupt" + } else { + conditionMessage(cond$parent) + } + add_exp <- substr(msg[1], 1, 1) != "!" + if (add_exp) { + msg[1] <- paste0(exp, msg[1]) + } + c(format_header_line_plain(cond$parent, prefix = "Caused by error"), + msg + ) + } + ) + } + + # -- printing error with cli ------------------------------------------ + + # Error parts: + # - "Error:" or "Error in " prefix, the latter if the error has a call + # - the call, possibly syntax highlightedm possibly trimmed (?) + # - source ref, with link to the file, potentially in a new line in cli + # - error message, just `conditionMessage()` + # - advice about .Last.error and/or .Last.error.trace + + format_error_cli <- function(x, trace = TRUE, class = TRUE, + advice = !trace, full = trace, + header = TRUE, ...) { + p_class <- if (class) format_class_cli(x) + p_header <- if (header) format_header_line_cli(x) + p_msg <- cnd_message_cli(x, full) + p_advice <- if (advice) format_advice_cli(x) else NULL + p_trace <- if (trace && !is.null(x$trace)) { + c("---", "Backtrace:", format_trace_cli(x$trace)) + } + + c(p_class, + p_header, + p_msg, + p_advice, + p_trace) + } + + format_header_line_cli <- function(x, prefix = NULL) { + p_error <- format_error_heading_cli(x, prefix) + p_call <- format_call_cli(x[["call"]]) + p_srcref <- format_srcref_cli(conditionCall(x), x$procsrcref %||% x$srcref) + paste0(p_error, p_call, p_srcref, if (!is.null(conditionCall(x))) ":") + } + + format_class_cli <- function(x) { + cls <- unique(setdiff(class(x), "condition")) + cls # silence codetools + cli::format_inline("{.cls {cls}}") + } + + format_error_heading_cli <- function(x, prefix = NULL) { + str_error <- if (is.null(prefix)) { + cli::style_bold(cli::col_yellow("Error")) + } else { + cli::style_bold(paste0(prefix)) + } + if (is.null(conditionCall(x))) { + paste0(str_error, ": ") + } else { + paste0(str_error, " in ") + } + } + + format_call_cli <- function(call) { + if (is.null(call)) { + NULL + } else { + cl <- trimws(format(call)) + if (length(cl) > 1) cl <- paste0(cl[1], " ", cli::symbol$ellipsis) + cli::format_inline("{.code {cl}}") + } + } + + format_srcref_cli <- function(call, srcref = NULL) { + ref <- get_srcref(call, srcref) + if (is.null(ref)) return("") + + link <- if (ref$file != "") { + if (Sys.getenv("R_CLI_HYPERLINK_STYLE") == "iterm") { + cli::style_hyperlink( + cli::format_inline("{basename(ref$file)}:{ref$line}:{ref$col}"), + paste0("file://", ref$file, "#", ref$line, ":", ref$col) + ) + } else { + cli::style_hyperlink( + cli::format_inline("{basename(ref$file)}:{ref$line}:{ref$col}"), + paste0("file://", ref$file), + params = c(line = ref$line, col = ref$col) + ) + } + } else { + paste0("line ", ref$line) + } + + cli::col_silver(paste0(" at ", link)) + } + + str_advice <- "Type .Last.error to see the more details." + + format_advice_cli <- function(x) { + cli::col_silver(str_advice) + } + + format_trace_cli <- function(x, ...) { + x$num <- seq_len(nrow(x)) + + scope <- ifelse( + is.na(x$namespace), + ifelse(x$scope != "", paste0(x$scope, " "), ""), + paste0(x$namespace, x$scope) + ) + + visible <- if ("visible" %in% names(x)) { + x$visible + } else { + rep(TRUE, nrow(x)) + } + + srcref <- if ("srcref" %in% names(x) || "procsrcref" %in% names(x)) { + vapply( + seq_len(nrow(x)), + function(i) format_srcref_cli(x[["call"]][[i]], x$procsrcref[[i]] %||% x$srcref[[i]]), + character(1) + ) + } else { + unname(vapply(x[["call"]], format_srcref_cli, character(1))) + } + + lines <- paste0( + cli::col_silver(format(x$num), ". "), + ifelse (visible, "", "| "), + scope, + vapply(seq_along(x$call), function(i) { + format_trace_call_cli(x$call[[i]], x$namespace[[i]]) + }, character(1)), + srcref + ) + + lines[!visible] <- cli::col_silver(cli::ansi_strip( + lines[!visible], + link = FALSE + )) + + lines + } + + format_trace_call_cli <- function(call, ns = "") { + envir <- tryCatch(asNamespace(ns), error = function(e) .GlobalEnv) + cl <- trimws(format(call)) + if (length(cl) > 1) { cl <- paste0(cl[1], " ", cli::symbol$ellipsis) } + # Older cli does not have 'envir'. + if ("envir" %in% names(formals(cli::code_highlight))) { + fmc <- cli::code_highlight(cl, envir = envir)[1] + } else { + fmc <- cli::code_highlight(cl)[1] + } + cli::ansi_strtrim(fmc, cli::console_width() - 5) + } + + # ---------------------------------------------------------------------- + + format_error_plain <- function(x, trace = TRUE, class = TRUE, + advice = !trace, full = trace, header = TRUE, + ...) { + p_class <- if (class) format_class_plain(x) + p_header <- if (header) format_header_line_plain(x) + p_msg <- cnd_message_plain(x, full) + p_advice <- if (advice) format_advice_plain(x) else NULL + p_trace <- if (trace && !is.null(x$trace)) { + c("---", "Backtrace:", format_trace_plain(x$trace)) + } + + c(p_class, + p_header, + p_msg, + p_advice, + p_trace) + } + + format_trace_plain <- function(x, ...) { + x$num <- seq_len(nrow(x)) + + scope <- ifelse( + is.na(x$namespace), + ifelse(x$scope != "", paste0(x$scope, " "), ""), + paste0(x$namespace, x$scope) + ) + + visible <- if ("visible" %in% names(x)) { + x$visible + } else { + rep(TRUE, nrow(x)) + } + + srcref <- if ("srcref" %in% names(x) || "procsrfref" %in% names(x)) { + vapply( + seq_len(nrow(x)), + function(i) format_srcref_plain(x[["call"]][[i]], x$procsrcref[[i]] %||% x$srcref[[i]]), + character(1) + ) + } else { + unname(vapply(x[["call"]], format_srcref_plain, character(1))) + } + + lines <- paste0( + paste0(format(x$num), ". "), + ifelse (visible, "", "| "), + scope, + vapply(x[["call"]], format_trace_call_plain, character(1)), + srcref + ) + + lines + } + + format_advice_plain <- function(x, ...) { + str_advice + } + + format_header_line_plain <- function(x, prefix = NULL) { + p_error <- format_error_heading_plain(x, prefix) + p_call <- format_call_plain(x[["call"]]) + p_srcref <- format_srcref_plain(conditionCall(x), x$procsrcref %||% x$srcref) + paste0(p_error, p_call, p_srcref, if (!is.null(conditionCall(x))) ":") + } + + format_error_heading_plain <- function(x, prefix = NULL) { + str_error <- if (is.null(prefix)) "Error" else prefix + if (is.null(conditionCall(x))) { + paste0(str_error, ": ") + } else { + paste0(str_error, " in ") + } + } + + format_class_plain <- function(x) { + cls <- unique(setdiff(class(x), "condition")) + paste0("<", paste(cls, collapse = "/"), ">") + } + + format_call_plain <- function(call) { + if (is.null(call)) { + NULL + } else { + cl <- trimws(format(call)) + if (length(cl) > 1) cl <- paste0(cl[1], " ...") + paste0("`", cl, "`") + } + } + + format_srcref_plain <- function(call, srcref = NULL) { + ref <- get_srcref(call, srcref) + if (is.null(ref)) return("") + + link <- if (ref$file != "") { + paste0(basename(ref$file), ":", ref$line, ":", ref$col) + } else { + paste0("line ", ref$line) + } + + paste0(" at ", link) + } + + format_trace_call_plain <- function(call) { + fmc <- trimws(format(call)[1]) + if (length(fmc) > 1) { fmc <- paste0(fmc[1], " ...") } + strtrim(fmc, getOption("width") - 5) + } + + # -- utilities --------------------------------------------------------- + + cli_version <- function() { + # this loads cli! + package_version(asNamespace("cli")[[".__NAMESPACE__."]]$spec[["version"]]) + } + + has_cli <- function() { + "cli" %in% loadedNamespaces() && cli_version() >= "3.3.0" + } + + `%||%` <- function(l, r) if (is.null(l)) r else l + + bytes <- function(x) { + nchar(x, type = "bytes") + } + + process_call <- function(cond) { + cond[c("call", "srcref", "procsrcref")] <- list( + call = if (is.null(cond[["call"]])) { + NULL + } else if (is.character(cond[["call"]])) { + cond[["call"]] + } else { + deparse(cond[["call"]], nlines = 2) + }, + srcref = NULL, + procsrcref = get_srcref(cond[["call"]], cond$procsrcref %||% cond$srcref) + ) + cond + } + + get_srcref <- function(call, srcref = NULL) { + ref <- srcref %||% utils::getSrcref(call) + if (is.null(ref)) return(NULL) + if (inherits(ref, "processed_srcref")) return(ref) + file <- utils::getSrcFilename(ref, full.names = TRUE)[1] + if (is.na(file)) file <- "" + line <- utils::getSrcLocation(ref) %||% "" + col <- utils::getSrcLocation(ref, which = "column") %||% "" + structure( + list(file = file, line = line, col = col), + class = "processed_srcref" + ) + } + + is_interactive <- function() { + opt <- getOption("rlib_interactive") + if (isTRUE(opt)) { + TRUE + } else if (identical(opt, FALSE)) { + FALSE + } else if (tolower(getOption("knitr.in.progress", "false")) == "true") { + FALSE + } else if (tolower(getOption("rstudio.notebook.executing", "false")) == "true") { + FALSE + } else if (identical(Sys.getenv("TESTTHAT"), "true")) { + FALSE + } else { + interactive() + } + } + + no_sink <- function() { + sink.number() == 0 && sink.number("message") == 2 + } + + rstudio_stdout <- function() { + rstudio <- rstudio_detect() + rstudio$type %in% c( + "rstudio_console", + "rstudio_console_starting", + "rstudio_build_pane", + "rstudio_job", + "rstudio_render_pane" + ) + } + + default_output <- function() { + if ((is_interactive() || rstudio_stdout()) && no_sink()) { + stdout() + } else { + stderr() + } + } + + onload_hook <- function() { + reg_env <- Sys.getenv("R_LIB_ERROR_REGISTER_PRINT_METHODS", "TRUE") + if (tolower(reg_env) != "false") { + registerS3method("format", "rlib_error_3_0", format_error, baseenv()) + registerS3method("format", "rlib_trace_3_0", format_trace, baseenv()) + registerS3method("print", "rlib_error_3_0", print_error, baseenv()) + registerS3method("print", "rlib_trace_3_0", print_trace, baseenv()) + registerS3method("conditionMessage", "rlib_error_3_0", cnd_message, baseenv()) + } + } + + native_name <- function(x) { + if (inherits(x, "NativeSymbolInfo")) { + x$name + } else { + format(x) + } + } + + # There is no format() for 'name' in R 3.6.x and before + format_name <- function(x) { + if (is.name(x)) { + as.character(x) + } else { + format(x) + } + } + + # -- public API -------------------------------------------------------- + + err_env <- environment() + parent.env(err_env) <- baseenv() + + structure( + list( + .internal = err_env, + new_cond = new_cond, + new_error = new_error, + throw = throw, + throw_error = throw_error, + chain_error = chain_error, + chain_call = chain_call, + chain_clean_call = chain_clean_call, + add_trace_back = add_trace_back, + process_call = process_call, + onload_hook = onload_hook, + is_interactive = is_interactive, + format = list( + advice = format_advice, + call = format_call, + class = format_class, + error = format_error, + error_heading = format_error_heading, + header_line = format_header_line, + srcref = format_srcref, + trace = format_trace + ) + ), + class = c("standalone_errors", "standalone")) +}) + +# These are optional, and feel free to remove them if you prefer to +# call them through the `err` object. + +new_cond <- err$new_cond +new_error <- err$new_error +throw <- err$throw +throw_error <- err$throw_error +chain_error <- err$chain_error +chain_call <- err$chain_call +chain_clean_call <- err$chain_clean_call + +# nocov end diff --git a/R/gh.R b/R/gh.R new file mode 100644 index 0000000..b9877cb --- /dev/null +++ b/R/gh.R @@ -0,0 +1,75 @@ + +parse_gh_url <- function(url) { + pcs <- parse_url(url) + host <- pcs$host + if (pcs$host == "github.com") { + api <- paste0(pcs$protocol, "://api.github.com") + graphql <- paste0(pcs$protocol, "://api.github.com/graphql") + } else { + api <- paste0(pcs$protocol, "://", pcs$host, "/api/v3") + graphql <- paste0(pcs$protocol, "://", pcs$host, "/api/graphql") + } + cmps <- strsplit(pcs$path, "/", fixed = TRUE)[[1]] + if (cmps[1] == "") cmps <- cmps[-1] + if (length(cmps) < 2) cmps <- c(cmps, "", "")[1:2] + cmps[2] <- sub("[.]git$", "", cmps[2]) + list( + host = host, + api = api, + graphql = graphql, + user = cmps[1], + repo = cmps[2], + slug = paste0(cmps[1], "/", cmps[2]) + ) +} + +gh_headers <- function(token) { + c( + Accept = "application/vnd.github+json", + Authorization = paste0("Bearer ", token) + ) +} + +gh_query_process_response <- function(resp) { + if (grepl("^application/json\\b", resp$type)) { + resp$content <- jsonlite::fromJSON( + rawToChar(resp$content), + simplifyVector = FALSE + ) + } + resp$headers <- curl::parse_headers_list(resp$headers) + resp +} + +gh_rest_get <- function(host, endpoint, token) { + synchronise(async_gh_rest_get(host, endpoint, token = token)) +} + +async_gh_rest_get <- function(host, endpoint, token) { + url <- paste0(host, endpoint) + headers <- gh_headers(token) + http_get(url, headers = headers)$ + then(gh_query_process_response) +} + +gh_rest_post <- function(host, endpoint, token, data) { + synchronise(async_gh_rest_post(host, endpoint, token, data)) +} + +async_gh_rest_post <- function(host, endpoint, token, data) { + url <- paste0(host, endpoint) + headers <- gh_headers(token) + http_post(url, data = data, headers = headers)$ + then(gh_query_process_response) +} + +gh_gql_get <- function(host, query, token) { + synchronise(async_gh_rest_get(host, query, token)) +} + +async_gh_gql_get <- function(host, query, token) { + headers <- gh_headers(token) + data <- jsonlite::toJSON(list(query = query), auto_unbox = TRUE) + http_post(host, headers = headers, data = data)$ + then(gh_query_process_response) +} diff --git a/R/http-cache.R b/R/http-cache.R new file mode 100644 index 0000000..b1f917d --- /dev/null +++ b/R/http-cache.R @@ -0,0 +1,18 @@ + +the_cache <- new.env(parent = emptyenv()) + +async_cached_http_get <- function(url, headers = character(), + options = list()) { + hash <- cli::hash_md5(paste0("http-get-", url)) + if (hash %in% names(the_cache)) { + async_constant(the_cache[[hash]]) + } else { + http_get(url, headers = headers, options = options)$ + then(http_stop_for_status)$ + then(function(response) { + json <- rawToChar(response$content) + the_cache[[hash]] <- json + json + }) + } +} diff --git a/R/platforms.R b/R/platforms.R new file mode 100644 index 0000000..80babdc --- /dev/null +++ b/R/platforms.R @@ -0,0 +1,200 @@ + +get_platforms <- function() { + url_platforms <- "https://raw.githubusercontent.com/r-hub/rhub2/v1/actions/rhub-setup/platforms.json" + url_containers <- "https://r-hub.github.io/containers/manifest.json" + ret <- synchronise(when_all( + async_cached_http_get(url_platforms), + async_cached_http_get(url_containers) + )) + ret +} + +#' List R-hub platforms +#' +#' @return Data frame with columns: +#' * `name`: platform name. Use this in the `platforms` argument of +#' [rhub_check()]. +#' * `aliases`: alternative platform names. They can also be used in the +#' `platforms` argument of [rhub_check()]. +#' * `type`: `"os"` or `"container"`. +#' * `os_type`: Linux, macOS or Windows currently. +#' * `container`: URL of the container image for container platforms. +#' * `github_os`: name of the OS on GitHub Actions for non-container +#' platforms. +#' * `r_version`: R version string. If `"*"` then any supported R version +#' can be selected for this platform. +#' * `os_name`: name of the operating system, including Linux distribution +#' name and version for container actions. +#' +#' @export + +rhub_platforms <- function() { + ret <- get_platforms() + platforms <- jsonlite::fromJSON(ret[[1]]) + containers <- jsonlite::fromJSON(ret[[2]], simplifyVector = FALSE)$containers + + res <- data_frame( + name = platforms[["name"]], + aliases = lapply(zip(platforms[["cran-names"]], platforms[["aliases"]]), unique), + type = platforms[["type"]], + os_type = platforms[["os-type"]], + container = platforms[["container"]], + github_os = platforms[["os"]], + r_version = platforms[["r-version"]], + os_name = NA_character_ + ) + + wcnt <- res$type == "container" + cnt_tags <- vcapply(containers, "[[", "tag") + res$r_version[wcnt] <- vcapply(res$container[wcnt], function(x) { + if (! x %in% cnt_tags) return(NA_character_) + sess <- containers[[match(x, cnt_tags)]]$builds[[1]]$`sessionInfo()` + strsplit(sess, "\n", fixed = TRUE)[[1]][1] + }) + + res$os_name[wcnt] <- vcapply(res$container[wcnt], function(x) { + if (! x %in% cnt_tags) return(NA_character_) + osr <- containers[[match(x, cnt_tags)]]$builds[[1]]$`/etc/os-release` + osr <- strsplit(osr, "\n", fixed = TRUE)[[1]] + pn <- grep("^PRETTY_NAME", osr, value = TRUE)[1] + pn <- sub("^PRETTY_NAME=", "", pn) + pn <- unquote(pn) + pn + }) + + res <- res[order(res$type == "container", res$name), ] + + res <- add_class(res, "rhub2_platforms") + res +} + +#' @export + +format.rhub2_platforms <- function(x, ...) { + ret <- character() + wvms <- which(x$type == "os") + wcts <- which(x$type == "container") + counter <- 1L + grey <- cli::make_ansi_style("gray70", grey = TRUE) + if (length(wvms)) { + vm <- if (has_emoji()) "\U1F5A5 " else "[VM] " + ret <- c(ret, cli::rule("Virtual machines")) + for (p in wvms) { + ret <- c( + ret, + paste0( + format(counter, width = 2), " ", vm, " ", + cli::style_bold(cli::col_blue(x$name[p])) + ), + if (x$r_version[p] == "*") { + grey(paste0(" All R versions on GitHub Actions ", x$github_os[p])) + } else { + x$r_version + } + ) + counter <- counter + 1L + } + } + if (length(wcts)) { + if (length(ret)) ret <- c(ret, "") + ret <- c(ret, cli::rule("Containers")) + for (p in wcts) { + ct <- if (has_emoji()) "\U1F40B" else "[CT] " + rv <- x$r_version[p] + os <- x$os_name[p] + al <- sort(unique(x$aliases[[p]])) + al <- if (length(al)) { + grey(paste0(" [", paste(al, collapse = ", "), "]")) + } else { + "" + } + ret <- c( + ret, + paste0( + format(counter, width = 2), " ", ct, " ", + cli::style_bold(cli::col_blue(x$name[p])), + al + ), + grey(paste0( + " ", + if (!is.na(rv)) rv, + if (!is.na(rv) && !is.na(os)) " on ", + if (!is.na(os)) os + )), + cli::style_italic(grey(paste0(" ", x$container[p]))) + ) + counter <- counter + 1L + } + } + + ret +} + +#' @export + +print.rhub2_platforms <- function(x, ...) { + writeLines(cli::ansi_strtrim(format(x, ...))) +} + +#' @export + +`[.rhub2_platforms` <- function(x, i, j, drop = FALSE) { + class(x) <- setdiff(class(x), "rhub2_platforms") + NextMethod("[") +} + +#' @export + +summary.rhub2_platforms <- function(object, ...) { + class(object) <- c("rhub2_platforms_summary", class(object)) + object +} + +#' @export + +format.rhub2_platforms_summary <- function(x, ...) { + num <- format(seq_len(nrow(x))) + icon <- if (!has_emoji()) { + ifelse(x$type == "os", "[VM]", "[CT]") + } else { + ifelse(x$type == "os", "\U1F5A5", "\U1F40B") + } + name <- cli::style_bold(cli::col_blue(x$name)) + rv <- abbrev_version(x$r_version) + os <- ifelse( + is.na(x$os_name), + paste0(x$github_os, " on GitHub"), + x$os_name + ) + + lines <- paste( + ansi_align_width(num), + ansi_align_width(icon), + ansi_align_width(name), + ansi_align_width(rv), + ansi_align_width(os) + ) + + trimws(lines, which = "right") +} + +#' @export + +print.rhub2_platforms_summary <- function(x, ...) { + writeLines(cli::ansi_strtrim(format(x, ...))) +} + +abbrev_version <- function(x) { + sel <- grepl("^R Under development", x) + x[sel] <- sub("R Under development [(]unstable[)]", "R-devel", x[sel]) + + sel <- grepl("R version [0-9.]+ Patched", x) + x[sel] <- sub("R version ([0-9.]+) Patched", "R-\\1 (patched)", x[sel]) + + sel <- grepl("R version [0-9.]+", x) + x[sel] <- sub("R version ([0-9.]+)", "R-\\1", x[sel]) + + x[x == "*"] <- "R-* (any version)" + + x +} diff --git a/R/rematch.R b/R/rematch.R new file mode 100644 index 0000000..6af12d9 --- /dev/null +++ b/R/rematch.R @@ -0,0 +1,36 @@ +re_match <- function(text, pattern, perl = TRUE, ...) { + + stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) + text <- as.character(text) + + match <- regexpr(pattern, text, perl = perl, ...) + + start <- as.vector(match) + length <- attr(match, "match.length") + end <- start + length - 1L + + matchstr <- substring(text, start, end) + matchstr[ start == -1 ] <- NA_character_ + + res <- data.frame( + stringsAsFactors = FALSE, + .text = text, + .match = matchstr + ) + + if (!is.null(attr(match, "capture.start"))) { + + gstart <- attr(match, "capture.start") + glength <- attr(match, "capture.length") + gend <- gstart + glength - 1L + + groupstr <- substring(text, gstart, gend) + groupstr[ gstart == -1 ] <- NA_character_ + dim(groupstr) <- dim(gstart) + + res <- cbind(groupstr, res, stringsAsFactors = FALSE) + } + + names(res) <- c(attr(match, "capture.names"), ".text", ".match") + res +} diff --git a/R/rhubv1.R b/R/rhubv1.R index 0366d09..df35d63 100644 --- a/R/rhubv1.R +++ b/R/rhubv1.R @@ -1,2394 +1,206 @@ - -baseurl <- function() { - paste0(Sys.getenv("RHUB_SERVER", "https://builder.r-hub.io"), "/api") -} - -rhub_server <- baseurl - -endpoints <- list( - c("GET PLATFORMS", "GET", "/platform/list", FALSE), - c("VALIDATE EMAIL", "POST", "/check/validate_email", FALSE), - c("SUBMIT PACKAGE", "POST", "/check/submit", FALSE), - c("GET STATUS", "POST", "/status", FALSE), - c("GET GROUP STATUS", "GET", "/status/group/:id", FALSE), - c("LIST BUILDS EMAIL", "GET", "/list/:email", TRUE), - c("LIST BUILDS PACKAGE", "GET", "/list/:email/:package", TRUE), - c("LIVE LOG", "GET", "/livelog/text/:id", FALSE) -) - -default_headers <- c( - "Accept" = "application/json", - "Content-Type" = "application/json", - "User-Agent" = "R-hub client" -) - -#' @importFrom httr GET POST DELETE add_headers -#' @importFrom jsonlite toJSON - -query <- function(endpoint, params = list(), data = NULL, - query = list(), headers = character(), as = NULL) { - - ep <- get_endpoint(endpoint, params) - headers <- update( - update(default_headers, ep$headers), - as.character(headers)) - - url <- paste0(baseurl(), ep$path) - - json <- if (!is.null(data)) toJSON(data) - - response <- if (ep$method == "GET") { - GET(url, add_headers(.headers = headers), query = query) - - } else if (ep$method == "POST") { - POST(url, add_headers(.headers = headers), body = json, query = query) - - } else if (ep$method == "DELETE") { - DELETE(url, add_headers(.headers = headers), query = query) - - } else { - stop("Unexpected HTTP verb, internal rhub error") - } - - report_error(response) - - parse_response(response, as = as) -} - -get_endpoint <- function(endpoint, params) { - - idx <- match(endpoint, vapply(endpoints, "[[", "", 1)) - if (is.na(idx)) stop("Unknown API endpoint: ", sQuote(endpoint)) - - method <- endpoints[[idx]][2] - path <- endpoints[[idx]][3] - - colons <- re_match_all(path, ":[a-zA-Z0-9_]+")$.match[[1]] - - for (col in colons) { - col1 <- substring(col, 2) - value <- params[[col1]] %||% stop("Unknown API parameter: ", col) - path <- gsub(col, value, path, fixed = TRUE) - } - - headers <- if (endpoints[[idx]][[4]]) { - if (is.null(params$token)) { - stop("Cannot find token, email address is not validated?") - } - c("Authorization" = paste("token", params$token)) - } - - list(method = method, path = path, headers = headers) -} - -#' @importFrom httr headers content -#' @importFrom jsonlite fromJSON - -parse_response <- function(response, as = NULL) { - - content_type <- headers(response)$`content-type` - - if (is.null(content_type) || length(content_type) == 0) { - content(response, as = "text") - - } else if (grepl("^application/json", content_type, ignore.case = TRUE)) { - if (is.null(as)) { - fromJSON(content(response, as = "text"), simplifyVector = FALSE) - } else { - content(response, as = as) - } - - } else { - content(response, as = "text") - } -} - -#' @importFrom assertthat assert_that on_failure<- - -is_pkg_dir <- function(path) { - file.exists(path) && - file.info(path)$isdir && - file.exists(file.path(path, "DESCRIPTION")) -} - -is_pkg_tarball <- function(path) { - file.exists(path) && - grepl("\\.tar\\.gz", path) -} - -is_pkg_dir_or_tarball <- function(path) { - is_pkg_tarball(path) || is_pkg_dir(path) -} - -on_failure(is_pkg_dir_or_tarball) <- function(call, env) { - paste0( - deparse(call$path), - " is not an R package directory or source R package" - ) -} - -is_string <- function(x) { - !is.null(x) && - is.character(x) && - length(x) == 1 && - !is.na(x) -} - -on_failure(is_string) <- function(call, env) { - paste0(deparse(call$x), " is not a string") -} - -is_string_or_null <- function(x) { - is_string(x) || is.null(x) -} - -on_failure(is_string_or_null) <- function(call, env) { - paste0(deparse(call$x), " is not a string and not NULL") -} - -is_email <- function(x) { - assert_that(is_string(x)) - grepl(".@.", x) -} - -on_failure(is_email) <- function(call, env) { - paste0(deparse(call$x), " is not an email address") -} - -is_flag <- function(x) { - !is.null(x) && - is.logical(x) && - length(x) == 1 && - !is.na(x) -} - -on_failure(is_flag) <- function(call, env) { - paste0(deparse(call$x), " is not a flag (length one logical)") -} - -is_named <- function(x) { - length(names(x)) == length(x) && - all(names(x) != "") -} - -on_failure(is_named) <- function(call, env) { - paste0(deparse(call$x), " does not have names") -} - -is_token <- function(x) { - assert_that(is_string(x)) - grepl("[a-zA-Z0-9]{6}", x, perl = TRUE) -} - -on_failure(is_token) <- function(call, env) { - paste0(deparse(call$x), " does not look like an R-hub token") -} - -is_check_ids <- function(x) { - is.character(x) && length(x) >= 1 && all(x != "") -} - -on_failure(is_check_ids) <- function(call, env) { - paste0(deparse(call$x), " is not a vector of check ids") -} - -is_count <- function(x) { - is.numeric(x) && length(x) == 1 && as.integer(x) == x -} - -on_failure(is_count) <- function(call, env) { - paste0(deparse(call$x), " is not a count (length 1 integer)") -} - -as_timeout <- function(x) { - if (inherits(x, "difftime")) return(x) - as.difftime(as.double(x), units = "secs") -} - -is_timeout <- function(x) { - inherits(x, "difftime") && length(x) == 1 && !is.na(x) -} - -on_failure(is_timeout) <- function(call, env) { - paste0(deparse(call$x), " must be a timeout, a 'difftime' constant") -} - -#' @importFrom withr with_dir -#' @importFrom callr rcmd_safe - -build_package <- function(path, tmpdir) { - - path <- normalizePath(path) - - dir.create(tmpdir) - file.copy(path, tmpdir, recursive = TRUE) - - ## If not a tar.gz, build it. Otherwise just leave it as it is. - if (file.info(path)$isdir) { - build_status <- with_dir( - tmpdir, - rcmd_safe("build", basename(path)) - ) - unlink(file.path(tmpdir, basename(path)), recursive = TRUE) - report_system_error("Build failed", build_status) - } - - file.path( - tmpdir, - list.files(tmpdir, pattern = "\\.tar\\.gz$") - ) -} - -#' @title R-hub check ids -#' @section R-hub ids: -#' -#' Every R-hub check has a unique id, that is constructed from the -#' name of the source package archive, and a random string. For example: -#' ```r -#' devtools_2.0.0.tar.gz-fe53bbba85de4a579f6dc3b852bf76a3 -#' ``` -#' -#' @section R-hub group ids: -#' -#' For every check submission, R-hub also creates a unique check group id. -#' One check group may contain multiple checks. E.g. [check_for_cran()] -#' typically creates three or four check groups. Group ids look the same -#' as individual check ids. -#' -#' @section Abbreviating ids: -#' -#' The rhub package keeps a list of all the checks that it has seen in the -#' current session, and these checks can be also referenced by any unique -#' prefix of the random string part of the id, e.g. in the [get_check()] -#' function. E.g. if rhub already know the devtools check above, then -#' ```r -#' get_check("fe53bbb") -#' ``` -#' works. -#' -#' This is only recommended in interactive mode, and we suggest that you -#' always use the full ids when using rhub programmatically. -#' -#' @name rhub-ids -NULL - -#' An `rhub_check` object holds status and results of rhub checks -#' -#' @section Usage: -#' ``` -#' ch <- rhub_check$new(ids = NULL, status = NULL, group = NULL) -#' ch$get_ids() -#' ch$update() -#' ch$print(...) -#' ch$browse(which = NULL) -#' ch$urls(which = NULL) -#' ch$livelog(which = 1) -#' ch$cran_summary() -#' ``` -#' -#' @section Arguments: -#' * `ch` An rhub check object. It can be created using [`check()`], -#' and other check functions including [`check_for_cran`]. -#' See also [last_check()]. -#' * `ids` Character vector of check ids. -#' * `status` Check status for `ids` or `group`. -#' * `group` Check group id, string scalar. Either `group` or `ids` must -#' be non-`NULL`. -#' * `...` Extra arguments are currently ignored. -#' * `which` Which check to show, if the object contains multiple -#' checks. For `browse` the default is all checks. For `livelog` the -#' default is the first check. A check can be selected via its number -#' or id. -#' -#' @section Details: -#' -#' An `rhub_check` object can be created by [check()], [list_my_checks()], -#' or [list_package_checks()]. [last_check()] returns the last check(s) -#' submitted from the current R session. Do not confuse `rhub_check`/`rhub_check_for_cran` -#' (classes) with [check()] or [check_for_cran()] (functions). -#' -#' `ch$get_ids()` returns the check ids. These can be used to query if a -#' check has finished. -#' -#' `ch$update()` updates the status of the check. Printing the check -#' status to the screen does not perform an update, unless the status of -#' the check(s) is unknown. -#' -#' `ch$print()` prints the status of the check(s) to the screen. -#' -#' `ch$cran_summary()` prints text to be copy-pasted in cran-comments.md, -#' it is especially useful on the output of [`check_for_cran()`]. -#' -#' `ch$browse()` opens a tab or window in the default web browser, that points -#' to the detailed logs of the check(s). -#' -#' `ch$urls()` return a [`tibble::tibble`] with URL to the html log, text log and artifacts -#' of the check(s). -#' -#' For both `ch$browse()` and `ch$urls()`, note that the logs and artifacts -#' are not kept forever, they are accessible for a few days after submission. -#' -#' `ch$livelog()` shows the live log of the check. The live log can be -#' interrupted using the usual interruption keyboard shortcut, usually -#' `CTRL+c` or `ESC`. -#' -#' @name rhub_check -NULL - -#' @importFrom R6 R6Class - -rhub_check <- R6Class( - "rhub_check", - - public = list( - - initialize = function(ids = NULL, status = NULL, group = NULL) - check_init(self, private, ids, status, group), - - get_ids = function() private$ids_, - - update = function() - check_update(self, private), - - print = function(...) - check_print(self, private, ...), - - web = function(which = NULL) - check_web(self, private, which), - - browse = function(which = NULL) - self$web(which), - - urls = function(which = NULL) - check_urls(self, private, which), - - livelog = function(which = 1) - check_livelog(self, private, which), - - cran_summary = function() - check_cran_summary(self, private) - ), - - private = list( - ids_ = NULL, # character vector of ids - group_ = NULL, # group id - status_ = NULL, # list of status objects, as in DB - status_updated_ = NULL # last time status was updated +deprecated <- function() { + message( + "This function is deprecated and defunct since rhub v2.\n", + "Please see `?rhubv2` on transitioning to the new rhub functions." ) -) - -check_init <- function(self, private, ids, status, group) { - assert_that( - is_check_ids(ids) || is.null(ids), - (is_check_ids(group) && length(group) == 1) || is.null(group), - !is.null(ids) || !is.null(group)) - - private$ids_ <- ids - private$group_ <- group - private$status_ <- status - status_updated_ <- Sys.time() - invisible(self) -} - -check_update <- function(self, private) { - ## If it is a group, we need to get the ids first. This also updates - ## the status of the individual checks - if (!is.null(private$group_) && is.null(private$ids_)) { - grp <- query("GET GROUP STATUS", list(id = private$group_)) - private$ids_ <- map_chr(grp, "[[", "id") - private$status_ <- grp - private$status_updated_ <- Sys.time() - for (i in seq_along(grp)) cache_put(grp[[i]]$id, grp[[i]]) - return(invisible(self)) - } - - ## Check which ones need update. We need to update if we don't know - ## anything about the id, or if it has not finished yet. - cached <- lapply(private$ids_, cache_get) - need_upd <- map_lgl(cached, function(x) { - is.null(x) || x$status %in% c("created", "in-progress") - }) - - if (any(need_upd)) { - ## Update - upd <- query("GET STATUS", data = list(id = private$ids_[need_upd])) - cached[need_upd] <- upd - - ## Update the cache - for (i in seq_along(upd)) cache_put(private$ids_[need_upd][i], upd[[i]]) - } - - ## Update the object, we always do this, in case the object is outdated, - ## but the cache is not - private$status_ <- cached - private$status_updated_ <- Sys.time() - - invisible(self) -} - -#' @importFrom utils browseURL - -check_web <- function(self, private, which) { - - ids <- select_ids(which = which, self = self, - private = private) - - urls <- paste0(sub("/api$", "/status/", baseurl()), ids) - - lapply(urls, browseURL) - invisible(self) -} - -check_urls <- function(self, private, which) { - - ids <- select_ids(which = which, self = self, - private = private) - - tibble::tibble(html = paste0(sub("/api$", "/status/", baseurl()), ids), - text = paste0(sub("/api$", "/status/original/", baseurl()), - ids), - artifacts = paste0("https://artifacts.r-hub.io/", ids), - stringsAsFactors = FALSE) -} - -select_ids <- function(which, self, private){ - ids <- if (is.null(which)) { - private$ids_ - } else if (is.numeric(which)) { - private$ids_[which] - } else if (is.character(which)) { - intersect(private$ids_, which) - } else { - stop("Unknown check selected", - call. = FALSE) - } - - return(ids) -} - -check_cran_summary <- function(self, private) { - - self$update() - - x <- private$status_ - - statuses <- map_chr(x, "[[", "status") - - if (any(statuses %in% c("in-progress", "created"))) { - stop(paste("At least one of the builds has not finished yet.", - "Please wait before calling `cran_summary()` again."), - call. = FALSE) - } - - if (any(statuses %in% problem_statuses())) { - platforms <- lapply(x, "[[", "platform") - platform_names <- map_chr(platforms, "[[", "name") - stop(paste("Build failures on platforms:", - toString(platform_names[statuses %in% problem_statuses()]), - ". \n", - "Read the log(s) to fix and if needed ask for help via ", - "https://docs.r-hub.io/#pkg-dev-help"), - call. = FALSE) - } - - result <- do.call("rbind", - lapply(x, rectangle_status)) - - systems <- paste0("- R-hub ", - vapply(x, function(xx) xx$platform$name, ""), - " (", - vapply(x, function(xx) xx$platform$rversion, ""), - ")") - lines <- paste0(systems, "\n") - - - result <- result[!is.na(result$type),] - - if (nrow(result) > 0){ - message("For a CRAN submission we recommend that you fix all NOTEs, WARNINGs and ERRORs.") - unique_results <- unique(result[, c("type", "hash")]) - - makeshift <- structure( - list( - package = x$package, - version = toString(vapply(x, function(xx) xx$platform$name, "")), - rversion = toString(systems), - output = list(), - platform = toString(systems), - notes = unlist(lapply(unique(unique_results$hash[unique_results$type == "NOTE"]), - combine_message, result = result)), - warnings = unlist(lapply(unique(unique_results$hash[unique_results$type == "WARNING"]), - combine_message, result = result)), - errors = unlist(lapply(unique(unique_results$hash[unique_results$type == "ERROR"]), - combine_message, result = result)) - ), - class = "rcmdcheck" - ) - - } else { - makeshift <- structure( - list( - package = x$package, - version = toString(vapply(x, function(xx) xx$platform$name, "")), - rversion = toString(systems), - output = list(), - platform = toString(systems), - notes = NULL, - warnings = NULL, - errors = NULL - ), - class = "rcmdcheck" - ) - } - - cat("## Test environments\n") - cat(lines, sep = "") - cat("\n") - cat("## R CMD check results\n") - print(makeshift, header = FALSE) - - invisible(self) -} - - -get_status_part <- function(part, x){ - output <- unlist(x[part]) - if(is.null(output)){ - return("") - }else{ - output - } -} - -rectangle_status <- function(x){ - - df <- rbind(data.frame(type = "ERROR", - message = get_status_part("errors", x$result), - stringsAsFactors = FALSE), - data.frame(type = "WARNING", - message = get_status_part("warnings", x$result), - stringsAsFactors = FALSE), - data.frame(type = "NOTE", - message = get_status_part("notes", x$result), - stringsAsFactors = FALSE)) - - df <- df[df$message != "",] - - if(nrow(df) == 0){ - df <- data.frame(package = x$package, - type = NA, - message = NA, - hash = NA) - } else{ - df$hash <- hash_check(df$message) - } - - df$package <- x$package - df$version <- x$version - df$submitted <- x$submitted - df$platform <- paste0(x$platform$name, " (", x$platform$rversion, - ")") - - return(df) -} - -combine_message <- function(hash, result){ - paste0("On ", toString(result$platform[result$hash == hash]), "\n", - result$message[result$hash == hash][1]) -} - -# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/968fd9ba76ee9b7bf65d192568555ab57160165e/R/parse.R#L110 -#' @importFrom digest digest - -hash_check <- function(check) { - cleancheck <- gsub("[^a-zA-Z0-9]", "", first_line(check)) - vapply(cleancheck, digest::digest, "") } -# from rcmdcheck https://github.com/r-lib/rcmdcheck/blob/afadc6c53310cad2b64e0a58e399efd1ae18d7dd/R/utils.R#L91 -first_line <- function(x) { - l <- strsplit(x, "\n", fixed = TRUE) - vapply(l, "[[", "", 1) -} - -#' Retrieve the result of R-hub checks -#' -#' @param ids One of the following: -#' - A single R-hub check id. -#' - A character vector of check ids. -#' - An R-hub check group id. -#' All ids can be abbreviated, see [R-hub ids][rhub-ids]. -#' @return An [rhub_check] object. -#' -#' @section Examples: -#' ``` -#' chk <- get_check("915ee61") -#' chk -#' chk$update() -#' chk$browse() -#' chk$cran_summary() -#' chk$urls() -#' ``` +#' This function is deprecated and defunct. Please see [rhubv2]. #' +#' @param ... Deprecated. #' @export -#' @seealso [list_my_checks()] and [list_package_checks()] to list -#' R-hub checks. -get_check <- function(ids) { - assert_that(is_check_ids(ids)) - - short <- grep(re_id, ids, invert = TRUE, value = TRUE) - if (length(short) && - length(package_data$ids) == 0 && - length(package_data$groups) == 0) { - stop( - "Short check id '", short[1], "' ", - if (length(short) > 1) paste0("(and ", length(short)-1, " more) "), - "can only be used for cached ids, and no ids are cached yet.\n", - " Try calling `list_my_checks()` or `list_package_checks()` first." - ) - } - - sle <- cache_get_ids(ids) - grp <- cache_get_group_ids(ids) - - err <- NULL - - ## If we are not sure that it is a group id, then query single ids - res <- if (length(ids) > 1 || is.na(grp)) { - ids2 <- ifelse(is.na(sle), ids, sle) - tryCatch( - rhub_check$new(ids2)$update(), - error = function(e) { err <<- e; NULL } - ) - } - - if (!is.null(res)) return(res) - - ## If there is a chance that it is a group, then we try that as well - if (length(ids) == 1 && is.na(sle)) { - ids3 <- if (is.na(grp)) ids else grp - res <- rhub_check$new(group = ids3)$update() - res - } else { - stop(err) - } +get_check <- function(...) { + deprecated() } -re_id <- "-[0-9a-f]{32}$" - -#' Check an R-package on R-hub, for a CRAN submission -#' -#' This function calls [check()] with arguments and platforms, that -#' are suggested for a CRAN submission. -#' -#' In particular, if `platforms` is `NULL` (the default), then -#' * It checks the package on Windows, and Linux. -#' * It checks the package on R-release and R-devel. -#' * It uses the `--as-cran` argument to `R CMD check`. -#' * It requires all dependencies, including suggested ones. -#' -#' @details This function is wrapped by `devtools::check_rhub()` which you -#' might find useful if you load `devtools` via your .Rprofile (see `usethis::use_devtools()`). -#' -#' @param check_args Arguments for `R CMD check`. By default `--as-cran` -#' is used. -#' @param env_vars Character vector of environment variables to set on the builder. -#' By default `_R_CHECK_FORCE_SUGGESTS_="true"` is set, to require all packages used. -#' `_R_CHECK_CRAN_INCOMING_USE_ASPELL_="true"` is also set, to use the -#' spell checker. -#' @param ... Additional arguments are passed to [check()]. -#' @inheritParams check -#' @return An [rhub_check] object. +#' This function is deprecated and defunct. Please see [rhubv2]. #' +#' @param ... Deprecated. #' @export -#' @examples -#' \dontrun{ -#' ch <- check_for_cran("package", show_status = FALSE) -#' ch$update() -#' ch$livelog(3) -#' } - -check_for_cran <- function( - path = ".", email = NULL, check_args = "--as-cran", - env_vars = c("_R_CHECK_FORCE_SUGGESTS_" = "true", - "_R_CHECK_CRAN_INCOMING_USE_ASPELL_" = "true"), platforms = NULL, - ...) { - - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - - platforms <- platforms %||% default_cran_check_platforms(path) - check(path = path, platforms = platforms, email = email, - check_args = check_args, env_vars = env_vars, ...) +check_for_cran <- function(...) { + deprecated() } -default_cran_check_platforms <- function(path) { - c( - "windows-x86_64-devel", - "ubuntu-gcc-release", - "fedora-clang-devel", - if (needs_compilation(path)) "linux-x86_64-rocker-gcc-san" - ) -} - -## Various OSes -------------------------------------------------------- - -#' Check an R package on an R-hub platform -#' -#' These functions provide a quick easy to use interface to check a -#' package on a platform with some particular aspect. Which platform -#' they use might change over time. -#' -#' @param ... Additional arguments are passed to [check()]. -#' @return An [rhub_check] object. -#' @inheritParams check +#' This function is deprecated and defunct. Please see [rhubv2]. #' +#' @param ... Deprecated. #' @export #' @rdname check_shortcuts -check_on_linux <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$linux, ...) +check_on_linux <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_windows <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$windows, ...) +check_on_windows <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_macos <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$macos, ...) +check_on_macos <- function(...) { + deprecated() } -## Various Linux OSes -------------------------------------------------- - #' @export #' @rdname check_shortcuts -check_on_debian <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$debian, ...) +check_on_debian <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_ubuntu <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$ubuntu, ...) +check_on_ubuntu <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_fedora <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$fedora, ...) +check_on_fedora <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_solaris <- function(path = ".", check_args = - "'--no-manual --no-build-vignettes'", ...) { - check(path = path, platforms = check_shortcut_platforms$solaris, - check_args = check_args, ...) +check_on_solaris <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_on_centos <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$centos, ...) +check_on_centos <- function(...) { + deprecated() } -## R versions -------------------------------------------------------- - #' @export #' @rdname check_shortcuts -check_with_roldrel <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$roldrel, ...) +check_with_roldrel <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_with_rrelease <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rrelease, ...) +check_with_rrelease <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_with_rpatched <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rpatched, ...) +check_with_rpatched <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_with_rdevel <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$rdevel, ...) +check_with_rdevel <- function(...) { + deprecated() } -## Extra checks -------------------------------------------------------- - #' @export #' @rdname check_shortcuts -check_with_valgrind <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$valgrind, - valgrind = TRUE, ...) +check_with_valgrind <- function(...) { + deprecated() } #' @export #' @rdname check_shortcuts -check_with_sanitizers <- function(path = ".", ...) { - check(path = path, platforms = check_shortcut_platforms$sanitizers, ...) +check_with_sanitizers <- function(...) { + deprecated() } -## ------------------------------------------------------------------- - - -check_shortcut_platforms <- list( - "linux" = "debian-gcc-release", - "windows" = "windows-x86_64-release", - "macos" = "macos-highsierra-release", - "valgrind" = "debian-gcc-release", - "sanitizers" = "linux-x86_64-rocker-gcc-san", - "roldrel" = "windows-x86_64-oldrel", - "rrelease" = "debian-gcc-release", - "rpatched" = "debian-gcc-patched", - "rdevel" = "debian-gcc-devel", - "debian" = "debian-gcc-release", - "ubuntu" = "ubuntu-gcc-release", - "fedora" = "fedora-gcc-devel", - "centos" = "linux-x86_64-centos6-epel", - "solaris" = "solaris-x86-patched" -) - -#' Check an R package on R-hub +#' This function is deprecated and defunct. Please see [rhubv2]. #' -#' @param path Path to a directory containing an R package, or path to -#' source R package tarball built with `R CMD build` or -#' `devtools::build()`. -#' @param platforms A character vector of one or more platforms to build/check -#' the package on. See [platforms()] for the available platforms. If this is -#' \code{NULL}, and the R session is interactive, then a menu is shown. If it -#' is \code{NULL}, and the session is not interactive, then the default R-hub -#' platforms are used. A vector of platforms which saves time by building one -#' R package tarball that is used for all the platforms specified. -#' @param email Email address to send notification to about the check. -#' It must be a validated email address, see [validate_email()]. If -#' `NULL`, then the email address of the maintainer is used, as defined -#' in the `DESCRIPTION` file of the package. -#' @param valgrind Whether to run the check in valgrind. Only supported on -#' Linux currently, and ignored on other platforms. -#' @param check_args Extra arguments for the `R CMD check` command. -#' @param env_vars Environment variables to set on the builder machine -#' before the check. A named character vector. -#' @param show_status Whether to show the status of the build and check -#' (live log) as it is happening. -#' @return An [rhub_check] object. -#' -#' @export -#' @examples -#' \dontrun{ -#' check(".") -#' check("mypackage_1.0.0.tar.gz", platforms = "fedora-clang-devel") -#' } - -check <- function(path = ".", platforms = NULL, - email = NULL, valgrind = FALSE, check_args = character(), - env_vars = character(), show_status = interactive()) { - - ## Check that it is a package - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - assert_that(is_flag(valgrind)) - assert_that(is_named(env_vars)) - assert_that(is.character(env_vars)) - - ## Make sure that maintainer email was validated - if (is.null(email)) email <- get_maintainer_email(path) - if (is.na(email)) stop("Cannot get email address from package") - assert_validated_email_for_check(email) - - platforms <- match_platform(platforms) - - ## Build the tar.gz, if needed - if (file.info(path)$isdir) { - header_line("Building package") - pkg_targz <- build_package(path, tmpdir <- tempfile()) - } else { - pkg_targz <- path - } - - ## Add valgrind to check_args - check_args <- c( - check_args, - if (valgrind) "--use-valgrind" - ) - - ## Submit to R-hub - response <- submit_package( - email, - pkg_targz, - platforms = platforms, - check_args = check_args, - env_vars = env_vars - ) - - ids <- vapply(response, "[[", "", "id") - chk <- rhub_check$new(ids = ids) - - package_data$last_handle <- chk - lapply(ids, cache_put, status = NULL) - - ## Show the live status, if requested - if (show_status) chk$livelog() - - invisible(chk) -} - -assert_validated_email_for_check <- function(email) { - - assert_that(is_email(email)) - code <- email_get_token(email) - if (is.null(code)) { - if (is_interactive()) { - cat("\n") - message(paste(collapse = "\n", strwrap(indent = 2, exdent = 2, paste0( - sQuote(crayon::green(email)), " is not validated, or does not match ", - "the package maintainer's email. To validate it now, please enter ", - "the email address below. Note that R-hub will send a token to ", - "this address. If the address does not belong to you, quit now by ", - "pressing ", crayon::yellow("ENTER"), ". You can also specify a ", - "different email by suppling email=." - )))) - cat("\n") - email2 <- readline(" Email address: ") - cat("\n") - if (email2 == "") { - stop("Aborting.", call. = FALSE) - } else if (email != email2) { - stop("Emails don't match, aborting", call. = FALSE) - } - validate_email(email) - } else { - stop(sQuote(email), " is not validated") - } - } -} - -column_dt <- function(x) { - as.difftime(x / 1000, units = "secs") -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple -#' @importFrom prettyunits pretty_dt -#' @export - -pillar_shaft.difftime <- function(x, ...) { - cx <- my_pretty_dt(x) - new_pillar_shaft_simple(cx, ...) -} - -column_group_id <- function(x) { - structure(x, class = unique(c("rhub_column_group_id", class(x)))) -} - -#' @export - -`[.rhub_column_group_id` <- function(x, i) { - column_group_id(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' @param ... Deprecated. #' @export -pillar_shaft.rhub_column_group_id <- function(x, ...) { - cx <- shorten_rhub_id(x) - new_pillar_shaft_simple(cx, ...) +check <- function(...) { + deprecated() } -#' @importFrom pillar type_sum -#' @export - -type_sum.rhub_column_group_id <- function(x) { - "rhub::group_id" -} - -column_id <- function(x) { - structure(x, class = unique(c("rhub_column_id", class(x)))) -} - -#' @export - -`[.rhub_column_id` <- function(x, i) { - column_id(NextMethod("[")) -} - -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -pillar_shaft.rhub_column_id <- function(x, ...) { - cx <- shorten_rhub_id(x) - new_pillar_shaft_simple(cx, ...) +validate_email <- function(...) { + deprecated() } -#' @importFrom pillar type_sum +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -type_sum.rhub_column_id <- function(x) { - "rhub::id" -} -column_result <- function(x) { - structure(x, class = unique(c("rhub_column_result", class(x)))) +list_validated_emails <- function(...) { + deprecated() } +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -`[.rhub_column_result` <- function(x, i) { - column_result(NextMethod("[")) +last_check <- function(...) { + deprecated() } -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -pillar_shaft.rhub_column_result <- function(x, ...) { - cx <- lapply(x, color_column_result) - new_pillar_shaft_simple(cx, ...) -} - -color_column_result <- function(x) { - if (is.null(x)) return("in-progress") - E <- if (n <- length(x$errors)) status_style_error(strrep("E", n)) - W <- if (n <- length(x$warnings)) status_style_error(strrep("W", n)) - N <- if (n <- length(x$notes)) status_style_note(strrep("N", n)) - - switch( - x$status, - "parseerror" = status_style_error("parseerror"), - "preperror" = status_style_error("preperror"), - "aborted" = status_style_aborted("aborted"), - "ok" = status_style_ok("ok"), - paste0(E, W, N)) +list_my_checks <- function(...) { + deprecated() } -#' @importFrom pillar type_sum +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -type_sum.rhub_column_result <- function(x) { - "rhub::result" -} - -column_status <- function(x) { - structure(x, class = unique(c("rhub_column_status", class(x)))) +list_package_checks <- function(...) { + deprecated() } +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -`[.rhub_column_status` <- function(x, i) { - column_status(NextMethod("[")) +local_check_linux <- function(...) { + deprecated() } -#' @importFrom pillar pillar_shaft new_pillar_shaft_simple +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -pillar_shaft.rhub_column_status <- function(x, ...) { - ## status can be - ## - created - ## - in-progress - ## - parseerror (the R-hub output parser failed) - ## - preperror (build failed before R CMD check has started - ## - aborted (build was aborted) - ## - error - ## - warning - ## - note - ## - ok - - hst <- c( - "created" = status_style_created("created"), - "in-progress" = status_style_in_progress("in-progress"), - "parseerror" = status_style_error("parseerror"), - "preperror" = status_style_error("preperror"), - "aborted" = status_style_aborted("aborted"), - "error" = status_style_error("error"), - "warning" = status_style_error("warning"), - "note" = status_style_note("note"), - "ok" = status_style_ok("ok")) - - cx <- hst[x] - cx[is.na(cx)] <- x[is.na(cx)] - - new_pillar_shaft_simple(cx, ...) +local_check_linux_images <- function(...) { + deprecated() } -#' @importFrom pillar type_sum +#' This function is deprecated and defunct. Please see [rhubv2]. +#' +#' @param ... Deprecated. #' @export -type_sum.rhub_column_status <- function(x) { - "rhub::status" -} - -#' Validate an email address on R-hub -#' -#' To build and check R packages on R-hub, you need to validate your -#' email address. This is because R-hub sends out emails about check -#' results. -#' -#' The `rhub` package stores validated email addresses in a user -#' configuration file, at a platform-dependent location. -#' On your current platform the file is at -#' \Sexpr[stage=render]{rhub:::email_file()}. -#' -#' To validate a new email address, call this function from an interactive -#' R session, without any arguments. -#' -#' To add an email address that was validated before (probably on another -#' machine), to the configuration file, call this function with the `email` -#' and `token` arguments. -#' -#' @param email The email address to validate. -#' @param token Token obtained from `rhub`, to validate the email address. -#' -#' @family email validation -#' @export -#' @importFrom jsonlite unbox - -validate_email <- function(email = NULL, token = NULL) { - - if (is.null(email) || is.null(token)) { - if (!is_interactive()) { - stop("No email or no token and not in interactive mode") - } - return(validate_email_interactive(email, token)) - } - - assert_that(is_email(email)) - assert_that(is_token(token)) - - email_add_token(email, token) - message("Token added for ", sQuote(email)) - cat("\n") - token_file_msg() - cat("\n") - invisible() -} - -#' @importFrom cli symbol -#' @importFrom utils menu -#' @importFrom whoami email_address - -get_email_to_validate <- function(path) { - - ## Find out email first. List currently validated addresses, - ## Offer address by whoami::email_address(), and also the - ## maintainer address, if any. - - valid <- list_validated_emails2(msg_if_empty = FALSE) - guess <- email_address() - maint <- tryCatch(get_maintainer_email(path), error = function(e) NULL) - - choices <- rbind( - if (nrow(valid)) cbind(valid = TRUE, valid), - if (!is.null(guess) && ! guess %in% valid$email) { - data_frame(valid = FALSE, email = guess, token = NA) - }, - if (!is.null(maint) && ! maint %in% valid$email && maint != guess) { - data_frame(valid = FALSE, email = maint, token = NA) - }, - data_frame(valid = NA, email = "New email address", token = NA) - ) - - ## Only show the menu if there is more than one thing there - if (nrow(choices) != 1) { - choices_str <- paste( - sep = " ", - ifelse( - choices$valid & !is.na(choices$valid), - crayon::green(symbol$tick), - " " - ), - choices$email - ) - - cat("\n") - title <- crayon::yellow(paste0( - symbol$line, symbol$line, - " Choose email address to (re)validate (or 0 to exit)" - )) - ch <- menu(choices_str, title = title) - - if (ch == 0) stop("Cancelled email validation", call. = FALSE) - - } else { - ch <- 1 - } - - ## Get another address if that is selected - if (is.na(choices$valid[ch])) { - cat("\n") - email <- readline("Email address: ") - } else { - email <- choices$email[ch] - } -} - -validate_email_interactive <- function(email, token, path = ".") { - - if (is.null(email)) email <- get_email_to_validate(path) - assert_that(is_email(email)) - - ## Token next. For this we need to make an API query. - if (is.null(token)) { - query("VALIDATE EMAIL", data = list(email = unbox(email))) - message(crayon::yellow( - "Please check your emails for the R-hub access token." - )) - token <- readline("Token: ") - } - assert_that(is_token(token)) - - ## We got everything now - validate_email(email, token) -} - -#' List validated email addresses -#' -#' @description List email addresses validated on R-hub on the current machine. -#' -#' @return A `data.frame` with two columns: `email` and `token`. -#' If in interactive mode, and there are no validated email addresses, -#' then a message is printed and the data frame is returned invisibly. -#' -#' @family email validation -#' @export - -list_validated_emails <- function() { - list_validated_emails2() -} - -list_validated_emails2 <- function(msg_if_empty = TRUE) { - file <- email_file() - res <- if (file.exists(file)) { - if (is_interactive()) { - token_file_msg() - } - - structure( - read.csv(file, stringsAsFactors = FALSE, header = FALSE), - names = c("email", "token") - ) - } else { - data.frame( - email = character(), - token = character(), - stringsAsFactors = FALSE - ) - } - if (is_interactive() && nrow(res) == 0) { - if (msg_if_empty) message("No validated emails found.") - invisible(res) - } else { - res - } -} - -#' @importFrom rappdirs user_data_dir - -email_file <- function() { - rhub_data_dir <- user_data_dir("rhub", "rhub") - file.path(rhub_data_dir, "validated_emails.csv") -} - -#' @importFrom utils read.csv - -email_get_token <- function(email) { - file <- email_file() - if (! file.exists(file)) return(NULL) - - tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) - if (! email %in% tokens[,1]) return(NULL) - - tokens[match(email, tokens[,1]), 2] -} - -## If it exists already, then overwrites - -#' @importFrom utils read.csv write.table - -email_add_token <- function(email, token) { - - assert_that(is_email(email)) - assert_that(is_token(token)) - - file <- email_file() - - if (!file.exists(file)) { - parent <- dirname(file) - if (!file.exists(parent)) dir.create(parent, recursive = TRUE) - tokens <- data.frame( - V1 = character(), - V2 = character(), - stringsAsFactors = FALSE - ) - - } else { - tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) - } - - if (! email %in% tokens[,1]) { - tokens <- rbind(tokens, c(email, token)) - - } else{ - tokens[match(email, tokens[,1]), 2] <- token - } - - write.table( - tokens, - file = file, - sep = ",", - col.names = FALSE, - row.names = FALSE - ) - - invisible() -} - -token_file_msg <- function() { - message( - crayon::green( - paste0( - "For info the token(s) and email(s) are stored at ", - email_file() - ) - ) - ) -} - -package_data <- new.env(parent = emptyenv()) -package_data$status <- new.env(parent = emptyenv()) -package_data$ids <- character() -package_data$groups <- character() - -## Since the status can be NULL, meaning unknown, we put all cache elements -## in a list of length 1. - -cache_get <- function(id) { - e <- package_data$status - if (!is.null(x <- e[[id]][[1]])) return(x) - nms <- ls(e) - sts <- grep(paste0("-", id, "[0-9a-f]*$"), nms) - if (length(sts) == 0) return(NULL) - if (length(sts) == 1) return(e[[ nms[sts] ]][[1]]) - stop("Multiple checks match, please use a more specific id", call. = FALSE) -} - -cache_put <- function(id, status) { - cache_put_ids(id) - cache_put_group_ids(status$group) - package_data$status[[id]] <- list(status) - invisible() -} - -cache_put_ids <- function(id) { - id <- unique(setdiff(id, package_data$ids)) - if (length(id)) package_data$ids <- c(id, package_data$ids) -} - -cache_put_group_ids <- function(id) { - id <- unique(setdiff(id, package_data$groups)) - if (length(id)) package_data$groups <- c(id, package_data$groups) -} - -cache_get_ids <- function(ids) { - w <- match_partial(ids, package_data$ids) - package_data$ids[w] -} - -cache_get_group_ids <- function(ids) { - w <- match_partial(ids, package_data$groups) - package_data$groups[w] -} - -match_partial <- function(x, table) { - hash <- sub("^.*-", "", table) - m <- match(x, table) - ifelse(is.na(m), pmatch(x, hash), m) -} - -#' @importFrom crayon yellow red underline - -report_system_error <- function(msg, status) { - - if (status$status == 0) return() - - if (status$stderr == "") { - stop( - msg, ", unknown error, standard output:\n", - yellow(status$stdout), - call. = FALSE - ) - - } else { - stop( - underline(yellow(paste0("\n", msg, ", standard output:\n\n"))), - yellow(status$stdout), "\n", - underline(red("Standard error:\n\n")), red(status$stderr), - call. = FALSE - ) - } -} - -#' @importFrom httr status_code - -report_error <- function(response) { - if (status_code(response) < 300) { - invisible(response) - } else { - call <- sys.call(-1) - stop(create_condition(response, "error", call = call)) - } -} - -#' @importFrom httr content - -create_condition <- function(response, - class = c("error", "warning", "message"), - call) { - - class <- match.arg(class) - - message <- content(response)$message %||% "rhub error" - - structure( - list(message = message, call = call), - class = c("rhub_error", class, "condition") - ) -} - -handle_id <- function(x) { - if (is.character(x)) { - unname(sub("^.*/([^/]+)$", "\\1", x, perl = TRUE)) - } else if (inherits(x, "rhub_handle")) { - unname(vapply(x, "[[", "", "id")) - } else { - stop("Invalid R-hub check id") - } -} - -#' @export - -print.rhub_handle <- function(x, ...) { - id <- handle_id(x) - if (length(id) == 1) { - cat("R-hub check: ", id, "\n", sep = "") - - } else { - cat( - "R-hub checks:\n", - paste(" ", id, collapse = "\n") - ) - } - invisible(x) -} - -#' The last rhub check of this R session -#' -#' `rhub` caches the id(s) of the last submission. This can be retrieved -#' with `last_check`. -#' -#' @return An rhub_check object. -#' -#' @export -#' @examples -#' \dontrun{ -#' check("packagedir") -#' last_check() -#' last_check()$livelog() -#' } - -last_check <- function() { - package_data$last_handle -} - -#' List all checks for an email address -#' -#' @param email Email address. By default it is guessed with -#' [whoami::email_address()]. The address must be validated, see -#' [validate_email()]. -#' @param package `NULL`, or a character scalar. Can be used to restrict -#' the search for a single package. -#' @param howmany How many check groups (checks submitted simultaneously) -#' to show. The current API limit is 20. -#' @return A [tibble::tibble] with columns: -#' * package Name of the package. -#' * version Package version. -#' * result: More detailed result of the check. Can be `NULL` for errors. -#' This is a list column with members: `status`, `errors`, `warnings`, -#' `notes`. -#' * group: R-hub check group id. -#' * id: `R-hub check id. -#' * platform_name: Name of the check platform. -#' * build_time: Build time, a [difftime] object. -#' * submitted: Time of submission. -#' * started: Time of the check start. -#' * platform: Detailed platform data, a list column. -#' * builder: Name of the builder machine. -#' * status Status of the check. Possible values: -#' - `created`: check job was created, but not running yet. -#' - `in-progress`: check job is running. -#' - `parseerror`: internal R-hub error parsing the check results. -#' - `preperror`: check error, before the package check has started. -#' - `aborted`: aborted by admin or user. -#' - `error`: failed check. (Possibly warnings and notes as well.) -#' - `warning`: `R CMD check` reported warnings. (Possibly notes as well.) -#' - `note`: `R CMD check` reported notes. -#' - `ok`: successful check. -#' * email: Email address of maintainer / submitter. -#' -#' @export -#' @seealso list_package_checks -#' @examples -#' \dontrun{ -#' ch <- list_my_checks() -#' ch -#' ch$details() -#' } - -list_my_checks <- function(email = email_address(), package = NULL, - howmany = 20) { - - assert_that(is_email(email)) - assert_that(is_string_or_null(package)) - assert_that(is_count(howmany)) - - response <- if (is.null(package)) { - query( - "LIST BUILDS EMAIL", - params = list(email = email, token = email_get_token(email))) - } else { - query( - "LIST BUILDS PACKAGE", - params = list(email = email, package = package, - token = email_get_token(email))) - } - - if (length(response) > howmany) response <- response[seq_len(howmany)] - - make_check_list(response) -} - - -#' List checks of a package -#' -#' @param package Directory of an R package, or a package tarball. -#' @param email Email address that was used for the check(s). -#' If `NULL`, then the maintainer address is used. -#' @param howmany How many checks to show. The current maximum of the API -#' is 20. -#' @inherit list_my_checks return -#' -#' @export -#' @importFrom desc desc_get -#' @examples -#' \dontrun{ -#' ch <- list_package_checks() -#' ch -#' ch$details(1) -#' } - -list_package_checks <- function(package = ".", email = NULL, howmany = 20) { - - assert_that(is_pkg_dir_or_tarball(package)) - if (is.null(email)) email <- get_maintainer_email(package) - assert_that(is_email(email)) - assert_that(is_count(howmany)) - - package <- unname(desc_get("Package", file = package)) - - response <- query( - "LIST BUILDS PACKAGE", - params = list(email = email, package = package, - token = email_get_token(email)) - ) - - if (length(response) > howmany) response <- response[seq_len(howmany)] - - make_check_list(response) -} - -make_check_list <- function(response) { - data <- unlist(response, recursive = FALSE) - - df <- tibble::tibble( - package = map_chr(data, "[[", "package"), - version = map_chr(data, "[[", "version"), - result = column_result(map(data, function(x) x$result)), - group = column_group_id(map_chr(data, "[[", "group")), - id = column_id(map_chr(data, "[[", "id")), - platform_name = map_chr(data, function(x) x$platform$name), - build_time = column_dt(map_int(data, function(x) { - suppressWarnings(as.integer(x$build_time %||% NA_integer_)) - })), - submitted = column_time(map_chr(data, "[[", "submitted")), - started = column_time(map_chr(data, function(x) x$started %||% NA_character_)), - platform = map(data, "[[", "platform"), - builder = map_chr(data, function(x) x$builder_machine %||% NA_character_), - status = column_status(map_chr(data, "[[", "status")), - email = map_chr(data, "[[", "email") - ) - - cache_put_ids(df$id) - cache_put_group_ids(df$group) - - df -} - -column_time <- function(x) { - res <- rep(as.POSIXct(NA_character_), length(x)) - res[! is.na(x)] <- parse_iso_8601(x[!is.na(x)]) - res -} - -check_livelog <- function(self, private, which) { - assert_that(is_count(which) || is_string(which)) - if (is_count(which) && (which < 1 || which > length(private$ids_))) { - stop("Unknown check selected") - } - if (is.character(which) && ! which %in% private$ids_) { - stop("Unknow check selected") - } - - make_streamer(private$ids_[[which]], make_status_parser) - self$update() - invisible(self) -} - -make_streamer <- function(id, parser_factory) { - - if (length(id) > 1) { - warning("Only first submission is streamed") - id <- id[1] - } - - start <- 0 - parser <- parser_factory() - - spinner <- c("-", "/", "|", "\\") - spin <- function() { - cat("\r", spinner[1], sep = "") - spinner <<- c(spinner[-1], spinner[1]) - } - - errors <- 100 - - repeat { - response <- tryCatch( - query( - "LIVE LOG", - params = list(id = id), - query = list(start = start) - ), - error = function(e) { - if (errors > 0) { - errors <- errors - 1 - list(text = list(), more = TRUE, size = start) - } else { - stop("Internal R-hub error") - list(text = list(), more = FALSE) - } - } - ) - - for (i in response$text) parser(i) - if (!response$more) break; - start <- response$size - for (i in 1:5) { Sys.sleep(0.1); spin() } - } - - cat("\r \n") - - if (grepl( - "^(Finished: ABORTED|Finished: ERROR)$", - response$text[[length(response$text)]] - )) { - cat(response$text[[length(response$text)]], "\n", sep = "") - } -} - -#' @importFrom rcmdcheck rcmdcheck - -make_status_parser <- function() { - - first <- TRUE - checking <- FALSE - - ## This is to make sure that `rhub` works with older and newer - ## rcmdcheck versions as well. Older versions expect a call for each - ## line. Newer versions just take a block of output. - formatter <- try( - ("rcmdcheck" %:::% "check_callback")(top_line = FALSE), - silent = TRUE - ) - if (inherits(formatter, "try-error")) { - cb <- ("rcmdcheck" %:::% "block_callback")(top_line = FALSE) - formatter <- function(x) cb(paste0(x, "\n")) - } - - function(x) { - - ## Make sure we are at the beginning of the line - cat("\r") - - if (first) { - header_line("Build started") - first <<- FALSE - } - - ## Get rid of potential \r characters - x <- gsub("[\r]+", "", x) - - ## Checking (already, and still) - - if (checking) { - if (grepl("^Status: ", x)) { - checking <<- FALSE - return(formatter(x)) - } else { - return(formatter(x)) - } - } - - ## Not checking (yet, or any more) - - if (grepl("^>>>>>=====+ Running R CMD check", x)) { - checking <<- TRUE - x <- sub("^>>>>>=+ ", "", x) - header_line(x) - - } else if (grepl("^>>>>>=====", x)) { - x <- sub("^>>>>>=+ ", "", x) - header_line(x) - - } else if (grepl("^\\+R-HUB-R-HUB-R-HUB", x)) { - x <- sub("^\\+R-HUB-R-HUB-R-HUB", "", x) - - } else { - ## print nothing - } - } -} - -#' Run a package check locally, in a Docker container -#' -#' @description Run a package check locally, in a Docker container. UNTESTED -#' ON WINDOWS, bug reports welcome. :-) -#' -#' @param quiet Whether to print the check output -#' @param image Docker image to use. If `NULL`, a default image is selected. -#' @param valgrind Whether to run the check with Valgrind. -#' @param timeout Timeout for a check, a `difftime` object or a scalar -#' that will be interpreted as seconds. -#' @param artifacts Where to copy the build artifacts after the build. -#' @inheritParams check -#' @return An `rcmdcheck::rcmdcheck` object, with extra fields: -#' * `all_output`: all output from the check, both standard output and -#' error. -#' * `container_name`: name of the Docker container that performed the -#' build. It is a random name. -#' * `artifacts`: directory of build artifacts. -#' -#' @export -#' @importFrom withr with_dir -#' @importFrom processx run -#' @importFrom utils tail -#' @importFrom uuid UUIDgenerate -#' -#' @details You'll need to have bash and Docker installed. - -local_check_linux <- function(path = ".", quiet = FALSE, image = NULL, - valgrind = FALSE, check_args = character(), - env_vars = character(), timeout = Inf, artifacts = tempfile()) { - - ## Check that it is a package - path <- normalizePath(path) - assert_that(is_pkg_dir_or_tarball(path)) - assert_that(is_flag(quiet)) - assert_that(is.null(image) || is.character(image)) - assert_that(is_flag(valgrind)) - assert_that(is_named(env_vars)) - assert_that(is.character(env_vars)) - assert_that(is_timeout(timeout <- as_timeout(timeout))) - assert_that(is.character(artifacts)) - - if ((bash <- Sys.which("bash")) == "" || Sys.which("docker") == "") { - stop("You need bash and Docker to run local Linux checks") - } - - ## Build the tar.gz, if needed - if (file.info(path)$isdir) { - header_line("Building package") - pkg_targz <- build_package(path, tmpdir <- tempfile()) - } else { - pkg_targz <- path - } - - ## Add valgrind to check_args - check_args <- c( - check_args, - if (valgrind) "--use-valgrind" - ) - - dir.create(artifacts, showWarnings = FALSE, recursive = TRUE) - artifacts <- normalizePath(artifacts) - - container_name <- UUIDgenerate() - if (!quiet) { - cat(sep = "", "\nContainer name: ", container_name, "-2", "\n") - cat("It will _not_ be removed after the check.\n\n") - } - - ## Arguments - env_str <- paste(paste0(names(env_vars), "=", env_vars), collapse = "\n") - args <- c( - "-k", - if (!is.null(image)) c("-i", image), - if (length(check_args)) c("-c", paste(check_args, collapse = " ")), - if (length(env_vars)) c("-e", env_str), - c("-a", artifacts), - c("-d", container_name), - pkg_targz) - - output <- character() - callback <- function(x, proc) output <<- c(output, x) - - ## Run it - wd <- system.file(package = .packageName, "bin") - result <- with_dir( - wd, - run(bash, c(file.path(wd, "rhub-linux.sh"), args), echo = TRUE, - stdout_line_callback = callback, stderr_line_callback = callback, - timeout = timeout, spinner = FALSE) - ) - - ## TODO: better error object - if (result$timeout) stop("Check timed out") - - if (!quiet) cat("Artifacts in", artifacts, "\n") - if (!quiet) cat(sep = "", "Container name: ", container_name, "-2", "\n\n") - - ## Try to parse as R CMD check result - check_start <- grep("^>>>>>=====+ Running R CMD check", output)[1] - if (is.na(check_start)) stop("Failed before check started") - check_output <- tail(output, -check_start) - check_result <- tryCatch( - rcmdcheck::parse_check(text = check_output), - error = function(e) NULL) - - result <- list( - check_result = check_result, - output = output, - image = image, - artifacts = artifacts, - container_name = paste0(container_name, "-2")) - class(result) <- "rhub_local_check" - result -} - -#' @importFrom utils head -#' @export - -print.rhub_local_check <- function(x, ...) { - cat0("\n") - if (!is.null(x$image)) cat0(symbol$bullet, " image: ", x$image, "\n") - if (!is.null(x$output)) { - cat0(symbol$bullet, " output:\n") - cat(paste0(" ", c(head(x$output, 5), "...")), sep = "\n") - } - cat0(symbol$bullet, " container_name: ", x$container_name, "\n") - if (!is.null(x$artifacts)) { - cat0(symbol$bullet, " artifacts: \n ", x$artifacts, "\n") - } - if (!is.null(x$check_result)) { - cat0(symbol$bullet, " check_result:\n") - print(x$check_result) - } -} - -#' List R-hub Docker images -#' -#' The images are pretty-printed in a short format. Use -#' `as.data.frame()` to get all available platform metadata. -#' -#' @export - -local_check_linux_images <- function() { - plat <- platforms() - plat <- plat[!is.na(plat$`docker-image`), ] - class(plat) <- c("rhub_docker_images", class(plat)) - plat -} - -#' @export - -print.rhub_docker_images <- function(x, ...) { - res <- paste(cyan(paste0("rhub/", x$`docker-image`)), - green(x$description), sep = ":\n ") - cat(res, sep = "\n") - invisible(x) -} - -#' List all R-hub platforms -#' -#' The platforms are pretty-printed in a short format. Use -#' `as.data.frame(platforms())` to get all available platform metadata. -#' -#' @export -#' @importFrom jsonlite fromJSON -#' @importFrom crayon green cyan -#' @examples -#' \dontrun{ -#' platforms() -#' as.data.frame(platforms()) -#' } - -platforms <- function() { - json <- query("GET PLATFORMS", as = "text") - pls <- fromJSON(json, simplifyDataFrame = TRUE) - pls <- pls[order(pls$name), , drop = FALSE] - class(pls) <- c("rhub_platforms", class(pls)) - pls -} - -#' @export - -print.rhub_platforms <- function(x, ...) { - res <- paste(cyan(x$name), green(x$description), sep = ":\n ") - cat(res, sep = "\n") - invisible(x) -} - -match_platform <- function(platform) { - all_platforms <- platforms() - if (is.null(platform)) { - if (is_interactive()) { - select_platform_interactively(all_platforms) - } else { - all_platforms$name[1] - } - - } else { - if (! all(platform %in% all_platforms$name)) { - stop("Unknown R-hub platform, see rhub::platforms() for a list") - } - platform - } -} - -select_platform_interactively <- function(platforms) { - - choices <- paste0( - platforms$description, - crayon::green(" (", platforms$name, ")", sep = "") - ) - - cat("\n") - title <- crayon::yellow(paste0( - symbol$line, symbol$line, - " Choose build platform" - )) - ch <- menu(choices, title = title) - cat("\n") - if (ch == 0) stop("R-hub check aborted", call. = FALSE) - - platforms$name[ch] -} - -check_print <- function(self, private) { - self$update() - for (x in private$status_) check_print2(x) - invisible(self) -} - -#' @importFrom parsedate parse_iso_8601 -#' @importFrom prettyunits pretty_ms -#' @importFrom crayon make_style red yellow - -check_print2 <- function(x) { - - title_line(paste0(x$package, " ", x$version, ": ", toupper(x$status))) - - greyish <- make_style("darkgrey") - - submitted_time <- as.numeric(Sys.time() - parse_iso_8601(x$submitted), units = "secs") - submitted <- if (submitted_time > 0) { - paste(pretty_ms(submitted_time * 1000), "ago") - } else { - "just now" - } - - build_time <- if (!is.null(x$build_time) && x$build_time != 0) { - paste0(greyish(" Build time: "), pretty_ms(x$build_time), "\n") - } - - cat( - sep = "", - greyish(" Build ID: "), x$id, "\n", - greyish(" Platform: "), x$platform$description, "\n", - greyish(" Submitted: "), submitted, "\n", - build_time %||% "", - "\n" - ) - - ## If not done, then this is all we do - if (is.null(build_time)) return(invisible(x)) - - ## R CMD check error - if (tolower(x$status) != "preperror" && tolower(x$status) != "aborted") { - makeshift <- structure( - list( - package = x$package, - version = x$version, - rversion = x$platform$rversion, - output = list(stdout = x$check_output, stderr = "", status = 0), - platform = x$platform$name, - notes = x$result$notes, - warnings = x$result$warnings, - errors = x$result$errors - ), - class = "rcmdcheck" - ) - print(makeshift, header = FALSE) - - ## Or we never got to R CMD check - } else { - clog <- gsub("+R-HUB-R-HUB-R-HUB", "", fixed = TRUE, x$preperror_log) - clog <- gsub("\necho >>>>>=========[^\n]*\n", "\n", clog) - clog <- gsub( - "\n>>>>>=======* (.+)\n", - yellow(sep = "", "\n\n", symbol$line, " \\1\n\n"), - clog, - perl = TRUE - ) - - cat(red(paste0(symbol$pointer, " Build failed during preparation or aborted\n"))) - cat(greyish("\n[...]\n")) - cat(greyish(clog)) - cat("\n") - } - - invisible(x) -} - -#' @importFrom crayon make_style -#' @importFrom cli symbol - -header_line <- function(x) { - - greyish <- make_style("darkgrey") - - cat( - paste0("\r", greyish(symbol$line), " "), - greyish(x), - "\n", - sep = "" - ) -} - -#' @importFrom crayon yellow -#' @importFrom cli symbol - -title_line <- function(x) { - - cat( - sep ="", - "\n", - yellow(paste0(symbol$line, symbol$line, " ", x)), - "\n\n" - ) -} - -#' @importFrom cli make_ansi_style style_bold style_inverse -#' col_red col_blue col_green - -status_style_created <- function(x) { - x -} - -status_style_in_progress <- function(x) { - x -} - -status_style_error <- function(x) { - style_inverse(style_bold(col_red(x))) -} - -status_style_aborted <- function(x) { - style_bold(col_blue(x)) -} - -status_style_note <- function(x) { - orange <- make_ansi_style("orange") - style_bold(orange(x)) -} - -status_style_ok <- function(x) { - style_inverse(style_bold(col_green(x))) -} - -re_match_all <- function(text, pattern, ...) { - - text <- as.character(text) - stopifnot(is.character(pattern), length(pattern) == 1, !is.na(pattern)) - - ## Need to handle this case separately, as gregexpr effectively - ## does not work for this. - if (length(text) == 0) return(empty_result(text, pattern, ...)) - - match <- gregexpr(pattern, text, perl = TRUE, ...) - - num_groups <- length(attr(match[[1]], "capture.names")) - - ## Non-matching strings have a rather strange special form, - ## so we just treat them differently - non <- vapply(match, function(m) m[1] == -1, TRUE) - yes <- !non - res <- replicate(length(text), list(), simplify = FALSE) - if (any(non)) { - res[non] <- list(replicate(num_groups + 1, character(), simplify = FALSE)) - } - if (any(yes)) { - res[yes] <- mapply(match1, text[yes], match[yes], SIMPLIFY = FALSE) - } - - ## Need to assemble the final data frame "manually". - ## There is apparently no function for this. rbind() is almost - ## good, but simplifies to a matrix if the dimensions allow it.... - res <- lapply(seq_along(res[[1]]), function(i) { - lapply(res, "[[", i) - }) - - structure( - res, - names = c(attr(match[[1]], "capture.names"), ".match"), - row.names = seq_along(text), - class = c("data.frame") - ) -} - -match1 <- function(text1, match1) { - - matchstr <- substring( - text1, - match1, - match1 + attr(match1, "match.length") - 1L - ) - - ## substring fails if the index is length zero, - ## need to handle special case - if (is.null(attr(match1, "capture.start"))) { - list(.match = matchstr) - - } else { - gstart <- attr(match1, "capture.start") - glength <- attr(match1, "capture.length") - gend <- gstart + glength - 1L - - groupstr <- substring(text1, gstart, gend) - dim(groupstr) <- dim(gstart) - - c(lapply(seq_len(ncol(groupstr)), function(i) groupstr[, i]), - list(.match = matchstr) - ) - } -} - -empty_result <- function(text, pattern, ...) { - match <- regexpr(pattern, text, perl = TRUE, ...) - num_groups <- length(attr(match, "capture.names")) - structure( - replicate(num_groups + 1, list(), simplify = FALSE), - names = c(attr(match, "capture.names"), ".match"), - row.names = integer(0), - class = "data.frame" - ) -} -#' @keywords internal -"_PACKAGE" - -# The following block is used by usethis to automatically manage -# roxygen namespace tags. Modify with care! -## usethis namespace: start -## usethis namespace: end -NULL - -#' @importFrom rematch re_match -#' @importFrom jsonlite base64_enc -#' @importFrom crayon blue - -submit_package <- function(email, pkg_targz, platforms, check_args, - env_vars) { - - assert_that(is_email(email)) - assert_that( - is.character(platforms), - length(platforms) >= 1 - ) - - m <- re_match( - pattern = "^(?.+)_(?.+)\\.tar\\.gz", - basename(pkg_targz) - ) - - header_line("Uploading package") - buf <- readBin(pkg_targz, raw(), file.info(pkg_targz)$size) - response <- query( - "SUBMIT PACKAGE", - data = list( - email = unbox(email), - token = unbox(email_get_token(email)), - package = unbox(unname(m[, "package"])), - version = unbox(unname(m[, "version"])), - platform = platforms, - env = as.list(env_vars), - check_args = unbox(paste(check_args, collapse = " ")), - file = unbox(base64_enc(buf)) - ) - ) - - header_line(paste0( - "Preparing build, see status at\n", - blue(paste( - " ", - vapply(response, "[[", "", "status-url"), - collapse = "\n" - )) - )) - - response -} - -update <- function(original, new) { - - if (length(new)) { - if (length(original)) assert_that(is_named(original)) - assert_that(is_named(new)) - original[names(new)] <- new - } - - original -} - -#' @importFrom rematch re_match - -parse_email <- function(x) { - unname( - re_match(pattern = "<(?[^>]+)>", x)[, "email"] - ) -} - -`%||%` <- function(l, r) if (is.null(l)) r else l - -#' @importFrom desc desc_get_maintainer -#' @importFrom utils untar - -get_maintainer_email <- function(path) { - path <- normalizePath(path) - if (is_dir(path)) { - if (!file.exists(file.path(path, "DESCRIPTION"))) { - stop("No 'DESCRIPTION' file found") - } - parse_email(desc_get_maintainer(path)) - } else { - dir.create(tmp <- tempfile()) - files <- untar(path, list = TRUE, tar = "internal") - desc <- grep("^[^/]+/DESCRIPTION$", files, value = TRUE) - if (length(desc) < 1) stop("No 'DESCRIPTION' file in package") - untar(path, desc, exdir = tmp, tar = "internal") - parse_email(desc_get_maintainer(file.path(tmp, desc))) - } -} - -needs_compilation <- function(path) { - path <- normalizePath(path) - if (is_dir(path)) { - file.exists(file.path(path, "src")) - } else { - dir.create(tmp <- tempfile()) - files <- untar(path, list = TRUE, tar = "internal") - any(grepl("^[^/]+/src/?$", files)) - } -} - -`%:::%` <- function(p, f) { - get(f, envir = asNamespace(p)) -} - -is_interactive <- function() { - interactive() -} - -is_dir <- function(x) { - file.info(x)$isdir -} - -data_frame <- function(...) { - data.frame(stringsAsFactors = FALSE, ...) -} - -drop_nulls <- function(x) { - x [ ! vapply(x, is.null, TRUE) ] -} - -get_group <- function(l){ - if (! "group" %in% names(l)){ - "" - } else { - l[["group"]] - } -} - -cat0 <- function(..., sep = "") { - cat(..., sep = sep) -} - -map <- function(.x, .f, ...) { - lapply(.x, .f, ...) -} - -map_lgl <- function(.x, .f, ...) { - vapply(.x, .f, logical(1), ...) -} - -map_chr <- function(.x, .f, ...) { - vapply(.x, .f, character(1), ...) -} - -map_int <- function(.x, .f, ...) { - vapply(.x, .f, integer(1), ...) -} - -shorten_rhub_id <- function(x) { - sx <- strsplit(x, "-", fixed = TRUE) - substr(map_chr(sx, tail, 1), 1, 7) -} - -## This is a workaround to handle NAs - -my_pretty_dt <- function(x, compact = TRUE) { - res <- rep("?", length(x)) - res[!is.na(x)] <- pretty_dt(x[!is.na(x)], compact = compact) - res -} - -problem_statuses <- function(){ - c("parseerror", "preperror", "aborted") -} +platforms <- function(...) { + deprecated() +} \ No newline at end of file diff --git a/R/rhubv2.R b/R/rhubv2.R new file mode 100644 index 0000000..801dd93 --- /dev/null +++ b/R/rhubv2.R @@ -0,0 +1,17 @@ +#' Tools for R package developers +#' +#' ```{r man-readme, child = "README.Rmd"} +#' ``` +#' +#' @keywords internal +#' @name rhub-package +#' @rdname rhub-package +#' @aliases rhub +NULL + +#' ```{r include = FALSE, child = "vignettes/rhubv2.Rmd"} +#' ``` +#' @title R-hub v2 +#' @name rhubv2 +#' @rdname rhubv2 +NULL \ No newline at end of file diff --git a/R/setup.R b/R/setup.R new file mode 100644 index 0000000..0e0a6c0 --- /dev/null +++ b/R/setup.R @@ -0,0 +1,146 @@ +check_rpkg_root <- function(rpkg_root, git_root) { + if (rpkg_root != git_root) { + throw(pkg_error( + "R-hub currently requires that your R package is at the root of the + git repository.", + i = "Your R package is at {.path {rpkg_root}}.", + i = "Your git repository root is at {.path {git_root}}." + )) + } +} + +#' Setup the current R package for use with R-hub +#' +#' It adds or updates the R-hub workflow file to the current package, +#' and advises on next steps. +#' +#' @param overwrite if `TRUE`, [rhub_setup()] will overwrite an already +#' existing workflow file. +#' @return Nothing. +#' +#' @export + +rhub_setup <- function(overwrite = FALSE) { + cli::cli_bullets("Setting up R-hub v2.") + rpkg_root <- setup_find_r_package() + git_root <- setup_find_git_root() + check_rpkg_root(rpkg_root, git_root) + + url <- "https://raw.githubusercontent.com/r-hub/rhub2/v1/inst/workflow/rhub.yaml" + resp <- synchronise(http_get(url)) + if (resp$status_code != 200) { + throw(pkg_error( + "Failed to download R-hub worflow file from GitHub.", + i = "URL: {.url {url}}.", + i = "HTTP status: {resp$status_code}.", + i = "Make sure that you are online and GitHub is up." + )) + } + wf <- resp$content + wfc <- rawToChar(wf) + Encoding(wfc) <- "UTF-8" + + updated <- FALSE + wf_file <- file.path(git_root, ".github", "workflows", "rhub.yaml") + if (file.exists(wf_file)) { + wf_current <- read_file(wf_file) + if (wfc != wf_current) { + if (overwrite) { + dir.create(dirname(wf_file), showWarnings = FALSE, recursive = TRUE) + writeBin(wf, wf_file) + updated <- TRUE + cli::cli_bullets(c( + i = "Updated existing workflow file at {.file {wf_file}}, + as requested" + )) + } else { + throw(pkg_error( + "Workflow file already exists at {.file {wf_file}}.", + i = "Use {.code overwrite = TRUE} for overwriting it." + )) + } + } else { + cli::cli_bullets(c( + v = "Workflow file {.file {wf_file}} already exists and it is current." + )) + } + } else { + dir.create(dirname(wf_file), showWarnings = FALSE, recursive = TRUE) + writeBin(wf, wf_file) + updated <- TRUE + cli::cli_bullets(c( + v = "Created workflow file {.file {wf_file}}." + )) + } + + cli::cli_text() + cli::cli_bullets(c( + "Notes:", + "*" = "The workflow file must be added to the {.emph default} branch + of the GitHub repository.", + "*" = "GitHub actions must be enabled for the repository. They are + disabled for forked repositories by default." + )) + cli::cli_text() + cli::cli_bullets(c( + "Next steps:", + "*" = "Add the workflow file to git using {.code git add }.", + "*" = if (updated) "Commit it to git using {.code git commit}.", + "*" = if (!updated) "Commit it to git using {.code git commit} (if not committed already).", + "*" = if (updated) "Push the commit to GitHub using {.code git push}.", + "*" = if (!updated) "Push the commit to GitHub using {.code git push} (if not pushed already).", + "*" = "Call {.run rhub2::rhub_doctor()} to check that you have set up + R-hub correctly.", + "*" = "Call {.run rhub2::rhub_check()} to check your package." + )) + + invisible(NULL) +} + +setup_find_r_package <- function() { + pid <- cli_status("Is the current directory part of an R package?") + tryCatch( + rpkg_root <- rprojroot::find_root(rprojroot::is_r_package), + error = function(e) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "The current directory is not part of an R package.", + i = "You can create an R package in the current directory if you run + {.run usethis::create_package('.')}.", + i = "Alternatively, if you want to use R-hub for a package that is + already on GitHub, supply the {.arg gh_url} argument to + {.fun rhub_setup}." + )) + } + ) + cli::cli_status_clear(pid, result = "clear") + cli::cli_alert_success("Found R package at {.file {rpkg_root}}.") + + rpkg_root +} + +setup_find_git_root <- function() { + pid <- cli_status( + "Is the current directory part of a git repository?" + ) + tryCatch( + git_root <- rprojroot::find_root(rprojroot::is_git_root), + error = function(e) { + cli::cli_status_clear(pid, result = "failed") + throw(pkg_error( + call. = FALSE, + "The current R package is not in a git repository.", + i = "You can create a git repository for the current package or + project if you run {.run usethis::use_git()}.", + i = "Alternatively, if you want to use R-hub for a package that is + already on GitHub, supply the {.arg gh_url} argument to + {.fun rhub_setup}." + )) + } + ) + cli::cli_status_clear(result = "clear") + cli::cli_alert_success("Found git repository at {.file {git_root}}.") + + git_root +} diff --git a/R/utils.R b/R/utils.R new file mode 100644 index 0000000..4a504fc --- /dev/null +++ b/R/utils.R @@ -0,0 +1,109 @@ + +pkg_error <- function(..., .data = NULL, .class = NULL, .envir = parent.frame(), + call. = TRUE) { + .hide_from_trace <- TRUE + cnd <- new_error( + call. = call., + cli::format_error( + .envir = .envir, + c( + ... + ) + ) + ) + + if (length(.data)) cnd[names(.data)] <- .data + if (length(class)) class(cnd) <- c(.class, class(cnd)) + + cnd +} + +stop <- function(..., call. = TRUE, domain = NA) { + .hide_from_trace <- TRUE + args <- list(...) + if (length(args) == 1L && inherits(args[[1L]], "condition")) { + throw( + add_class(args[[1]], c("rlib_error_3_0", "rlib_error"), "end"), + frame = parent.frame() + ) + } else { + throw(new_error(..., call. = call., domain = domain)) + } +} + +stopifnot <- function(...) { + assert_that(..., env = parent.frame()) +} + +add_class <- function(obj, classes, where = c("start", "end")) { + where <- match.arg(where) + nc <- c( + if (where == "start") classes, + class(obj), + if (where == "end") classes + ) + class(obj) <- unique(nc) + obj +} + +zip <- function(x, y) { + mapply(FUN = c, x, y, SIMPLIFY = FALSE) +} + +first_char <- function(x) { + substr(x, 1, 1) +} + +last_char <- function(x) { + substr(x, nchar(x), nchar(x)) +} + +unquote <- function(x) { + ifelse( + first_char(x) == last_char(x) & first_char(x) %in% c("'", '"'), + substr(x, 2L, nchar(x) - 1L), + x + ) +} + +has_emoji <- function() { + if (!cli::is_utf8_output()) return(FALSE) + if (isTRUE(opt <- getOption("pkg.emoji"))) return(TRUE) + if (identical(opt, FALSE)) return(FALSE) + if (Sys.info()[["sysname"]] != "Darwin") return(FALSE) + TRUE +} + +parse_url <- function(url) { + re_url <- paste0( + "^(?[a-zA-Z0-9]+)://", + "(?:(?[^@/:]+)(?::(?[^@/]+))?@)?", + "(?[^/]+)", + "(?.*)$" # don't worry about query params here... + ) + + mch <- re_match(url, re_url) + mch[, setdiff(colnames(mch), c(".match", ".text")), drop = FALSE] +} + +read_file <- function(path) { + bin <- readBin(path, "raw", file.size(path)) + chr <- rawToChar(bin) + Encoding(chr) <- "UTF-8" + chr +} + +ansi_align_width <- function(text) { + if (length(text) == 0) return(text) + width <- max(cli::ansi_nchar(text, type = "width")) + cli::ansi_align(text, width = width) +} + +random_id <- function() { + r <- paste0(sample(c(letters, LETTERS, 0:9), 20, replace = TRUE), collapse = "") + gsub(" ", "-", cli::hash_animal(r, n_adj = 1)$hash) +} + +readline <- function(prompt) { + base::readline(prompt) +} diff --git a/README.Rmd b/README.Rmd new file mode 100644 index 0000000..03ee78f --- /dev/null +++ b/README.Rmd @@ -0,0 +1,116 @@ +--- +output: + github_document: + toc: true + toc_depth: 3 + includes: + before_body: inst/header.md +always_allow_html: yes +editor_options: + markdown: + wrap: sentence +--- + +```{r, setup, include = FALSE} +knitr::opts_chunk$set( + comment = "#>", + fig.path = "man/figures", + fig.width = 10, + asciicast_theme = if (Sys.getenv("IN_PKGDOWN") == "true") "pkgdown" else "readme" +) +asciicast::init_knitr_engine( + echo = TRUE, + echo_input = FALSE, + startup = quote({ + library(cli) + options(cli.num_colors = cli::truecolor) + }) +) +``` + +```{asciicast asciicast-setup, include = FALSE, results = "hide"} +pkgload::load_all() +# emoji output is slightly incorrect currently, maybe a font issue +options(pkg.emoji = FALSE) +# we do this to have a package to use in the examples +setwd("/tmp") +if (!file.exists("cli")) system("git clone --depth 1 https://github.com/r-lib/cli") +setwd("cli") +unlink(".github/workflows/rhub.yaml") +``` + +# rhub + +## Installation + +Install rhub from CRAN: + +```{r, asciicast-install, eval = FALSE, cache = FALSE} +pak::pkg_install("rhub") +``` + +## Usage + +### Requirements + +- A Github account. +- Your R package must be in a GitHub repository. +- You need a GitHub [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). + You can use the [gitcreds package](https://gitcreds.r-lib.org/) to add + the token to the git credential store. + +### Private repositories + +rhub uses GitHub Actions, which is free for public repositories. +For private repositories you also get some minutes for free, depending on +the GitHub subscription you have. See +[About billing for GitHub Actions](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions) for details. + +### Setup + +1. Switch to the directory of your package, and call `rhub::rhub_setup()` to + add the R-hub workflow file to your package. +```{asciicast rhub-setup} +rhub::rhub_setup() +``` + +2. Run `git commit` and `git push` to push the workflow file to GitHub. + +3. Run `rhub::rhub_doctor()` to check if everything is set up correctly: +```{asciicast rhub-doctor} +rhub::rhub_doctor() +``` + +### Run checks + +Use `rhub::rhub_platforms()` to get a list of supported platforms and checks: +```{asciicast rhub-platforms} +rhub::rhub_platforms() +``` + +```{asciicast include = FALSE} +testthat::local_mocked_bindings( + gh_rest_post = function(...) list(status_code = 204L), + readline = function(prompt) { + cat(prompt) + Sys.sleep(1) + cat("1, 5\n") + "1, 5" + } +) +``` + +Run `rhub::rhub_check()` to start R-hub 2 checks on GitHub Actions: +```{asciicast rhub-check} +rhub::rhub_check() +``` + +## Code of Conduct + +Please note that the callr project is released with a +[Contributor Code of Conduct](https://callr.r-lib.org/CODE_OF_CONDUCT.html). +By contributing to this project, you agree to abide by its terms. + +## License + +MIT © R Consortium diff --git a/README.md b/README.md index 6067955..0a33aa3 100644 --- a/README.md +++ b/README.md @@ -1,47 +1,116 @@ -# rhub -> Connect to R-hub, from R + + + +# rhub + +> R-hub version 2 -[![](https://www.r-pkg.org/badges/version/rhub)](https://www.r-pkg.org/pkg/rhub) -[![CRAN RStudio mirror downloads](https://cranlogs.r-pkg.org/badges/rhub)](https://www.r-pkg.org/pkg/rhub) -[![Project Status: Active – The project has reached a stable, usable state and is being actively developed.](https://www.repostatus.org/badges/latest/active.svg)](https://www.repostatus.org/#active) -[![Gitter chat](https://badges.gitter.im/gitterHQ/gitter.png)](https://gitter.im/r-hub/community) -[![Codecov test coverage](https://codecov.io/gh/r-hub/rhub/branch/master/graph/badge.svg)](https://app.codecov.io/gh/r-hub/rhub?branch=master) +[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) [![R-CMD-check](https://github.com/r-hub/rhub/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-hub/rhub/actions/workflows/R-CMD-check.yaml) +[![](https://www.r-pkg.org/badges/version/rhub)](https://www.r-pkg.org/pkg/rhub) +[![Codecov test coverage](https://codecov.io/gh/r-hub/rhub/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-hub/rhub?branch=main) -## Introduction +R-hub 2 uses GitHub Actions to run `R CMD check` and similar package checks. +The rhub package helps you set up R-hub 2 for your R package, and start +running checks. -The [R-hub builder](https://builder.r-hub.io/) is a multi-platform build and -check service for R packages. The `rhub` packages use the R-hub API to connect to -the R-hub builder and start package checks on various architectures: -**Run `R CMD check` on any of the R-hub builder architectures, from R**. +--- -The `rhub` package also supports accessing **statuses of previous checks**, and -**local use of the R-hub Linux platforms via Docker**. +- Installation +- Usage + - Requirements + - Private + repositories + - Setup + - Run checks +- Code of Conduct +- License ## Installation -Install the package from CRAN: +Install rhub from CRAN: -```r -install.packages("rhub") +``` r +pak::pkg_install("rhub") ``` -Or get the development version from GitHub: +## Usage + +### Requirements -```r -# install.packages("remotes") -remotes::install_github("r-hub/rhub") +- A Github account. +- Your R package must be in a GitHub repository. +- You need a GitHub [Personal Access + Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token). + You can use the [gitcreds package](https://gitcreds.r-lib.org/) to add + the token to the git credential store. + +### Private repositories + +rhub uses GitHub Actions, which is free for public repositories. For +private repositories you also get some minutes for free, depending on +the GitHub subscription you have. See [About billing for GitHub +Actions](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions) +for details. + +### Setup + +1. Switch to the directory of your package, and call + `rhub::rhub_setup()` to add the R-hub workflow file to your + package. + +``` r +rhub::rhub_setup() ``` -## Usage + + + + +2. Run `git commit` and `git push` to push the workflow file to GitHub. + +3. Run `rhub::rhub_doctor()` to check if everything is set up + correctly: + +``` r +rhub::rhub_doctor() +``` + + + + + +### Run checks + +Use `rhub::rhub_platforms()` to get a list of supported platforms and +checks: + +``` r +rhub::rhub_platforms() +``` + + + + + +Run `rhub::rhub_check()` to start R-hub 2 checks on GitHub Actions: + +``` r +rhub::rhub_check() +``` + + + + -Refer to the [`pkgdown` website](https://r-hub.github.io/rhub/), in particular -the ["Get started" vignette](https://r-hub.github.io/rhub/articles/rhub.html). +## Code of Conduct -![recording of a check on a screen](https://r-hub.github.io/rhub/articles/figures/check-output.gif) +Please note that the rhub project is released with a [Contributor Code +of Conduct](https://callr.r-lib.org/CODE_OF_CONDUCT.html). By +contributing to this project, you agree to abide by its terms. ## License diff --git a/man/check.Rd b/man/check.Rd index 7d9fbd1..55397e0 100644 --- a/man/check.Rd +++ b/man/check.Rd @@ -2,55 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{check} \alias{check} -\title{Check an R package on R-hub} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -check( - path = ".", - platforms = NULL, - email = NULL, - valgrind = FALSE, - check_args = character(), - env_vars = character(), - show_status = interactive() -) +check(...) } \arguments{ -\item{path}{Path to a directory containing an R package, or path to -source R package tarball built with \verb{R CMD build} or -\code{devtools::build()}.} - -\item{platforms}{A character vector of one or more platforms to build/check -the package on. See \code{\link[=platforms]{platforms()}} for the available platforms. If this is -\code{NULL}, and the R session is interactive, then a menu is shown. If it -is \code{NULL}, and the session is not interactive, then the default R-hub -platforms are used. A vector of platforms which saves time by building one -R package tarball that is used for all the platforms specified.} - -\item{email}{Email address to send notification to about the check. -It must be a validated email address, see \code{\link[=validate_email]{validate_email()}}. If -\code{NULL}, then the email address of the maintainer is used, as defined -in the \code{DESCRIPTION} file of the package.} - -\item{valgrind}{Whether to run the check in valgrind. Only supported on -Linux currently, and ignored on other platforms.} - -\item{check_args}{Extra arguments for the \verb{R CMD check} command.} - -\item{env_vars}{Environment variables to set on the builder machine -before the check. A named character vector.} - -\item{show_status}{Whether to show the status of the build and check -(live log) as it is happening.} -} -\value{ -An \link{rhub_check} object. +\item{...}{Deprecated.} } \description{ -Check an R package on R-hub -} -\examples{ -\dontrun{ -check(".") -check("mypackage_1.0.0.tar.gz", platforms = "fedora-clang-devel") -} +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/check_for_cran.Rd b/man/check_for_cran.Rd index 374d883..554ecda 100644 --- a/man/check_for_cran.Rd +++ b/man/check_for_cran.Rd @@ -2,68 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{check_for_cran} \alias{check_for_cran} -\title{Check an R-package on R-hub, for a CRAN submission} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -check_for_cran( - path = ".", - email = NULL, - check_args = "--as-cran", - env_vars = c(`_R_CHECK_FORCE_SUGGESTS_` = "true", `_R_CHECK_CRAN_INCOMING_USE_ASPELL_` - = "true"), - platforms = NULL, - ... -) +check_for_cran(...) } \arguments{ -\item{path}{Path to a directory containing an R package, or path to -source R package tarball built with \verb{R CMD build} or -\code{devtools::build()}.} - -\item{email}{Email address to send notification to about the check. -It must be a validated email address, see \code{\link[=validate_email]{validate_email()}}. If -\code{NULL}, then the email address of the maintainer is used, as defined -in the \code{DESCRIPTION} file of the package.} - -\item{check_args}{Arguments for \verb{R CMD check}. By default \code{--as-cran} -is used.} - -\item{env_vars}{Character vector of environment variables to set on the builder. -By default \verb{_R_CHECK_FORCE_SUGGESTS_="true"} is set, to require all packages used. -\verb{_R_CHECK_CRAN_INCOMING_USE_ASPELL_="true"} is also set, to use the -spell checker.} - -\item{platforms}{A character vector of one or more platforms to build/check -the package on. See \code{\link[=platforms]{platforms()}} for the available platforms. If this is -\code{NULL}, and the R session is interactive, then a menu is shown. If it -is \code{NULL}, and the session is not interactive, then the default R-hub -platforms are used. A vector of platforms which saves time by building one -R package tarball that is used for all the platforms specified.} - -\item{...}{Additional arguments are passed to \code{\link[=check]{check()}}.} -} -\value{ -An \link{rhub_check} object. +\item{...}{Deprecated.} } \description{ -This function calls \code{\link[=check]{check()}} with arguments and platforms, that -are suggested for a CRAN submission. -} -\details{ -In particular, if \code{platforms} is \code{NULL} (the default), then -\itemize{ -\item It checks the package on Windows, and Linux. -\item It checks the package on R-release and R-devel. -\item It uses the \code{--as-cran} argument to \verb{R CMD check}. -\item It requires all dependencies, including suggested ones. -} - -This function is wrapped by \code{devtools::check_rhub()} which you -might find useful if you load \code{devtools} via your .Rprofile (see \code{usethis::use_devtools()}). -} -\examples{ -\dontrun{ -ch <- check_for_cran("package", show_status = FALSE) -ch$update() -ch$livelog(3) -} +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/check_shortcuts.Rd b/man/check_shortcuts.Rd index e13b60a..1bf601d 100644 --- a/man/check_shortcuts.Rd +++ b/man/check_shortcuts.Rd @@ -15,54 +15,39 @@ \alias{check_with_rdevel} \alias{check_with_valgrind} \alias{check_with_sanitizers} -\title{Check an R package on an R-hub platform} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -check_on_linux(path = ".", ...) +check_on_linux(...) -check_on_windows(path = ".", ...) +check_on_windows(...) -check_on_macos(path = ".", ...) +check_on_macos(...) -check_on_debian(path = ".", ...) +check_on_debian(...) -check_on_ubuntu(path = ".", ...) +check_on_ubuntu(...) -check_on_fedora(path = ".", ...) +check_on_fedora(...) -check_on_solaris( - path = ".", - check_args = "'--no-manual --no-build-vignettes'", - ... -) +check_on_solaris(...) -check_on_centos(path = ".", ...) +check_on_centos(...) -check_with_roldrel(path = ".", ...) +check_with_roldrel(...) -check_with_rrelease(path = ".", ...) +check_with_rrelease(...) -check_with_rpatched(path = ".", ...) +check_with_rpatched(...) -check_with_rdevel(path = ".", ...) +check_with_rdevel(...) -check_with_valgrind(path = ".", ...) +check_with_valgrind(...) -check_with_sanitizers(path = ".", ...) +check_with_sanitizers(...) } \arguments{ -\item{path}{Path to a directory containing an R package, or path to -source R package tarball built with \verb{R CMD build} or -\code{devtools::build()}.} - -\item{...}{Additional arguments are passed to \code{\link[=check]{check()}}.} - -\item{check_args}{Extra arguments for the \verb{R CMD check} command.} -} -\value{ -An \link{rhub_check} object. +\item{...}{Deprecated.} } \description{ -These functions provide a quick easy to use interface to check a -package on a platform with some particular aspect. Which platform -they use might change over time. +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/get_check.Rd b/man/get_check.Rd index e6a8172..a968a3a 100644 --- a/man/get_check.Rd +++ b/man/get_check.Rd @@ -2,38 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{get_check} \alias{get_check} -\title{Retrieve the result of R-hub checks} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -get_check(ids) +get_check(...) } \arguments{ -\item{ids}{One of the following: -\itemize{ -\item A single R-hub check id. -\item A character vector of check ids. -\item An R-hub check group id. -All ids can be abbreviated, see \link[=rhub-ids]{R-hub ids}. -}} -} -\value{ -An \link{rhub_check} object. +\item{...}{Deprecated.} } \description{ -Retrieve the result of R-hub checks -} -\section{Examples}{ - - -\if{html}{\out{
}}\preformatted{chk <- get_check("915ee61") -chk -chk$update() -chk$browse() -chk$cran_summary() -chk$urls() -}\if{html}{\out{
}} -} - -\seealso{ -\code{\link[=list_my_checks]{list_my_checks()}} and \code{\link[=list_package_checks]{list_package_checks()}} to list -R-hub checks. +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/last_check.Rd b/man/last_check.Rd index 817b442..6ceb048 100644 --- a/man/last_check.Rd +++ b/man/last_check.Rd @@ -2,21 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{last_check} \alias{last_check} -\title{The last rhub check of this R session} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -last_check() +last_check(...) } -\value{ -An rhub_check object. +\arguments{ +\item{...}{Deprecated.} } \description{ -\code{rhub} caches the id(s) of the last submission. This can be retrieved -with \code{last_check}. -} -\examples{ -\dontrun{ -check("packagedir") -last_check() -last_check()$livelog() -} +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/list_my_checks.Rd b/man/list_my_checks.Rd index 07aa205..ffc48e6 100644 --- a/man/list_my_checks.Rd +++ b/man/list_my_checks.Rd @@ -2,62 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{list_my_checks} \alias{list_my_checks} -\title{List all checks for an email address} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -list_my_checks(email = email_address(), package = NULL, howmany = 20) +list_my_checks(...) } \arguments{ -\item{email}{Email address. By default it is guessed with -\code{\link[whoami:email_address]{whoami::email_address()}}. The address must be validated, see -\code{\link[=validate_email]{validate_email()}}.} - -\item{package}{\code{NULL}, or a character scalar. Can be used to restrict -the search for a single package.} - -\item{howmany}{How many check groups (checks submitted simultaneously) -to show. The current API limit is 20.} -} -\value{ -A \link[tibble:tibble]{tibble::tibble} with columns: -\itemize{ -\item package Name of the package. -\item version Package version. -\item result: More detailed result of the check. Can be \code{NULL} for errors. -This is a list column with members: \code{status}, \code{errors}, \code{warnings}, -\code{notes}. -\item group: R-hub check group id. -\item id: `R-hub check id. -\item platform_name: Name of the check platform. -\item build_time: Build time, a \link{difftime} object. -\item submitted: Time of submission. -\item started: Time of the check start. -\item platform: Detailed platform data, a list column. -\item builder: Name of the builder machine. -\item status Status of the check. Possible values: -\itemize{ -\item \code{created}: check job was created, but not running yet. -\item \verb{in-progress}: check job is running. -\item \code{parseerror}: internal R-hub error parsing the check results. -\item \code{preperror}: check error, before the package check has started. -\item \code{aborted}: aborted by admin or user. -\item \code{error}: failed check. (Possibly warnings and notes as well.) -\item \code{warning}: \verb{R CMD check} reported warnings. (Possibly notes as well.) -\item \code{note}: \verb{R CMD check} reported notes. -\item \code{ok}: successful check. -} -\item email: Email address of maintainer / submitter. -} +\item{...}{Deprecated.} } \description{ -List all checks for an email address -} -\examples{ -\dontrun{ -ch <- list_my_checks() -ch -ch$details() -} -} -\seealso{ -list_package_checks +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/list_package_checks.Rd b/man/list_package_checks.Rd index 6344d32..eb767d8 100644 --- a/man/list_package_checks.Rd +++ b/man/list_package_checks.Rd @@ -2,57 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{list_package_checks} \alias{list_package_checks} -\title{List checks of a package} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -list_package_checks(package = ".", email = NULL, howmany = 20) +list_package_checks(...) } \arguments{ -\item{package}{Directory of an R package, or a package tarball.} - -\item{email}{Email address that was used for the check(s). -If \code{NULL}, then the maintainer address is used.} - -\item{howmany}{How many checks to show. The current maximum of the API -is 20.} -} -\value{ -A \link[tibble:tibble]{tibble::tibble} with columns: -\itemize{ -\item package Name of the package. -\item version Package version. -\item result: More detailed result of the check. Can be \code{NULL} for errors. -This is a list column with members: \code{status}, \code{errors}, \code{warnings}, -\code{notes}. -\item group: R-hub check group id. -\item id: `R-hub check id. -\item platform_name: Name of the check platform. -\item build_time: Build time, a \link{difftime} object. -\item submitted: Time of submission. -\item started: Time of the check start. -\item platform: Detailed platform data, a list column. -\item builder: Name of the builder machine. -\item status Status of the check. Possible values: -\itemize{ -\item \code{created}: check job was created, but not running yet. -\item \verb{in-progress}: check job is running. -\item \code{parseerror}: internal R-hub error parsing the check results. -\item \code{preperror}: check error, before the package check has started. -\item \code{aborted}: aborted by admin or user. -\item \code{error}: failed check. (Possibly warnings and notes as well.) -\item \code{warning}: \verb{R CMD check} reported warnings. (Possibly notes as well.) -\item \code{note}: \verb{R CMD check} reported notes. -\item \code{ok}: successful check. -} -\item email: Email address of maintainer / submitter. -} +\item{...}{Deprecated.} } \description{ -List checks of a package -} -\examples{ -\dontrun{ -ch <- list_package_checks() -ch -ch$details(1) -} +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/list_validated_emails.Rd b/man/list_validated_emails.Rd index bea8172..a8f526f 100644 --- a/man/list_validated_emails.Rd +++ b/man/list_validated_emails.Rd @@ -2,20 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{list_validated_emails} \alias{list_validated_emails} -\title{List validated email addresses} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -list_validated_emails() +list_validated_emails(...) } -\value{ -A \code{data.frame} with two columns: \code{email} and \code{token}. -If in interactive mode, and there are no validated email addresses, -then a message is printed and the data frame is returned invisibly. +\arguments{ +\item{...}{Deprecated.} } \description{ -List email addresses validated on R-hub on the current machine. +This function is deprecated and defunct. Please see \link{rhubv2}. } -\seealso{ -Other email validation: -\code{\link{validate_email}()} -} -\concept{email validation} diff --git a/man/local_check_linux.Rd b/man/local_check_linux.Rd index deb1da7..e862d4c 100644 --- a/man/local_check_linux.Rd +++ b/man/local_check_linux.Rd @@ -2,54 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{local_check_linux} \alias{local_check_linux} -\title{Run a package check locally, in a Docker container} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -local_check_linux( - path = ".", - quiet = FALSE, - image = NULL, - valgrind = FALSE, - check_args = character(), - env_vars = character(), - timeout = Inf, - artifacts = tempfile() -) +local_check_linux(...) } \arguments{ -\item{path}{Path to a directory containing an R package, or path to -source R package tarball built with \verb{R CMD build} or -\code{devtools::build()}.} - -\item{quiet}{Whether to print the check output} - -\item{image}{Docker image to use. If \code{NULL}, a default image is selected.} - -\item{valgrind}{Whether to run the check with Valgrind.} - -\item{check_args}{Extra arguments for the \verb{R CMD check} command.} - -\item{env_vars}{Environment variables to set on the builder machine -before the check. A named character vector.} - -\item{timeout}{Timeout for a check, a \code{difftime} object or a scalar -that will be interpreted as seconds.} - -\item{artifacts}{Where to copy the build artifacts after the build.} -} -\value{ -An \code{rcmdcheck::rcmdcheck} object, with extra fields: -\itemize{ -\item \code{all_output}: all output from the check, both standard output and -error. -\item \code{container_name}: name of the Docker container that performed the -build. It is a random name. -\item \code{artifacts}: directory of build artifacts. -} +\item{...}{Deprecated.} } \description{ -Run a package check locally, in a Docker container. UNTESTED -ON WINDOWS, bug reports welcome. :-) -} -\details{ -You'll need to have bash and Docker installed. +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/local_check_linux_images.Rd b/man/local_check_linux_images.Rd index 2fe6d28..9f45019 100644 --- a/man/local_check_linux_images.Rd +++ b/man/local_check_linux_images.Rd @@ -2,11 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{local_check_linux_images} \alias{local_check_linux_images} -\title{List R-hub Docker images} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -local_check_linux_images() +local_check_linux_images(...) +} +\arguments{ +\item{...}{Deprecated.} } \description{ -The images are pretty-printed in a short format. Use -\code{as.data.frame()} to get all available platform metadata. +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/platforms.Rd b/man/platforms.Rd index dee8e38..953b85f 100644 --- a/man/platforms.Rd +++ b/man/platforms.Rd @@ -2,17 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{platforms} \alias{platforms} -\title{List all R-hub platforms} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -platforms() +platforms(...) } -\description{ -The platforms are pretty-printed in a short format. Use -\code{as.data.frame(platforms())} to get all available platform metadata. -} -\examples{ -\dontrun{ -platforms() -as.data.frame(platforms()) +\arguments{ +\item{...}{Deprecated.} } +\description{ +This function is deprecated and defunct. Please see \link{rhubv2}. } diff --git a/man/rhub-ids.Rd b/man/rhub-ids.Rd deleted file mode 100644 index 0751aab..0000000 --- a/man/rhub-ids.Rd +++ /dev/null @@ -1,44 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rhubv1.R -\name{rhub-ids} -\alias{rhub-ids} -\title{R-hub check ids} -\description{ -R-hub check ids -} -\section{R-hub ids}{ - - -Every R-hub check has a unique id, that is constructed from the -name of the source package archive, and a random string. For example: - -\if{html}{\out{
}}\preformatted{devtools_2.0.0.tar.gz-fe53bbba85de4a579f6dc3b852bf76a3 -}\if{html}{\out{
}} -} - -\section{R-hub group ids}{ - - -For every check submission, R-hub also creates a unique check group id. -One check group may contain multiple checks. E.g. \code{\link[=check_for_cran]{check_for_cran()}} -typically creates three or four check groups. Group ids look the same -as individual check ids. -} - -\section{Abbreviating ids}{ - - -The rhub package keeps a list of all the checks that it has seen in the -current session, and these checks can be also referenced by any unique -prefix of the random string part of the id, e.g. in the \code{\link[=get_check]{get_check()}} -function. E.g. if rhub already know the devtools check above, then - -\if{html}{\out{
}}\preformatted{get_check("fe53bbb") -}\if{html}{\out{
}} - -works. - -This is only recommended in interactive mode, and we suggest that you -always use the full ids when using rhub programmatically. -} - diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index 8534a72..b1a27d1 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -1,36 +1,212 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rhubv1.R -\docType{package} +% Please edit documentation in R/rhubv2.R \name{rhub-package} -\alias{rhub} \alias{rhub-package} -\title{rhub: Connect to 'R-hub'} +\alias{rhub} +\title{Tools for R package developers} \description{ -\if{html}{\figure{logo.png}{options: style='float: right' alt='logo' width='120'}} +Tools for R package developers +} +\section{rhub \if{html}{\out{}}}{ +\subsection{Installation}{ + +Install rhub from CRAN: -Run 'R CMD check' on any of the 'R-hub' (\url{https://builder.r-hub.io/}) architectures, from the command line. The current architectures include 'Windows', 'macOS', 'Solaris' and various 'Linux' distributions. +\if{html}{\out{
}}\preformatted{pak::pkg_install("rhub") +}\if{html}{\out{
}} } -\seealso{ -Useful links: + +\subsection{Usage}{ +\subsection{Requirements}{ \itemize{ - \item \url{https://github.com/r-hub/rhub} - \item \url{https://r-hub.github.io/rhub/} - \item Report bugs at \url{https://github.com/r-hub/rhub/issues} +\item A Github account. +\item Your R package must be in a GitHub repository. +\item You need a GitHub \href{https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token}{Personal Access Token}. +You can use the \href{https://gitcreds.r-lib.org/}{gitcreds package} to add +the token to the git credential store. +} } +\subsection{Private repositories}{ + +rhub uses GitHub Actions, which is free for public repositories. +For private repositories you also get some minutes for free, depending on +the GitHub subscription you have. See +\href{https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions}{About billing for GitHub Actions} for details. } -\author{ -\strong{Maintainer}: Gábor Csárdi \email{csardi.gabor@gmail.com} -Authors: -\itemize{ - \item Maëlle Salmon \email{maelle.salmon@yahoo.se} (\href{https://orcid.org/0000-0002-2815-0399}{ORCID}) +\subsection{Setup}{ +\enumerate{ +\item Switch to the directory of your package, and call \code{rhub::rhub_setup()} to +add the R-hub workflow file to your package. } -Other contributors: -\itemize{ - \item R Consortium [funder] +\if{html}{\out{
}}\preformatted{rhub::rhub_setup() +}\if{html}{\out{
}}\if{html}{\out{ +
+#> Setting up R-hub v2.                                                            
+#>  Found R package at /private/tmp/cli.                                          
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.           
+#>                                                                                 
+#> Notes:                                                                          
+#>  The workflow file must be added to the default branch of the GitHub           
+#>   repository.                                                                   
+#>  GitHub actions must be enabled for the repository. They are disabled for      
+#>   forked repositories by default.                                               
+#>                                                                                 
+#> Next steps:                                                                     
+#>  Add the workflow file to git using `git add <filename>`.                      
+#>  Commit it to git using `git commit`.                                          
+#>  Push the commit to GitHub using `git push`.                                   
+#>  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.    
+#>  Call `rhub2::rhub_check()` to check your package.                             
+
+}} + +\enumerate{ +\item Run \verb{git commit} and \verb{git push} to push the workflow file to GitHub. +\item Run \code{rhub::rhub_doctor()} to check if everything is set up correctly: } +\if{html}{\out{
}}\preformatted{rhub::rhub_doctor() +}\if{html}{\out{
}}\if{html}{\out{ +
+#>  Found R package at /private/tmp/cli.                                          
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Found GitHub PAT.                                                             
+#>  Found repository on GitHub at <https://github.com/r-lib/cli>.                 
+#>  GitHub PAT has the right scopes.                                              
+#>  Found R-hub workflow in default branch, and it is active.                     
+#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package.             
+
+}} + } + +\subsection{Run checks}{ + +Use \code{rhub::rhub_platforms()} to get a list of supported platforms and checks: + +\if{html}{\out{
}}\preformatted{rhub::rhub_platforms() +}\if{html}{\out{
}}\if{html}{\out{ +
+#> ── Virtual machines ─────────────────────────────────────────────────────────── 
+#>  1 [VM]  linux                                                                  
+#>    All R versions on GitHub Actions ubuntu-latest                               
+#>  2 [VM]  macos                                                                  
+#>    All R versions on GitHub Actions macos-latest                                
+#>  3 [VM]  macos-arm64                                                            
+#>    All R versions on GitHub Actions macos-14                                    
+#>  4 [VM]  windows                                                                
+#>    All R versions on GitHub Actions windows-latest                              
+#>                                                                                 
+#> ── Containers ───────────────────────────────────────────────────────────────── 
+#>  5 [CT]  atlas  [ATLAS]                                                         
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/atlas:latest                                        
+#>  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang-asan:latest                                   
+#>  7 [CT]  clang16  [clang16]                                                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang16:latest                                      
+#>  8 [CT]  clang17  [clang17]                                                     
+#>    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang17:latest                                      
+#>  9 [CT]  clang18  [clang18]                                                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang18:latest                                      
+#> 10 [CT]  donttest  [donttest]                                                   
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/donttest:latest                                     
+#> 11 [CT]  gcc13  [gcc13]                                                         
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/gcc13:latest                                        
+#> 12 [CT]  intel  [Intel]                                                         
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/intel:latest                                        
+#> 13 [CT]  mkl  [MKL]                                                             
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/mkl:latest                                          
+#> 14 [CT]  nold  [noLD]                                                           
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/nold:latest                                         
+#> 15 [CT]  nosuggests  [noSuggests]                                               
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/nosuggests:latest                                   
+#> 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]                      
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/ubuntu-clang:latest                                 
+#> 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]                        
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/ubuntu-gcc12:latest                                 
+#> 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]               
+#>    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS            
+#>    ghcr.io/r-hub/containers/ubuntu-next:latest                                  
+#> 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]            
+#>    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS                           
+#>    ghcr.io/r-hub/containers/ubuntu-release:latest                               
+#> 20 [CT]  valgrind  [valgrind]                                                   
+#>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+#>    ghcr.io/r-hub/containers/valgrind:latest                                     
+
+}} + + +Run \code{rhub::rhub_check()} to start R-hub 2 checks on GitHub Actions: + +\if{html}{\out{
}}\preformatted{rhub::rhub_check() +}\if{html}{\out{
}}\if{html}{\out{ +
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Found GitHub PAT.                                                             
+#>                                                                                 
+#> Available platforms (see `rhub2::rhub_platforms()` for details):                
+#>                                                                                 
+#>  1 [VM] linux          R-* (any version)                     ubuntu-latest on G…
+#>  2 [VM] macos          R-* (any version)                     macos-latest on Gi…
+#>  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub 
+#>  4 [VM] windows        R-* (any version)                     windows-latest on …
+#>  5 [CT] atlas          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#>  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#>  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#>  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS 
+#>  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#> 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#> 11 [CT] gcc13          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#> 12 [CT] intel          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#> 13 [CT] mkl            R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#> 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 15 [CT] nosuggests     R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#> 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS 
+#> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS 
+#> 20 [CT] valgrind       R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+#>                                                                                 
+#> Selection (comma separated numbers, 0 to cancel): 1, 5                          
+#>                                                                                 
+#>  Check started: linux, atlas (francium-vaquita).                               
+#>   See <https://github.com/r-lib/cli/actions> for live output!                   
+
+}} + +} + +} + +\subsection{Code of Conduct}{ + +Please note that the callr project is released with a +\href{https://callr.r-lib.org/CODE_OF_CONDUCT.html}{Contributor Code of Conduct}. +By contributing to this project, you agree to abide by its terms. +} + +\subsection{License}{ + +MIT © R Consortium +} +} + \keyword{internal} diff --git a/man/rhub_check.Rd b/man/rhub_check.Rd index a381511..a8b90d2 100644 --- a/man/rhub_check.Rd +++ b/man/rhub_check.Rd @@ -1,74 +1,28 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/rhubv1.R +% Please edit documentation in R/check.R \name{rhub_check} \alias{rhub_check} -\title{An \code{rhub_check} object holds status and results of rhub checks} -\description{ -An \code{rhub_check} object holds status and results of rhub checks +\title{Check a package on R-hub} +\usage{ +rhub_check(gh_url = NULL, platforms = NULL, r_versions = NULL, branch = NULL) } -\section{Usage}{ - +\arguments{ +\item{gh_url}{GitHub URL of a package to check, or \code{NULL} to check +the package in the current directory.} -\if{html}{\out{
}}\preformatted{ch <- rhub_check$new(ids = NULL, status = NULL, group = NULL) -ch$get_ids() -ch$update() -ch$print(...) -ch$browse(which = NULL) -ch$urls(which = NULL) -ch$livelog(which = 1) -ch$cran_summary() -}\if{html}{\out{
}} -} +\item{platforms}{Platforms to use, a character vector. Use \code{NULL} to +select from a list in interactive sessions. See \code{\link[=rhub_platforms]{rhub_platforms()}}.} -\section{Arguments}{ +\item{r_versions}{Which R version(s) to use for the platforms that +supports multiple R versions. This arguemnt is not implemented yet.} -\itemize{ -\item \code{ch} An rhub check object. It can be created using \code{\link[=check]{check()}}, -and other check functions including \code{\link{check_for_cran}}. -See also \code{\link[=last_check]{last_check()}}. -\item \code{ids} Character vector of check ids. -\item \code{status} Check status for \code{ids} or \code{group}. -\item \code{group} Check group id, string scalar. Either \code{group} or \code{ids} must -be non-\code{NULL}. -\item \code{...} Extra arguments are currently ignored. -\item \code{which} Which check to show, if the object contains multiple -checks. For \code{browse} the default is all checks. For \code{livelog} the -default is the first check. A check can be selected via its number -or id. +\item{branch}{Branch to use to run R-hub. Defaults to the current +branch if \code{gh_url} is \code{NULL}. Otherwise defaults to \code{"main"}. Note that +this branch also need to include the \code{rhub.yaml} workflow file.} } +\value{ +TODO } - -\section{Details}{ - - -An \code{rhub_check} object can be created by \code{\link[=check]{check()}}, \code{\link[=list_my_checks]{list_my_checks()}}, -or \code{\link[=list_package_checks]{list_package_checks()}}. \code{\link[=last_check]{last_check()}} returns the last check(s) -submitted from the current R session. Do not confuse \code{rhub_check}/\code{rhub_check_for_cran} -(classes) with \code{\link[=check]{check()}} or \code{\link[=check_for_cran]{check_for_cran()}} (functions). - -\code{ch$get_ids()} returns the check ids. These can be used to query if a -check has finished. - -\code{ch$update()} updates the status of the check. Printing the check -status to the screen does not perform an update, unless the status of -the check(s) is unknown. - -\code{ch$print()} prints the status of the check(s) to the screen. - -\code{ch$cran_summary()} prints text to be copy-pasted in cran-comments.md, -it is especially useful on the output of \code{\link[=check_for_cran]{check_for_cran()}}. - -\code{ch$browse()} opens a tab or window in the default web browser, that points -to the detailed logs of the check(s). - -\code{ch$urls()} return a \code{\link[tibble:tibble]{tibble::tibble}} with URL to the html log, text log and artifacts -of the check(s). - -For both \code{ch$browse()} and \code{ch$urls()}, note that the logs and artifacts -are not kept forever, they are accessible for a few days after submission. - -\code{ch$livelog()} shows the live log of the check. The live log can be -interrupted using the usual interruption keyboard shortcut, usually -\code{CTRL+c} or \code{ESC}. +\description{ +Check a package on R-hub } - diff --git a/man/rhub_doctor.Rd b/man/rhub_doctor.Rd new file mode 100644 index 0000000..a3a1535 --- /dev/null +++ b/man/rhub_doctor.Rd @@ -0,0 +1,17 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/doctor.R +\name{rhub_doctor} +\alias{rhub_doctor} +\title{Check if the current or the specified package is ready to use with R-hub} +\usage{ +rhub_doctor(gh_url = NULL) +} +\arguments{ +\item{gh_url}{Use \code{NULL} for the package in the current working +directory. Alternatively, use the URL of a GitHub repository that +contains an R package that was set up to use with R-hub.} +} +\description{ +Errors if the package or repository is not set up correctly, and +advises on possible solutions. +} diff --git a/man/rhub_platforms.Rd b/man/rhub_platforms.Rd new file mode 100644 index 0000000..efaf412 --- /dev/null +++ b/man/rhub_platforms.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/platforms.R +\name{rhub_platforms} +\alias{rhub_platforms} +\title{List R-hub platforms} +\usage{ +rhub_platforms() +} +\value{ +Data frame with columns: +\itemize{ +\item \code{name}: platform name. Use this in the \code{platforms} argument of +\code{\link[=rhub_check]{rhub_check()}}. +\item \code{aliases}: alternative platform names. They can also be used in the +\code{platforms} argument of \code{\link[=rhub_check]{rhub_check()}}. +\item \code{type}: \code{"os"} or \code{"container"}. +\item \code{os_type}: Linux, macOS or Windows currently. +\item \code{container}: URL of the container image for container platforms. +\item \code{github_os}: name of the OS on GitHub Actions for non-container +platforms. +\item \code{r_version}: R version string. If \code{"*"} then any supported R version +can be selected for this platform. +\item \code{os_name}: name of the operating system, including Linux distribution +name and version for container actions. +} +} +\description{ +List R-hub platforms +} diff --git a/man/rhub_setup.Rd b/man/rhub_setup.Rd new file mode 100644 index 0000000..d673a4c --- /dev/null +++ b/man/rhub_setup.Rd @@ -0,0 +1,19 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/setup.R +\name{rhub_setup} +\alias{rhub_setup} +\title{Setup the current R package for use with R-hub} +\usage{ +rhub_setup(overwrite = FALSE) +} +\arguments{ +\item{overwrite}{if \code{TRUE}, \code{\link[=rhub_setup]{rhub_setup()}} will overwrite an already +existing workflow file.} +} +\value{ +Nothing. +} +\description{ +It adds or updates the R-hub workflow file to the current package, +and advises on next steps. +} diff --git a/man/rhubv2.Rd b/man/rhubv2.Rd new file mode 100644 index 0000000..17c51ff --- /dev/null +++ b/man/rhubv2.Rd @@ -0,0 +1,8 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rhubv2.R +\name{rhubv2} +\alias{rhubv2} +\title{R-hub v2} +\description{ +TODO +} diff --git a/man/roxygen/meta.R b/man/roxygen/meta.R new file mode 100644 index 0000000..7aadefa --- /dev/null +++ b/man/roxygen/meta.R @@ -0,0 +1,24 @@ +if (exists(".knitr_asciicast_process", envir = .GlobalEnv)) { + rm(list = ".knitr_asciicast_process", envir = .GlobalEnv) +} + +asciicast::init_knitr_engine( + echo = TRUE, + echo_input = FALSE, + timeout = as.integer(Sys.getenv("ASCIICAST_TIMEOUT", 10)), + startup = quote(options(cli.num_colors = 256)) +) + +knitr::opts_chunk$set( + asciicast_knitr_output = "html", + asciicast_include_style = FALSE, + cache = TRUE, + cache.path = file.path(getwd(), "man/_cache/"), + fig.path = file.path(getwd(), "man/figures"), + error = TRUE +) + +list( + markdown = TRUE, + restrict_image_formats = TRUE +) diff --git a/man/validate_email.Rd b/man/validate_email.Rd index 0d46707..1273269 100644 --- a/man/validate_email.Rd +++ b/man/validate_email.Rd @@ -2,35 +2,13 @@ % Please edit documentation in R/rhubv1.R \name{validate_email} \alias{validate_email} -\title{Validate an email address on R-hub} +\title{This function is deprecated and defunct. Please see \link{rhubv2}.} \usage{ -validate_email(email = NULL, token = NULL) +validate_email(...) } \arguments{ -\item{email}{The email address to validate.} - -\item{token}{Token obtained from \code{rhub}, to validate the email address.} +\item{...}{Deprecated.} } \description{ -To build and check R packages on R-hub, you need to validate your -email address. This is because R-hub sends out emails about check -results. +This function is deprecated and defunct. Please see \link{rhubv2}. } -\details{ -The \code{rhub} package stores validated email addresses in a user -configuration file, at a platform-dependent location. -On your current platform the file is at -\Sexpr[stage=render]{rhub:::email_file()}. - -To validate a new email address, call this function from an interactive -R session, without any arguments. - -To add an email address that was validated before (probably on another -machine), to the configuration file, call this function with the \code{email} -and \code{token} arguments. -} -\seealso{ -Other email validation: -\code{\link{list_validated_emails}()} -} -\concept{email validation} diff --git a/tests/testthat/helpers.R b/tests/testthat/helpers.R deleted file mode 100644 index 9cf8cf2..0000000 --- a/tests/testthat/helpers.R +++ /dev/null @@ -1,24 +0,0 @@ - -create_minimal_package <- function(dir = tempfile()) { - if (!file.exists(dir)) dir.create(dir) - - ## /R This is not strictly necessary, actually - dir.create(file.path(dir, "R")) - cat("f <- function() { }\n", file = file.path(dir, "R", "package.R")) - - ## NAMESPACE - cat("", file = file.path(dir, "NAMESPACE")) - - ## DESCRIPTION - desc::description$new("!new")$ - set(Package = basename(dir))$ - set(Title = "Title Case")$ - set(Maintainer = "first second ")$ - set(Description = "Minimal package for testing. Multiple.")$ - set(License = "GPL-2")$ - del("URL")$ - del("BugReports")$ - write(file.path(dir, "DESCRIPTION")) - - dir -} diff --git a/tests/testthat/test-api.R b/tests/testthat/test-api.R deleted file mode 100644 index 5ad307f..0000000 --- a/tests/testthat/test-api.R +++ /dev/null @@ -1,60 +0,0 @@ - -context("api") - -test_that("query", { - res <- NULL - with_mock( - `httr::GET` = function(...) res <<- list(...), - `httr::status_code` = function(...) { 200 }, - `httr::headers` = function(...) { }, - `httr::content` = function(...) { }, - query("GET PLATFORMS") - ) - expect_equal(length(res), 3) - expect_true(is_string(res[[1]])) - expect_equal(class(res[[2]]), "request") - - called <- FALSE - with_mock( - `rhub:::get_endpoint` = function(endpoint, params) - list(method = endpoint, path = "p"), - `httr::POST` = function(...) called <<- "POST", - `httr::DELETE` = function(...) called <<- "DELETE", - `rhub:::report_error` = function(...) { }, - `rhub:::parse_response` = function(...) { }, - query("POST"), - expect_identical(called, "POST"), - query("DELETE"), - expect_identical(called, "DELETE"), - expect_error(query("FOOBAR"), "Unexpected HTTP verb") - ) -}) - -test_that("parse_response", { - with_mock( - `httr::headers` = function(...) - list("content-type" = "application/json; charset: utf8"), - `httr::content` = function(...) - '{ "foo": "bar", "bar": [1,2,3] }', - expect_equal( - parse_response(NULL, as = NULL), - list(foo = "bar", bar = list(1,2,3)) - ), - expect_equal( - parse_response(NULL, as = "text"), - '{ "foo": "bar", "bar": [1,2,3] }' - ) - ) - - with_mock( - `httr::headers` = function(...) list(), - `httr::content` = function(...) "foobar", - expect_equal(parse_response(NULL), "foobar") - ) - - with_mock( - `httr::headers` = function(...) list("content-type" = "text/plain"), - `httr::content` = function(...) "foobar", - expect_equal(parse_response(NULL), "foobar") - ) -}) diff --git a/tests/testthat/test-assertions.R b/tests/testthat/test-assertions.R deleted file mode 100644 index c6233ae..0000000 --- a/tests/testthat/test-assertions.R +++ /dev/null @@ -1,90 +0,0 @@ - -context("assertions") - -test_that("is_pkg_dir", { - tmppkg <- tempfile() - dir.create(tmppkg) - - expect_false(is_pkg_dir(tmppkg)) - expect_false(is_pkg_dir_or_tarball(tmppkg)) - - cat("dummy\n", file = file.path(tmppkg, "DESCRIPTION")) - expect_true(is_pkg_dir(tmppkg)) - expect_true(is_pkg_dir_or_tarball(tmppkg)) -}) - -test_that("is_pkg_tarball", { - tmp <- tempfile(fileext="dummy") - cat("dummy\n", file = tmp) - tmppkg <- tempfile(fileext = ".tar.gz") - expect_false(is_pkg_tarball(tmp)) - expect_false(is_pkg_dir_or_tarball(tmppkg)) - - cat("dummy\n", file = tmppkg) - expect_true(is_pkg_tarball(tmppkg)) - expect_true(is_pkg_dir_or_tarball(tmppkg)) -}) - -test_that("is_string", { - pos <- list( - "foo", - "" - ) - for (p in pos) expect_true(is_string(p)) - - neg <- list( - character(), - 1:10, - c("foo", "bar"), - NULL - ) - for (n in neg) expect_false(is_string(n)) -}) - -test_that("assert_validated_email_for_check", { - - with_mock( - `rhub::email_get_token` = function(x) "your-token", - expect_silent(assert_validated_email_for_check("foobar@domain")) - ) - - with_mock( - `rhub::is_interactive` = function(x) FALSE, - expect_error(assert_validated_email_for_check(basename(tempfile()))) - ) -}) - -test_that("is_flag", { - pos <- list( - TRUE, - FALSE - ) - for (p in pos) expect_true(is_flag(p)) - - neg <- list( - logical(), - c(TRUE, TRUE), - "TRUE", - NULL - ) - for (n in neg) expect_false(is_flag(n)) -}) - -test_that("is_named", { - - pos <- list( - c(a = 1, b = 2, c = 3), - structure(double(), names = character()), - list(foo = 1), - structure(list(), names = character()) - ) - for (p in pos) expect_true(is_named(p)) - - neg <- list( - 1:5, - c(a = 1, 2, c = 3), - list(1, 2, 3), - list(a = 1, 2, c = 3) - ) - for (n in neg) expect_false(is_named(n)) -}) diff --git a/tests/testthat/test-build.R b/tests/testthat/test-build.R deleted file mode 100644 index 0d639d5..0000000 --- a/tests/testthat/test-build.R +++ /dev/null @@ -1,19 +0,0 @@ - -context("build") - -test_that("build_package", { - ## directory is packed up properly - create_minimal_package(pkg <- tempfile()) - path <- build_package(pkg, tempfile()) - expect_true(is_pkg_tarball(path)) - - ## tarball is not touched - path2 <- build_package(path, tempfile()) - expect_true(is_pkg_tarball(path2)) - expect_equal(file.info(path)$size, file.info(path2)$size) - - ## Error is reported if R CMD build fails - create_minimal_package(pkg <- tempfile()) - file.remove(file.path(pkg, "DESCRIPTION")) - expect_error(build_package(pkg, tempfile())) -}) diff --git a/tests/testthat/test-check.R b/tests/testthat/test-check.R deleted file mode 100644 index 0c4b07b..0000000 --- a/tests/testthat/test-check.R +++ /dev/null @@ -1,67 +0,0 @@ - -context("check") - -test_that("check", { - pkg <- create_minimal_package() - - ## From tarball - pkg_targz <- build_package(pkg, tempfile()) - sub <- NULL - ch <- with_mock( - `rhub::assert_validated_email_for_check` = function(...) TRUE, - `rhub::submit_package` = function(...) { - sub <<- list(...) - list(list(id = "foobar")) - }, - `rhub:::match_platform` = function(x) x, - check(pkg_targz, email = "e", platforms = "p", show_status = FALSE) - ) - - expect_equal(sub[[1]], "e") - expect_equal(sub[[3]], "p") - expect_equal(sub[[4]], character()) -}) - -test_that("check shortcuts", { - with_mock( - `rhub::check` = function(path = ".", platforms, ...) platforms, - expect_equal(check_on_linux(), check_shortcut_platforms$linux), - expect_equal(check_on_windows(), check_shortcut_platforms$windows), - - expect_equal(check_on_debian(), check_shortcut_platforms$debian), - expect_equal(check_on_ubuntu(), check_shortcut_platforms$ubuntu), - expect_equal(check_on_fedora(), check_shortcut_platforms$fedora), - - expect_equal(check_with_roldrel(), check_shortcut_platforms$roldrel), - expect_equal(check_with_rrelease(), check_shortcut_platforms$rrelease), - expect_equal(check_with_rpatched(), check_shortcut_platforms$rpatched), - expect_equal(check_with_rdevel(), check_shortcut_platforms$rdevel), - - expect_equal(check_with_valgrind(), check_shortcut_platforms$valgrind), - expect_equal( - check_with_sanitizers(), - check_shortcut_platforms$sanitizers - ) - ) -}) - -test_that("get_check", { - package_data$ids <- character() - package_data$groups <- character() - expect_error( - get_check("foo"), - "Short check id 'foo' can only be used for cached ids", - fixed = TRUE - ) - expect_error( - get_check(c("foo", "bar")), - "Short check id 'foo' (and 1 more) can only be used for cached ids", - fixed = TRUE - ) - real <- "rversions_2.1.1.9000.tar.gz-73d9f48a0ede4deeac27fb9910be2a02" - expect_error( - get_check(c("foo", "bar", real)), - "Short check id 'foo' (and 1 more) can only be used for cached ids", - fixed = TRUE - ) -}) diff --git a/tests/testthat/test-email.R b/tests/testthat/test-email.R deleted file mode 100644 index c0341ea..0000000 --- a/tests/testthat/test-email.R +++ /dev/null @@ -1,43 +0,0 @@ - -context("email") - -test_that("validate_email", { - - with_mock( - `rhub::is_interactive` = function() FALSE, - expect_error(validate_email("foo")) - ) -}) - -test_that("email_file", { - ## Cannot easily test the value - expect_silent(email_file()) -}) - -test_that("email_get_token, email_add_token", { - tmp <- tempfile() - with_mock( - `rhub::email_file` = function() tmp, - { - expect_null(email_get_token("bugs.bunny@acme.com")) - email_add_token("bugs.bunny@acme.com", "tokenxxx") - expect_equal(email_get_token("bugs.bunny@acme.com"), "tokenxxx") - expect_null(email_get_token("duffy.duck@acme.com")) - - email_add_token("bugs.bunny@acme.com", "token2") - expect_equal(email_get_token("bugs.bunny@acme.com"), "token2") - expect_null(email_get_token("duffy.duck@acme.com")) - } - ) - -}) - -test_that("validate_email assertions", { - - ## not an email address - expect_error(validate_email("foo", "bar")) - - ## not a valid token - expect_error(validate_email("foo@dom", "")) - expect_error(validate_email("foo@dom", "bar")) -}) diff --git a/tests/testthat/test-error.R b/tests/testthat/test-error.R deleted file mode 100644 index 2e78e6c..0000000 --- a/tests/testthat/test-error.R +++ /dev/null @@ -1,41 +0,0 @@ - -context("error") - -test_that("report_system_error", { - expect_silent(report_system_error(status = list(status = 0))) - - expect_error( - report_system_error( - "this is unacceptable", - list(status = 1, stderr = "", stdout = "out") - ), - "this is unacceptable" - ) - - expect_error( - report_system_error( - "this is unacceptable", - list(status = 1, stderr = "puff", stdout = "out") - ), - "this is unacceptable.*puff" - ) -}) - -test_that("report_error", { - with_mock( - `httr::status_code` = function(response) 200, - expect_silent(report_error("dummy")) - ) - with_mock( - `httr::status_code` = function(response) 404, - expect_error(report_error("dummy")) - ) -}) - -test_that("create_condition", { - with_mock( - `httr::content` = function(...) list(message = "not at all"), - cond <- create_condition("not good", call = sys.call()) - ) - expect_true("rhub_error" %in% class(cond)) -}) diff --git a/tests/testthat/test-platforms.R b/tests/testthat/test-platforms.R deleted file mode 100644 index 4a8f69a..0000000 --- a/tests/testthat/test-platforms.R +++ /dev/null @@ -1,171 +0,0 @@ - -context("platforms") - -json <- '[ - { - "name": "debian-gcc-devel", - "description": "Debian Linux, R-devel, GCC", - "cran-name": "r-devel-linux-x86_64-debian-gcc", - "rversion": "r-devel", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Debian GNU/Linux testing", - "compilers": "GCC 5.4.0 (Debian 5.4.0-4)", - "docker-image": "debian-gcc-devel", - "sysreqs-platform": "linux-x86_64-debian-gcc" - }, - - { - "name": "debian-gcc-release", - "description": "Debian Linux, R-release, GCC", - "cran-name": "r-release-linux-x86_64", - "rversion": "r-release", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Debian GNU/Linux testing", - "compilers": "GCC 5.3.1 (Debian 5.3.1-14)", - "docker-image": "debian-gcc-release", - "sysreqs-platform": "linux-x86_64-debian-gcc" - }, - - { - "name": "debian-gcc-patched", - "description": "Debian Linux, R-patched, GCC", - "cran-name": "r-patched-linux-x86_64", - "rversion": "r-patched", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Debian GNU/Linux testing", - "compilers": "GCC 5.4.0 (Debian 5.4.0-4)", - "docker-image": "debian-gcc-patched", - "sysreqs-platform": "linux-x86_64-debian-gcc" - }, - - { - "name": "fedora-gcc-devel", - "description": "Fedora Linux, R-devel, GCC", - "cran-name": "r-devel-linux-x86_64-fedora-gcc", - "rversion": "r-devel", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Fedora 24", - "compilers": "GCC 6.1.1", - "docker-image": "fedora-gcc-devel", - "sysreqs-platform": "linux-x86_64-fedora-gcc" - }, - - { - "name": "fedora-clang-devel", - "description": "Fedora Linux, R-devel, clang, gfortran", - "cran-name": "r-devel-linux-x86_64-fedora-clang", - "rversion": "r-devel", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Fedora 24", - "compilers": "clang version 3.8.0; GNU Fortran 6.1.1", - "docker-image": "fedora-clang-devel", - "sysreqs-platform": "linux-x86_64-fedora-clang" - }, - - { - "name": "ubuntu-gcc-devel", - "description": "Ubuntu Linux 16.04 LTS, R-devel, GCC", - "cran-name": null, - "rversion": "r-devel", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Ubuntu 16.04 LTS", - "compilers": "GCC 5.3.1", - "docker-image": "ubuntu-gcc-devel", - "sysreqs-platform": "linux-x86_64-ubuntu-gcc" - }, - - { - "name": "ubuntu-gcc-release", - "description": "Ubuntu Linux 16.04 LTS, R-release, GCC", - "cran-name": null, - "rversion": "r-release", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Ubuntu 16.04 LTS", - "compilers": "GCC 5.3.1", - "docker-image": "ubuntu-gcc-release", - "sysreqs-platform": "linux-x86_64-ubuntu-gcc" - }, - - { - "name": "linux-x86_64-centos6-epel", - "description": "CentOS 6, stock R from EPEL", - "cran-name": null, - "rversion": "r-release", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "CentOS 6", - "compilers": "GCC 4.4.x", - "docker-image": "centos6-epel", - "sysreqs-platform": "linux-x86_64-centos6-epel" - }, - - { - "name": "linux-x86_64-centos6-epel-rdt", - "description": "CentOS 6 with Redhat Developer Toolset, R from EPEL", - "cran-name": null, - "rversion": "r-release", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "CentOS 6", - "compilers": "GCC 5.2.1", - "docker-image": "centos6-epel-rdt", - "sysreqs-platform": "linux-x86_64-centos6-epel" - }, - - { - "name": "linux-x86_64-rocker-gcc-san", - "description": "Debian Linux, R-devel, GCC ASAN/UBSAN", - "cran-name": null, - "rversion": "r-devel", - "os-type": "Linux", - "cpu-type": "x86_64", - "os-info": "Debian GNU/Linux testing", - "compilers": "GCC 5.4.0 (Debian 5.4.0-4)", - "docker-image": "rocker-gcc-san", - "sysreqs-platform": "linux-x86_64-debian-gcc" - }, - - { - "name": "windows-x86_64-oldrel", - "description": "Windows Server 2008 R2 SP1, R-oldrel, 64 bit", - "cran-name": null, - "rversion": "r-oldrel", - "os-type": "Windows", - "cpu-type": "x86_64", - "os-info": "Windows Server 2008 R2 SP1", - "compilers": "GCC 4.6.3, Rtools 3.3", - "docker-image": null, - "sysreqs-platform": "windows-2008" - } -]' - -test_that("platforms", { - - with_mock( - `rhub::query` = function(...) json, - { - expect_silent(p <- platforms()) - expect_true("rhub_platforms" %in% class(p)) - expect_true("data.frame" %in% class(p)) - expect_equal(nrow(p), 11) - } - ) -}) - -test_that("print.rhub_platforms", { - - with_mock( - `rhub::query` = function(...) json, - expect_output( - print(platforms()), - "debian-gcc-patched:.*Debian Linux, R-patched, GCC" - ) - ) -}) diff --git a/tests/testthat/test-print.R b/tests/testthat/test-print.R deleted file mode 100644 index 02aa70e..0000000 --- a/tests/testthat/test-print.R +++ /dev/null @@ -1,9 +0,0 @@ - -context("print") - -test_that("header_line", { - expect_output( - header_line("title"), - "title" - ) -}) diff --git a/tests/testthat/test-submit.R b/tests/testthat/test-submit.R deleted file mode 100644 index 408005a..0000000 --- a/tests/testthat/test-submit.R +++ /dev/null @@ -1,38 +0,0 @@ - -context("submit") - -test_that("submit_package", { - pkg <- create_minimal_package() - pkg_targz <- build_package(pkg, tempfile()) - - args <- NULL - sp <- with_mock( - `rhub::header_line` = function(...) { }, - `rhub::query` = function(...) args <<- list(...), - `rhub::email_get_token` = function(...) "token", - submit_package("e@d", pkg_targz, "platform", c("arg1", "arg2"), - c("env" = "var")) - ) - - expect_identical(args[[1]], "SUBMIT PACKAGE") - - expect_identical( - names(args[[2]]), - c("email", "token", "package", "version", "platform", "env", - "check_args", "file") - ) - - expect_identical(args[[2]]$email, jsonlite::unbox("e@d")) - expect_identical(args[[2]]$token, jsonlite::unbox("token")) - expect_identical(args[[2]]$package, jsonlite::unbox(basename(pkg))) - expect_identical(args[[2]]$version, jsonlite::unbox("1.0.0")) - expect_identical(args[[2]]$platform, "platform") - expect_identical(args[[2]]$check_args, jsonlite::unbox("arg1 arg2")) - - ## Must be a base64 string - expect_match( - gsub("\\s+", "", args[[2]]$file), - "^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$", - perl = TRUE - ) -}) diff --git a/tests/testthat/test-utils.R b/tests/testthat/test-utils.R deleted file mode 100644 index 982c264..0000000 --- a/tests/testthat/test-utils.R +++ /dev/null @@ -1,66 +0,0 @@ - -context("utils") - -test_that("update", { - expect_equal( - update(list(a = 10, b = 20), list(a = 100, c = 5)), - list(a = 100, b = 20, c = 5) - ) - - expect_equal( - update(list(), list(a = 1, b = 2)), - list(a = 1, b = 2) - ) - - expect_equal( - update(list(a = 1, b = 2), list()), - list(a = 1, b = 2) - ) -}) - -test_that("parse_email", { - expect_equal( - parse_email("first second "), - "mail@foo.com" - ) - - expect_equal( - parse_email("the is no email here"), - NA_character_ - ) - - expect_equal( - parse_email(""), - "just-email@foo.com" - ) -}) - -test_that("get_maintainer_email", { - pkg <- create_minimal_package() - targz <- build_package(pkg, tempfile()) - - expect_equal(get_maintainer_email(pkg), "first.second@foo.bar") - expect_equal(get_maintainer_email(targz), "first.second@foo.bar") - - file.remove(file.path(pkg, "DESCRIPTION")) - tar(targz <- tempfile(fileext = ".tar.gz"), pkg, tar = "internal") - expect_error( - get_maintainer_email(targz), - "No 'DESCRIPTION' file in package" - ) -}) - -test_that("%||%", { - expect_identical( NULL %||% NULL, NULL) - expect_identical( NULL %||% "OK", "OK") - expect_identical( "OK" %||% NULL, "OK") - expect_silent( "OK" %||% print("foobar")) -}) - -test_that("is_interactive", { - expect_identical(is_interactive(), interactive()) -}) - -test_that("%:::%", { - expect_equal(parse_email, "rhub" %:::% "parse_email") -}) diff --git a/tests/testthat/test.R b/tests/testthat/test.R new file mode 100644 index 0000000..64b4fee --- /dev/null +++ b/tests/testthat/test.R @@ -0,0 +1,3 @@ +test_that("Placeholder", { + expect_true(TRUE) +}) diff --git a/vignettes/.gitignore b/vignettes/.gitignore deleted file mode 100644 index 097b241..0000000 --- a/vignettes/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -*.html -*.R diff --git a/vignettes/figures/check-output.gif b/vignettes/figures/check-output.gif deleted file mode 100644 index a0f35885b748467091769107ccda91d28ce4eb9c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 642364 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 z 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%0D44Gp8pATs!asw2Cc=I~Gu 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

`QMm!Yt*v0r3e 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 z

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 diff --git a/vignettes/figures/email-validation.png b/vignettes/figures/email-validation.png deleted file mode 100644 index 1ecb245146d0aafbbff44eecd470bb754b14800b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 112491 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 bJ+Y+}*sf!QZzQz}@D8{w!lv8`{mZ`r8~vE2 diff --git a/vignettes/local-debugging.Rmd b/vignettes/local-debugging.Rmd deleted file mode 100644 index 154910d..0000000 --- a/vignettes/local-debugging.Rmd +++ /dev/null @@ -1,140 +0,0 @@ ---- -title: "Local Linux checks with Docker" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{Local Linux checks with Docker} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -```{r setup} -library(rhub) -``` - -## Introduction - -Scenario: there's a bug in the check results of your package on a CRAN -Linux platform, or you saw such a bug even before CRAN submission, by -building your package on a R-hub Linux platform. How can you reproduce and -fix the bug? Submitting to the R-hub platform -([or the R-hub platform that's closest to the CRAN platform](https://docs.r-hub.io/#rhub-cran-platforms)) -after each tweak of your code would have a high turnaround so is not -optimal for debugging. R-hub's Linux Docker images are available for you to -use, so you can run the R-hub Linux builders locally. - -**Warning: at the moment, the functions are not tested on Windows! Bug - reports are welcome :-)** - -## Install and get to know Docker - -To be able to use the feature, you will need to install Docker. Please -refer to [Docker docs](https://docs.docker.com/install/). On Windows, -installation might be trickier, check that your machine -[meets the system requirements](https://docs.docker.com/docker-for-windows/install/#what-to-know-before-you-install). On -Linux, make sure to -[run the post-installation steps](https://docs.docker.com/install/linux/linux-postinstall/) -to make the `docker` command available to your user without the `sudo` -prefix. - -If you are new to Docker, for the basic use shown in the next two sections -you don't need to learn anything, you won't have to leave R. Nonetheless, -if you're curious, this tutorial -[features a nice introduction](https://jsta.github.io/r-docker-tutorial/01-what-and-why.html). -Also see [this blog post](https://colinfay.me/docker-r-reproducibility/) -and the list of resources it shows at the end. - -## List R-hub Linux images - -Each of R-hub Linux platforms is associated to a Docker image, whose -Dockerfile is stored in the -[r-hub/rhub-linux-builders repository](https://github.com/r-hub/rhub-linux-builders#rhub-linux-builders), -and that is built and available on Docker Hub. Note, if you're used to -using Docker images outside of R, you might want to just refer to the -information in -[R-hub Linux Docker images GitHub repository](https://github.com/r-hub/rhub-linux-builders#rhub-linux-builders) -(including links to the built images on Docker Hub). The advantage of using -the rhub package instead of Docker directly, is that the package will -install the system requirements properly. - -To list the available images from R, you can use the -`local_check_linux_images()` function that returns a `data.frame` and has a -pretty default printing. - -```{r list} -imgs <- local_check_linux_images() -imgs -knitr::kable(imgs, row.names = FALSE) -``` - -Of particular interest are - -* the `cranname` columns if you're trying to find an equivalent to a CRAN - platform; - -* the `name` platform which is the ID you should use to select that - platform. - -In theory, you could also use images that are not listed in the list above, -e.g. your own Docker images. - -## Run local checks - -Below we'll start a check of a package on the "rhub/debian-gcc-release" -image (Debian Linux, R-release, GCC). The first time you use an image on -your machine, it'll be downloaded from Docker Hub, which might take a -while. The image won't be deleted after use, so next time will be faster -until you clean up your machine's Docker images, which one should do once -in a while (note that R-hub images are regularly updated). - -```r -pkg_path <- "/home/maelle/Documents/R-hub/test-packages/note" -local_check_linux(pkg_path, image = "rhub/debian-gcc-release") -``` - -You can either just run the check as shown above, which will print a log to -the screen, including `R CMD check` results in the end, or assign it to an -object: - -```r -pkg_path <- "/home/maelle/Documents/R-hub/test-packages/note" -chk <- local_check_linux(pkg_path, image = "rhub/debian-gcc-release") -``` - -The object returned is of the class `rcmdcheck::rcmdcheck` which is an S3 -object with fields `errors`, `warnings` and `notes` (character vectors), -that you could operate on if you wish. - -The `local_check_linux()` function creates a container (instance of the -image) that won't be deleted after use so you might want to clean up once -in a while. - -## Do more with R-hub Linux images - -If running checks in images iteratively isn't enough for your debugging, -you might want to run the container created by `local_check_linux()`. Take -note of the container name and run (in a shell, not in R) - -``` -docker container start 7181196d-bc3c-4fc8-a0e8-dc511150335d-2 -docker exec -it 7181196d-bc3c-4fc8-a0e8-dc511150335d-2 bash -``` - -where `7181196d-bc3c-4fc8-a0e8-dc511150335d-2` is the container name, this -is printed out by `local_check_linux()`. After running these commands, you -will get a shell within the Docker container, where you can run R. Note -that on some containers R is installed in `/opt/`. - -For more information, you may want to look at the shell script that `rhub` -uses to set up the container for running the check. To find it, run the -code below. - -```{r} -system.file(package = "rhub", "bin", "rhub-linux-docker.sh") -``` diff --git a/vignettes/rhub.Rmd b/vignettes/rhub.Rmd deleted file mode 100644 index 1612937..0000000 --- a/vignettes/rhub.Rmd +++ /dev/null @@ -1,362 +0,0 @@ ---- -title: "Get started with `rhub`" -output: rmarkdown::html_vignette -vignette: > - %\VignetteIndexEntry{get-started} - %\VignetteEngine{knitr::rmarkdown} - %\VignetteEncoding{UTF-8} ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -In this article you'll learn how to use `rhub` to connect to the R-hub -builder API to start new checks and get the results and artifacts of recent -checks. - -```{r} -library(rhub) -``` - - -## Validate your email address - -To build and check packages, first you need to validate your email address with -`validate_email()`. - -![](figures/email-validation.png) - -The package tries to detect your email address using [`whoami`](https://github.com/r-lib/whoami#whoami) -(note that `whoami` does so using your global git config) -and the maintainer email listed in DESCRIPTION; and if it fails to do this -correctly, you'll need to specify it. This means that if running `validate_email()` -gives an error, you should either run `validate_email("youremail@example.com")` ( -quickest fix), or edit your global git config (less quick, but useful for -package development in general; to set it up smoothly -[refer to this `usethis` helper](https://usethis.r-lib.org/articles/articles/usethis-setup.html#configure-user-name-and-user-emails)). - -`rhub` stores the token permanently on the machine, so you do not need -to validate your email again. You can also copy your token to other -machines: run `list_validated_emails()` to get the token, and use the -`validate_email()` function on the new machine, using both the `email` and - `token` arguments. - -Currently you cannot use the token obtained via this function in the Web -UI of the R-hub builder. - -## Run a package check - -`check()` runs an `R CMD check` on the package in the specified directory, -or specified source R package tarball created by `R CMD build` or -`devtools::build()`. It defaults to the working directory. - -```r -check() -``` - -If the `platform` argument is NULL, and the R session is interactive, then -a menu is shown. If it is NULL, and the session is not interactive, then the -default R-hub platform `platforms()$name[1]`, i.e. `r platforms()$name[1]`, -is used. - -In interactive R sessions, the output of the check is printed to -the screen unless you set the `show_status` argument to `FALSE`. Therefore, -by default, your R session is busy showing the log until the check is finished, -so set `show_status` to `FALSE` if you want to submit a check and then go on -with your work in the same session. - -In all cases, you will receive a notification email with results after the check. - -![recording of a check on a screen](figures/check-output.gif) - -You can either just run the function, or assign its output to an object, that -you can use to print results to the screen, to browse the web page of the check, -and to retrieve URLs to the web page of the check but also to its artifacts -that are kept a few days. - -```r -mycheck <- check() -mycheck$browse() -mycheck$print() -mycheck$livelog() -mycheck$urls() -``` - -To retrieve such objects from previous checks, see [the corresponding section](#browse-previous-checks). - -## Select a building and checking architecture - -You can run checks on any platform. You can use the platform ids (e.g. `"debian-gcc-devel"` -or `c("debian-gcc-devel", "debian-gcc-patched")`) to select between platforms. -You should not run checks on all platforms at once. E.g. if preparing for a -CRAN submission, use the shortcut function `check_for_cran()` that will submit -your package to a few recommended platforms. The following subsections give -more info on how to select platforms. - -### Listing R-hub platforms - -If looking for a platform with particular characteristics, in -particular to reproduce a result from CRAN's own platform, have a look at the -R-hub platform characteristics. - -```{r platforms-info} -knitr::kable(platforms(), row.names = FALSE) -``` - -### Shortcuts for quick checks - -These are quick shortcuts that select the right platform(s): - -* `check_on_linux()` and `check_on_windows()` select the operating system. -* `check_on_debian()`, `check_on_ubuntu()`, `check_on_fedora()` and - `check_on_centos()` select an appropriate Linux platform. -* `check_on_solaris()` also selects an operating system, Solaris, and by -default checks neither vignettes nor manual (`--no-manual --no-build-vignettes`). -* `check_with_roldrel()`, `check_with_rrelease()`, `check_with_rpatched()` - and `check_with_rdevel()` select an R version. -* `check_for_cran()` runs checks on platforms that are closest to platforms used by CRAN on submission: - * Fedora Linux, R-devel, clang, gfortran, - * Ubuntu Linux 16.04 LTS, R-release, GCC, - * Windows Server 2008 R2 SP1, R-devel, 32⁄64 bit, - * and, if your package needs compilation, Debian Linux, R-devel, GCC ASAN/UBSAN. -You can run `rhub:::default_cran_check_platforms()` to find out which -platforms will be selected for your package. -* `check_with_valgrind()` runs the build and check on Linux, in `valgrind` - to find memory leaks and pointer errors. -* `check_with_sanitizers()` runs all package package tests, examples and - vignettes with Address Sanitizer and Undefined Behavior Sanitizer, see - below. - -### Sanitizers for compiled code - -R-hub provides a special Docker image to run Address Sanitizer (ASAN) and -Undefined Behavior Sanitizer (UBSAN). This is based on the `r-devel-san` -image of the [Rocker project](https://github.com/rocker-org/r-devel-san). - -This image does not run `R CMD check` at all, but it runs - -1. package tests, -2. all manual examples, and -3. all vignette code - -with ASAN and UBSAN enabled. Use it via `check_with_sanitizers()`. - -## Browse previous checks - -Once a check is finished (or failed), you will get a notification email but -you can also get information from R. E.g. you could submit a check for a -package located at ``, then turn off your computer and on the following days retrieve results -via - -```r -previous_checks <- rhub::list_package_checks(, - email = "maelle.salmon@yahoo.se", - howmany = 4) -previous_checks -``` - -```r -# A tibble: 10 x 13 - package version result group id platform_name build_time -

+ +
+## Setting up R-hub v2.
+##  Found R package at /private/tmp/cli.
+##  Found git repository at /private/tmp/cli.
+##  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.
+##
+## Notes:
+##  The workflow file must be added to the default branch of the GitHub
+##   repository.
+##  GitHub actions must be enabled for the repository. They are disabled for
+##   forked repositories by default.
+##
+## Next steps:
+##  Add the workflow file to git using `git add <filename>`.
+##  Commit it to git using `git commit`.
+##  Push the commit to GitHub using `git push`.
+##  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.
+##  Call `rhub2::rhub_check()` to check your package.
+
+ +
2. Run `git commit` and `git push` to push the workflow file to GitHub. @@ -79,9 +98,20 @@ rhub::rhub_setup() rhub::rhub_doctor() ``` - - - +
+ +
+##  Found R package at /private/tmp/cli.
+##  Found git repository at /private/tmp/cli.
+##  Found GitHub PAT.
+##  Found repository on GitHub at <https://github.com/r-lib/cli>.
+##  GitHub PAT has the right scopes.
+##  Found R-hub workflow in default branch, and it is active.
+## → WOOT! You are ready to run `rhub2::rhub_check()` on this package.
+
+ +
### Run checks @@ -92,23 +122,120 @@ checks: rhub::rhub_platforms() ``` - - - - -Run `rhub::rhub_check()` to start R-hub 2 checks on GitHub Actions: +
+ +
+## ── Virtual machines ───────────────────────────────────────────────────────────
+##  1 [VM]  linux
+##    All R versions on GitHub Actions ubuntu-latest
+##  2 [VM]  macos
+##    All R versions on GitHub Actions macos-latest
+##  3 [VM]  macos-arm64
+##    All R versions on GitHub Actions macos-14
+##  4 [VM]  windows
+##    All R versions on GitHub Actions windows-latest
+##
+## ── Containers ─────────────────────────────────────────────────────────────────
+##  5 [CT]  atlas  [ATLAS]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/atlas:latest
+##  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/clang-asan:latest
+##  7 [CT]  clang16  [clang16]
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/clang16:latest
+##  8 [CT]  clang17  [clang17]
+##    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/clang17:latest
+##  9 [CT]  clang18  [clang18]
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/clang18:latest
+## 10 [CT]  donttest  [donttest]
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/donttest:latest
+## 11 [CT]  gcc13  [gcc13]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/gcc13:latest
+## 12 [CT]  intel  [Intel]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/intel:latest
+## 13 [CT]  mkl  [MKL]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/mkl:latest
+## 14 [CT]  nold  [noLD]
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/nold:latest
+## 15 [CT]  nosuggests  [noSuggests]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/nosuggests:latest
+## 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/ubuntu-clang:latest
+## 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/ubuntu-gcc12:latest
+## 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]
+##    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/ubuntu-next:latest
+## 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]
+##    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS
+##    ghcr.io/r-hub/containers/ubuntu-release:latest
+## 20 [CT]  valgrind  [valgrind]
+##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
+##    ghcr.io/r-hub/containers/valgrind:latest
+
+ +
+ +Run `rhub::rhub_check()` to start R-hub v2 checks on GitHub Actions: ``` r rhub::rhub_check() ``` - - - +
+ +
+##  Found git repository at /private/tmp/cli.
+##  Found GitHub PAT.
+##
+## Available platforms (see `rhub2::rhub_platforms()` for details):
+##
+##  1 [VM] linux          R-* (any version)                     ubuntu-latest on G…
+##  2 [VM] macos          R-* (any version)                     macos-latest on Gi…
+##  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub
+##  4 [VM] windows        R-* (any version)                     windows-latest on …
+##  5 [CT] atlas          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+##  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+##  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+##  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS
+##  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+## 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+## 11 [CT] gcc13          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+## 12 [CT] intel          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+## 13 [CT] mkl            R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+## 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+## 15 [CT] nosuggests     R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+## 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+## 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+## 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS
+## 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS
+## 20 [CT] valgrind       R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
+##
+## Selection (comma separated numbers, 0 to cancel): 1, 5
+##
+##  Check started: linux, atlas (daft-acornwoodpecker).
+##   See <https://github.com/r-lib/cli/actions> for live output!
+
+ +
## Code of Conduct -Please note that the rhub project is released with a [Contributor Code +Please note that the callr project is released with a [Contributor Code of Conduct](https://callr.r-lib.org/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. diff --git a/_pkgdown.yml b/_pkgdown.yml index 62769ca..dd799e2 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -9,13 +9,18 @@ toc: depth: 3 reference: +- title: Introduction + desc: | + Start here if you are new to R-hub v2: + contents: + - rhubv2 + - title: All functions contents: - rhub_check - rhub_doctor - rhub_platforms - rhub_setup - - rhubv2 - title: internal contents: - check diff --git a/inst/header.md b/inst/header.md new file mode 100644 index 0000000..158aec3 --- /dev/null +++ b/inst/header.md @@ -0,0 +1,19 @@ + + + +# rhub + +> R-hub v2 + + +[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) +[![R-CMD-check](https://github.com/r-hub/rhub/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/r-hub/rhub/actions/workflows/R-CMD-check.yaml) +[![](https://www.r-pkg.org/badges/version/rhub)](https://www.r-pkg.org/pkg/rhub) +[![Codecov test coverage](https://codecov.io/gh/r-hub/rhub/branch/main/graph/badge.svg)](https://app.codecov.io/gh/r-hub/rhub?branch=main) + + +R-hub v2 uses GitHub Actions to run `R CMD check` and similar package checks. +The rhub package helps you set up R-hub v2 for your R package, and start +running checks. + +--- diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index b1a27d1..f5074cc 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -44,23 +44,23 @@ add the R-hub workflow file to your package. \if{html}{\out{
}}\preformatted{rhub::rhub_setup() }\if{html}{\out{
}}\if{html}{\out{
-#> Setting up R-hub v2.                                                            
-#>  Found R package at /private/tmp/cli.                                          
-#>  Found git repository at /private/tmp/cli.                                     
-#>  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.           
-#>                                                                                 
-#> Notes:                                                                          
-#>  The workflow file must be added to the default branch of the GitHub           
-#>   repository.                                                                   
-#>  GitHub actions must be enabled for the repository. They are disabled for      
-#>   forked repositories by default.                                               
-#>                                                                                 
-#> Next steps:                                                                     
-#>  Add the workflow file to git using `git add <filename>`.                      
-#>  Commit it to git using `git commit`.                                          
-#>  Push the commit to GitHub using `git push`.                                   
-#>  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.    
-#>  Call `rhub2::rhub_check()` to check your package.                             
+#> Setting up R-hub v2.
+#>  Found R package at /private/tmp/cli.
+#>  Found git repository at /private/tmp/cli.
+#>  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.
+#>
+#> Notes:
+#>  The workflow file must be added to the default branch of the GitHub
+#>   repository.
+#>  GitHub actions must be enabled for the repository. They are disabled for
+#>   forked repositories by default.
+#>
+#> Next steps:
+#>  Add the workflow file to git using `git add <filename>`.
+#>  Commit it to git using `git commit`.
+#>  Push the commit to GitHub using `git push`.
+#>  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.
+#>  Call `rhub2::rhub_check()` to check your package.
 
}} @@ -72,13 +72,13 @@ add the R-hub workflow file to your package. \if{html}{\out{
}}\preformatted{rhub::rhub_doctor() }\if{html}{\out{
}}\if{html}{\out{
-#>  Found R package at /private/tmp/cli.                                          
-#>  Found git repository at /private/tmp/cli.                                     
-#>  Found GitHub PAT.                                                             
-#>  Found repository on GitHub at <https://github.com/r-lib/cli>.                 
-#>  GitHub PAT has the right scopes.                                              
-#>  Found R-hub workflow in default branch, and it is active.                     
-#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package.             
+#>  Found R package at /private/tmp/cli.
+#>  Found git repository at /private/tmp/cli.
+#>  Found GitHub PAT.
+#>  Found repository on GitHub at <https://github.com/r-lib/cli>.
+#>  GitHub PAT has the right scopes.
+#>  Found R-hub workflow in default branch, and it is active.
+#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package.
 
}} @@ -91,104 +91,104 @@ Use \code{rhub::rhub_platforms()} to get a list of supported platforms and check \if{html}{\out{
}}\preformatted{rhub::rhub_platforms() }\if{html}{\out{
}}\if{html}{\out{
-#> ── Virtual machines ─────────────────────────────────────────────────────────── 
-#>  1 [VM]  linux                                                                  
-#>    All R versions on GitHub Actions ubuntu-latest                               
-#>  2 [VM]  macos                                                                  
-#>    All R versions on GitHub Actions macos-latest                                
-#>  3 [VM]  macos-arm64                                                            
-#>    All R versions on GitHub Actions macos-14                                    
-#>  4 [VM]  windows                                                                
-#>    All R versions on GitHub Actions windows-latest                              
-#>                                                                                 
-#> ── Containers ───────────────────────────────────────────────────────────────── 
-#>  5 [CT]  atlas  [ATLAS]                                                         
+#> ── Virtual machines ───────────────────────────────────────────────────────────
+#>  1 [VM]  linux
+#>    All R versions on GitHub Actions ubuntu-latest
+#>  2 [VM]  macos
+#>    All R versions on GitHub Actions macos-latest
+#>  3 [VM]  macos-arm64
+#>    All R versions on GitHub Actions macos-14
+#>  4 [VM]  windows
+#>    All R versions on GitHub Actions windows-latest
+#>
+#> ── Containers ─────────────────────────────────────────────────────────────────
+#>  5 [CT]  atlas  [ATLAS]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/atlas:latest                                        
-#>  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]                     
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/clang-asan:latest                                   
-#>  7 [CT]  clang16  [clang16]                                                     
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/clang16:latest                                      
-#>  8 [CT]  clang17  [clang17]                                                     
-#>    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/clang17:latest                                      
-#>  9 [CT]  clang18  [clang18]                                                     
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/clang18:latest                                      
-#> 10 [CT]  donttest  [donttest]                                                   
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/donttest:latest                                     
-#> 11 [CT]  gcc13  [gcc13]                                                         
+#>    ghcr.io/r-hub/containers/atlas:latest
+#>  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/clang-asan:latest
+#>  7 [CT]  clang16  [clang16]
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/clang16:latest
+#>  8 [CT]  clang17  [clang17]
+#>    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/clang17:latest
+#>  9 [CT]  clang18  [clang18]
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/clang18:latest
+#> 10 [CT]  donttest  [donttest]
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/donttest:latest
+#> 11 [CT]  gcc13  [gcc13]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/gcc13:latest                                        
-#> 12 [CT]  intel  [Intel]                                                         
+#>    ghcr.io/r-hub/containers/gcc13:latest
+#> 12 [CT]  intel  [Intel]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/intel:latest                                        
-#> 13 [CT]  mkl  [MKL]                                                             
+#>    ghcr.io/r-hub/containers/intel:latest
+#> 13 [CT]  mkl  [MKL]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/mkl:latest                                          
-#> 14 [CT]  nold  [noLD]                                                           
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/nold:latest                                         
-#> 15 [CT]  nosuggests  [noSuggests]                                               
+#>    ghcr.io/r-hub/containers/mkl:latest
+#> 14 [CT]  nold  [noLD]
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/nold:latest
+#> 15 [CT]  nosuggests  [noSuggests]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/nosuggests:latest                                   
-#> 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]                      
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/ubuntu-clang:latest                                 
-#> 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]                        
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
-#>    ghcr.io/r-hub/containers/ubuntu-gcc12:latest                                 
-#> 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]               
-#>    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS            
-#>    ghcr.io/r-hub/containers/ubuntu-next:latest                                  
-#> 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]            
-#>    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS                           
-#>    ghcr.io/r-hub/containers/ubuntu-release:latest                               
-#> 20 [CT]  valgrind  [valgrind]                                                   
+#>    ghcr.io/r-hub/containers/nosuggests:latest
+#> 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/ubuntu-clang:latest
+#> 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/ubuntu-gcc12:latest
+#> 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]
+#>    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/ubuntu-next:latest
+#> 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]
+#>    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS
+#>    ghcr.io/r-hub/containers/ubuntu-release:latest
+#> 20 [CT]  valgrind  [valgrind]
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/valgrind:latest                                     
+#>    ghcr.io/r-hub/containers/valgrind:latest
 
}} -Run \code{rhub::rhub_check()} to start R-hub 2 checks on GitHub Actions: +Run \code{rhub::rhub_check()} to start R-hub v2 checks on GitHub Actions: \if{html}{\out{
}}\preformatted{rhub::rhub_check() }\if{html}{\out{
}}\if{html}{\out{
-#>  Found git repository at /private/tmp/cli.                                     
-#>  Found GitHub PAT.                                                             
-#>                                                                                 
-#> Available platforms (see `rhub2::rhub_platforms()` for details):                
-#>                                                                                 
+#>  Found git repository at /private/tmp/cli.
+#>  Found GitHub PAT.
+#>
+#> Available platforms (see `rhub2::rhub_platforms()` for details):
+#>
 #>  1 [VM] linux          R-* (any version)                     ubuntu-latest on G…
 #>  2 [VM] macos          R-* (any version)                     macos-latest on Gi…
-#>  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub 
+#>  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub
 #>  4 [VM] windows        R-* (any version)                     windows-latest on …
 #>  5 [CT] atlas          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#>  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
-#>  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
-#>  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS 
-#>  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
-#> 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#>  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+#>  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+#>  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS
+#>  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+#> 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
 #> 11 [CT] gcc13          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 #> 12 [CT] intel          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 #> 13 [CT] mkl            R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#> 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
 #> 15 [CT] nosuggests     R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#> 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
-#> 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
-#> 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS 
-#> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS 
+#> 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+#> 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+#> 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS
+#> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS
 #> 20 [CT] valgrind       R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#>                                                                                 
-#> Selection (comma separated numbers, 0 to cancel): 1, 5                          
-#>                                                                                 
-#>  Check started: linux, atlas (francium-vaquita).                               
-#>   See <https://github.com/r-lib/cli/actions> for live output!                   
+#>
+#> Selection (comma separated numbers, 0 to cancel): 1, 5
+#>
+#>  Check started: linux, atlas (francium-vaquita).
+#>   See <https://github.com/r-lib/cli/actions> for live output!
 
}} From 0cfd990bc7c570f67ae0239f032d434f4ae17bda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 14 Mar 2024 12:29:41 +0100 Subject: [PATCH 06/22] Update GHA workflows, require R 4.0 --- .github/workflows/R-CMD-check.yaml | 9 +++++---- .github/workflows/pkgdown.yaml | 8 +++----- .github/workflows/pr-commands.yaml | 4 ++-- .github/workflows/test-coverage.yaml | 23 +++++++++++++++++++++-- DESCRIPTION | 2 ++ 5 files changed, 33 insertions(+), 13 deletions(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 091d3e1..4d6d4f5 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -22,11 +22,11 @@ jobs: fail-fast: false matrix: config: - - {os: macOS-latest, r: 'release'} + - {os: macos-latest, r: 'release'} - {os: windows-latest, r: 'release'} - # Use 3.6 to trigger usage of RTools35 - - {os: windows-latest, r: '3.6'} + # use 4.1 to check with rtools40's older compiler + - {os: windows-latest, r: '4.1'} - {os: ubuntu-latest, r: 'devel', http-user-agent: 'release'} - {os: ubuntu-latest, r: 'release'} @@ -40,7 +40,7 @@ jobs: R_KEEP_PKG_SOURCE: yes steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 @@ -58,3 +58,4 @@ jobs: - uses: r-lib/actions/check-r-package@v2 with: upload-snapshots: true + build_args: 'c("--no-manual","--compact-vignettes=gs+qpdf")' diff --git a/.github/workflows/pkgdown.yaml b/.github/workflows/pkgdown.yaml index cb7e7d8..f1a0231 100644 --- a/.github/workflows/pkgdown.yaml +++ b/.github/workflows/pkgdown.yaml @@ -23,7 +23,7 @@ jobs: permissions: contents: write steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-pandoc@v2 @@ -33,9 +33,7 @@ jobs: - uses: r-lib/actions/setup-r-dependencies@v2 with: - extra-packages: | - any::pkgdown - local::. + extra-packages: any::pkgdown, local::. needs: website - name: Build site @@ -48,7 +46,7 @@ jobs: - name: Deploy to GitHub pages 🚀 if: github.event_name != 'pull_request' - uses: JamesIves/github-pages-deploy-action@v4.4.1 + uses: JamesIves/github-pages-deploy-action@v4.5.0 with: clean: false branch: gh-pages diff --git a/.github/workflows/pr-commands.yaml b/.github/workflows/pr-commands.yaml index 97271eb..eea58c5 100644 --- a/.github/workflows/pr-commands.yaml +++ b/.github/workflows/pr-commands.yaml @@ -14,7 +14,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: @@ -51,7 +51,7 @@ jobs: env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: r-lib/actions/pr-fetch@v2 with: diff --git a/.github/workflows/test-coverage.yaml b/.github/workflows/test-coverage.yaml index 4b65418..21b8a93 100644 --- a/.github/workflows/test-coverage.yaml +++ b/.github/workflows/test-coverage.yaml @@ -15,7 +15,7 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: r-lib/actions/setup-r@v2 with: @@ -27,5 +27,24 @@ jobs: needs: coverage - name: Test coverage - run: covr::codecov(quiet = FALSE) + run: | + covr::codecov( + quiet = FALSE, + clean = FALSE, + install_path = file.path(normalizePath(Sys.getenv("RUNNER_TEMP"), winslash = "/"), "package") + ) shell: Rscript {0} + + - name: Show testthat output + if: always() + run: | + ## -------------------------------------------------------------------- + find '${{ runner.temp }}/package' -name 'testthat.Rout*' -exec cat '{}' \; || true + shell: bash + + - name: Upload test results + if: failure() + uses: actions/upload-artifact@v4 + with: + name: coverage-test-failures + path: ${{ runner.temp }}/package diff --git a/DESCRIPTION b/DESCRIPTION index db6c3a5..415de29 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -15,6 +15,8 @@ URL: https://github.com/r-hub/rhub, https://r-hub.github.io/rhub/ BugReports: https://github.com/r-hub/rhub/issues RoxygenNote: 7.3.1.9000 Roxygen: list(markdown = TRUE) +Depends: + R (>= 4.0) Imports: callr, cli, From 8905ab7db8504be254e3d5ce205b9b6956f8ba9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Thu, 14 Mar 2024 12:32:53 +0100 Subject: [PATCH 07/22] GHA: no oldrel-4 for now We need R 4.0 for magick. [ci skip] --- .github/workflows/R-CMD-check.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 4d6d4f5..b0aabba 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -33,7 +33,6 @@ jobs: - {os: ubuntu-latest, r: 'oldrel-1'} - {os: ubuntu-latest, r: 'oldrel-2'} - {os: ubuntu-latest, r: 'oldrel-3'} - - {os: ubuntu-latest, r: 'oldrel-4'} env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} From 262bd1d015c73728efbbbba6302c51583c31252e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 15 Mar 2024 16:29:46 +0100 Subject: [PATCH 08/22] Start writing RC API --- DESCRIPTION | 14 +-- LICENSE | 4 +- NAMESPACE | 10 ++ R/api.R | 32 ++++++ R/rc.R | 243 ++++++++++++++++++++++++++++++++++++++++++++ R/utils.R | 53 ++++++++++ man/rhub-package.Rd | 200 ++++++++++++++++++------------------ 7 files changed, 446 insertions(+), 110 deletions(-) create mode 100644 R/api.R create mode 100644 R/rc.R diff --git a/DESCRIPTION b/DESCRIPTION index 415de29..977aaf2 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,15 +1,15 @@ Package: rhub -Title: Connect to 'R-hub' -Version: 1.1.2.9000 +Title: Tools for R package developers +Version: 1.9.9.9000 Authors@R: c( person("Gábor", "Csárdi",, "csardi.gabor@gmail.com", role = c("aut", "cre")), person("Maëlle", "Salmon", role = "aut", email = "maelle.salmon@yahoo.se", comment = c(ORCID = "0000-0002-2815-0399")), person("R Consortium", role = c("fnd"))) -Description: Run 'R CMD check' on any of the 'R-hub' () - architectures, from the command line. The current architectures include - 'Windows', 'macOS', 'Solaris' and various 'Linux' distributions. +Description: R-hub v2 uses GitHub Actions to run `R CMD check` and + similar package checks. The rhub package helps you set up + R-hub v2 for your R package, and start running checks. License: MIT + file LICENSE URL: https://github.com/r-hub/rhub, https://r-hub.github.io/rhub/ BugReports: https://github.com/r-hub/rhub/issues @@ -26,8 +26,10 @@ Imports: gitcreds, jsonlite, processx, + rematch, R6, - rprojroot + rprojroot, + utils Suggests: asciicast, debugme, diff --git a/LICENSE b/LICENSE index 0b95b9e..9d833b7 100644 --- a/LICENSE +++ b/LICENSE @@ -1,2 +1,2 @@ -YEAR: 2019 -COPYRIGHT HOLDER: R Consortium +YEAR: 2019-2024 +COPYRIGHT HOLDER: R Consortium, Posit PBC diff --git a/NAMESPACE b/NAMESPACE index 8800019..23521b3 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,6 +30,8 @@ export(list_validated_emails) export(local_check_linux) export(local_check_linux_images) export(platforms) +export(rc_list_repos) +export(rc_new_token) export(rhub_check) export(rhub_doctor) export(rhub_platforms) @@ -40,6 +42,7 @@ importFrom(callr,r_process) importFrom(callr,r_process_options) importFrom(callr,r_session) importFrom(callr,rcmd_safe_env) +importFrom(cli,symbol) importFrom(curl,handle_data) importFrom(curl,handle_setheaders) importFrom(curl,handle_setopt) @@ -52,10 +55,17 @@ importFrom(curl,multi_set) importFrom(curl,new_handle) importFrom(curl,new_pool) importFrom(curl,parse_headers_list) +importFrom(jsonlite,toJSON) importFrom(processx,conn_get_fileno) importFrom(processx,process) +importFrom(rappdirs,user_data_dir) +importFrom(rematch,re_match) importFrom(utils,getSrcDirectory) importFrom(utils,getSrcFilename) importFrom(utils,getSrcLocation) importFrom(utils,head) +importFrom(utils,menu) importFrom(utils,modifyList) +importFrom(utils,read.csv) +importFrom(utils,write.table) +importFrom(whoami,email_address) diff --git a/R/api.R b/R/api.R new file mode 100644 index 0000000..3917b33 --- /dev/null +++ b/R/api.R @@ -0,0 +1,32 @@ +baseurl <- function() { + paste0(Sys.getenv("RHUB_SERVER", "https://builder2.rhub.io"), "/api/-") +} + +default_headers <- c( + "Accept" = "application/json", + "Content-Type" = "application/json", + "User-Agent" = "R-hub client" +) + +#' @importFrom jsonlite toJSON + +query <- function(endpoint, method = "GET", headers = character(), + data = NULL) { + + url <- paste0(baseurl(), endpoint) + headers <- update(default_headers, headers) + + response <- if (method == "GET") { + synchronise(http_get(url, headers = headers)) + + } else if (method == "POST") { + synchronise(http_post(url, headers = headers, data = data)) + + } else { + stop("Unexpected HTTP verb, internal rhub error") + } + + http_stop_for_status(response) + + response +} diff --git a/R/rc.R b/R/rc.R new file mode 100644 index 0000000..63c22d7 --- /dev/null +++ b/R/rc.R @@ -0,0 +1,243 @@ +# ========================================================================= +#' @export + +rc_new_token <- function(email = NULL, token = NULL) { + if (is.null(email) || is.null(token)) { + if (!is_interactive()) { + throw(pkg_error("No email or no token and not in interactive mode")) + } + return(rc_new_token_interactive(email, token)) + } + + email_add_token(email, token) + cli::cli_alert_success("Added token for {.val email}.", wrap = TRUE) + cli::cli_alert_info("R-hub tokens are stored at {.path {email_file()}}.") + invisible() +} + +# ------------------------------------------------------------------------- +#' @export + +rc_list_repos <- function(email = NULL) { + email <- email %||% guess_email(message = TRUE) + resp <- query("/repos", headers = get_auth_header(email)) + jsonlite::fromJSON(rawToChar(resp$content)) +} + +# ------------------------------------------------------------------------- +#' @export + +rc_submit <- function(path = ".", platforms = NULL, email = NULL, + r_versions = NULL) { + pkg_name <- desc::desc_get("Package", file = path)[[1]] + if (is.na(pkg_name)) { + throw(pkg_error( + "Could not query R package name at {.path {path}}.", + i = paste( + "Make sure that {.arg path} is an R package or a directory", + "contaiing an R package." + ) + )) + } + + email <- email %||% get_maintainer_email(path = path) + + if (is_dir(path)) { + path <- pkgbuild::build(path = path) + } + + query("job/") +} + +# ========================================================================= +# Internals +# ========================================================================= + +guess_email <- function(path = ".", message = TRUE) { + valid <- list_validated_emails2(message = FALSE) + maint <- tryCatch(get_maintainer_email(path), error = function(e) NULL) + if (!is.null(maint)) { + if (message) { + cli::cli_alert_info( + wrap = TRUE, + "Using maintainer email address {.val {maint}}." + ) + return(maint) + } + } + + guess <- email_address() + if (message) { + cli::cli_alert_info( + wrap = TRUE, + "Using email address {.val {guess}}." + ) + } +} + +get_auth_header <- function(email) { + valid <- list_validated_emails2(message = FALSE) + if (! email %in% valid$email) { + throw(pkg_error( + "Can't find token for email address {.val {guess}}.", + i = "Call {.code rhub::rc_new_token()} to get a token." + )) + } + token <- valid$token[match(email, valid$email)] + c("Authorization" = paste("Bearer", token)) +} + +#' @importFrom cli symbol +#' @importFrom utils menu +#' @importFrom whoami email_address + +get_email_to_validate <- function(path) { + + ## Find out email first. List currently validated addresses, + ## Offer address by whoami::email_address(), and also the + ## maintainer address, if any. + + valid <- list_validated_emails2(msg_if_empty = FALSE) + guess <- email_address() + maint <- tryCatch(get_maintainer_email(path), error = function(e) NULL) + + choices <- rbind( + if (nrow(valid)) cbind(valid = TRUE, valid), + if (!is.null(guess) && ! guess %in% valid$email) { + data_frame(valid = FALSE, email = guess, token = NA) + }, + if (!is.null(maint) && ! maint %in% valid$email && maint != guess) { + data_frame(valid = FALSE, email = maint, token = NA) + }, + data_frame(valid = NA, email = "New email address", token = NA) + ) + + ## Only show the menu if there is more than one thing there + if (nrow(choices) != 1) { + choices_str <- paste( + sep = " ", + ifelse( + choices$valid & !is.na(choices$valid), + cli::col_green(cli::symbol$tick), + " " + ), + choices$email + ) + + cat("\n") + title <- cli::col_yellow(paste0( + cli::symbol$line, cli::symbol$line, + " Choose email address to request token for (or 0 to exit)" + )) + ch <- menu(choices_str, title = title) + + if (ch == 0) throw(pkg_error("Cancelled requesting new token")) + + } else { + ch <- 1 + } + + ## Get another address if that is selected + if (is.na(choices$valid[ch])) { + cat("\n") + email <- readline("Email address: ") + } else { + email <- choices$email[ch] + } +} + +list_validated_emails2 <- function(message = is_interactive(), + msg_if_empty = TRUE) { + file <- email_file() + res <- if (file.exists(file)) { + if (message) { + cli::cli_alert( + "R-hub tokens are stored at {.path {email_file()}}." + ) + } + + structure( + read.csv(file, stringsAsFactors = FALSE, header = FALSE), + names = c("email", "token") + ) + } else { + data.frame( + email = character(), + token = character(), + stringsAsFactors = FALSE + ) + } + if (is_interactive() && nrow(res) == 0) { + if (msg_if_empty) { + cli::cli_alert_info("No R-hub tokens found.") + } + invisible(res) + } else { + res + } +} + +#' @importFrom rappdirs user_data_dir + +email_file <- function() { + rhub_data_dir <- user_data_dir("rhub", "rhub") + file.path(rhub_data_dir, "validated_emails.csv") +} + +rc_new_token_interactive <- function(email, token, path = ".") { + + if (is.null(email)) email <- get_email_to_validate(path) + + ## Token next. For this we need to make an API query. + if (is.null(token)) { + query( + method = "POST", + "/user/validate", + headers = c("content-type" = "application/x-www-form-urlencoded"), + data = jsonlite::toJSON(list(email = jsonlite::unbox(email))) + ) + cli::cli_alert_info( + "Please check your emails for the R-hub access token." + ) + token <- readline("Token: ") + } + + ## We got everything now + rc_new_token(email, token) +} + +#' @importFrom utils read.csv write.table + +email_add_token <- function(email, token) { + file <- email_file() + + if (!file.exists(file)) { + parent <- dirname(file) + if (!file.exists(parent)) dir.create(parent, recursive = TRUE) + tokens <- data.frame( + V1 = character(), + V2 = character(), + stringsAsFactors = FALSE + ) + + } else { + tokens <- read.csv(file, stringsAsFactors = FALSE, header = FALSE) + } + + if (! email %in% tokens[,1]) { + tokens <- rbind(tokens, c(email, token)) + + } else{ + tokens[match(email, tokens[,1]), 2] <- token + } + + write.table( + tokens, + file = file, + sep = ",", + col.names = FALSE, + row.names = FALSE + ) + + invisible() +} diff --git a/R/utils.R b/R/utils.R index 4a504fc..979da7e 100644 --- a/R/utils.R +++ b/R/utils.R @@ -107,3 +107,56 @@ random_id <- function() { readline <- function(prompt) { base::readline(prompt) } + +is_interactive <- function() { + opt <- getOption("rlib_interactive") + if (isTRUE(opt)) { + TRUE + } else if (identical(opt, FALSE)) { + FALSE + } else if (tolower(getOption("knitr.in.progress", "false")) == "true") { + FALSE + } else if (tolower(getOption("rstudio.notebook.executing", "false")) == "true") { + FALSE + } else if (identical(Sys.getenv("TESTTHAT"), "true")) { + FALSE + } else { + interactive() + } +} + +update <- function (original, new) { + if (length(new)) { + original[names(new)] <- new + } + original +} + +get_maintainer_email <- function(path = ".") { + path <- normalizePath(path) + if (is_dir(path)) { + if (!file.exists(file.path(path, "DESCRIPTION"))) { + stop("No 'DESCRIPTION' file found") + } + parse_email(desc::desc_get_maintainer(path)) + } else { + dir.create(tmp <- tempfile()) + files <- untar(path, list = TRUE, tar = "internal") + desc <- grep("^[^/]+/DESCRIPTION$", files, value = TRUE) + if (length(desc) < 1) stop("No 'DESCRIPTION' file in package") + untar(path, desc, exdir = tmp, tar = "internal") + parse_email(desc::desc_get_maintainer(file.path(tmp, desc))) + } +} + +is_dir <- function(x) { + file.info(x)$isdir +} + +#' @importFrom rematch re_match + +parse_email <- function(x) { + unname( + re_match(pattern = "<(?[^>]+)>", x)[, "email"] + ) +} diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index f5074cc..a03472a 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -5,9 +5,6 @@ \alias{rhub} \title{Tools for R package developers} \description{ -Tools for R package developers -} -\section{rhub \if{html}{\out{}}}{ \subsection{Installation}{ Install rhub from CRAN: @@ -44,23 +41,23 @@ add the R-hub workflow file to your package. \if{html}{\out{
}}\preformatted{rhub::rhub_setup() }\if{html}{\out{
}}\if{html}{\out{
-#> Setting up R-hub v2.
-#>  Found R package at /private/tmp/cli.
-#>  Found git repository at /private/tmp/cli.
-#>  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.
-#>
-#> Notes:
-#>  The workflow file must be added to the default branch of the GitHub
-#>   repository.
-#>  GitHub actions must be enabled for the repository. They are disabled for
-#>   forked repositories by default.
-#>
-#> Next steps:
-#>  Add the workflow file to git using `git add <filename>`.
-#>  Commit it to git using `git commit`.
-#>  Push the commit to GitHub using `git push`.
-#>  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.
-#>  Call `rhub2::rhub_check()` to check your package.
+#> Setting up R-hub v2.                                                            
+#>  Found R package at /private/tmp/cli.                                          
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.           
+#>                                                                                 
+#> Notes:                                                                          
+#>  The workflow file must be added to the default branch of the GitHub           
+#>   repository.                                                                   
+#>  GitHub actions must be enabled for the repository. They are disabled for      
+#>   forked repositories by default.                                               
+#>                                                                                 
+#> Next steps:                                                                     
+#>  Add the workflow file to git using `git add <filename>`.                      
+#>  Commit it to git using `git commit`.                                          
+#>  Push the commit to GitHub using `git push`.                                   
+#>  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.    
+#>  Call `rhub2::rhub_check()` to check your package.                             
 
}} @@ -72,13 +69,13 @@ add the R-hub workflow file to your package. \if{html}{\out{
}}\preformatted{rhub::rhub_doctor() }\if{html}{\out{
}}\if{html}{\out{
-#>  Found R package at /private/tmp/cli.
-#>  Found git repository at /private/tmp/cli.
-#>  Found GitHub PAT.
-#>  Found repository on GitHub at <https://github.com/r-lib/cli>.
-#>  GitHub PAT has the right scopes.
-#>  Found R-hub workflow in default branch, and it is active.
-#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package.
+#>  Found R package at /private/tmp/cli.                                          
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Found GitHub PAT.                                                             
+#>  Found repository on GitHub at <https://github.com/r-lib/cli>.                 
+#>  GitHub PAT has the right scopes.                                              
+#>  Found R-hub workflow in default branch, and it is active.                     
+#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package.             
 
}} @@ -91,65 +88,65 @@ Use \code{rhub::rhub_platforms()} to get a list of supported platforms and check \if{html}{\out{
}}\preformatted{rhub::rhub_platforms() }\if{html}{\out{
}}\if{html}{\out{
-#> ── Virtual machines ───────────────────────────────────────────────────────────
-#>  1 [VM]  linux
-#>    All R versions on GitHub Actions ubuntu-latest
-#>  2 [VM]  macos
-#>    All R versions on GitHub Actions macos-latest
-#>  3 [VM]  macos-arm64
-#>    All R versions on GitHub Actions macos-14
-#>  4 [VM]  windows
-#>    All R versions on GitHub Actions windows-latest
-#>
-#> ── Containers ─────────────────────────────────────────────────────────────────
-#>  5 [CT]  atlas  [ATLAS]
+#> ── Virtual machines ─────────────────────────────────────────────────────────── 
+#>  1 [VM]  linux                                                                  
+#>    All R versions on GitHub Actions ubuntu-latest                               
+#>  2 [VM]  macos                                                                  
+#>    All R versions on GitHub Actions macos-latest                                
+#>  3 [VM]  macos-arm64                                                            
+#>    All R versions on GitHub Actions macos-14                                    
+#>  4 [VM]  windows                                                                
+#>    All R versions on GitHub Actions windows-latest                              
+#>                                                                                 
+#> ── Containers ───────────────────────────────────────────────────────────────── 
+#>  5 [CT]  atlas  [ATLAS]                                                         
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/atlas:latest
-#>  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/clang-asan:latest
-#>  7 [CT]  clang16  [clang16]
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/clang16:latest
-#>  8 [CT]  clang17  [clang17]
-#>    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/clang17:latest
-#>  9 [CT]  clang18  [clang18]
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/clang18:latest
-#> 10 [CT]  donttest  [donttest]
-#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/donttest:latest
-#> 11 [CT]  gcc13  [gcc13]
+#>    ghcr.io/r-hub/containers/atlas:latest                                        
+#>  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang-asan:latest                                   
+#>  7 [CT]  clang16  [clang16]                                                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang16:latest                                      
+#>  8 [CT]  clang17  [clang17]                                                     
+#>    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang17:latest                                      
+#>  9 [CT]  clang18  [clang18]                                                     
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/clang18:latest                                      
+#> 10 [CT]  donttest  [donttest]                                                   
+#>    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/donttest:latest                                     
+#> 11 [CT]  gcc13  [gcc13]                                                         
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/gcc13:latest
-#> 12 [CT]  intel  [Intel]
+#>    ghcr.io/r-hub/containers/gcc13:latest                                        
+#> 12 [CT]  intel  [Intel]                                                         
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/intel:latest
-#> 13 [CT]  mkl  [MKL]
+#>    ghcr.io/r-hub/containers/intel:latest                                        
+#> 13 [CT]  mkl  [MKL]                                                             
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/mkl:latest
-#> 14 [CT]  nold  [noLD]
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/nold:latest
-#> 15 [CT]  nosuggests  [noSuggests]
+#>    ghcr.io/r-hub/containers/mkl:latest                                          
+#> 14 [CT]  nold  [noLD]                                                           
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/nold:latest                                         
+#> 15 [CT]  nosuggests  [noSuggests]                                               
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/nosuggests:latest
-#> 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/ubuntu-clang:latest
-#> 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]
-#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/ubuntu-gcc12:latest
-#> 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]
-#>    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/ubuntu-next:latest
-#> 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]
-#>    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS
-#>    ghcr.io/r-hub/containers/ubuntu-release:latest
-#> 20 [CT]  valgrind  [valgrind]
+#>    ghcr.io/r-hub/containers/nosuggests:latest                                   
+#> 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]                      
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/ubuntu-clang:latest                                 
+#> 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]                        
+#>    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+#>    ghcr.io/r-hub/containers/ubuntu-gcc12:latest                                 
+#> 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]               
+#>    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS            
+#>    ghcr.io/r-hub/containers/ubuntu-next:latest                                  
+#> 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]            
+#>    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS                           
+#>    ghcr.io/r-hub/containers/ubuntu-release:latest                               
+#> 20 [CT]  valgrind  [valgrind]                                                   
 #>    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-#>    ghcr.io/r-hub/containers/valgrind:latest
+#>    ghcr.io/r-hub/containers/valgrind:latest                                     
 
}} @@ -159,36 +156,36 @@ Run \code{rhub::rhub_check()} to start R-hub v2 checks on GitHub Actions: \if{html}{\out{
}}\preformatted{rhub::rhub_check() }\if{html}{\out{
}}\if{html}{\out{
-#>  Found git repository at /private/tmp/cli.
-#>  Found GitHub PAT.
-#>
-#> Available platforms (see `rhub2::rhub_platforms()` for details):
-#>
+#>  Found git repository at /private/tmp/cli.                                     
+#>  Found GitHub PAT.                                                             
+#>                                                                                 
+#> Available platforms (see `rhub2::rhub_platforms()` for details):                
+#>                                                                                 
 #>  1 [VM] linux          R-* (any version)                     ubuntu-latest on G…
 #>  2 [VM] macos          R-* (any version)                     macos-latest on Gi…
-#>  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub
+#>  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub 
 #>  4 [VM] windows        R-* (any version)                     windows-latest on …
 #>  5 [CT] atlas          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#>  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-#>  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-#>  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS
-#>  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-#> 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+#>  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#>  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#>  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS 
+#>  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+#> 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
 #> 11 [CT] gcc13          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 #> 12 [CT] intel          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 #> 13 [CT] mkl            R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#> 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+#> 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
 #> 15 [CT] nosuggests     R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#> 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
-#> 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
-#> 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS
-#> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS
+#> 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+#> 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS 
+#> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS 
 #> 20 [CT] valgrind       R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-#>
-#> Selection (comma separated numbers, 0 to cancel): 1, 5
-#>
-#>  Check started: linux, atlas (francium-vaquita).
-#>   See <https://github.com/r-lib/cli/actions> for live output!
+#>                                                                                 
+#> Selection (comma separated numbers, 0 to cancel): 1, 5                          
+#>                                                                                 
+#>  Check started: linux, atlas (francium-vaquita).                               
+#>   See <https://github.com/r-lib/cli/actions> for live output!                   
 
}} @@ -208,5 +205,4 @@ By contributing to this project, you agree to abide by its terms. MIT © R Consortium } } - \keyword{internal} From c1ac71f1b39118330c7140367ef74908c97d4472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Fri, 15 Mar 2024 16:30:35 +0100 Subject: [PATCH 09/22] Update embedded async --- R/aaa-async.R | 181 ++++++++++++++++++++++++++++++++++---------------- 1 file changed, 124 insertions(+), 57 deletions(-) diff --git a/R/aaa-async.R b/R/aaa-async.R index 7736865..d1ed1b1 100644 --- a/R/aaa-async.R +++ b/R/aaa-async.R @@ -1334,7 +1334,7 @@ def__resolve <- function(self, private, value) { #' @param private private self #' @return error object #' -#' @noRd +#' @keywords internal def__make_error_object <- function(self, private, err) { class(err) <- unique(c("async_rejected", class(err))) @@ -1757,8 +1757,6 @@ el_init <- function(self, private) { invisible(self) } -#' @importFrom curl multi_add parse_headers_list handle_data - el_add_http <- function(self, private, handle, callback, progress, file, data) { self; private; handle; callback; progress; outfile <- file; data @@ -1770,7 +1768,7 @@ el_add_http <- function(self, private, handle, callback, progress, file, content <- NULL - multi_add( + curl::multi_add( handle = handle, pool = private$pool, done = function(response) { @@ -1852,13 +1850,11 @@ el_add_next_tick <- function(self, private, func, callback, data) { private$next_ticks <- c(private$next_ticks, id) } -#' @importFrom curl multi_cancel - el_cancel <- function(self, private, id) { private$next_ticks <- setdiff(private$next_ticks, id) private$timers <- private$timers[setdiff(names(private$timers), id)] if (id %in% names(private$tasks) && private$tasks[[id]]$type == "http") { - multi_cancel(private$tasks[[id]]$data$handle) + curl::multi_cancel(private$tasks[[id]]$data$handle) } else if (id %in% names(private$tasks) && private$tasks[[id]]$type %in% c("process", "r-process")) { private$tasks[[id]]$data$process$kill() @@ -1870,11 +1866,9 @@ el_cancel <- function(self, private, id) { invisible(self) } -#' @importFrom curl multi_cancel multi_list - el_cancel_all <- function(self, private) { - http <- multi_list(pool = private$pool) - lapply(http, multi_cancel) + http <- curl::multi_list(pool = private$pool) + lapply(http, curl::multi_cancel) private$next_ticks <- character() private$timers <- Sys.time()[numeric()] @@ -1969,8 +1963,6 @@ el__run_pending <- function(self, private) { length(next_ticks) > 0 || finished_pool } -#' @importFrom curl multi_run multi_fdset - el__io_poll <- function(self, private, timeout) { types <- vcapply(private$tasks, "[[", "type") @@ -2026,7 +2018,7 @@ el__io_poll <- function(self, private, timeout) { } if (!is.null(private$curl_timer) && private$curl_timer <= private$time) { - multi_run(timeout = 0L, poll = TRUE, pool = private$pool) + curl::multi_run(timeout = 0L, poll = TRUE, pool = private$pool) private$curl_timer <- NULL } @@ -2038,7 +2030,7 @@ el__io_poll <- function(self, private, timeout) { ## Any HTTP? if (private$curl_poll && pollables$ready[match("curl", pollables$type)] == "event") { - multi_run(timeout = 0L, poll = TRUE, pool = private$pool) + curl::multi_run(timeout = 0L, poll = TRUE, pool = private$pool) } ## Any processes @@ -2111,8 +2103,6 @@ el__create_task <- function(self, private, callback, data, ..., id, type) { id } -#' @importFrom curl new_pool - el__ensure_pool <- function(self, private) { getopt <- function(nm) { anm <- paste0("async_http_", nm) @@ -2126,7 +2116,7 @@ el__ensure_pool <- function(self, private) { host_con = getopt("host_con") %||% 6, multiplex = getopt("multiplex") %||% TRUE ) - private$pool <- new_pool( + private$pool <- curl::new_pool( total_con = private$http_opts$total_con, host_con = private$http_opts$host_con, multiplex = private$http_opts$multiplex @@ -2134,14 +2124,12 @@ el__ensure_pool <- function(self, private) { } } -#' @importFrom curl multi_set - el_http_setopt <- function(self, private, total_con, host_con, multiplex) { private$ensure_pool() if (!is.null(total_con)) private$http_opts$total_con <- total_con if (!is.null(host_con)) private$http_opts$host_con <- host_con if (!is.null(multiplex)) private$http_opts$multiplex <- multiplex - multi_set( + curl::multi_set( pool = private$pool, total_con = private$http_opts$total_con, host_con = private$http_opts$host_con, @@ -2195,10 +2183,8 @@ el__update_time <- function(self, private) { private$time <- Sys.time() } -#' @importFrom curl multi_fdset -#' el__update_curl_data <- function(self, private) { - private$curl_fdset <- multi_fdset(private$pool) + private$curl_fdset <- curl::multi_fdset(private$pool) num_fds <- length(unique(unlist(private$curl_fdset[1:3]))) private$curl_poll <- num_fds > 0 private$curl_timer <- if ((t <- private$curl_fdset$timeout) != -1) { @@ -2536,7 +2522,6 @@ async_reject <- mark_as_async(async_reject) #' #' @family asyncronous HTTP calls #' @noRd -#' @importFrom curl new_handle handle_setheaders #' @examples #' \donttest{ #' afun <- async(function() { @@ -2555,8 +2540,8 @@ http_get <- function(url, headers = character(), file = NULL, make_deferred_http( function() { assert_that(is_string(url)) - handle <- new_handle(url = url) - handle_setheaders(handle, .list = headers) + handle <- curl::new_handle(url = url) + curl::handle_setheaders(handle, .list = headers) if (!is.null(on_progress)) { options$noprogress <- FALSE @@ -2575,7 +2560,7 @@ http_get <- function(url, headers = character(), file = NULL, reg.finalizer(handle, function(...) fun, onexit = TRUE) } - handle_setopt(handle, .list = options) + curl::handle_setopt(handle, .list = options) list(handle = handle, options = options) }, file @@ -2591,7 +2576,6 @@ http_get <- mark_as_async(http_get) #' #' @family asyncronous HTTP calls #' @noRd -#' @importFrom curl handle_setopt #' @examples #' \donttest{ #' afun <- async(function() { @@ -2618,9 +2602,9 @@ http_head <- function(url, headers = character(), file = NULL, make_deferred_http( function() { assert_that(is_string(url)) - handle <- new_handle(url = url) - handle_setheaders(handle, .list = headers) - handle_setopt(handle, customrequest = "HEAD", nobody = TRUE, + handle <- curl::new_handle(url = url) + curl::handle_setheaders(handle, .list = headers) + curl::handle_setopt(handle, customrequest = "HEAD", nobody = TRUE, .list = options) list(handle = handle, options = options) }, @@ -2637,7 +2621,13 @@ http_head <- mark_as_async(http_head) #' #' @inheritParams http_get #' @param data Data to send. Either a raw vector, or a character string -#' that will be converted to raw with [base::charToRaw]. +#' that will be converted to raw with [base::charToRaw]. At most one of +#' `data`, `data_file` and `data_form` can be non `NULL`. +#' @param data_file Data file to send. At most one of `data`, `data_file` +#' and `data_form` can be non `NULL`. +#' @param data_form Form data to send. A name list, where each element +#' is created with either [curl::form_data()] or [curl::form_file()]. +#' At most one of `data`, `data_file` and `data_form` can be non `NULL`. #' @param on_progress Progress handler function. It is only used if the #' response body is written to a file. See details at [http_get()]. #' @@ -2656,21 +2646,34 @@ http_head <- mark_as_async(http_head) #' #' synchronise(do()) -http_post <- function(url, data, headers = character(), file = NULL, +http_post <- function(url, data = NULL, data_file = NULL, + data_form = NULL, headers = character(), file = NULL, options = list(), on_progress = NULL) { - url; data; headers; file; options; on_progress - if (!is.raw(data)) data <- charToRaw(data) + url; data; data_file; data_form; headers; file; options; on_progress + if ((!is.null(data) + !is.null(data_file) + !is.null(data_form)) > 1) { + stop( + "At most one of `data`, `data_file` and `data_form` ", + "can be non `NULL`." + ) + } + if (!is.null(data_file)) { + data <- readBin(data_file, "raw", file.size(data_file)) + } + if (!is.null(data) && !is.raw(data)) data <- charToRaw(data) options <- get_default_curl_options(options) make_deferred_http( function() { assert_that(is_string(url)) - handle <- new_handle(url = url) - handle_setheaders(handle, .list = headers) - handle_setopt(handle, customrequest = "POST", + handle <- curl::new_handle(url = url) + curl::handle_setheaders(handle, .list = headers) + curl::handle_setopt(handle, customrequest = "POST", postfieldsize = length(data), postfields = data, .list = options) + if (!is.null(data_form)) { + curl::handle_setform(handle, .list = data_form) + } list(handle = handle, options = options) }, file @@ -2679,6 +2682,24 @@ http_post <- function(url, data, headers = character(), file = NULL, http_post <- mark_as_async(http_post) +http_delete <- function(url, headers = character(), file = NULL, + options = list()) { + url; headers; options; + + make_deferred_http( + function() { + assert_that(is_string(url)) + handle <- curl::new_handle(url = url) + curl::handle_setheaders(handle, .list = headers) + curl::handle_setopt(handle, customrequest = "DELETE", .list = options) + list(handle = handle, options = options) + }, + file + ) +} + +http_delete <- mark_as_async(http_delete) + #' @importFrom utils modifyList get_default_curl_options <- function(options) { @@ -2957,7 +2978,10 @@ async_map_limit <- function(.x, .f, ..., .args = list(), .limit = Inf) { ## nocov start .onLoad <- function(libname, pkgname) { - if (requireNamespace("debugme", quietly = TRUE)) debugme::debugme() + if (Sys.getenv("DEBUGME") != "" && + requireNamespace("debugme", quietly = TRUE)) { + debugme::debugme() + } } ## nocov end @@ -2974,7 +2998,6 @@ async_map_limit <- function(.x, .f, ..., .args = list(), .limit = Inf) { #' #' @family asynchronous external processes #' @noRd -#' @importFrom processx process #' @examples #' \dontrun{ #' afun <- function() { @@ -3001,9 +3024,10 @@ run_process <- function(command = NULL, args = character(), reject <- environment(resolve)$private$reject stdout <- tempfile() stderr <- tempfile() - px <- process$new(command, args = args, + px <- processx::process$new(command, args = args, stdout = stdout, stderr = stderr, poll_connection = TRUE, - env = env, cleanup = TRUE, wd = wd, encoding = encoding, ...) + env = env, cleanup = TRUE, cleanup_tree = TRUE, wd = wd, + encoding = encoding, ...) pipe <- px$get_poll_connection() id <<- get_default_event_loop()$add_process( list(pipe), @@ -3026,7 +3050,6 @@ run_process <- mark_as_async(run_process) #' #' @inheritParams callr::r_bg #' @noRd -#' @importFrom callr r_process_options r_process rcmd_safe_env #' #' @examples #' \dontrun{ @@ -3039,7 +3062,7 @@ run_process <- mark_as_async(run_process) run_r_process <- function(func, args = list(), libpath = .libPaths(), repos = c(getOption("repos"), c(CRAN = "https://cloud.r-project.org")), cmdargs = c("--no-site-file", "--slave", "--no-save", "--no-restore"), - system_profile = FALSE, user_profile = FALSE, env = rcmd_safe_env()) { + system_profile = FALSE, user_profile = FALSE, env = callr::rcmd_safe_env()) { func; args; libpath; repos; cmdargs; system_profile; user_profile; env @@ -3052,12 +3075,13 @@ run_r_process <- function(func, args = list(), libpath = .libPaths(), reject <- environment(resolve)$private$reject stdout <- tempfile() stderr <- tempfile() - opts <- r_process_options( + opts <- callr::r_process_options( func = func, args = args, libpath = libpath, repos = repos, cmdargs = cmdargs, system_profile = system_profile, user_profile = user_profile, env = env, stdout = stdout, - stderr = stderr) - rx <- r_process$new(opts) + stderr = stderr, extra = list(cleanup_tree = TRUE)) + + rx <- callr::r_process$new(opts) pipe <- rx$get_poll_connection() id <<- get_default_event_loop()$add_r_process( list(pipe), @@ -3073,6 +3097,43 @@ run_r_process <- function(func, args = list(), libpath = .libPaths(), run_r_process <- mark_as_async(run_r_process) +#' A deferred value that resolves when the specified number of deferred +#' values resolve, or is rejected when one of them is rejected +#' +#' These functions are similar to [when_some()] and [when_any()], but they +#' do not ignore errors. If a deferred is rejected, then `async_race_some()` and +#' `async_race()` are rejected as well. +#' +#' `async_race()` is a special case of `count = `: it resolves or is rejected +#' as soon as one deferred resolves or is rejected. +#' +#' async has auto-cancellation, so if the required number of deferred values +#' are resolved, or any deferred value is rejected, the rest are cancelled. +#' +#' @param count Number of deferred values that need to resolve. +#' @param ... Deferred values. +#' @param .list More deferred values. +#' @return A deferred value, that is conditioned on all deferred values +#' in `...` and `.list`. +#' +#' @noRd + +async_race_some <- function(count, ..., .list = list()) { + when_some_internal(count, ..., .list = .list, .race = TRUE) +} + +async_race_some <- mark_as_async(async_race_some) + +#' @noRd +#' @rdname async_race_some + +async_race <- function(..., .list = list()) { + when_some_internal(1L, ..., .list = .list, .race = TRUE)$ + then(function(x) x[[1]]) +} + +async_race <- mark_as_async(async_race) + #' Make an asynchronous function that always succeeds #' #' This is sometimes useful, if the function is applied to entries in @@ -3837,7 +3898,7 @@ get_private <- function(x) { #' or the error thrown. #' @param info Extra info to add to the error object. Must be a named list. #' -#' @noRd +#' @keywords internal call_with_callback <- function(func, callback, info = NULL) { recerror <- NULL @@ -4045,7 +4106,14 @@ when_all <- mark_as_async(when_all) #' } when_some <- function(count, ..., .list = list()) { + when_some_internal(count, ..., .list = .list, .race = FALSE) +} + +when_some <- mark_as_async(when_some) + +when_some_internal <- function(count, ..., .list, .race) { force(count) + force(.race) defs <- c(list(...), .list) num_defs <- length(defs) num_failed <- 0L @@ -4072,6 +4140,9 @@ when_some <- function(count, ..., .list = list()) { } }, parent_reject = function(value, resolve) { + if (.race) { + stop(value) + } num_failed <<- num_failed + 1L errors <<- c(errors, list(value)) if (num_failed + count == num_defs + 1L) { @@ -4084,8 +4155,6 @@ when_some <- function(count, ..., .list = list()) { ) } -when_some <- mark_as_async(when_some) - #' @noRd #' @rdname when_some @@ -4203,9 +4272,6 @@ wp_init <- function(self, private) { invisible(self) } -#' @importFrom callr r_session -#' @importFrom processx conn_get_fileno - wp_start_workers <- function(self, private) { num <- worker_pool_size() @@ -4214,8 +4280,8 @@ wp_start_workers <- function(self, private) { ## Yeah, start some more to_start <- num - NROW(private$workers) - sess <- lapply(1:to_start, function(x) r_session$new(wait = FALSE)) - fd <- viapply(sess, function(x) conn_get_fileno(x$get_poll_connection())) + sess <- lapply(1:to_start, function(x) callr::r_session$new(wait = FALSE)) + fd <- viapply(sess, function(x) processx::conn_get_fileno(x$get_poll_connection())) new_workers <- data.frame( stringsAsFactors = FALSE, session = I(sess), @@ -4481,6 +4547,7 @@ external_process <- function(process_generator, error_on_status = TRUE, process_generator; error_on_status; args <- list(...) args$encoding <- args$encoding %||% "" + args$cleanup_tree <- args$cleanup_tree %||% TRUE id <- NULL @@ -4497,7 +4564,7 @@ external_process <- function(process_generator, error_on_status = TRUE, list(pipe), function(err, res) if (is.null(err)) resolve(res) else reject(err), list(process = px, stdout = stdout, stderr = stderr, - error_on_status = TRUE, encoding = args$encoding) + error_on_status = error_on_status, encoding = args$encoding) ) }, on_cancel = function(reason) { From 6938e693be04cd6a16fefa48912082bd5ec36410 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Mon, 18 Mar 2024 21:22:31 +0100 Subject: [PATCH 10/22] Update embedded async To have HTTP event emitters and SSE. --- R/aaa-async.R | 238 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 231 insertions(+), 7 deletions(-) diff --git a/R/aaa-async.R b/R/aaa-async.R index d1ed1b1..290df27 100644 --- a/R/aaa-async.R +++ b/R/aaa-async.R @@ -1087,9 +1087,10 @@ deferred <- R6Class( initialize = function(action = NULL, on_progress = NULL, on_cancel = NULL, parents = NULL, parent_resolve = NULL, parent_reject = NULL, type = NULL, - call = sys.call(-1)) + call = sys.call(-1), event_emitter = NULL) async_def_init(self, private, action, on_progress, on_cancel, - parents, parent_resolve, parent_reject, type, call), + parents, parent_resolve, parent_reject, type, call, + event_emitter), then = function(on_fulfilled) def_then(self, private, on_fulfilled), catch = function(...) @@ -1098,7 +1099,9 @@ deferred <- R6Class( def_finally(self, private, on_finally), cancel = function(reason = "Cancelled") def_cancel(self, private, reason), - share = function() { private$shared <<- TRUE; invisible(self) } + share = function() { private$shared <<- TRUE; invisible(self) }, + + event_emitter = NULL ), private = list( @@ -1150,7 +1153,7 @@ deferred <- R6Class( async_def_init <- function(self, private, action, on_progress, on_cancel, parents, parent_resolve, - parent_reject, type, call) { + parent_reject, type, call, event_emitter) { private$type <- type private$id <- get_id() @@ -1158,6 +1161,7 @@ async_def_init <- function(self, private, action, on_progress, private$parents <- parents private$action <- action private$mycall <- call + self$event_emitter <- event_emitter "!DEBUG NEW `private$id` (`type`)" @@ -1773,12 +1777,15 @@ el_add_http <- function(self, private, handle, callback, progress, file, pool = private$pool, done = function(response) { task <- private$tasks[[id]] + task$data$data$event_emitter$emit("end") private$tasks[[id]] <- NULL response$content <- do.call(c, as.list(content)) response$file <- outfile task$callback(NULL, response) }, data = function(bytes, ...) { + task <- private$tasks[[id]] + task$data$data$event_emitter$emit("data", bytes) if (!is.null(outfile)) { ## R runs out of connections very quickly, especially because they ## are not removed until a gc(). However, calling gc() is @@ -2268,7 +2275,7 @@ el__update_curl_data <- function(self, private) { #' #' In an error happen within an `error` listener, then the same happens, #' the last `synchronise()` or `run_event_loop()` call fails. You can -#' want to wrap the body of the error listeners in a `tryCatch()` call, +#' wrap the body of the error listeners in a `tryCatch()` call, #' if you want to avoid this. #' #' @noRd @@ -2491,12 +2498,200 @@ async_reject <- function(.x, .p, ...) { } async_reject <- mark_as_async(async_reject) +#' HTTP event emitter for server-sent events +#' +#' Server-sent events are a technique to stream events from a web server +#' to a client, through an open HTTP connection. +#' +#' This class implements an event emitter on an async HTTP query created +#' with [http_get()] and friends, that fires an `"event"` event when the +#' server sends an event. An `"end"` event is emitted when the server +#' closes the connection. +#' +#' An event is a named character vector, the names are the keys of the +#' events. +#' +#' Example using our built-in toy web app: +#' ```r +#' http <- webfakes::new_app_process(async:::sseapp()) +#' stream_events <- function() { +#' query <- http_get(http$url("/sse")) +#' sse <- sse_events$new(query) +#' sse$ +#' listen_on("event", function(event) { +#' writeLines("Got an event:") +#' print(event) +#' })$ +#' listen_on("end", function() { +#' writeLines("Done.") +#' }) +#' query +#' } +#' +#' response <- synchronise(stream_events()) +#' ``` +#' +#' +#' @noRd + +sse_events <- R6Class( + "sse_events", + inherit = event_emitter, + public = list( + initialize = function(http_handle) { + super$initialize() + http_handle$event_emitter$listen_on("data", function(bytes) { + private$data <- c(private$data, bytes) + private$emit_events() + }) + http_handle$event_emitter$listen_on("end", function() { + self$emit("end") + }) + } + ), + + private = list( + data = NULL, + sep = as.raw(c(0xaL, 0xaL)), + emit_events = function() { + evs <- chunk_sse_events(private$data, private$sep) + private$data <- evs$rest + for (ev in evs$events) { + self$emit("event", ev) + } + } + ) +) + +chunk_sse_events <- function(data, sep = NULL) { + # skip leading \n + no <- 0L + while (no <= length(data) && data[no + 1] == 0x0a) { + no <- no + 1L + } + if (no > 0) { + data <- data[(no + 1L):length(data)] + } + sep <- sep %||% as.raw(c(0xaL, 0xaL)) + mtch <- grepRaw(sep, data, fixed = TRUE, all = TRUE) + # shortcut for no events + if (length(mtch) == 0) { + return(list(events = list(), rest = data)) + } + + events <- vector("list", length(mtch)) + for (p in seq_along(mtch)) { + from <- if (p == 1) 1L else mtch[p - 1] + 2L + to <- mtch[p] - 1L + events[[p]] <- parse_sse_event(data[from:to]) + } + events <- drop_nulls(events) + + restfrom <- mtch[length(mtch)] + 2L + rest <- if (restfrom <= length(data)) { + data[restfrom:length(data)] + } else { + raw() + } + list(events = events, rest = rest) +} + +parse_sse_event <- function(data) { + txt <- rawToChar(data) + Encoding(txt) <- "UTF-8" + lines <- strsplit(txt, "\n", fixed = TRUE)[[1]] + lines <- lines[lines != ""] + if (length(lines) == 0) { + return(NULL) + } + keys <- sub(":.*$", "", lines) + vals <- sub("^[^:]*:[ ]*", "", lines) + structure(vals, names = keys) +} + +drop_nulls <- function(x) { + x[!vapply(x, is.null, logical(1))] +} + +sseapp <- function() { + app <- webfakes::new_app() + app$get("/sse", function(req, res) { + `%||%` <- function(l, r) if (is.null(l)) r else l + if (is.null(res$locals$sse)) { + duration <- as.double(req$query$duration %||% 2) + delay <- as.double(req$query$delay %||% 0) + numevents <- as.integer(req$query$numevents %||% 5) + pause <- max(duration / numevents, 0.01) + res$locals$sse <- list( + sent = 0, + numevents = numevents, + pause = pause + ) + + res$ + set_header("cache-control", "no-cache")$ + set_header("content-type", "text/event-stream")$ + set_header("access-control-allow-origin", "*")$ + set_header("connection", "keep-alive")$ + set_status(200) + + if (delay > 0) { + return(res$delay(delay)) + } + } + + msg <- paste0( + "event: ", res$locals$sse$sent + 1L, "\n", + "message: live long and prosper\n\n" + ) + res$locals$sse$sent <- res$locals$sse$sent + 1L + res$write(msg) + + if (res$locals$sse$sent == res$locals$sse$numevents) { + res$send("") + } else { + res$delay(res$locals$sse$pause) + } + }) +} #' Asynchronous HTTP GET request #' #' Start an HTTP GET request in the background, and report its completion #' via a deferred. #' +#' @section HTTP event emitters: +#' An async HTTP deferred object is also an event emitter, see +#' [event_emitter]. Use `$event_emitter` to access the event emitter API, +#' and call `$event_emitter$listen_on()` etc. to listen on HTTP events, +#' etc. +#' +#' * `"data"` is emitted when we receive data from the server, the data is +#' passed on to the listeners as a raw vector. Note that zero-length +#' raw vectors might also happen. +#' * `"end"` is emitted at the end of the HTTP data stream, without +#' additional arguments (Also on error.) +#' +#' Here is an example, that uses the web server from the webfakes +#' package: +#' ```r +#' http <- webfakes::new_app_process(webfakes::httpbin_app()) +#' stream_http <- function() { +#' query <- http_get(http$url("/drip?duration=3&numbytes=10")) +#' query$event_emitter$ +#' listen_on("data", function(bytes) { +#' writeLines(paste("Got", length(bytes), "byte(s):")) +#' print(bytes) +#' })$ +#' listen_on("end", function() { +#' writeLines("Done.") +#' }) +#' query +#' } +#' +#' response <- synchronise(stream_http()) +#' ``` +#' #' @param url URL to connect to. #' @param headers HTTP headers to send. #' @param file If not `NULL`, it must be a string, specifying a file. @@ -2571,6 +2766,9 @@ http_get <- mark_as_async(http_get) #' Asynchronous HTTP HEAD request #' +#' An async HTTP deferred object is also an event emitter, see +#' [http_get()] for details, and also [event_emitter]. +#' #' @inheritParams http_get #' @return Deferred object. #' @@ -2619,6 +2817,9 @@ http_head <- mark_as_async(http_head) #' Start an HTTP POST request in the background, and report its completion #' via a deferred value. #' +#' An async HTTP deferred object is also an event emitter, see +#' [http_get()] for details, and also [event_emitter]. +#' #' @inheritParams http_get #' @param data Data to send. Either a raw vector, or a character string #' that will be converted to raw with [base::charToRaw]. At most one of @@ -2721,9 +2922,30 @@ get_default_curl_options <- function(options) { ) } +http_events <- R6Class( + "http_events", + inherit = event_emitter, + public = list( + listen_on = function(event, callback) { + private$check(event) + super$listen_on(event, callback) + }, + listen_off = function(event, callback) { + private$check(event) + super$listen_off(event, callback) + } + ), + private = list( + check = function(event) { + stopifnot(event %in% c("data", "end")) + } + ) +) + make_deferred_http <- function(cb, file) { cb; file id <- NULL + ee <- http_events$new() deferred$new( type = "http", call = sys.call(), action = function(resolve, progress) { @@ -2738,11 +2960,13 @@ make_deferred_http <- function(cb, file) { function(err, res) if (is.null(err)) resolve(res) else reject(err), progress, file, - data = ho$options) + data = c(ho$options, list(event_emitter = ee)) + ) }, on_cancel = function(reason) { if (!is.null(id)) get_default_event_loop()$cancel(id) - } + }, + event_emitter = ee ) } From ff3439464f5554899bb87909173d5882d847a3df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Mon, 25 Mar 2024 15:59:27 +0100 Subject: [PATCH 11/22] First version --- .github/CODE_OF_CONDUCT.md | 126 +++++++++++++++++++++++++++++++++++++ NAMESPACE | 31 +++------ R/api.R | 15 +++-- R/check.R | 57 +---------------- R/doctor.R | 4 +- R/platforms.R | 79 ++++++++++++++++++++--- R/rc.R | 22 ++++++- R/setup.R | 6 +- README.Rmd | 4 +- README.md | 12 ++-- _pkgdown.yml | 3 + man/rhub-package.Rd | 74 +++++++++++----------- 12 files changed, 288 insertions(+), 145 deletions(-) create mode 100644 .github/CODE_OF_CONDUCT.md diff --git a/.github/CODE_OF_CONDUCT.md b/.github/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..3ac34c8 --- /dev/null +++ b/.github/CODE_OF_CONDUCT.md @@ -0,0 +1,126 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of + any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, + without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible for enforcement at codeofconduct@posit.co. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][https://github.com/mozilla/inclusion]. + +For answers to common questions about this code of conduct, see the FAQ at +. Translations are available at . + +[homepage]: https://www.contributor-covenant.org diff --git a/NAMESPACE b/NAMESPACE index 23521b3..484bbef 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,11 +1,11 @@ # Generated by roxygen2: do not edit by hand -S3method("[",rhub2_platforms) -S3method(format,rhub2_platforms) -S3method(format,rhub2_platforms_summary) -S3method(print,rhub2_platforms) -S3method(print,rhub2_platforms_summary) -S3method(summary,rhub2_platforms) +S3method("[",rhub_platforms) +S3method(format,rhub_platforms) +S3method(format,rhub_platforms_summary) +S3method(print,rhub_platforms) +S3method(print,rhub_platforms_summary) +S3method(summary,rhub_platforms) export(check) export(check_for_cran) export(check_on_centos) @@ -32,32 +32,15 @@ export(local_check_linux_images) export(platforms) export(rc_list_repos) export(rc_new_token) +export(rc_submit) export(rhub_check) export(rhub_doctor) export(rhub_platforms) export(rhub_setup) export(validate_email) importFrom(R6,R6Class) -importFrom(callr,r_process) -importFrom(callr,r_process_options) -importFrom(callr,r_session) -importFrom(callr,rcmd_safe_env) importFrom(cli,symbol) -importFrom(curl,handle_data) -importFrom(curl,handle_setheaders) -importFrom(curl,handle_setopt) -importFrom(curl,multi_add) -importFrom(curl,multi_cancel) -importFrom(curl,multi_fdset) -importFrom(curl,multi_list) -importFrom(curl,multi_run) -importFrom(curl,multi_set) -importFrom(curl,new_handle) -importFrom(curl,new_pool) -importFrom(curl,parse_headers_list) importFrom(jsonlite,toJSON) -importFrom(processx,conn_get_fileno) -importFrom(processx,process) importFrom(rappdirs,user_data_dir) importFrom(rematch,re_match) importFrom(utils,getSrcDirectory) diff --git a/R/api.R b/R/api.R index 3917b33..8907712 100644 --- a/R/api.R +++ b/R/api.R @@ -3,15 +3,15 @@ baseurl <- function() { } default_headers <- c( - "Accept" = "application/json", - "Content-Type" = "application/json", - "User-Agent" = "R-hub client" + "accept" = "application/json", + "content-type" = "application/json", + "user-agent" = "R-hub client" ) #' @importFrom jsonlite toJSON query <- function(endpoint, method = "GET", headers = character(), - data = NULL) { + data = NULL, data_form = NULL) { url <- paste0(baseurl(), endpoint) headers <- update(default_headers, headers) @@ -20,7 +20,12 @@ query <- function(endpoint, method = "GET", headers = character(), synchronise(http_get(url, headers = headers)) } else if (method == "POST") { - synchronise(http_post(url, headers = headers, data = data)) + synchronise(http_post( + url, + headers = headers, + data = data, + data_form = data_form + )) } else { stop("Unexpected HTTP verb, internal rhub error") diff --git a/R/check.R b/R/check.R index 1fd83e5..6b0ed0f 100644 --- a/R/check.R +++ b/R/check.R @@ -35,60 +35,7 @@ rhub_check <- function(gh_url = NULL, platforms = NULL, r_versions = NULL, } } - tryCatch( - plat <- rhub_platforms(), - error = function(e) { - throw(parent = e, pkg_error( - "Failed to download the list of R-hub platforms.", - i = "Make sure that you are online and Github is also online." - )) - } - ) - - if (is.null(platforms)) { - if (!interactive()) { - throw(pkg_error( - "{.arg platforms} argument is missing for {.fun rhub_check}.", - i = "You need to specify {.arg platforms} in non-interactive - sessions" - )) - } - cli::cli_text() - cli::cli_text( - "Available platforms - (see {.code rhub2::rhub_platforms()} for details):" - ) - cli::cli_text() - cli::cli_verbatim(paste( - cli::ansi_strtrim(format(summary(plat))), - collapse = "\n" - )) - pnums <- trimws(readline( - prompt = "\nSelection (comma separated numbers, 0 to cancel): " - )) - if (pnums == "" || pnums == "0") { - throw(pkg_error("R-hub check cancelled")) - } - pnums <- unique(trimws(strsplit(pnums, ",", fixed = TRUE)[[1]])) - pnums2 <- suppressWarnings(as.integer(pnums)) - bad <- is.na(pnums2) | pnums2 < 1 | pnums2 > nrow(plat) - if (any(bad)) { - throw(pkg_error( - "Invalid platform number{?s}: {.val {pnums[bad]}}." - )) - } - platforms <- plat$name[pnums2] - - } else { - platforms <- unique(platforms) - bad <- !platforms %in% unlist(plat$name, plat$aliaeses) - if (any(bad)) { - throw(pkg_error( - "Unknown platform{?s}: {.val {platforms[bad]}}.", - i = "See {.run rhub::rhub_platforms()} for the list of platforms" - )) - } - } + platforms <- select_platforms() url <- parse_gh_url(gh_url) ep <- glue::glue("/repos/{url$user}/{url$repo}/actions/workflows/rhub.yaml/dispatches") @@ -110,7 +57,7 @@ rhub_check <- function(gh_url = NULL, platforms = NULL, r_versions = NULL, if (resp$status_code != 204) { throw(pkg_error( ":( Failed to start check: {resp$content$message}.", - i = "If you think this is a bug in the {.pkg rhub2} package, please + i = "If you think this is a bug in the {.pkg rhub} package, please open an issues at {.url https://github.com/r-hub/rhub/issues}." )) } diff --git a/R/doctor.R b/R/doctor.R index 9eb4fbf..ca809de 100644 --- a/R/doctor.R +++ b/R/doctor.R @@ -52,7 +52,7 @@ rhub_doctor <- function(gh_url = NULL) { doctor_check_workflow(gh_url, resp$gql, resp$wfl) cli::cli_alert( - "WOOT! You are ready to run {.run rhub2::rhub_check()} on this package.", + "WOOT! You are ready to run {.run rhub::rhub_check()} on this package.", wrap = TRUE ) @@ -134,7 +134,7 @@ doctor_check_github <- function(gh_url, resp) { repository.", i = "R-hub only supports GitHub packages in GitHub repositories currently.", - i = "If you think that this is a bug in the {pkg rhub2} package, + i = "If you think that this is a bug in the {pkg rhub} package, please let us know!" )) } diff --git a/R/platforms.R b/R/platforms.R index 80babdc..b62c324 100644 --- a/R/platforms.R +++ b/R/platforms.R @@ -1,6 +1,6 @@ get_platforms <- function() { - url_platforms <- "https://raw.githubusercontent.com/r-hub/rhub2/v1/actions/rhub-setup/platforms.json" + url_platforms <- "https://raw.githubusercontent.com/r-hub/actions/v1/setup/platforms.json" url_containers <- "https://r-hub.github.io/containers/manifest.json" ret <- synchronise(when_all( async_cached_http_get(url_platforms), @@ -64,13 +64,13 @@ rhub_platforms <- function() { res <- res[order(res$type == "container", res$name), ] - res <- add_class(res, "rhub2_platforms") + res <- add_class(res, "rhub_platforms") res } #' @export -format.rhub2_platforms <- function(x, ...) { +format.rhub_platforms <- function(x, ...) { ret <- character() wvms <- which(x$type == "os") wcts <- which(x$type == "container") @@ -132,27 +132,27 @@ format.rhub2_platforms <- function(x, ...) { #' @export -print.rhub2_platforms <- function(x, ...) { +print.rhub_platforms <- function(x, ...) { writeLines(cli::ansi_strtrim(format(x, ...))) } #' @export -`[.rhub2_platforms` <- function(x, i, j, drop = FALSE) { - class(x) <- setdiff(class(x), "rhub2_platforms") +`[.rhub_platforms` <- function(x, i, j, drop = FALSE) { + class(x) <- setdiff(class(x), "rhub_platforms") NextMethod("[") } #' @export -summary.rhub2_platforms <- function(object, ...) { - class(object) <- c("rhub2_platforms_summary", class(object)) +summary.rhub_platforms <- function(object, ...) { + class(object) <- c("rhub_platforms_summary", class(object)) object } #' @export -format.rhub2_platforms_summary <- function(x, ...) { +format.rhub_platforms_summary <- function(x, ...) { num <- format(seq_len(nrow(x))) icon <- if (!has_emoji()) { ifelse(x$type == "os", "[VM]", "[CT]") @@ -180,7 +180,7 @@ format.rhub2_platforms_summary <- function(x, ...) { #' @export -print.rhub2_platforms_summary <- function(x, ...) { +print.rhub_platforms_summary <- function(x, ...) { writeLines(cli::ansi_strtrim(format(x, ...))) } @@ -198,3 +198,62 @@ abbrev_version <- function(x) { x } + +select_platforms <- function(platforms = NULL) { + tryCatch( + plat <- rhub_platforms(), + error = function(e) { + throw(parent = e, pkg_error( + "Failed to download the list of R-hub platforms.", + i = "Make sure that you are online and Github is also online." + )) + } + ) + + if (is.null(platforms)) { + if (!is_interactive()) { + throw(pkg_error( + "{.arg platforms} argument is missing for {.fun rhub_check}.", + i = "You need to specify {.arg platforms} in non-interactive + sessions" + )) + } + cli::cli_text() + cli::cli_text( + "Available platforms + (see {.code rhub::rhub_platforms()} for details):" + ) + cli::cli_text() + cli::cli_verbatim(paste( + cli::ansi_strtrim(format(summary(plat))), + collapse = "\n" + )) + pnums <- trimws(readline( + prompt = "\nSelection (comma separated numbers, 0 to cancel): " + )) + if (pnums == "" || pnums == "0") { + throw(pkg_error("R-hub check cancelled")) + } + pnums <- unique(trimws(strsplit(pnums, ",", fixed = TRUE)[[1]])) + pnums2 <- suppressWarnings(as.integer(pnums)) + bad <- is.na(pnums2) | pnums2 < 1 | pnums2 > nrow(plat) + if (any(bad)) { + throw(pkg_error( + "Invalid platform number{?s}: {.val {pnums[bad]}}." + )) + } + platforms <- plat$name[pnums2] + + } else { + platforms <- unique(platforms) + bad <- !platforms %in% unlist(plat$name, plat$aliaeses) + if (any(bad)) { + throw(pkg_error( + "Unknown platform{?s}: {.val {platforms[bad]}}.", + i = "See {.run rhub::rhub_platforms()} for the list of platforms" + )) + } + } + + platforms +} diff --git a/R/rc.R b/R/rc.R index 63c22d7..9bc3c6d 100644 --- a/R/rc.R +++ b/R/rc.R @@ -42,11 +42,31 @@ rc_submit <- function(path = ".", platforms = NULL, email = NULL, email <- email %||% get_maintainer_email(path = path) + platforms <- select_platforms() + if (is_dir(path)) { path <- pkgbuild::build(path = path) } - query("job/") + id <- random_id() + ep <- paste0("/job/", pkg_name) + form <- list( + config = curl::form_data(paste(platforms, collapse = ",")), + id = curl::form_data(id), + package = curl::form_file(path) + ) + query( + method = "POST", + ep, + data_form = form, + headers = c( + get_auth_header(email), + "content-type" = "multipart/form-data", + "accept" = "text/event-stream", + "cache-control" = "no-cache", + "connection" = "keep-alive" + ) + ) } # ========================================================================= diff --git a/R/setup.R b/R/setup.R index 0e0a6c0..9861567 100644 --- a/R/setup.R +++ b/R/setup.R @@ -26,7 +26,7 @@ rhub_setup <- function(overwrite = FALSE) { git_root <- setup_find_git_root() check_rpkg_root(rpkg_root, git_root) - url <- "https://raw.githubusercontent.com/r-hub/rhub2/v1/inst/workflow/rhub.yaml" + url <- "https://raw.githubusercontent.com/r-hub/actions/v1/workflows/rhub.yaml" resp <- synchronise(http_get(url)) if (resp$status_code != 200) { throw(pkg_error( @@ -89,9 +89,9 @@ rhub_setup <- function(overwrite = FALSE) { "*" = if (!updated) "Commit it to git using {.code git commit} (if not committed already).", "*" = if (updated) "Push the commit to GitHub using {.code git push}.", "*" = if (!updated) "Push the commit to GitHub using {.code git push} (if not pushed already).", - "*" = "Call {.run rhub2::rhub_doctor()} to check that you have set up + "*" = "Call {.run rhub::rhub_doctor()} to check that you have set up R-hub correctly.", - "*" = "Call {.run rhub2::rhub_check()} to check your package." + "*" = "Call {.run rhub::rhub_check()} to check your package." )) invisible(NULL) diff --git a/README.Rmd b/README.Rmd index fdaa24a..68c8d07 100644 --- a/README.Rmd +++ b/README.Rmd @@ -105,8 +105,8 @@ rhub::rhub_check() ## Code of Conduct -Please note that the callr project is released with a -[Contributor Code of Conduct](https://callr.r-lib.org/CODE_OF_CONDUCT.html). +Please note that the rhub package is released with a +[Contributor Code of Conduct](https://r-hub.github.io/rhub/dev/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. ## License diff --git a/README.md b/README.md index c8cb8fd..f472e81 100644 --- a/README.md +++ b/README.md @@ -83,8 +83,8 @@ style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream ## Add the workflow file to git using `git add <filename>`. ## Commit it to git using `git commit`. ## Push the commit to GitHub using `git push`. -## Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly. -## Call `rhub2::rhub_check()` to check your package. +## Call `rhub::rhub_doctor()` to check that you have set up R-hub correctly. +## Call `rhub::rhub_check()` to check your package. @@ -108,7 +108,7 @@ style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream ## Found repository on GitHub at <https://github.com/r-lib/cli>. ## GitHub PAT has the right scopes. ## Found R-hub workflow in default branch, and it is active. -## → WOOT! You are ready to run `rhub2::rhub_check()` on this package. +## → WOOT! You are ready to run `rhub::rhub_check()` on this package. @@ -202,7 +202,7 @@ style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream ## Found git repository at /private/tmp/cli. ## Found GitHub PAT. ## -## Available platforms (see `rhub2::rhub_platforms()` for details): +## Available platforms (see `rhub::rhub_platforms()` for details): ## ## 1 [VM] linux R-* (any version) ubuntu-latest on G… ## 2 [VM] macos R-* (any version) macos-latest on Gi… @@ -235,8 +235,8 @@ style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream ## Code of Conduct -Please note that the callr project is released with a [Contributor Code -of Conduct](https://callr.r-lib.org/CODE_OF_CONDUCT.html). By +Please note that the rhub package is released with a [Contributor Code +of Conduct](https://r-hub.github.io/rhub/dev/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms. ## License diff --git a/_pkgdown.yml b/_pkgdown.yml index dd799e2..21d841e 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -8,6 +8,9 @@ authors: toc: depth: 3 +development: + mode: auto + reference: - title: Introduction desc: | diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index a03472a..09e6fcb 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -56,8 +56,8 @@ add the R-hub workflow file to your package. #> Add the workflow file to git using `git add <filename>`. #> Commit it to git using `git commit`. #> Push the commit to GitHub using `git push`. -#> Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly. -#> Call `rhub2::rhub_check()` to check your package. +#> Call `rhub::rhub_doctor()` to check that you have set up R-hub correctly. +#> Call `rhub::rhub_check()` to check your package. }} @@ -75,7 +75,7 @@ add the R-hub workflow file to your package. #> Found repository on GitHub at <https://github.com/r-lib/cli>. #> GitHub PAT has the right scopes. #> Found R-hub workflow in default branch, and it is active. -#> → WOOT! You are ready to run `rhub2::rhub_check()` on this package. +#> → WOOT! You are ready to run `rhub::rhub_check()` on this package. }} @@ -100,52 +100,52 @@ Use \code{rhub::rhub_platforms()} to get a list of supported platforms and check #> #> ── Containers ───────────────────────────────────────────────────────────────── #> 5 [CT] atlas [ATLAS] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/atlas:latest #> 6 [CT] clang-asan [asan, clang-ASAN, clang-UBSAN, ubsan] -#> R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-19 r86153) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/clang-asan:latest #> 7 [CT] clang16 [clang16] -#> R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-18 r86148) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/clang16:latest #> 8 [CT] clang17 [clang17] -#> R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-18 r86148) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/clang17:latest #> 9 [CT] clang18 [clang18] -#> R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-18 r86148) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/clang18:latest #> 10 [CT] donttest [donttest] -#> R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-18 r86148) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/donttest:latest #> 11 [CT] gcc13 [gcc13] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/gcc13:latest #> 12 [CT] intel [Intel] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/intel:latest #> 13 [CT] mkl [MKL] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/mkl:latest #> 14 [CT] nold [noLD] -#> R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-19 r86153) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/nold:latest #> 15 [CT] nosuggests [noSuggests] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/nosuggests:latest #> 16 [CT] ubuntu-clang [r-devel-linux-x86_64-debian-clang] -#> R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-19 r86153) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/ubuntu-clang:latest #> 17 [CT] ubuntu-gcc12 [r-devel-linux-x86_64-debian-gcc] -#> R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS +#> R Under development (unstable) (2024-03-19 r86153) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/ubuntu-gcc12:latest #> 18 [CT] ubuntu-next [r-next, r-patched, r-patched-linux-x86_64] -#> R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS +#> R version 4.3.3 Patched (2024-02-29 r86153) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/ubuntu-next:latest #> 19 [CT] ubuntu-release [r-release, r-release-linux-x86_64, ubuntu] #> R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS #> ghcr.io/r-hub/containers/ubuntu-release:latest #> 20 [CT] valgrind [valgrind] -#> R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta… +#> R Under development (unstable) (2024-03-19 r86153) on Fedora Linux 38 (Conta… #> ghcr.io/r-hub/containers/valgrind:latest }} @@ -159,32 +159,32 @@ Run \code{rhub::rhub_check()} to start R-hub v2 checks on GitHub Actions: #> Found git repository at /private/tmp/cli. #> Found GitHub PAT. #> -#> Available platforms (see `rhub2::rhub_platforms()` for details): +#> Available platforms (see `rhub::rhub_platforms()` for details): #> #> 1 [VM] linux R-* (any version) ubuntu-latest on G… #> 2 [VM] macos R-* (any version) macos-latest on Gi… #> 3 [VM] macos-arm64 R-* (any version) macos-14 on GitHub #> 4 [VM] windows R-* (any version) windows-latest on … -#> 5 [CT] atlas R-devel (2024-03-13 r86113) Fedora Linux 38 (C… -#> 6 [CT] clang-asan R-devel (2024-03-12 r86109) Ubuntu 22.04.4 LTS -#> 7 [CT] clang16 R-devel (2024-03-12 r86109) Ubuntu 22.04.4 LTS -#> 8 [CT] clang17 R-devel (2024-03-11 r86098) Ubuntu 22.04.4 LTS -#> 9 [CT] clang18 R-devel (2024-03-12 r86109) Ubuntu 22.04.4 LTS -#> 10 [CT] donttest R-devel (2024-03-12 r86109) Ubuntu 22.04.4 LTS -#> 11 [CT] gcc13 R-devel (2024-03-13 r86113) Fedora Linux 38 (C… -#> 12 [CT] intel R-devel (2024-03-13 r86113) Fedora Linux 38 (C… -#> 13 [CT] mkl R-devel (2024-03-13 r86113) Fedora Linux 38 (C… -#> 14 [CT] nold R-devel (2024-03-13 r86113) Ubuntu 22.04.4 LTS -#> 15 [CT] nosuggests R-devel (2024-03-13 r86113) Fedora Linux 38 (C… -#> 16 [CT] ubuntu-clang R-devel (2024-03-13 r86113) Ubuntu 22.04.4 LTS -#> 17 [CT] ubuntu-gcc12 R-devel (2024-03-13 r86113) Ubuntu 22.04.4 LTS -#> 18 [CT] ubuntu-next R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS +#> 5 [CT] atlas R-devel (2024-03-19 r86153) Fedora Linux 38 (C… +#> 6 [CT] clang-asan R-devel (2024-03-19 r86153) Ubuntu 22.04.4 LTS +#> 7 [CT] clang16 R-devel (2024-03-18 r86148) Ubuntu 22.04.4 LTS +#> 8 [CT] clang17 R-devel (2024-03-18 r86148) Ubuntu 22.04.4 LTS +#> 9 [CT] clang18 R-devel (2024-03-18 r86148) Ubuntu 22.04.4 LTS +#> 10 [CT] donttest R-devel (2024-03-18 r86148) Ubuntu 22.04.4 LTS +#> 11 [CT] gcc13 R-devel (2024-03-19 r86153) Fedora Linux 38 (C… +#> 12 [CT] intel R-devel (2024-03-19 r86153) Fedora Linux 38 (C… +#> 13 [CT] mkl R-devel (2024-03-19 r86153) Fedora Linux 38 (C… +#> 14 [CT] nold R-devel (2024-03-19 r86153) Ubuntu 22.04.4 LTS +#> 15 [CT] nosuggests R-devel (2024-03-19 r86153) Fedora Linux 38 (C… +#> 16 [CT] ubuntu-clang R-devel (2024-03-19 r86153) Ubuntu 22.04.4 LTS +#> 17 [CT] ubuntu-gcc12 R-devel (2024-03-19 r86153) Ubuntu 22.04.4 LTS +#> 18 [CT] ubuntu-next R-4.3.3 (patched) (2024-02-29 r86153) Ubuntu 22.04.4 LTS #> 19 [CT] ubuntu-release R-4.3.3 (2024-02-29) Ubuntu 22.04.4 LTS -#> 20 [CT] valgrind R-devel (2024-03-13 r86113) Fedora Linux 38 (C… +#> 20 [CT] valgrind R-devel (2024-03-19 r86153) Fedora Linux 38 (C… #> #> Selection (comma separated numbers, 0 to cancel): 1, 5 #> -#> Check started: linux, atlas (francium-vaquita). +#> Check started: linux, atlas (apricot-flycatcher). #> See <https://github.com/r-lib/cli/actions> for live output! }} @@ -195,8 +195,8 @@ Run \code{rhub::rhub_check()} to start R-hub v2 checks on GitHub Actions: \subsection{Code of Conduct}{ -Please note that the callr project is released with a -\href{https://callr.r-lib.org/CODE_OF_CONDUCT.html}{Contributor Code of Conduct}. +Please note that the rhub package is released with a +\href{https://r-hub.github.io/rhub/dev/CODE_OF_CONDUCT.html}{Contributor Code of Conduct}. By contributing to this project, you agree to abide by its terms. } From b5820166a0567470e4f6ef06c806b04e6478c936 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 23 Mar 2024 16:05:43 +0100 Subject: [PATCH 12/22] Merge pull request #21 from krlmlr/f-tweaks chore: Fix typo --- .Rbuildignore | 15 ++++----------- R/doctor.R | 2 +- 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/.Rbuildignore b/.Rbuildignore index 2f3534c..1e38ff4 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,14 +4,7 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^Makefile$ -^README.md$ -^.travis.yml$ -^appveyor.yml$ -^cran-comments\.md$ -^revdep$ -^codecov\.yml$ -^\.github$ -^vignettes$ -^man/_cache$ -^README_cache$ -^README\.html$ +^README\.Rmd$ +^README[.]html$ +^rhub2\.Rproj$ +^\.Rproj\.user$ diff --git a/R/doctor.R b/R/doctor.R index ca809de..f8c36fc 100644 --- a/R/doctor.R +++ b/R/doctor.R @@ -40,7 +40,7 @@ rhub_doctor <- function(gh_url = NULL) { # # So we'll have # - a graphql query for (1), (2), (3), (4), (7) - # - a REST query for (%) and (6) + # - a REST query for (5) and (6) resp <- synchronise(when_all( gql = doctor_async_gql(gh_url, token = pat), From 1eda4ec2a452a2be6ea368b28b7ff54a92a2f621 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 23 Mar 2024 16:05:24 +0100 Subject: [PATCH 13/22] Merge pull request #20 from krlmlr/b-10-ssh fix: Support parsing SSH URLs --- R/utils.R | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/R/utils.R b/R/utils.R index 979da7e..317bc14 100644 --- a/R/utils.R +++ b/R/utils.R @@ -83,7 +83,20 @@ parse_url <- function(url) { ) mch <- re_match(url, re_url) - mch[, setdiff(colnames(mch), c(".match", ".text")), drop = FALSE] + + if (is.na(mch[[1]])) { + ssh_re_url <- "^git@(?[^:]+):(?.*)[.]git$" + mch <- re_match(url, ssh_re_url) + + if (is.na(mch[[1]])) { + cli::cli_abort("Invalid URL: {.url {url}}") + } + + # Used for accessing the server's API + mch$protocol <- "https" + } + + mch[c("protocol", "host", "path")] } read_file <- function(path) { From fe1fd3745ae34b9123f8cc29073af112d8c7e921 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 26 Mar 2024 08:42:59 +0100 Subject: [PATCH 14/22] Update .Rbuildignore after merge mishap [ci skip] --- .Rbuildignore | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.Rbuildignore b/.Rbuildignore index 1e38ff4..5fffd81 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -4,6 +4,17 @@ ^.*\.Rproj$ ^\.Rproj\.user$ ^Makefile$ +^README.md$ +^.travis.yml$ +^appveyor.yml$ +^cran-comments\.md$ +^revdep$ +^codecov\.yml$ +^\.github$ +^vignettes$ +^man/_cache$ +^README_cache$ +^README\.html$ ^README\.Rmd$ ^README[.]html$ ^rhub2\.Rproj$ From 3ee81c467d3da3089fb289c63b0c11306d968102 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 26 Mar 2024 13:32:41 +0100 Subject: [PATCH 15/22] Docs for RC functions --- R/rc.R | 73 ++++++++++++++++++++++++++++++++++++++++++-- man/rc_list_repos.Rd | 32 +++++++++++++++++++ man/rc_new_token.Rd | 43 ++++++++++++++++++++++++++ man/rc_submit.Rd | 43 ++++++++++++++++++++++++++ 4 files changed, 189 insertions(+), 2 deletions(-) create mode 100644 man/rc_list_repos.Rd create mode 100644 man/rc_new_token.Rd create mode 100644 man/rc_submit.Rd diff --git a/R/rc.R b/R/rc.R index 9bc3c6d..fe1a195 100644 --- a/R/rc.R +++ b/R/rc.R @@ -1,5 +1,35 @@ # ========================================================================= +# API +# ========================================================================= + +#' Request a new token for submissions to the R Consortium runners +#' +#' To build and check R packages on the RC runners of R-hub, you'll need +#' to validate your email address. R-hub will send a token to your email +#' address, and this token will be stored on your computer. +#' +#' You need to validate your email on each computer you want to submit +#' jobs from, either using the same token from the email you got, or +#' you can request another token for the new machine. Your old token +#' will stay valid as well. +#' +#' If you already have a token from a previous version of R-hub, you can +#' reuse that and you don't need to do anything. +#' +#' Run +#' ``` +#' rhub:::email_file() +#' ``` +#' to see the file rhub uses to store your validated tokens. +#' +#' @param email Email address to validate. We try to detect this, but +#' if the detection fails, you can specify it explicitly. +#' @param token Token to add to the list of validated tokens. +#' If this argument is missing (or `NULL`), then you can specify it +#' interactively. +#' #' @export +#' @family RC runners API rc_new_token <- function(email = NULL, token = NULL) { if (is.null(email) || is.null(token)) { @@ -16,7 +46,24 @@ rc_new_token <- function(email = NULL, token = NULL) { } # ------------------------------------------------------------------------- +#' List your repositories created by the R Consortium runners +#' +#' Lists repositories created by [rc_submit()] submissions. +#' +#' @param email Email address. We try to detect this, but +#' if the detection fails, you can specify it explicitly. +#' +#' @return Data frame with columns: +#' +#' * `repo_name`: Name of the repository. +#' * `repo_url`: URL of the repository. +#' * `builds_url`: URL to the builds of the repository. +#' +#' Additional columns and customized printing will be probably added +#' later to the result. +#' #' @export +#' @family RC runners API rc_list_repos <- function(email = NULL) { email <- email %||% guess_email(message = TRUE) @@ -25,10 +72,32 @@ rc_list_repos <- function(email = NULL) { } # ------------------------------------------------------------------------- +#' Submit a package to the R Consortium runners +#' +#' @param path Path to package file or package directory. +#' @param platforms Platforms to checks. If not specified, then you +#' can select the platforms interactively. Must be specified in +#' non-interactive sessions. +#' @param email Email address. You must have a token on the local machhine, +#' that corresponds to the email address, see [rc_new_token()]. +#' If not specified (or `NULL`) then the email address of the package +#' maintainer is used. +#' @return A list with data about the submission, invisibly. +#' Currently it has: +#' +#' * `result`: Should be the string `"OK"`. +#' * `repo_url`: URL to the repository. +#' * `actions_url`: URL to the builds inside the repository. +#' * `id`: Build id. This is a string with a randomly generated id. +#' * `name`: Build name, this is a string, the concatenation of the +#' build platforms. +#' +#' More fields might be added later. +#' #' @export +#' @family RC runners API -rc_submit <- function(path = ".", platforms = NULL, email = NULL, - r_versions = NULL) { +rc_submit <- function(path = ".", platforms = NULL, email = NULL) { pkg_name <- desc::desc_get("Package", file = path)[[1]] if (is.na(pkg_name)) { throw(pkg_error( diff --git a/man/rc_list_repos.Rd b/man/rc_list_repos.Rd new file mode 100644 index 0000000..c58f257 --- /dev/null +++ b/man/rc_list_repos.Rd @@ -0,0 +1,32 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rc.R +\name{rc_list_repos} +\alias{rc_list_repos} +\title{List your repositories created by the R Consortium runners} +\usage{ +rc_list_repos(email = NULL) +} +\arguments{ +\item{email}{Email address. We try to detect this, but +if the detection fails, you can specify it explicitly.} +} +\value{ +Data frame with columns: +\itemize{ +\item \code{repo_name}: Name of the repository. +\item \code{repo_url}: URL of the repository. +\item \code{builds_url}: URL to the builds of the repository. +} + +Additional columns and customized printing will be probably added +later to the result. +} +\description{ +Lists repositories created by \code{\link[=rc_submit]{rc_submit()}} submissions. +} +\seealso{ +Other RC runners API: +\code{\link{rc_new_token}()}, +\code{\link{rc_submit}()} +} +\concept{RC runners API} diff --git a/man/rc_new_token.Rd b/man/rc_new_token.Rd new file mode 100644 index 0000000..06fc49c --- /dev/null +++ b/man/rc_new_token.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rc.R +\name{rc_new_token} +\alias{rc_new_token} +\title{Request a new token for submissions to the R Consortium runners} +\usage{ +rc_new_token(email = NULL, token = NULL) +} +\arguments{ +\item{email}{Email address to validate. We try to detect this, but +if the detection fails, you can specify it explicitly.} + +\item{token}{Token to add to the list of validated tokens. +If this argument is missing (or \code{NULL}), then you can specify it +interactively.} +} +\description{ +To build and check R packages on the RC runners of R-hub, you'll need +to validate your email address. R-hub will send a token to your email +address, and this token will be stored on your computer. +} +\details{ +You need to validate your email on each computer you want to submit +jobs from, either using the same token from the email you got, or +you can request another token for the new machine. Your old token +will stay valid as well. + +If you already have a token from a previous version of R-hub, you can +reuse that and you don't need to do anything. + +Run + +\if{html}{\out{
}}\preformatted{rhub:::email_file() +}\if{html}{\out{
}} + +to see the file rhub uses to store your validated tokens. +} +\seealso{ +Other RC runners API: +\code{\link{rc_list_repos}()}, +\code{\link{rc_submit}()} +} +\concept{RC runners API} diff --git a/man/rc_submit.Rd b/man/rc_submit.Rd new file mode 100644 index 0000000..94a12b2 --- /dev/null +++ b/man/rc_submit.Rd @@ -0,0 +1,43 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rc.R +\name{rc_submit} +\alias{rc_submit} +\title{Submit a package to the R Consortium runners} +\usage{ +rc_submit(path = ".", platforms = NULL, email = NULL) +} +\arguments{ +\item{path}{Path to package file or package directory.} + +\item{platforms}{Platforms to checks. If not specified, then you +can select the platforms interactively. Must be specified in +non-interactive sessions.} + +\item{email}{Email address. You must have a token on the local machhine, +that corresponds to the email address, see \code{\link[=rc_new_token]{rc_new_token()}}. +If not specified (or \code{NULL}) then the email address of the package +maintainer is used.} +} +\value{ +A list with data about the submission, invisibly. +Currently it has: +\itemize{ +\item \code{result}: Should be the string \code{"OK"}. +\item \code{repo_url}: URL to the repository. +\item \code{actions_url}: URL to the builds inside the repository. +\item \code{id}: Build id. This is a string with a randomly generated id. +\item \code{name}: Build name, this is a string, the concatenation of the +build platforms. +} + +More fields might be added later. +} +\description{ +Submit a package to the R Consortium runners +} +\seealso{ +Other RC runners API: +\code{\link{rc_list_repos}()}, +\code{\link{rc_new_token}()} +} +\concept{RC runners API} From f391befd48804d593ae524402e9463c25023932b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 26 Mar 2024 13:33:10 +0100 Subject: [PATCH 16/22] RC submission improvements Handle errors better, print error message. E.g. error for the five minute delay. --- DESCRIPTION | 9 +++++-- R/aaa-async.R | 4 ++- R/api.R | 75 ++++++++++++++++++++++++++++++++++++++++++++++++--- R/rc.R | 15 ++++++++++- R/utils.R | 4 +-- 5 files changed, 97 insertions(+), 10 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 977aaf2..633fb98 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -21,20 +21,25 @@ Imports: callr, cli, curl, + desc, gert, glue, gitcreds, jsonlite, + pkgbuild, processx, + rappdirs, rematch, R6, rprojroot, - utils + utils, + whoami Suggests: asciicast, debugme, knitr, pillar, rmarkdown, - testthat (>= 3.0.0) + testthat (>= 3.0.0), + webfakes Encoding: UTF-8 diff --git a/R/aaa-async.R b/R/aaa-async.R index 290df27..29cd6bc 100644 --- a/R/aaa-async.R +++ b/R/aaa-async.R @@ -1338,6 +1338,7 @@ def__resolve <- function(self, private, value) { #' @param private private self #' @return error object #' +#' @noRd #' @keywords internal def__make_error_object <- function(self, private, err) { @@ -2539,7 +2540,7 @@ sse_events <- R6Class( inherit = event_emitter, public = list( initialize = function(http_handle) { - super$initialize() + super$initialize(async = FALSE) http_handle$event_emitter$listen_on("data", function(bytes) { private$data <- c(private$data, bytes) private$emit_events() @@ -4122,6 +4123,7 @@ get_private <- function(x) { #' or the error thrown. #' @param info Extra info to add to the error object. Must be a named list. #' +#' @noRd #' @keywords internal call_with_callback <- function(func, callback, info = NULL) { diff --git a/R/api.R b/R/api.R index 8907712..0cb825d 100644 --- a/R/api.R +++ b/R/api.R @@ -11,11 +11,80 @@ default_headers <- c( #' @importFrom jsonlite toJSON query <- function(endpoint, method = "GET", headers = character(), - data = NULL, data_form = NULL) { + data = NULL, data_form = NULL, sse = FALSE) { url <- paste0(baseurl(), endpoint) headers <- update(default_headers, headers) + response <- if (sse) { + query_sse(method, url, headers, data, data_form) + } else { + query_plain(method, url, headers, data, data_form) + } + + if (response$status_code >= 400) { + cnd <- http_error(response) + tryCatch({ + bdy <- jsonlite::fromJSON( + rawToChar(response$content), + simplifyVector = FALSE + ) + }, error = function(err) { stop(cnd) }) + if ("message" %in% names(bdy)) { + throw(new_error(bdy[["message"]]), parent = cnd) + } else { + stop(cnd) + } + } + + response +} + +query_sse <- function(method, url, headers, data, data_form) { + synchronise( + query_sse_async(method, url, headers, data, data_form) + ) +} + +query_sse_async <- function(method, url, headers, data, data_form) { + if (method == "GET") { + q <- http_get(url, headers = headers) + } else if (method == "POST") { + q <- http_post( + url, + headers = headers, + data = data, + data_form = data_form + ) + } else { + stop("Unexpected HTTP verb, internal rhub error") + } + + msgs <- list() + handle_sse <- function(evt) { + msgs <<- c(msgs, list(evt)) + if (evt[["event"]] == "progress") { + msg <- jsonlite::fromJSON(evt[["data"]]) + cli::cli_alert(msg, .envir = emptyenv()) + } else if (evt[["event"]] == "result") { + cli::cli_alert_success("Done.") + } else if (evt[["event"]] == "error") { + msg <- jsonlite::fromJSON(evt[["data"]]) + cli::cli_alert_danger(msg, .envir = emptyenv()) + stop("Aborting") + } + } + + evs <- sse_events$new(q) + evs$listen_on("event", handle_sse) + + q$then(function(response) { + response$sse <- msgs + response + }) +} + +query_plain <- function(method, url, headers, data, data_form) { response <- if (method == "GET") { synchronise(http_get(url, headers = headers)) @@ -31,7 +100,5 @@ query <- function(endpoint, method = "GET", headers = character(), stop("Unexpected HTTP verb, internal rhub error") } - http_stop_for_status(response) - response -} +} \ No newline at end of file diff --git a/R/rc.R b/R/rc.R index fe1a195..0bd2d33 100644 --- a/R/rc.R +++ b/R/rc.R @@ -124,9 +124,11 @@ rc_submit <- function(path = ".", platforms = NULL, email = NULL) { id = curl::form_data(id), package = curl::form_file(path) ) - query( + + resp <- query( method = "POST", ep, + sse = TRUE, data_form = form, headers = c( get_auth_header(email), @@ -136,6 +138,17 @@ rc_submit <- function(path = ".", platforms = NULL, email = NULL) { "connection" = "keep-alive" ) ) + + resevt <- Filter(function(x) x[["event"]] == "result", resp$sse) + if (length(resevt) == 0) { + stop("Invalid response from R-hub server, please report this.") + } + + retval <- jsonlite::fromJSON( + resevt[[1]][["data"]], + simplifyVector = FALSE + ) + invisible(retval) } # ========================================================================= diff --git a/R/utils.R b/R/utils.R index 317bc14..c79af4f 100644 --- a/R/utils.R +++ b/R/utils.R @@ -154,10 +154,10 @@ get_maintainer_email <- function(path = ".") { parse_email(desc::desc_get_maintainer(path)) } else { dir.create(tmp <- tempfile()) - files <- untar(path, list = TRUE, tar = "internal") + files <- utils::untar(path, list = TRUE, tar = "internal") desc <- grep("^[^/]+/DESCRIPTION$", files, value = TRUE) if (length(desc) < 1) stop("No 'DESCRIPTION' file in package") - untar(path, desc, exdir = tmp, tar = "internal") + utils::untar(path, desc, exdir = tmp, tar = "internal") parse_email(desc::desc_get_maintainer(file.path(tmp, desc))) } } From 7c1d249ee30e3c524daf8c2f3ce54ce121771025 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 26 Mar 2024 13:53:20 +0100 Subject: [PATCH 17/22] Fix pkgdown --- R/rc.R | 6 +++--- _pkgdown.yml | 7 ++++++- man/rc_submit.Rd | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/R/rc.R b/R/rc.R index 0bd2d33..7fc3e0a 100644 --- a/R/rc.R +++ b/R/rc.R @@ -75,9 +75,9 @@ rc_list_repos <- function(email = NULL) { #' Submit a package to the R Consortium runners #' #' @param path Path to package file or package directory. -#' @param platforms Platforms to checks. If not specified, then you -#' can select the platforms interactively. Must be specified in -#' non-interactive sessions. +#' @param platforms Platforms to checks. See [rhub_platforms()] for a +#' current list. If not specified, then you can select the platforms +#' interactively. Must be specified in non-interactive sessions. #' @param email Email address. You must have a token on the local machhine, #' that corresponds to the email address, see [rc_new_token()]. #' If not specified (or `NULL`) then the email address of the package diff --git a/_pkgdown.yml b/_pkgdown.yml index 21d841e..a00f598 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -18,12 +18,17 @@ reference: contents: - rhubv2 -- title: All functions +- title: Functions for GitHub repositories contents: - rhub_check - rhub_doctor - rhub_platforms - rhub_setup +- title: The R Consortium runners + contents: + - rc_list_repos + - rc_new_token + - rc_submit - title: internal contents: - check diff --git a/man/rc_submit.Rd b/man/rc_submit.Rd index 94a12b2..2cac8cc 100644 --- a/man/rc_submit.Rd +++ b/man/rc_submit.Rd @@ -9,9 +9,9 @@ rc_submit(path = ".", platforms = NULL, email = NULL) \arguments{ \item{path}{Path to package file or package directory.} -\item{platforms}{Platforms to checks. If not specified, then you -can select the platforms interactively. Must be specified in -non-interactive sessions.} +\item{platforms}{Platforms to checks. See \code{\link[=rhub_platforms]{rhub_platforms()}} for a +current list. If not specified, then you can select the platforms +interactively. Must be specified in non-interactive sessions.} \item{email}{Email address. You must have a token on the local machhine, that corresponds to the email address, see \code{\link[=rc_new_token]{rc_new_token()}}. From 55e1219bde6f9a7c018a465ed3ee8cd29d33acde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Tue, 26 Mar 2024 14:32:49 +0100 Subject: [PATCH 18/22] More docs, rc_list_local_tokens --- NAMESPACE | 1 + R/rc.R | 27 +++- README.Rmd | 47 +++++++ README.md | 249 ++++++++++++++++++++++-------------- _pkgdown.yml | 1 + man/rc_list_local_tokens.Rd | 21 +++ man/rc_list_repos.Rd | 1 + man/rc_new_token.Rd | 18 +-- man/rc_submit.Rd | 3 + man/rhub-package.Rd | 52 ++++++++ 10 files changed, 308 insertions(+), 112 deletions(-) create mode 100644 man/rc_list_local_tokens.Rd diff --git a/NAMESPACE b/NAMESPACE index 484bbef..1e1c0c0 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -30,6 +30,7 @@ export(list_validated_emails) export(local_check_linux) export(local_check_linux_images) export(platforms) +export(rc_list_local_tokens) export(rc_list_repos) export(rc_new_token) export(rc_submit) diff --git a/R/rc.R b/R/rc.R index 7fc3e0a..ae849a6 100644 --- a/R/rc.R +++ b/R/rc.R @@ -5,12 +5,12 @@ #' Request a new token for submissions to the R Consortium runners #' #' To build and check R packages on the RC runners of R-hub, you'll need -#' to validate your email address. R-hub will send a token to your email +#' to verify your email address. R-hub will send a token to your email #' address, and this token will be stored on your computer. #' -#' You need to validate your email on each computer you want to submit +#' You need to store a token on every computer you want to submit #' jobs from, either using the same token from the email you got, or -#' you can request another token for the new machine. Your old token +#' you can request additional tokens for the new machines. Your old token #' will stay valid as well. #' #' If you already have a token from a previous version of R-hub, you can @@ -20,13 +20,14 @@ #' ``` #' rhub:::email_file() #' ``` -#' to see the file rhub uses to store your validated tokens. +#' to see the file rhub uses to store your tokens. #' -#' @param email Email address to validate. We try to detect this, but +#' @param email Email address to verify We try to detect this, but #' if the detection fails, you can specify it explicitly. -#' @param token Token to add to the list of validated tokens. #' If this argument is missing (or `NULL`), then you can specify it #' interactively. +#' @param token Token to add. If you already received a token in an email +#' from R-hub, you can specify that here. #' #' @export #' @family RC runners API @@ -45,6 +46,19 @@ rc_new_token <- function(email = NULL, token = NULL) { invisible() } +# ------------------------------------------------------------------------- +#' Show your tokens for the R Consortium runners +#' +#' Lists all tokens stored on the local machine. +#' +#' @return Data frame with string columns `email` and `token`. +#' @export +#' @family RC runners API + +rc_list_local_tokens <- function() { + list_validated_emails2(message = FALSE, msg_if_empty = FALSE) +} + # ------------------------------------------------------------------------- #' List your repositories created by the R Consortium runners #' @@ -96,6 +110,7 @@ rc_list_repos <- function(email = NULL) { #' #' @export #' @family RC runners API +#' @seealso [rhub_platforms()] for a list of supported platforms. rc_submit <- function(path = ".", platforms = NULL, email = NULL) { pkg_name <- desc::desc_get("Package", file = path)[[1]] diff --git a/README.Rmd b/README.Rmd index 68c8d07..9b42dbe 100644 --- a/README.Rmd +++ b/README.Rmd @@ -57,6 +57,9 @@ pak::pkg_install("rhub") You can use the [gitcreds package](https://gitcreds.r-lib.org/) to add the token to the git credential store. +See the [R Consortium runners](#the-r-consortium-runners) section for +using rhub if your package is not on GitHub. + ### Private repositories rhub uses GitHub Actions, which is free for public repositories. @@ -103,6 +106,50 @@ Run `rhub::rhub_check()` to start R-hub v2 checks on GitHub Actions: rhub::rhub_check() ``` +## The R Consortium runners + +If you don't want to put your package on GitHub, you can still use the +rhub package to run package checks on any supported platform using a +shared pool of runners in the https://github.com/r-hub2 GitHub +organization. + +The process is similar to the first version of R-hub: + +* Set your working directory to the R package you want to check. +* Obtain a token from R-hub, to verify your email address: + ``` + rc_new_token() + ``` + (You do not need to do this, if you already submitted packages to a + previous version of R-hub from the same machine, using the same email + address. Call `rc_list_local_tokens()` to check if you already have + tokens.) +* Submit a build with + ``` + rc_submit() + ``` +* Select the platforms you want to use, and follow the instructions and + the link provided to see your check results. + +### Limitations of the R Consortium runners + +* You package will be public for the world, and will be stored in the + https://github.com/r-hub2 organization. Your check output and results + will be public for anyone with a GitHub account. If you want to keep + your package private, you can put it in a private GitHub repository, + and use the `rhub_setup()` and `rhub_check()` functions instead. +* The R Consortium runners are shared among all users, so you might need + to wait for your builds to start. +* You have to wait at least five minutes between submissions with + `rc_submit()`. +* Currently you need to create a GitHub account to see the check logs of + your package. You don't need a GitHub account to submit the checks. + +To avoid these limitations (except for the neeed for a GitHub accounr), +put your package in a GitHub repository, and use the `rhub_setup()` and +`rhub_check()` functions instead of `rc_submit()` and the R Consortium +runners. + ## Code of Conduct Please note that the rhub package is released with a diff --git a/README.md b/README.md index f472e81..35b0bd1 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,9 @@ running checks. - [Private repositories](#private-repositories) - [Setup](#setup) - [Run checks](#run-checks) +- [The R Consortium runners](#the-r-consortium-runners) + - [Limitations of the R Consortium + runners](#limitations-of-the-r-consortium-runners) - [Code of Conduct](#code-of-conduct) - [License](#license) @@ -47,6 +50,9 @@ pak::pkg_install("rhub") You can use the [gitcreds package](https://gitcreds.r-lib.org/) to add the token to the git credential store. +See the [R Consortium runners](#the-r-consortium-runners) section for +using rhub if your package is not on GitHub. + ### Private repositories rhub uses GitHub Actions, which is free for public repositories. For @@ -68,23 +74,23 @@ rhub::rhub_setup() style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream Vera Sans Mono','Powerline Symbols',monospace;line-height: 1.300000">
-## Setting up R-hub v2.
-##  Found R package at /private/tmp/cli.
-##  Found git repository at /private/tmp/cli.
-##  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.
-##
-## Notes:
-##  The workflow file must be added to the default branch of the GitHub
-##   repository.
-##  GitHub actions must be enabled for the repository. They are disabled for
-##   forked repositories by default.
-##
-## Next steps:
-##  Add the workflow file to git using `git add <filename>`.
-##  Commit it to git using `git commit`.
-##  Push the commit to GitHub using `git push`.
-##  Call `rhub::rhub_doctor()` to check that you have set up R-hub correctly.
-##  Call `rhub::rhub_check()` to check your package.
+## Setting up R-hub v2.                                                            
+##  Found R package at /private/tmp/cli.                                          
+##  Found git repository at /private/tmp/cli.                                     
+##  Created workflow file /private/tmp/cli/.github/workflows/rhub.yaml.           
+##                                                                                 
+## Notes:                                                                          
+##  The workflow file must be added to the default branch of the GitHub           
+##   repository.                                                                   
+##  GitHub actions must be enabled for the repository. They are disabled for      
+##   forked repositories by default.                                               
+##                                                                                 
+## Next steps:                                                                     
+##  Add the workflow file to git using `git add <filename>`.                      
+##  Commit it to git using `git commit`.                                          
+##  Push the commit to GitHub using `git push`.                                   
+##  Call `rhub2::rhub_doctor()` to check that you have set up R-hub correctly.    
+##  Call `rhub2::rhub_check()` to check your package.                             
 
@@ -102,13 +108,13 @@ rhub::rhub_doctor() style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream Vera Sans Mono','Powerline Symbols',monospace;line-height: 1.300000">
-##  Found R package at /private/tmp/cli.
-##  Found git repository at /private/tmp/cli.
-##  Found GitHub PAT.
-##  Found repository on GitHub at <https://github.com/r-lib/cli>.
-##  GitHub PAT has the right scopes.
-##  Found R-hub workflow in default branch, and it is active.
-## → WOOT! You are ready to run `rhub::rhub_check()` on this package.
+##  Found R package at /private/tmp/cli.                                          
+##  Found git repository at /private/tmp/cli.                                     
+##  Found GitHub PAT.                                                             
+##  Found repository on GitHub at <https://github.com/r-lib/cli>.                 
+##  GitHub PAT has the right scopes.                                              
+##  Found R-hub workflow in default branch, and it is active.                     
+## → WOOT! You are ready to run `rhub2::rhub_check()` on this package.             
 
@@ -126,65 +132,65 @@ rhub::rhub_platforms() style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream Vera Sans Mono','Powerline Symbols',monospace;line-height: 1.300000">
-## ── Virtual machines ───────────────────────────────────────────────────────────
-##  1 [VM]  linux
-##    All R versions on GitHub Actions ubuntu-latest
-##  2 [VM]  macos
-##    All R versions on GitHub Actions macos-latest
-##  3 [VM]  macos-arm64
-##    All R versions on GitHub Actions macos-14
-##  4 [VM]  windows
-##    All R versions on GitHub Actions windows-latest
-##
-## ── Containers ─────────────────────────────────────────────────────────────────
-##  5 [CT]  atlas  [ATLAS]
+## ── Virtual machines ─────────────────────────────────────────────────────────── 
+##  1 [VM]  linux                                                                  
+##    All R versions on GitHub Actions ubuntu-latest                               
+##  2 [VM]  macos                                                                  
+##    All R versions on GitHub Actions macos-latest                                
+##  3 [VM]  macos-arm64                                                            
+##    All R versions on GitHub Actions macos-14                                    
+##  4 [VM]  windows                                                                
+##    All R versions on GitHub Actions windows-latest                              
+##                                                                                 
+## ── Containers ───────────────────────────────────────────────────────────────── 
+##  5 [CT]  atlas  [ATLAS]                                                         
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/atlas:latest
-##  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]
-##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/clang-asan:latest
-##  7 [CT]  clang16  [clang16]
-##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/clang16:latest
-##  8 [CT]  clang17  [clang17]
-##    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/clang17:latest
-##  9 [CT]  clang18  [clang18]
-##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/clang18:latest
-## 10 [CT]  donttest  [donttest]
-##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/donttest:latest
-## 11 [CT]  gcc13  [gcc13]
+##    ghcr.io/r-hub/containers/atlas:latest                                        
+##  6 [CT]  clang-asan  [asan, clang-ASAN, clang-UBSAN, ubsan]                     
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/clang-asan:latest                                   
+##  7 [CT]  clang16  [clang16]                                                     
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/clang16:latest                                      
+##  8 [CT]  clang17  [clang17]                                                     
+##    R Under development (unstable) (2024-03-11 r86098) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/clang17:latest                                      
+##  9 [CT]  clang18  [clang18]                                                     
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/clang18:latest                                      
+## 10 [CT]  donttest  [donttest]                                                   
+##    R Under development (unstable) (2024-03-12 r86109) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/donttest:latest                                     
+## 11 [CT]  gcc13  [gcc13]                                                         
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/gcc13:latest
-## 12 [CT]  intel  [Intel]
+##    ghcr.io/r-hub/containers/gcc13:latest                                        
+## 12 [CT]  intel  [Intel]                                                         
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/intel:latest
-## 13 [CT]  mkl  [MKL]
+##    ghcr.io/r-hub/containers/intel:latest                                        
+## 13 [CT]  mkl  [MKL]                                                             
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/mkl:latest
-## 14 [CT]  nold  [noLD]
-##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/nold:latest
-## 15 [CT]  nosuggests  [noSuggests]
+##    ghcr.io/r-hub/containers/mkl:latest                                          
+## 14 [CT]  nold  [noLD]                                                           
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/nold:latest                                         
+## 15 [CT]  nosuggests  [noSuggests]                                               
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/nosuggests:latest
-## 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]
-##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/ubuntu-clang:latest
-## 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]
-##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/ubuntu-gcc12:latest
-## 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]
-##    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/ubuntu-next:latest
-## 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]
-##    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS
-##    ghcr.io/r-hub/containers/ubuntu-release:latest
-## 20 [CT]  valgrind  [valgrind]
+##    ghcr.io/r-hub/containers/nosuggests:latest                                   
+## 16 [CT]  ubuntu-clang  [r-devel-linux-x86_64-debian-clang]                      
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/ubuntu-clang:latest                                 
+## 17 [CT]  ubuntu-gcc12  [r-devel-linux-x86_64-debian-gcc]                        
+##    R Under development (unstable) (2024-03-13 r86113) on Ubuntu 22.04.4 LTS     
+##    ghcr.io/r-hub/containers/ubuntu-gcc12:latest                                 
+## 18 [CT]  ubuntu-next  [r-next, r-patched, r-patched-linux-x86_64]               
+##    R version 4.3.3 Patched (2024-02-29 r86113) on Ubuntu 22.04.4 LTS            
+##    ghcr.io/r-hub/containers/ubuntu-next:latest                                  
+## 19 [CT]  ubuntu-release  [r-release, r-release-linux-x86_64, ubuntu]            
+##    R version 4.3.3 (2024-02-29) on Ubuntu 22.04.4 LTS                           
+##    ghcr.io/r-hub/containers/ubuntu-release:latest                               
+## 20 [CT]  valgrind  [valgrind]                                                   
 ##    R Under development (unstable) (2024-03-13 r86113) on Fedora Linux 38 (Conta…
-##    ghcr.io/r-hub/containers/valgrind:latest
+##    ghcr.io/r-hub/containers/valgrind:latest                                     
 
@@ -199,40 +205,87 @@ rhub::rhub_check() style="color: #B9C0CB;font-family: 'Fira Code',Monaco,Consolas,Menlo,'Bitstream Vera Sans Mono','Powerline Symbols',monospace;line-height: 1.300000">
-##  Found git repository at /private/tmp/cli.
-##  Found GitHub PAT.
-##
-## Available platforms (see `rhub::rhub_platforms()` for details):
-##
+##  Found git repository at /private/tmp/cli.                                     
+##  Found GitHub PAT.                                                             
+##                                                                                 
+## Available platforms (see `rhub2::rhub_platforms()` for details):                
+##                                                                                 
 ##  1 [VM] linux          R-* (any version)                     ubuntu-latest on G…
 ##  2 [VM] macos          R-* (any version)                     macos-latest on Gi…
-##  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub
+##  3 [VM] macos-arm64    R-* (any version)                     macos-14 on GitHub 
 ##  4 [VM] windows        R-* (any version)                     windows-latest on …
 ##  5 [CT] atlas          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-##  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-##  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-##  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS
-##  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
-## 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS
+##  6 [CT] clang-asan     R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+##  7 [CT] clang16        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+##  8 [CT] clang17        R-devel (2024-03-11 r86098)           Ubuntu 22.04.4 LTS 
+##  9 [CT] clang18        R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
+## 10 [CT] donttest       R-devel (2024-03-12 r86109)           Ubuntu 22.04.4 LTS 
 ## 11 [CT] gcc13          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 ## 12 [CT] intel          R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
 ## 13 [CT] mkl            R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-## 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
+## 14 [CT] nold           R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
 ## 15 [CT] nosuggests     R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-## 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
-## 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS
-## 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS
-## 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS
+## 16 [CT] ubuntu-clang   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+## 17 [CT] ubuntu-gcc12   R-devel (2024-03-13 r86113)           Ubuntu 22.04.4 LTS 
+## 18 [CT] ubuntu-next    R-4.3.3 (patched) (2024-02-29 r86113) Ubuntu 22.04.4 LTS 
+## 19 [CT] ubuntu-release R-4.3.3 (2024-02-29)                  Ubuntu 22.04.4 LTS 
 ## 20 [CT] valgrind       R-devel (2024-03-13 r86113)           Fedora Linux 38 (C…
-##
-## Selection (comma separated numbers, 0 to cancel): 1, 5
-##
-##  Check started: linux, atlas (daft-acornwoodpecker).
-##   See <https://github.com/r-lib/cli/actions> for live output!
+##                                                                                 
+## Selection (comma separated numbers, 0 to cancel): 1, 5                          
+##                                                                                 
+##  Check started: linux, atlas (daft-acornwoodpecker).                           
+##   See <https://github.com/r-lib/cli/actions> for live output!                   
 
+## The R Consortium runners + +If you don’t want to put your package on GitHub, you can still use the +rhub package to run package checks on any supported platform using a +shared pool of runners in the GitHub +organization. + +The process is similar to the first version of R-hub: + +- Set your working directory to the R package you want to check. + +- Obtain a token from R-hub, to verify your email address: + + rc_new_token() + + (You do not need to do this, if you already submitted packages to a + previous version of R-hub from the same machine, using the same email + address. Call `rc_list_local_tokens()` to check if you already have + tokens.) + +- Submit a build with + + rc_submit() + +- Select the platforms you want to use, and follow the instructions and + the link provided to see your check results. + +### Limitations of the R Consortium runners + +- You package will be public for the world, and will be stored in the + organization. Your check output and + results will be public for anyone with a GitHub account. If you want + to keep your package private, you can put it in a private GitHub + repository, and use the `rhub_setup()` and `rhub_check()` functions + instead. +- The R Consortium runners are shared among all users, so you might need + to wait for your builds to start. +- You have to wait at least five minutes between submissions with + `rc_submit()`. +- Currently you need to create a GitHub account to see the check logs of + your package. You don’t need a GitHub account to submit the checks. + +To avoid these limitations (except for the neeed for a GitHub accounr), +put your package in a GitHub repository, and use the `rhub_setup()` and +`rhub_check()` functions instead of `rc_submit()` and the R Consortium +runners. + ## Code of Conduct Please note that the rhub package is released with a [Contributor Code diff --git a/_pkgdown.yml b/_pkgdown.yml index a00f598..78faddb 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -26,6 +26,7 @@ reference: - rhub_setup - title: The R Consortium runners contents: + - rc_list_local_tokens - rc_list_repos - rc_new_token - rc_submit diff --git a/man/rc_list_local_tokens.Rd b/man/rc_list_local_tokens.Rd new file mode 100644 index 0000000..e1f0e45 --- /dev/null +++ b/man/rc_list_local_tokens.Rd @@ -0,0 +1,21 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/rc.R +\name{rc_list_local_tokens} +\alias{rc_list_local_tokens} +\title{Show your tokens for the R Consortium runners} +\usage{ +rc_list_local_tokens() +} +\value{ +Data frame with string columns \code{email} and \code{token}. +} +\description{ +Lists all tokens stored on the local machine. +} +\seealso{ +Other RC runners API: +\code{\link{rc_list_repos}()}, +\code{\link{rc_new_token}()}, +\code{\link{rc_submit}()} +} +\concept{RC runners API} diff --git a/man/rc_list_repos.Rd b/man/rc_list_repos.Rd index c58f257..fc325d2 100644 --- a/man/rc_list_repos.Rd +++ b/man/rc_list_repos.Rd @@ -26,6 +26,7 @@ Lists repositories created by \code{\link[=rc_submit]{rc_submit()}} submissions. } \seealso{ Other RC runners API: +\code{\link{rc_list_local_tokens}()}, \code{\link{rc_new_token}()}, \code{\link{rc_submit}()} } diff --git a/man/rc_new_token.Rd b/man/rc_new_token.Rd index 06fc49c..67bdc7c 100644 --- a/man/rc_new_token.Rd +++ b/man/rc_new_token.Rd @@ -7,22 +7,23 @@ rc_new_token(email = NULL, token = NULL) } \arguments{ -\item{email}{Email address to validate. We try to detect this, but -if the detection fails, you can specify it explicitly.} - -\item{token}{Token to add to the list of validated tokens. +\item{email}{Email address to verify We try to detect this, but +if the detection fails, you can specify it explicitly. If this argument is missing (or \code{NULL}), then you can specify it interactively.} + +\item{token}{Token to add. If you already received a token in an email +from R-hub, you can specify that here.} } \description{ To build and check R packages on the RC runners of R-hub, you'll need -to validate your email address. R-hub will send a token to your email +to verify your email address. R-hub will send a token to your email address, and this token will be stored on your computer. } \details{ -You need to validate your email on each computer you want to submit +You need to store a token on every computer you want to submit jobs from, either using the same token from the email you got, or -you can request another token for the new machine. Your old token +you can request additional tokens for the new machines. Your old token will stay valid as well. If you already have a token from a previous version of R-hub, you can @@ -33,10 +34,11 @@ Run \if{html}{\out{
}}\preformatted{rhub:::email_file() }\if{html}{\out{
}} -to see the file rhub uses to store your validated tokens. +to see the file rhub uses to store your tokens. } \seealso{ Other RC runners API: +\code{\link{rc_list_local_tokens}()}, \code{\link{rc_list_repos}()}, \code{\link{rc_submit}()} } diff --git a/man/rc_submit.Rd b/man/rc_submit.Rd index 2cac8cc..ee3e121 100644 --- a/man/rc_submit.Rd +++ b/man/rc_submit.Rd @@ -36,7 +36,10 @@ More fields might be added later. Submit a package to the R Consortium runners } \seealso{ +\code{\link[=rhub_platforms]{rhub_platforms()}} for a list of supported platforms. + Other RC runners API: +\code{\link{rc_list_local_tokens}()}, \code{\link{rc_list_repos}()}, \code{\link{rc_new_token}()} } diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index 09e6fcb..5e899ad 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -22,6 +22,9 @@ Install rhub from CRAN: You can use the \href{https://gitcreds.r-lib.org/}{gitcreds package} to add the token to the git credential store. } + +See the \href{#the-r-consortium-runners}{R Consortium runners} section for +using rhub if your package is not on GitHub. } \subsection{Private repositories}{ @@ -193,6 +196,55 @@ Run \code{rhub::rhub_check()} to start R-hub v2 checks on GitHub Actions: } +\subsection{The R Consortium runners}{ + +If you don't want to put your package on GitHub, you can still use the +rhub package to run package checks on any supported platform using a +shared pool of runners in the https://github.com/r-hub2 GitHub +organization. + +The process is similar to the first version of R-hub: +\itemize{ +\item Set your working directory to the R package you want to check. +\item Obtain a token from R-hub, to verify your email address: + +\if{html}{\out{
}}\preformatted{rc_new_token() +}\if{html}{\out{
}} + +(You do not need to do this, if you already submitted packages to a +previous version of R-hub from the same machine, using the same email +address. Call \code{rc_list_local_tokens()} to check if you already have +tokens.) +\item Submit a build with + +\if{html}{\out{
}}\preformatted{rc_submit() +}\if{html}{\out{
}} +\item Select the platforms you want to use, and follow the instructions and +the link provided to see your check results. +} +\subsection{Limitations of the R Consortium runners}{ +\itemize{ +\item You package will be public for the world, and will be stored in the +https://github.com/r-hub2 organization. Your check output and results +will be public for anyone with a GitHub account. If you want to keep +your package private, you can put it in a private GitHub repository, +and use the \code{rhub_setup()} and \code{rhub_check()} functions instead. +\item The R Consortium runners are shared among all users, so you might need +to wait for your builds to start. +\item You have to wait at least five minutes between submissions with +\code{rc_submit()}. +\item Currently you need to create a GitHub account to see the check logs of +your package. You don't need a GitHub account to submit the checks. +} + +To avoid these limitations (except for the neeed for a GitHub accounr), +put your package in a GitHub repository, and use the \code{rhub_setup()} and +\code{rhub_check()} functions instead of \code{rc_submit()} and the R Consortium +runners. +} + +} + \subsection{Code of Conduct}{ Please note that the rhub package is released with a From bdc3fb267dc3abcf5bbfdf57aad91ce270627448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Wed, 27 Mar 2024 08:59:37 +0100 Subject: [PATCH 19/22] Update NEWS, more docs --- NEWS.md | 21 +++++--- _pkgdown.yml | 10 ++-- man/rhubv2.Rd | 124 ++++++++++++++++++++++++++++++++++++++++++- vignettes/rhubv2.Rmd | 118 +++++++++++++++++++++++++++++++++++++++- 4 files changed, 259 insertions(+), 14 deletions(-) diff --git a/NEWS.md b/NEWS.md index 442c5f1..3340172 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,6 +1,15 @@ # rhub development version +## R-hub v2 + +This is a completely new system, see `?rhubv2` manual page or +the 'Getting started with R-hub v2' article at +https://r-hub.github.io/rhub/dev to start. + +Previous functions are now deprecated and defunct. They will be removed +in the next version of the package. + # rhub 1.1.2 * Replace `platform` parameter with `platforms` in `check()` (#497). @@ -17,17 +26,17 @@ ## Enhancements -* `cran_summary()` now messages that we recommend to fix all NOTEs, WARNINGs +* `cran_summary()` now messages that we recommend to fix all NOTEs, WARNINGs and ERRORs before a CRAN submission when the check results aren't 0 NOTE, 0 WARNING, 0 ERROR. - -* `cran_summary()` now outputs informative messages when any of the builds + +* `cran_summary()` now outputs informative messages when any of the builds of the group hasn't completed (yet, or at all). ## Bug fixes -* `cran_summary()` now works for packages whose R CMD Check result include - no NOTE/WARNING/ERROR, and gives an informative error message when not all +* `cran_summary()` now works for packages whose R CMD Check result include + no NOTE/WARNING/ERROR, and gives an informative error message when not all builds are completed yet. * `cran_summary()` now prints lines to screen without unwanted indentation. @@ -45,7 +54,7 @@ * New `get_check()` function that works with check ids, or a check group id. -* `list_package_checks()` and `list_my_checks()` now output a `tibble`, that +* `list_package_checks()` and `list_my_checks()` now output a `tibble`, that is nicely formatted when printed to the screen. * The output of `get_check()`, `check()`, `check_on_`, `check_for_cran()`, diff --git a/_pkgdown.yml b/_pkgdown.yml index 78faddb..14499b8 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -12,13 +12,10 @@ development: mode: auto reference: -- title: Introduction +- title: R-hub v2 desc: | - Start here if you are new to R-hub v2: - contents: - - rhubv2 - -- title: Functions for GitHub repositories + Start with the 'Get started with R-hub v2' article if you are + new to R-hub. contents: - rhub_check - rhub_doctor @@ -32,6 +29,7 @@ reference: - rc_submit - title: internal contents: + - rhubv2 - check - check_for_cran - check_on_linux diff --git a/man/rhubv2.Rd b/man/rhubv2.Rd index 17c51ff..e1e5c16 100644 --- a/man/rhubv2.Rd +++ b/man/rhubv2.Rd @@ -4,5 +4,127 @@ \alias{rhubv2} \title{R-hub v2} \description{ -TODO +R-hub v2 } +\section{R-hub v2}{ +\subsection{Introduction}{ + +R-hub v2, i.e. version 2 or later of the rhub package is a completely +new check system. In this acticle we highlight the differences between +the old and the new system. + +There are two ways to use R-hub v2. The recommended way is to store your +R package in a GitHub repository and use the \verb{rhub_*()} functions to +start checks on GitHub Actions, using your own GitHub account. + +Alternatively, if you don't want to store your R package at GitHub, you +can use the \verb{rc_*()} functions to run checks in a shared GitHub +organization at https://github.com/r-hub2, using the R Consortium runners. +See more about the R Consortium runners below. +} + +\subsection{Transitioning from R-hub v1}{ +\subsection{Requirements for using R-hub v2}{ +\itemize{ +\item First, you need a GitHub account. +\item Second, you need to have your R package in a GitHub repository. +In your local git clone make sure that the \code{origin} git remote is set +to the GitHub repository. +\item Third, you need a GitHub \href{https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token}{Personal Access Token} +and you need to store it in the git credential store on your machine. +You can use \code{gitcreds::gitcreds_set()} to add the token to the git +credential store. +} + +Call \code{rhub_setup()} from the local git clone to set up R-hub v2 for your +package. This adds a GitHub Actions workflow to your local repository. +Push this change to GitHub, into your default git branch and then you +are ready to call start checks with \code{rhub_check()}. +} + +\subsection{Differences from R-hub v1}{ +\itemize{ +\item The check picks up the package from GitHub, so it does not use +changes in your local git clone. You need to push the changes to +GitHub first. You can use a non-default branch, with the \code{branch} +argument of \code{rhub_check()}. +\item You'll not get an email about the check results. But you'll receive +regular GitHub notifications about check failures, unless you opt out. +Github can also turn these into emails if you like. +\item There is no live output from the check at the R console. See the +'Actions' tab of your repository on GitHub for a live check log. +\item Many more specialized platforms are available. +\item Most platforms use binary packages, so checks and in particular +installing dependencies is much faster. +} +} + +\subsection{Private repositories}{ + +GitHub Actions is free for public repositories. +For private repositories you also get some minutes for free, depending on +the GitHub subscription you have. See +\href{https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions}{About billing for GitHub Actions} +for details. +} + +\subsection{Branches}{ + +You can run checks on any branch that you push to GitHub, but you'll need +to add the R-hub workflow file (\code{.github/workflows/rhub.yaml} within +your repo) must be present in \strong{both} the default branch (usually \code{main}) +and also in the branch you want to run the check on. +} + +} + +\subsection{The R Consortium runners}{ + +If you don't want to put your package on GitHub, you can still use the +rhub package to run package checks on any supported platform using a +shared pool of runners in the https://github.com/r-hub2 GitHub +organization. + +The process is similar to the first version of R-hub: +\itemize{ +\item Set your working directory to the R package you want to check. +\item Obtain a token from R-hub, to verify your email address: + +\if{html}{\out{
}}\preformatted{rc_new_token() +}\if{html}{\out{
}} + +(You do not need to do this, if you already submitted packages to a +previous version of R-hub from the same machine, using the same email +address. Call \code{rc_list_local_tokens()} to check if you already have +tokens.) +\item Submit a build with + +\if{html}{\out{
}}\preformatted{rc_submit() +}\if{html}{\out{
}} +\item Select the platforms you want to use, and follow the instructions and +the link provided to see your check results. +} +\subsection{Limitations of the R Consortium runners}{ +\itemize{ +\item You package will be public for the world, and will be stored in the +https://github.com/r-hub2 organization. Your check output and results +will be public for anyone with a GitHub account. If you want to keep +your package private, you can put it in a private GitHub repository, +and use the \code{rhub_setup()} and \code{rhub_check()} functions instead. +\item The R Consortium runners are shared among all users, so you might need +to wait for your builds to start. +\item You have to wait at least five minutes between submissions with +\code{rc_submit()}. +\item Currently you need to create a GitHub account to see the check logs of +your package. You don't need a GitHub account to submit the checks. +} + +To avoid these limitations (except for the neeed for a GitHub accounr), +put your package in a GitHub repository, and use the \code{rhub_setup()} and +\code{rhub_check()} functions instead of \code{rc_submit()} and the R Consortium +runners. +} + +} +} + diff --git a/vignettes/rhubv2.Rmd b/vignettes/rhubv2.Rmd index 1333ed7..c38a9bb 100644 --- a/vignettes/rhubv2.Rmd +++ b/vignettes/rhubv2.Rmd @@ -1 +1,117 @@ -TODO +--- +title: "Get started with R-hub v2" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{Get started with R-hub v2} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +# R-hub v2 + +## Introduction + +R-hub v2, i.e. version 2 or later of the rhub package is a completely +new check system. In this acticle we highlight the differences between +the old and the new system. + +There are two ways to use R-hub v2. The recommended way is to store your +R package in a GitHub repository and use the `rhub_*()` functions to +start checks on GitHub Actions, using your own GitHub account. + +Alternatively, if you don't want to store your R package at GitHub, you +can use the `rc_*()` functions to run checks in a shared GitHub +organization at https://github.com/r-hub2, using the R Consortium runners. +See more about the R Consortium runners below. + +## Transitioning from R-hub v1 + +### Requirements for using R-hub v2 + +- First, you need a GitHub account. +- Second, you need to have your R package in a GitHub repository. + In your local git clone make sure that the `origin` git remote is set + to the GitHub repository. +- Third, you need a GitHub [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) + and you need to store it in the git credential store on your machine. + You can use `gitcreds::gitcreds_set()` to add the token to the git + credential store. + +Call `rhub_setup()` from the local git clone to set up R-hub v2 for your +package. This adds a GitHub Actions workflow to your local repository. +Push this change to GitHub, into your default git branch and then you +are ready to call start checks with `rhub_check()`. + +### Differences from R-hub v1 + +- The check picks up the package from GitHub, so it does not use + changes in your local git clone. You need to push the changes to + GitHub first. You can use a non-default branch, with the `branch` + argument of `rhub_check()`. +- You'll not get an email about the check results. But you'll receive + regular GitHub notifications about check failures, unless you opt out. + Github can also turn these into emails if you like. +- There is no live output from the check at the R console. See the + 'Actions' tab of your repository on GitHub for a live check log. +- Many more specialized platforms are available. +- Most platforms use binary packages, so checks and in particular + installing dependencies is much faster. + +### Private repositories + +GitHub Actions is free for public repositories. +For private repositories you also get some minutes for free, depending on +the GitHub subscription you have. See +[About billing for GitHub Actions](https://docs.github.com/en/billing/managing-billing-for-github-actions/about-billing-for-github-actions) +for details. + +### Branches + +You can run checks on any branch that you push to GitHub, but you'll need +to add the R-hub workflow file (`.github/workflows/rhub.yaml` within +your repo) must be present in **both** the default branch (usually `main`) +and also in the branch you want to run the check on. + +## The R Consortium runners + +If you don't want to put your package on GitHub, you can still use the +rhub package to run package checks on any supported platform using a +shared pool of runners in the https://github.com/r-hub2 GitHub +organization. + +The process is similar to the first version of R-hub: + +* Set your working directory to the R package you want to check. +* Obtain a token from R-hub, to verify your email address: + ``` + rc_new_token() + ``` + (You do not need to do this, if you already submitted packages to a + previous version of R-hub from the same machine, using the same email + address. Call `rc_list_local_tokens()` to check if you already have + tokens.) +* Submit a build with + ``` + rc_submit() + ``` +* Select the platforms you want to use, and follow the instructions and + the link provided to see your check results. + +### Limitations of the R Consortium runners + +* You package will be public for the world, and will be stored in the + https://github.com/r-hub2 organization. Your check output and results + will be public for anyone with a GitHub account. If you want to keep + your package private, you can put it in a private GitHub repository, + and use the `rhub_setup()` and `rhub_check()` functions instead. +* The R Consortium runners are shared among all users, so you might need + to wait for your builds to start. +* You have to wait at least five minutes between submissions with + `rc_submit()`. +* Currently you need to create a GitHub account to see the check logs of + your package. You don't need a GitHub account to submit the checks. + +To avoid these limitations (except for the neeed for a GitHub accounr), +put your package in a GitHub repository, and use the `rhub_setup()` and +`rhub_check()` functions instead of `rc_submit()` and the R Consortium +runners. From 618881cd5e68941514aea8b472cf0230ab82dcc6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 30 Mar 2024 11:41:13 +0100 Subject: [PATCH 20/22] Docs finetuning --- R/rhubv2.R | 12 ++++++++++-- man/rhub-package.Rd | 5 ++++- man/rhubv2.Rd | 3 ++- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/R/rhubv2.R b/R/rhubv2.R index 801dd93..a335238 100644 --- a/R/rhubv2.R +++ b/R/rhubv2.R @@ -1,5 +1,8 @@ -#' Tools for R package developers +#' @title The rhub package #' +#' @description Tools for R package developers +#' +#' @details #' ```{r man-readme, child = "README.Rmd"} #' ``` #' @@ -9,9 +12,14 @@ #' @aliases rhub NULL + +#' @title R-hub v2 +#' @description Start here to learn about R-hub v2, especially if you +#' used the previous version of R-hub before. +#' +#' @details #' ```{r include = FALSE, child = "vignettes/rhubv2.Rmd"} #' ``` -#' @title R-hub v2 #' @name rhubv2 #' @rdname rhubv2 NULL \ No newline at end of file diff --git a/man/rhub-package.Rd b/man/rhub-package.Rd index 5e899ad..b32bb9e 100644 --- a/man/rhub-package.Rd +++ b/man/rhub-package.Rd @@ -3,8 +3,11 @@ \name{rhub-package} \alias{rhub-package} \alias{rhub} -\title{Tools for R package developers} +\title{The rhub package} \description{ +Tools for R package developers +} +\details{ \subsection{Installation}{ Install rhub from CRAN: diff --git a/man/rhubv2.Rd b/man/rhubv2.Rd index e1e5c16..0afdd55 100644 --- a/man/rhubv2.Rd +++ b/man/rhubv2.Rd @@ -4,7 +4,8 @@ \alias{rhubv2} \title{R-hub v2} \description{ -R-hub v2 +Start here to learn about R-hub v2, especially if you +used the previous version of R-hub before. } \section{R-hub v2}{ \subsection{Introduction}{ From 532b87c70ffc491a3636a830c3bde5d4e55fa798 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 30 Mar 2024 12:04:21 +0100 Subject: [PATCH 21/22] Add confirmation for rc_submit --- R/rc.R | 31 ++++++++++++++++++++++++++++++- man/rc_submit.Rd | 5 ++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/R/rc.R b/R/rc.R index ae849a6..1d681c8 100644 --- a/R/rc.R +++ b/R/rc.R @@ -96,6 +96,8 @@ rc_list_repos <- function(email = NULL) { #' that corresponds to the email address, see [rc_new_token()]. #' If not specified (or `NULL`) then the email address of the package #' maintainer is used. +#' @param confirmation You must set this to `TRUE` to submit a package +#' from a non-interactive session. #' @return A list with data about the submission, invisibly. #' Currently it has: #' @@ -112,7 +114,16 @@ rc_list_repos <- function(email = NULL) { #' @family RC runners API #' @seealso [rhub_platforms()] for a list of supported platforms. -rc_submit <- function(path = ".", platforms = NULL, email = NULL) { +rc_submit <- function(path = ".", platforms = NULL, email = NULL, + confirmation = NULL) { + + if (isTRUE(confirmation) && !is_interactive()) { + throw(pkg_error( + "You need to set {.arg confirmation} to {.val TRUE} + to submit packages to R-hub from non-interactive R sessions." + )) + } + pkg_name <- desc::desc_get("Package", file = path)[[1]] if (is.na(pkg_name)) { throw(pkg_error( @@ -140,6 +151,24 @@ rc_submit <- function(path = ".", platforms = NULL, email = NULL) { package = curl::form_file(path) ) + if (!isTRUE(confirmation)) { + cat(cli::col_cyan(cli::rule("Confirmation"))) + cli::cli_bullets(c( + "!" = "Your package will be publicly readable at + {.url https://github.com/r-hub2}.", + " " = "Only continue if you are fine with this.", + " " = "See the {.fn rhub_setup} function for an alternative way + of using R-hub." + )) + ans <- trimws(readline( + prompt = "\nPlease type 'yes' to continue: " + )) + cli::cli_text() + if (ans != 'yes' && ans != "'yes'") { + throw(pkg_error("Aborted R-hub submission.")) + } + } + resp <- query( method = "POST", ep, diff --git a/man/rc_submit.Rd b/man/rc_submit.Rd index ee3e121..be04300 100644 --- a/man/rc_submit.Rd +++ b/man/rc_submit.Rd @@ -4,7 +4,7 @@ \alias{rc_submit} \title{Submit a package to the R Consortium runners} \usage{ -rc_submit(path = ".", platforms = NULL, email = NULL) +rc_submit(path = ".", platforms = NULL, email = NULL, confirmation = NULL) } \arguments{ \item{path}{Path to package file or package directory.} @@ -17,6 +17,9 @@ interactively. Must be specified in non-interactive sessions.} that corresponds to the email address, see \code{\link[=rc_new_token]{rc_new_token()}}. If not specified (or \code{NULL}) then the email address of the package maintainer is used.} + +\item{confirmation}{You must set this to \code{TRUE} to submit a package +from a non-interactive session.} } \value{ A list with data about the submission, invisibly. From 29b40fd5e5961e6547505b32c0c8007432c7df07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Cs=C3=A1rdi?= Date: Sat, 30 Mar 2024 12:14:17 +0100 Subject: [PATCH 22/22] Improve RC confirmation message [ci skip] --- R/rc.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/rc.R b/R/rc.R index 1d681c8..a4d6ec8 100644 --- a/R/rc.R +++ b/R/rc.R @@ -156,8 +156,9 @@ rc_submit <- function(path = ".", platforms = NULL, email = NULL, cli::cli_bullets(c( "!" = "Your package will be publicly readable at {.url https://github.com/r-hub2}.", - " " = "Only continue if you are fine with this.", - " " = "See the {.fn rhub_setup} function for an alternative way + ">" = "You will need a GitHub account to view the build logs.", + ">" = "Only continue if you are fine with this.", + ">" = "See the {.fn rhub_setup} function for an alternative way of using R-hub." )) ans <- trimws(readline(