.onLoad <- function(libname, pkgname) { # clear pkgpins cache tryCatch(expr = pkgpins::clear_cache(board = pkgpins::board(pkg = pkgname), max_age = funky::config_val(key = "global_max_cache_age", pkg = pkgname)), error = function(e) cli::cli_alert_warning(text = "Failed to clear pkgpins cache on load of {.pkg {pkgname}}. Error message: {e$message}")) }
R CMD check
notes about undefined global objects used in magrittr pipescf. https://github.com/tidyverse/magrittr/issues/29#issuecomment-74313262
utils::globalVariables(names = c(".", # tidyselect fns "everything", # other "is_pro", "key", "last_modified", "name"))
this_pkg <- utils::packageName()
all_bundled_tools
all_bundled_tools <- c("dart-sass", "deno", "esbuild", "pandoc", "quarto")
is_latest
#' Test if RStudio is up to date #' #' @inheritParams latest_version #' @param stable Set to `FALSE` in order to test against the latest [RStudio preview build](https://rstudio.com/products/rstudio/download/preview/) instead #' of the latest [stable build](https://rstudio.com/products/rstudio/download/). #' #' @return `TRUE` if the currently running RStudio version is greater or equal to the latest version, `FALSE` otherwise. #' @export is_latest <- function(stable = TRUE, os = NULL) { rstudioapi::versionInfo()$version >= latest_version(type = rstudioapi::versionInfo()$mode, stable = stable, os = os) }
latest_version
TODO:
NOTES:
cf. https://askubuntu.com/questions/1237088/automatizing-rstudio-updates
RStudio seems to host binary releases on three different domains:
On each stable release subdomain there's a file named current.ver
which stores the very latest version number across all releases. But since it doesn't
differentiate between the open-source and the proprietary RStudio editions (e.g. RStudio Desktop
vs. RStudio Desktop Pro) and the versions of the two editions can differ, it's not
of much use for our purpose.
To get the content of the current.ver
file, use:
``` r
readr::read_lines(file = "https://download1.rstudio.org/current.ver")
readr::read_lines(file = "https://download2.rstudio.org/current.ver") ```
RStudio provides canonical URLs for the latest binary releases for every supported OS. Examples:
stable:
preview: https://rstudio.org/download/latest/preview/desktop/bionic/rstudio-latest-amd64.deb
daily: https://rstudio.org/download/latest/daily/desktop/bionic/rstudio-latest-amd64.deb
#' Get latest RStudio version number #' #' @inheritParams releases #' @param pro `TRUE` for the proprietary RStudio (Server) Pro edition and `FALSE` for the open-source RStudio (Server) edition. #' @param os The OS _codename_ for which the RStudio version was built. If `NULL`, it will be auto-detected for the current system. #' #' @return `r pkgsnip::return_lbl("num_vrsn")` #' @export #' #' @examples #' latest_version(os = "macos", #' use_cache = FALSE) latest_version <- function(type = c("desktop", "server"), stable = TRUE, pro = FALSE, os = NULL, use_cache = TRUE, max_cache_age = "1 day") { type <- rlang::arg_match(type) checkmate::assert_flag(pro) data <- type |> releases(stable = stable, use_cache = use_cache, max_cache_age = max_cache_age) |> dplyr::filter(is_pro == pro) supported_os <- data[["os"]] |> unique() |> setdiff(NA) if (is.null(os)) { os <- if (xfun::is_linux()) { system2(command = "lsb_release", args = "-cs", stdout = TRUE, stderr = TRUE) } else if (xfun::is_macos()) { "macos" } else if (xfun::is_windows()) { "windows" } else { cli::cli_abort("Unknown operating system detected.") } if (!(os %in% supported_os)) { cli::cli_abort(paste0("The RStudio release suited to your Linux distribution {.field {utils::sessionInfo('base')$running}} codename {.field {os}} ", "couldn't be auto-detected. Please set {.arg os} to one of {.or {.val {supported_os}}}.")) } } else { os <- rlang::arg_match(arg = os, values = supported_os) } data |> dplyr::filter(os == os) %$% version |> max() |> unique() |> as.numeric_version() }
releases
TODO:
Improve parsing the XML file containing all the info. AWS
ListObjects
only returns the newest 1'000 results
and <IsTruncated>true</IsTruncated>
indicates that there are more -> Figure out how to fully retrieve this "paginated" XML!
We can use ListObjectsV2 on the preview URL: https://s3.amazonaws.com/rstudio-ide-build/?list-type=2
(Neither the ListObjects nor the ListObjectsV2 URL params seem to work on the stable URLs)
Then we can set URL param continuation-token
to the value of NextContinuationToken
to access the next page.
Or even better: Use delimiter=/
and progress hand over hand by setting prefix
to the value of CommonPrefixes
.
Or even better: Use aws.s3::get_bucket("rstudio-ide-build")
!
To do the same for the stable release server, we probably first need to figure out the Amazon S3 bucket behind it...?
Evaluate whether the stable redirect links listed here are of use for us.
#' Get RStudio release metadata #' #' @param type Either `"desktop"` for [RStudio Desktop](https://rstudio.com/products/rstudio/#rstudio-desktop) or `"server"` for #' [RStudio Server](https://rstudio.com/products/rstudio/#rstudio-server) release metadata. #' @param stable Set to `FALSE` to retrieve release metadata of [RStudio preview builds](https://rstudio.com/products/rstudio/download/preview/) instead of #' [stable builds](https://rstudio.com/products/rstudio/download/). #' @param use_cache `r pkgsnip::param_lbl("use_cache")` #' @param max_cache_age `r pkgsnip::param_lbl("max_cache_age")` Defaults to 1 day (24 hours). #' #' @return `r pkgsnip::return_lbl("tibble")` #' @export #' #' @examples #' releases(type = "server", #' max_cache_age = "1 year 2 months 3 weeks 4 days 5 hours 6 minutes 7 seconds") releases <- function(type = c("desktop", "server"), stable = TRUE, use_cache = TRUE, max_cache_age = "1 day") { type <- rlang::arg_match(type) checkmate::assert_flag(stable) pkgpins::with_cache(expr = get_releases(type = type, stable = stable), pkg = this_pkg, from_fn = "releases", stable, use_cache = use_cache, max_cache_age = max_cache_age) } get_releases <- function(type, stable) { stable |> ifelse(yes = paste0("https://download", ifelse(type == "desktop", 1L, 2L), ".rstudio.org/"), no = paste0("https://s3.amazonaws.com/rstudio-ide-build/")) |> xml2::read_xml() |> xml2::as_list() |> purrr::keep(\(x) x[["Name"]] == ifelse(stable, glue::glue("rstudio-{type}"), "rstudio-ide-build")) |> purrr::chuck("ListBucketResult") |> purrr::imap(\(x, i) { if (i == "Contents") x else NULL }) |> purrr::compact() |> purrr::map_depth(.depth = 2L, .f = unlist) |> purrr::map(tibble::as_tibble) |> purrr::list_rbind() |> dplyr::rename_with(.cols = everything(), .fn = heck::to_snake_case) |> dplyr::mutate(last_modified = last_modified |> clock::naive_time_parse(format = "%Y-%m-%dT%H:%M:%SZ", precision = "millisecond") |> clock::time_point_round(precision = "second") |> clock::as_date_time(zone = "UTC"), is_pro = stringr::str_detect(string = key, pattern = stringr::fixed("-pro-")), os = stringr::str_extract(string = key, pattern = "(?<=^desktop/)[^/]+(?=/)"), version = stringr::str_extract(string = key, pattern = "(?i)(?<=rstudio-((pro|server)-)?)\\d+([\\.-]\\d+)*")) |> dplyr::filter(key != "current.ver") }
bundled_cli_path
NOTES:
RSTUDIO_PANDOC
), but not the paths to the other CLI tools. But
since the shipped Pandoc version is – like all other relevant CLI tools – part of the shipped Quarto version, we can infer all paths from RSTUDIO_PANDOC
.#' Get path to CLI tool bundled with RStudio #' #' Returns the filesytem path to one of the command-line interface (CLI) tools bundled with RStudio, like [Quarto](https://quarto.org/), #' [Pandoc](https://pandoc.org/), [Dart Sass](https://sass-lang.com/dart-sass/), etc. #' #' @param tool Tool name. One of `r pal::enum_fn_param_defaults(param = "tool", fn = bundled_cli_path)`. #' #' @return `r pkgsnip::return_lbl("path")` #' @export #' #' @examples #' rstd::bundled_cli_path(tool = "pandoc") bundled_cli_path <- function(tool = all_bundled_tools) { tool <- rlang::arg_match(tool) dir_tools <- Sys.getenv("RSTUDIO_PANDOC") if (nchar(dir_tools) == 0L) { cli::cli_abort(paste0("The required {.href [environment variable](https://en.wikipedia.org/wiki/Environment_variable)} {.envvar RSTUDIO_PANDOC} is not ", "set. Note that running this function outside of RStudio is not supported.")) } switch(EXPR = tool, `dart-sass` = fs::dir_ls(path = dir_tools, recurse = TRUE, type = "file", regexp = "sass(\\.exe)?$"), deno = fs::dir_ls(path = dir_tools, recurse = TRUE, type = "file", regexp = "deno(\\.exe)?$"), esbuild = fs::dir_ls(path = dir_tools, recurse = TRUE, type = "file", regexp = "esbuild(\\.exe)?$"), pandoc = fs::dir_ls(path = dir_tools, recurse = TRUE, type = "file", regexp = "pandoc(\\.exe)?$"), quarto = fs::dir_ls(path = fs::path_dir(fs::path_dir(dir_tools)), recurse = TRUE, type = "file", regexp = "quarto(\\.exe)?$"), cli::cli_abort("Handling {.arg tool} {.val {tool}} is not yet implemented.", .internal = TRUE)) |> dplyr::first() }
bundled_cli_vrsn
#' Determine version of CLI tool bundled with RStudio #' #' Determines the version of one of the command-line interface (CLI) tools bundled with RStudio, like [Quarto](https://quarto.org/), #' [Pandoc](https://pandoc.org/), [Dart Sass](https://sass-lang.com/dart-sass/), etc. #' #' @inheritParams bundled_cli_path #' #' @return `r pkgsnip::return_lbl("num_vrsn")` #' @export #' #' @examples #' rstd::bundled_cli_vrsn(tool = "dart-sass") bundled_cli_vrsn <- function(tool = all_bundled_tools) { bundled_cli_path(tool = tool) |> system2(args = "--version", stdout = TRUE, stderr = TRUE) |> dplyr::first() |> stringr::str_extract("\\d+(\\.\\d+)*") |> as.numeric_version() }
pkg_status
#' List RStudio's R package dependencies' installation status #' #' @return `r pkgsnip::return_lbl("tibble")` #' @export pkg_status <- function() { rstudioapi::getRStudioPackageDependencies() %$% pal::is_pkg_installed(pkg = name, min_version = version) |> tibble::enframe(name = "package", value = "is_installed") }
funky_config
#' `r this_pkg` package configuration metadata #' #' A [tibble][tibble::tbl_df] with metadata of all possible `r this_pkg` package configuration options. See [funky::config_val()] for more information. #' #' @format `r pkgsnip::return_lbl("tibble_cols", cols = colnames(funky_config))` #' @export #' #' @examples #' rstd::funky_config "funky_config"
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.