diff --git a/.github/workflows/R-CMD-check.yaml b/.github/workflows/R-CMD-check.yaml index 11be514..997981e 100644 --- a/.github/workflows/R-CMD-check.yaml +++ b/.github/workflows/R-CMD-check.yaml @@ -7,7 +7,7 @@ on: branches: - main - master - + env: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} @@ -20,23 +20,19 @@ jobs: runs-on: ubuntu-latest container: - image: rocker/geospatial:4.1.2 + image: rocker/geospatial:latest steps: - uses: actions/checkout@v3 - + - name: ls run: ls shell: bash - name: bk-config.sh - run: sh bk-config.sh + run: bash bk-config.sh shell: bash - name: bk-install.R run: Rscript bk-install.R shell: bash - - - name: new-install.R - run: Rscript new-install.R - shell: bash diff --git a/bk-config.sh b/bk-config.sh index 9f42f20..00cf9c4 100644 --- a/bk-config.sh +++ b/bk-config.sh @@ -1,94 +1,137 @@ #!/bin/bash +# bk-config.sh — pour rocker/geospatial:latest (Ubuntu noble 24.04) +# +# Liste des paquets calibrée sur le contenu réel de geospatial:latest : +# tout ce qui est déjà fourni par l'image (libgdal-dev, libcairo2-dev, +# libsqlite3-dev, pandoc, etc.) a été retiré pour réduire le bruit. +# Si l'image change, certains paquets peuvent revenir manquants — c'est +# alors apt qui te le dira au build. +# +# Optimisations : +# - Détection automatique d'Azure (via wget car curl n'est pas dans +# geospatial:latest) → mirror azure.archive.ubuntu.com +# - Un seul apt-get update + un seul apt-get install consolidé -# Spatial stuff -apt-get update \ - && apt-get install -y --no-install-recommends \ - lbzip2 \ - libfftw3-dev \ - libgdal-dev \ - libgeos-dev \ - libudunits2-dev \ - libnode-dev \ - libcairo2-dev \ - libgsl0-dev \ - libgl1-mesa-dev \ - libglu1-mesa-dev \ - libhdf4-alt-dev \ - libhdf5-dev \ - libfribidi-dev \ - libharfbuzz-dev \ - libmagick++-dev \ - libjq-dev \ - libpq-dev \ - libproj-dev \ - libprotobuf-dev \ - libnetcdf-dev \ - libsqlite3-dev \ - libssl-dev \ - libudunits2-dev \ - netcdf-bin \ - postgis \ - protobuf-compiler \ - sqlite3 \ - tk-dev \ - unixodbc-dev \ - imagemagick \ - libsecret-1-dev - -apt-get install -y \ - libmagick++-dev \ - libjq-dev \ - libv8-dev \ - libprotobuf-dev \ - protobuf-compiler \ - libsodium-dev \ - imagemagick \ - libgit2-dev \ - xclip - -# database ---- -apt-get update \ - apt-get install -y --no-install-recommends \ +if [ -z "${BASH_VERSION:-}" ]; then + if command -v bash >/dev/null 2>&1; then + exec bash "$0" "$@" + fi + echo "ERROR: bk-config.sh doit être exécuté avec bash" >&2 + exit 1 +fi + +set -euo pipefail +trap 'echo "ERROR: bk-config.sh a échoué à la ligne $LINENO" >&2' ERR + +export DEBIAN_FRONTEND=noninteractive + +# --------------------------------------------------------------------------- +# Détection Azure via IMDS. Utilise wget (présent dans rocker) car curl ne +# l'est pas. Le header `Metadata: true` + le path `/metadata/instance` sont +# spécifiques à Azure : ne matchera pas par accident sur AWS/GCP qui ont +# leurs propres endpoints au même 169.254.169.254 mais avec d'autres specs. +# Override possible via APT_MIRROR=azure / APT_MIRROR=default. +# --------------------------------------------------------------------------- +USE_AZURE_MIRROR=0 + +azure_imds_check() { + if command -v curl >/dev/null 2>&1; then + curl -fsS -m 2 -H "Metadata:true" \ + "http://169.254.169.254/metadata/instance?api-version=2021-02-01" \ + >/dev/null 2>&1 + elif command -v wget >/dev/null 2>&1; then + wget -q --timeout=2 --tries=1 \ + --header='Metadata: true' \ + -O /dev/null \ + "http://169.254.169.254/metadata/instance?api-version=2021-02-01" \ + 2>/dev/null + else + return 1 + fi +} + +case "${APT_MIRROR:-auto}" in + azure) USE_AZURE_MIRROR=1 ;; + default) USE_AZURE_MIRROR=0 ;; + auto) + if azure_imds_check; then + USE_AZURE_MIRROR=1 + fi + ;; +esac + +if [ "$USE_AZURE_MIRROR" = "1" ]; then + echo "Azure detected — switching APT sources to azure.archive.ubuntu.com" + # Sur noble, les sources sont en deb822 (.sources). On gère les deux + # formats au cas où. + for f in /etc/apt/sources.list /etc/apt/sources.list.d/ubuntu.sources; do + if [ -f "$f" ]; then + sed -i \ + -e 's|http://archive\.ubuntu\.com/ubuntu/\?|http://azure.archive.ubuntu.com/ubuntu/|g' \ + -e 's|http://security\.ubuntu\.com/ubuntu/\?|http://azure.archive.ubuntu.com/ubuntu/|g' \ + "$f" + fi + done +else + echo "Non-Azure environment — keeping default APT mirrors" +fi + +APT_GET="apt-get -o Acquire::Retries=5 -o Acquire::http::Timeout=30 -o Acquire::https::Timeout=30" + +# --------------------------------------------------------------------------- +# Liste réduite : uniquement ce qui MANQUE dans geospatial:latest. +# +# Ce qui est déjà dans l'image (et donc retiré) : +# ca-certificates, libcairo2-dev, libfftw3-dev, libfribidi-dev, +# libgdal-dev, libgeos-dev, libgit2-dev, libgl1-mesa-dev, libglu1-mesa-dev, +# libgsl-dev, libharfbuzz-dev, libhdf5-dev, libjq-dev, libnetcdf-dev, +# libnss3, libpq-dev, libproj-dev, libprotobuf-dev, libsqlite3-dev, +# libssl-dev, libudunits2-dev, libxrender1, netcdf-bin, pandoc, postgis, +# protobuf-compiler, sqlite3, tk-dev, tzdata, unixodbc-dev, +# default-libmysqlclient-dev. +# --------------------------------------------------------------------------- + +$APT_GET update + +$APT_GET install -y --no-install-recommends \ + cron \ + curl \ default-mysql-client \ - default-libmysqlclient-dev - -# Divers -apt-get install -y r-cran-rjava cron nano - -# Locals -apt-get install -y tzdata -apt-get install -y language-pack-fr -mv /etc/localtime /etc/localtime_backup \ - && ln -fs /usr/share/zoneinfo/Europe/Paris /etc/localtime \ - && dpkg-reconfigure -f noninteractive tzdata - - -# Chromium for {pagedown} ---- - -apt-get update - -# TODO these libs are here -# as they were historically installed for Chrome, -# but I'm not sure if they are needed anymore, can we remove them? -apt-get -y install libxpm4 \ - libxrender1 \ - libgtk2.0-0 \ - libnss3 \ - libgconf-2-4 \ - xvfb \ - gtk2-engines-pixbuf \ - xfonts-cyrillic \ - xfonts-100dpi \ - xfonts-75dpi \ - xfonts-base \ - xfonts-scalable - -curl -LO https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb -apt-get install -y ./google-chrome-stable_current_amd64.deb -rm google-chrome-stable_current_amd64.deb - -# NodeJS - -apt-get -y install curl gnupg && \ - curl -sL https://deb.nodesource.com/setup_14.x | bash - && \ - apt-get -y --allow-unauthenticated install nodejs + imagemagick \ + language-pack-fr \ + libmagick++-dev \ + libnode-dev \ + libsecret-1-dev \ + libsodium-dev \ + libxpm4 \ + nano \ + nodejs \ + r-cran-rjava \ + xclip \ + xfonts-100dpi \ + xfonts-75dpi \ + xfonts-base \ + xfonts-cyrillic \ + xfonts-scalable \ + xvfb + +# Timezone Europe/Paris (idempotent : -f force, -n no-deref) +ln -fsn /usr/share/zoneinfo/Europe/Paris /etc/localtime +dpkg-reconfigure -f noninteractive tzdata + +# --------------------------------------------------------------------------- +# Chrome (pour {pagedown}). Le .deb déclare ses dépendances ; apt résout +# automatiquement ce qui manque (libgbm1, libxkbcommon0, etc.). +# --------------------------------------------------------------------------- +curl -fsSL --retry 3 --retry-connrefused \ + -o /tmp/google-chrome-stable_current_amd64.deb \ + https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb + +$APT_GET install -y --no-install-recommends \ + /tmp/google-chrome-stable_current_amd64.deb + +rm /tmp/google-chrome-stable_current_amd64.deb + +# Cleanup +$APT_GET clean +rm -rf /var/lib/apt/lists/* \ No newline at end of file diff --git a/bk-install.R b/bk-install.R index a35269f..87c9d4c 100644 --- a/bk-install.R +++ b/bk-install.R @@ -2,48 +2,66 @@ options( Ncpus = 6 ) -update.packages(ask = FALSE) +# Skip sysreqs: the Dockerfile (bk-config.sh) already installs the +# system libraries we need. This avoids ~50 redundant `apt-get install` +# checks across the install run. +Sys.setenv(PKG_SYSREQS = "false") -install.packages("pak") - -if (!requireNamespace("progress", quietly = TRUE)) { - pak::pkg_install("progress") -} -if (!requireNamespace("cli", quietly = TRUE)) { - pak::pkg_install("cli") +# Forward GitHub Actions token to GITHUB_PAT so pak/remotes use authenticated +# requests (60 → 5000 req/hr). Without this, the GH installs hit the +# unauthenticated rate limit after a couple of packages. +if (Sys.getenv("GITHUB_PAT") == "") { + gh_token <- Sys.getenv("GITHUB_TOKEN") + if (nzchar(gh_token)) { + Sys.setenv(GITHUB_PAT = gh_token) + } } -if (!requireNamespace("attempt", quietly = TRUE)) { - pak::pkg_install("attempt") + +# Install a recent pak from r-lib's distribution server. The CRAN +# snapshot pinned in this image (2022-03-09) only ships pak 0.2.1, +# which doesn't pick up Posit Package Manager binaries on Linux and +# ends up compiling everything from source. A modern pak transparently +# fetches pre-compiled binaries from PPM, cutting many minutes off +# the build. +install.packages( + "pak", + repos = sprintf( + "https://r-lib.github.io/p/pak/stable/%s/%s/%s", + .Platform$pkgType, + R.Version()$os, + R.Version()$arch + ) +) + +# Bootstrap helper packages used by this script +for (p in c("progress", "cli", "attempt")) { + if (!requireNamespace(p, quietly = TRUE)) { + pak::pkg_install(p, ask = FALSE) + } } -to_install <- unique( - sort( -c( +# CRAN packages: one pak call, parallel resolution + download +cran_pkgs <- c( "abind", "arsenal", "attachment", "attempt", "bbmle", "bit64", - "bsicons", "bslib", "bookdown", "broom", "car", "cartography", "ceramic", - "checkhelper", "chron", "class", "cluster", - "ColinFay/rfeel", "colorspace", "colourpicker", - "compiler", "covr", "cowplot", "cowsay", - "ThinkR-open/cranology", "data.table", "DBI", "devEMF", @@ -56,7 +74,6 @@ c( "dygraphs", "e1071", "ellipse", - "hadley/emo", "emojifont", "evaluate", "explor", @@ -64,7 +81,6 @@ c( "FactoMineR", "fcuk", "flextable", - "flux", "forecast", "foreign", "formatR", @@ -93,15 +109,10 @@ c( "gitlabr", "golem", "gplots", - "graphics", - "grDevices", - "grid", "gstat", "gt", "gtable", - "gtExtras", "h2o", - "hadley/emo", "haven", "here", "hflights", @@ -110,7 +121,6 @@ c( "htmltools", "httr", "icarus", - "ThinkR-open/inca3", "interp", "jpeg", "kableExtra", @@ -132,7 +142,6 @@ c( "mapview", "markdown", "MASS", - "methods", "microbenchmark", "mime", "mongolite", @@ -156,7 +165,6 @@ c( "prettydoc", "proto", "proustr", - "pryr", "quarto", "R6", "randomForest", @@ -180,11 +188,9 @@ c( "rmdformats", "rnaturalearth", "rnaturalearthdata", - "ropensci/rnaturalearthhires", "rosm", "roxygen2", "rpart", - "rstudio/renv", "rvest", "sandwich", "sas7bdat", @@ -201,127 +207,134 @@ c( "skimr", "sp", "spelling", - "splines", "sqldf", "stars", - "statnmap/cartomisc", - "stats", - "stringr", "styler", "survival", "targets", - "tcltk", "tcltk2", "terra", "thematic", "thinkr", - "ThinkR-open/inca3", - "ThinkR-open/prenoms", - "ThinkR-open/shopping", "tidystringdist", "tidytext", "tidyverse", "tinytex", "tmap", "togglr", - "tools", "topicmodels", "transformr", "tseries", "units", "usethis", - "utils", "V8", "visdat", "vroom", "webshot", "writexl", "xaringan", - "xaringanExtra", "xtable", "xts", "zoo" ) - ) + +# GitHub-only packages (those not on CRAN, or where we want a specific fork) +gh_pkgs <- c( + "rstudio/bsicons", + "ThinkR-open/checkhelper", + "ColinFay/rfeel", + "ThinkR-open/cranology", + "hadley/emo", + "jthomasmock/gtExtras", + "ThinkR-open/inca3", + "ropensci/rnaturalearthhires", + "rstudio/renv", + "statnmap/cartomisc", + "ThinkR-open/prenoms", + "ThinkR-open/shopping", + "gadenbuie/xaringanExtra" ) -failed <- c() -success <- c() +pkg_name <- function(x) { + if (grepl("/", x)) sub("^.*/", "", x) else x +} -cli::cat_rule("Starting packages installation") +cli::cat_rule("Bulk CRAN install (single pak call)") -library(progress) -pb <- progress_bar$new( - total = length(to_install) -) +cran_ok <- attempt::attempt({ + pak::pkg_install( + cran_pkgs, + upgrade = FALSE, + ask = FALSE + ) +}) -for (i in seq_along(to_install)) { +if (attempt::is_try_error(cran_ok)) { + cli::cat_bullet( + "Bulk CRAN install errored — aborting", + bullet = "cross" + ) + stop("Bulk CRAN install failed; not all packages were installed.") +} else { + cli::cat_bullet( + "Bulk CRAN install completed", + bullet = "tick" + ) +} - packs <- as.data.frame(installed.packages()) +cli::cat_rule("GitHub packages (one by one for resilience)") - pb$tick() +gh_failed <- c() - cli::cat_line() +library(progress) +pb <- progress_bar$new(total = length(gh_pkgs)) - pak <- to_install[i] +for (pkg in gh_pkgs) { + pb$tick() + cli::cat_line() - if (pak %in% packs$Package) { - cli::cat_rule( - sprintf( - "%s is already installed, skipping", - pak - ) - ) + installed <- as.data.frame(installed.packages())$Package + if (pkg_name(pkg) %in% installed) { + cli::cat_rule(sprintf("%s is already installed, skipping", pkg)) next() } - cli::cat_bullet( - sprintf( - "Starting %s installation", - pak - ), - bullet = "play" - ) + cli::cat_bullet(sprintf("Installing %s", pkg), bullet = "play") - tst <- attempt::attempt({ - pak::pak( - pak, - upgrade = FALSE - ) + res <- attempt::attempt({ + pak::pak(pkg, upgrade = FALSE, ask = FALSE) }) - if (attempt::is_try_error(tst)) { - cli::cat_bullet( - sprintf( - "Error installing %s", - pak - ), - bullet = "cross" - ) - failed <- c( - failed, - pak - ) + if (attempt::is_try_error(res)) { + cli::cat_bullet(sprintf("Failed: %s", pkg), bullet = "cross") + gh_failed <- c(gh_failed, pkg) } else { - cli::cat_bullet( - sprintf( - "%s installed", - pak - ), - bullet = "tick" - ) - success <- c(success, pak) + cli::cat_bullet(sprintf("OK: %s", pkg), bullet = "tick") } } -cli::cat_rule("Installation ended.") +# Reconcile: which packages from the full request list ended up installed? +all_requested <- c(cran_pkgs, gh_pkgs) +final_installed <- as.data.frame(installed.packages())$Package +success <- all_requested[ + vapply( + all_requested, + function(x) pkg_name(x) %in% final_installed, + logical(1) + ) +] +failed <- setdiff(all_requested, success) + +cli::cat_rule("Installation phase ended") +# tutor: forced reinstall to guarantee a known learnr version pairing +cli::cat_rule("Installing thinkr-open/tutor") -# LATEST thinkr-open/tutor -# Just to be sure we have the correct version of {learnr} -remove.packages("learnr") +if ("learnr" %in% as.data.frame(installed.packages())$Package) { + remove.packages("learnr") +} -tst <- attempt::attempt({ +tutor_ok <- attempt::attempt({ remotes::install_github( "thinkr-open/tutor", force = TRUE, @@ -329,68 +342,90 @@ tst <- attempt::attempt({ ) }) -# Rve the tutorials from learnr so that we only use the ones -# from {tutor} +# Drop learnr's bundled tutorials so only tutor's are exposed unlink( - system.file( - "tutorials", - package = "learnr" - ), - TRUE, - TRUE + system.file("tutorials", package = "learnr"), + recursive = TRUE, + force = TRUE ) -if (attempt::is_try_error(tst)) { - cli::cat_bullet( - sprintf( - "Error installing %s", - "tutor" - ), - bullet = "cross" - ) - failed <- c( - failed, - pak - ) +if (attempt::is_try_error(tutor_ok)) { + cli::cat_bullet("Failed: tutor", bullet = "cross") + failed <- c(failed, "tutor") } else { - cli::cat_bullet( - sprintf( - "%s installed", - "tutor" - ), - bullet = "tick" - ) - success <- c( - success, - pak - ) + cli::cat_bullet("OK: tutor", bullet = "tick") + success <- c(success, "tutor") } -cli::cat_line() -cli::cat_line() -cli::cat_rule("force keyring installation from source") -install.packages('keyring',repos='http://cran.rstudio.com') +# keyring forced from source (needs libsecret bindings on this image) +cli::cat_rule("Force-installing keyring from source") +install.packages( + "keyring", + repos = "http://cran.rstudio.com", + type = "source" +) cli::cat_line() -cli::cat_line() -cli::cat_rule("The following package(s) have been installed:") +cli::cat_rule("The following package(s) are installed:") cli::cat_bullet(success, bullet = "tick") cli::cat_line() cli::cat_rule("The following package(s) failed to install:") cli::cat_bullet(failed, bullet = "cross") -cli::cat_line() -cli::cat_rule("Installing webshot") +cli::cat_rule("Installing PhantomJS (via webshot)") webshot::install_phantomjs() system("cp ~/bin/phantomjs /usr/local/share/phantomjs") system("chmod 0755 /usr/local/share/phantomjs") system("ln -sf /usr/local/share/phantomjs /usr/local/bin") cli::cat_bullet("PhantomJS installed", bullet = "tick") -cli::cat_line() cli::cat_rule("Installing tinytex") -tinytex::install_tinytex(force = TRUE) -cli::cat_bullet("tinytex installed", bullet = "tick") +tinytex_installed <- FALSE + +# 1) daily (default — fastest when it works, but can 404) +res <- attempt::attempt({ + tinytex::install_tinytex(force = TRUE) +}) +if (!attempt::is_try_error(res)) { + tinytex_installed <- TRUE +} else { + cli::cat_bullet( + "tinytex daily install failed, trying latest", + bullet = "cross" + ) +} + +# 2) latest +if (!tinytex_installed) { + res <- attempt::attempt({ + tinytex::install_tinytex(force = TRUE, version = "latest") + }) + if (!attempt::is_try_error(res)) { + tinytex_installed <- TRUE + } else { + cli::cat_bullet( + "tinytex latest install failed, trying pinned version", + bullet = "cross" + ) + } +} +# 3) pinned fallback +if (!tinytex_installed) { + res <- attempt::attempt({ + tinytex::install_tinytex(force = TRUE, version = "v2026.05") + }) + if (!attempt::is_try_error(res)) { + tinytex_installed <- TRUE + } +} +if (tinytex_installed) { + cli::cat_bullet("tinytex installed", bullet = "tick") +} else { + cli::cat_bullet( + "tinytex install failed (all fallbacks exhausted)", + bullet = "cross" + ) +} diff --git a/new-install.R b/new-install.R deleted file mode 100644 index 7d1af08..0000000 --- a/new-install.R +++ /dev/null @@ -1,278 +0,0 @@ -packs <- as.data.frame(installed.packages()) -if (! "remotes" %in% packs$Package ){ - install.packages("remotes") -} -remotes::install_cran("withr") -remotes::install_cran("progress") -remotes::install_cran("cli") -remotes::install_version("attempt", "0.3.0") - -# Packages that are available on CRAN -to_install <- unique( - sort( - c( - "abind", - "abn", - "arsenal", - "attachment", - "attempt", - "bbmle", - "bit64", - "broom", - "bookdown", - "car", - "chron", - "class", - "cluster", - "colorspace", - "compiler", - "data.table", - "DBI", - "devEMF", - "devtools", - "dichromat", - "digest", - "doSNOW", - "dplyr", - "DT", - "dygraphs", - "e1071", - "ellipse", - "evaluate", - "explor", - "FactoMineR", - "fcuk", - "forecast", - "foreign", - "formatR", - "Formula", - "fortunes", - "fusen", - "gapminder", - "gert", - "gbm", - "ggplot2", - "ggraph", - "ggthemes", - "git2r", - "gitlabr", - "golem", - "gplots", - "graphics", - "grDevices", - "grid", - "gtable", - "h2o", - "haven", - "hflights", - "highr", - "Hmisc", - "htmltools", - "httr", - "icarus", - "jpeg", - "knitr", - "labeling", - "lattice", - "latticeExtra", - "leaps", - "markdown", - "MASS", - "methods", - "microbenchmark", - "mime", "munsell", - "nnet", - "nycflights13", - "openxlsx", - "packrat", - "pacman", - "pander", - "pkgbuild", - "pkgconfig", - "pkgload", - "plotly", - "proto", - "proustr", - "pryr", - "R6", - "randomForest", - "raster", - "RColorBrewer", - "Rcpp", - "readr", - "readxl", - "remedy", - "reprex", - "reshape", - "reshape2", - "rJava", - "RJSONIO", - "rmarkdown", - "rmdformats", - "roxygen2", - "rpart", - "rusk", - "flextable", - "rvest", - "sandwich", - "sas7bdat", - "scales", - "scatterplot3d", - "shinyBS", - "shinydashboard", - "shinyWidgets", - "skimr", - "spelling", - "splines", - "sqldf", - "stats", - "stringr", - "styler", - "survival", - "tcltk", - "tcltk2", - "thinkr", - "tidystringdist", - "tidytext", - "tidyverse", - "togglr", - "tools", - "topicmodels", - "tseries", - "usethis", - "utils", - "vroom", - "writexl", - "xaringan", - "XLConnect", - "XLConnectJars", - "xtable", - "xts", - "zoo", - "learnr" - ) - ) -) - -failed <- c() -success <- c() - -withr::with_options( - c(repos = "https://cran.rstudio.com"), { - cli::cat_rule("Starting packages installation") - - library(progress) - pb <- progress_bar$new(total = length(to_install)) - - for (i in seq_along(to_install)){ - pb$tick() - cli::cat_line() - pak <- to_install[i] - cli::cat_bullet( - sprintf( - "Starting %s installation", - pak - ), bullet = "play" - ) - - tst <- attempt::attempt({ - remotes::install_cran( - pak, - quiet = TRUE - ) - }) - if (attempt::is_try_error(tst)){ - cli::cat_bullet( - sprintf( - "Error installing %s", - pak - ), - bullet = "cross" - ) - failed <- c(failed, pak) - } else { - cli::cat_bullet( - sprintf( - "%s installed", pak - ), - bullet = "tick" - ) - success <- c(success, pak) - } - } - - } -) - -cli::cat_rule("Ended CRAN Installation. Starting GitHub Installation.") - -# GitHub-only packages (these are not on CRAN or not reliably available there) -# - bsicons is rstudio/bsicons (not JohnCoene/bsicons) -# - checkhelper is ThinkR-open/checkhelper -# - gtExtras is jthomasmock/gtExtras -# - xaringanExtra is gadenbuie/xaringanExtra - -to_install <- c( - "ThinkR-open/prenoms", - "ThinkR-open/shopping", - "rstudio/bsicons", - "ThinkR-open/checkhelper", - "jthomasmock/gtExtras", - "gadenbuie/xaringanExtra" -) - -withr::with_options( - c(repos = "https://cran.rstudio.com"), { - cli::cat_rule("Starting packages installation") - - library(progress) - pb <- progress_bar$new(total = length(to_install)) - - for (i in seq_along(to_install)){ - cli::cat_line() - pb$tick() - pak <- to_install[i] - cli::cat_bullet( - sprintf( - "Starting %s installation", - pak - ), - bullet = "play" - ) - - tst <- attempt::attempt({ - remotes::install_github( - pak, - upgrade = "always", - quiet = TRUE - ) - }) - if (attempt::is_try_error(tst)){ - cli::cat_bullet( - sprintf( - "Error installing %s", pak - ), - bullet = "cross" - ) - failed <- c(failed, pak) - } else { - cli::cat_bullet( - sprintf( - "%s installed", pak - ), - bullet = "tick" - ) - success <- c(success, pak) - } - - } - - } -) - -cli::cat_line() -cli::cat_line() -cli::cat_rule("The following package(s) have been installed:") -cli::cat_bullet(success, bullet="tick") -cli::cat_rule("The following package(s) failed to install:") -cli::cat_bullet(failed, bullet="cross")