From 569400105537cf32fcd82f1b35623420429f4ac3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:02:37 +0200 Subject: [PATCH 01/19] feat: add wrapper to quarto install extension --- R/install.R | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 R/install.R diff --git a/R/install.R b/R/install.R new file mode 100644 index 0000000..f965e31 --- /dev/null +++ b/R/install.R @@ -0,0 +1,43 @@ +#' Quarto Install Extension +#' +#' Install an extension into a Quarto project. +#' +#' @param extension The extension to install, either an archive or a GitHub +#' repository as described in the documentation +#' . +#' +#' @examples +#' \dontrun{ +#' # Install a template and set up a draft document from a GitHub repository +#' quarto_install_extension("quarto-ext/fontawesome") +#' +#' # Install a template and set up a draft document from a ZIP archive +#' quarto_install_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") +#' } +#' +#' @export +quarto_install_extension <- function(template = NULL) { + quarto_bin <- find_quarto() + message( + "Quarto templates may execute code when documents are rendered. ", + "If you do not trust the authors of the template, ", + "we recommend that you do not install or use the template." + ) + prompt_value <- tolower(readline("Do you trust the authors of this template (Y/n)? ")) + if (!prompt_value %in% "y") { + message("Quarto template not installed.") + return(invisible()) + } + + tryCatch( + system2(quarto_bin, stdout = TRUE, c( + "install", + "extension", + "--no-prompt", + template + )), + error = function(e) e, + warning = function(w) w + ) + invisible() +} From 35440258d33d19bb63e03569377d736375612f6d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:03:29 +0200 Subject: [PATCH 02/19] feat: add wrapper to quarto use template Fixes #42 --- R/use.R | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 R/use.R diff --git a/R/use.R b/R/use.R new file mode 100644 index 0000000..a6a27cf --- /dev/null +++ b/R/use.R @@ -0,0 +1,43 @@ +#' Quarto Use Template +#' +#' Install and use a template into a Quarto project. +#' +#' @param template The template to install, either an archive or a GitHub +#' repository as described in the documentation +#' . +#' +#' @examples +#' \dontrun{ +#' # Install a template and set up a draft document from a GitHub repository +#' quarto_use_template("quarto-journals/jss") +#' +#' # Install a template and set up a draft document from a ZIP archive +#' quarto_use_template("https://github.com/quarto-journals/jss/archive/refs/heads/main.zip") +#' } +#' +#' @export +quarto_use_template <- function(template = NULL) { + quarto_bin <- find_quarto() + message( + "Quarto templates may execute code when documents are rendered. ", + "If you do not trust the authors of the template, ", + "we recommend that you do not install or use the template." + ) + prompt_value <- tolower(readline("Do you trust the authors of this template (Y/n)? ")) + if (!prompt_value %in% "y") { + message("Quarto template not installed.") + return(invisible()) + } + + tryCatch( + system2(quarto_bin, stdout = TRUE, c( + "use", + "template", + "--no-prompt", + template + )), + error = function(e) e, + warning = function(w) w + ) + invisible() +} From eabe4fc6bd6d0227904ded015c1bf5d5323b805d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:05:38 +0200 Subject: [PATCH 03/19] fix(install.R): tweak messages --- R/install.R | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/R/install.R b/R/install.R index f965e31..8153a55 100644 --- a/R/install.R +++ b/R/install.R @@ -19,13 +19,13 @@ quarto_install_extension <- function(template = NULL) { quarto_bin <- find_quarto() message( - "Quarto templates may execute code when documents are rendered. ", - "If you do not trust the authors of the template, ", - "we recommend that you do not install or use the template." + "Quarto extensions may execute code when documents are rendered. ", + "If you do not trust the authors of the extension, ", + "we recommend that you do not install or use the extension" ) - prompt_value <- tolower(readline("Do you trust the authors of this template (Y/n)? ")) + prompt_value <- tolower(readline("Do you trust the authors of this extension (Y/n)? ")) if (!prompt_value %in% "y") { - message("Quarto template not installed.") + message("Quarto extension not installed.") return(invisible()) } From 4057e66752801719c97728bfbba330032b00811d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:10:12 +0200 Subject: [PATCH 04/19] chore: add NEWS.md for changelog Fixes #27 --- NEWS.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 NEWS.md diff --git a/NEWS.md b/NEWS.md new file mode 100644 index 0000000..4631795 --- /dev/null +++ b/NEWS.md @@ -0,0 +1,10 @@ +# quarto (development version) + +## Features + +- feat: add wrapper to quarto use template ([#42](https://github.com/quarto-dev/quarto-r/issues/42)). +- feat: add wrapper to quarto install extension. + +## Chores + +- chore: add NEWS.md for changelog ([#27](https://github.com/quarto-dev/quarto-r/issues/27)). From 4d7e4e5c161f00db64dd81364b278d68ddcf7ceb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Canouil?= <8896044+mcanouil@users.noreply.github.com> Date: Mon, 15 Aug 2022 12:12:53 +0200 Subject: [PATCH 05/19] docs: roxygen2::roxygenize() --- NAMESPACE | 2 ++ man/quarto_install_extension.Rd | 26 ++++++++++++++++++++++++++ man/quarto_use_template.Rd | 26 ++++++++++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 man/quarto_install_extension.Rd create mode 100644 man/quarto_use_template.Rd diff --git a/NAMESPACE b/NAMESPACE index 4ebefa0..2693dea 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(quarto_inspect) +export(quarto_install_extension) export(quarto_path) export(quarto_preview) export(quarto_preview_stop) @@ -9,6 +10,7 @@ export(quarto_publish_doc) export(quarto_publish_site) export(quarto_render) export(quarto_serve) +export(quarto_use_template) export(quarto_version) importFrom(jsonlite,fromJSON) importFrom(later,later) diff --git a/man/quarto_install_extension.Rd b/man/quarto_install_extension.Rd new file mode 100644 index 0000000..30d557e --- /dev/null +++ b/man/quarto_install_extension.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/install.R +\name{quarto_install_extension} +\alias{quarto_install_extension} +\title{Quarto Install Extension} +\usage{ +quarto_install_extension(template = NULL) +} +\arguments{ +\item{extension}{The extension to install, either an archive or a GitHub +repository as described in the documentation +\url{https://quarto.org/docs/extensions/formats.html}.} +} +\description{ +Install an extension into a Quarto project. +} +\examples{ +\dontrun{ +# Install a template and set up a draft document from a GitHub repository +quarto_install_extension("quarto-ext/fontawesome") + +# Install a template and set up a draft document from a ZIP archive +quarto_install_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") +} + +} diff --git a/man/quarto_use_template.Rd b/man/quarto_use_template.Rd new file mode 100644 index 0000000..36c6ca4 --- /dev/null +++ b/man/quarto_use_template.Rd @@ -0,0 +1,26 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/use.R +\name{quarto_use_template} +\alias{quarto_use_template} +\title{Quarto Use Template} +\usage{ +quarto_use_template(template = NULL) +} +\arguments{ +\item{template}{The template to install, either an archive or a GitHub +repository as described in the documentation +\url{https://quarto.org/docs/extensions/formats.html}.} +} +\description{ +Install and use a template into a Quarto project. +} +\examples{ +\dontrun{ +# Install a template and set up a draft document from a GitHub repository +quarto_use_template("quarto-journals/jss") + +# Install a template and set up a draft document from a ZIP archive +quarto_use_template("https://github.com/quarto-journals/jss/archive/refs/heads/main.zip") +} + +} From 0ab736bfbaa907085dc09e5b359dfca2ff2e1c3a Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 16:35:47 +0200 Subject: [PATCH 06/19] Add an internal quarto_run wrapper --- NAMESPACE | 1 + R/inspect.R | 2 +- R/quarto.R | 7 +++++++ R/render.R | 8 ++++---- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 2693dea..2c65638 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,7 @@ export(quarto_version) importFrom(jsonlite,fromJSON) importFrom(later,later) importFrom(processx,process) +importFrom(processx,run) importFrom(rmarkdown,relative_to) importFrom(rstudioapi,isAvailable) importFrom(rstudioapi,viewer) diff --git a/R/inspect.R b/R/inspect.R index f3f6788..691a92d 100644 --- a/R/inspect.R +++ b/R/inspect.R @@ -38,7 +38,7 @@ quarto_inspect <- function(input = ".", args <- c(args, c("--profile", paste0(profile, collapse = ","))) } - res <- processx::run(quarto_bin, args, echo_cmd = getOption("quarto.echo_cmd", FALSE)) + res <- quarto_run(args, echo_cmd = getOption("quarto.echo_cmd", FALSE), quarto_bin = quarto_bin) fromJSON(res$stdout) } diff --git a/R/quarto.R b/R/quarto.R index 4f36bad..305fdf6 100644 --- a/R/quarto.R +++ b/R/quarto.R @@ -36,3 +36,10 @@ quarto_version <- function() { quarto_bin <- find_quarto() as.numeric_version(system2(quarto_bin, "--version", stdout = TRUE)) } + +#' @importFrom processx run +quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FALSE, ...) { + res <- processx::run(quarto_bin, args = args, echo = FALSE, ...) + # TODO: handle better the outputs + invisible(res) +} diff --git a/R/render.R b/R/render.R index ab3e6a9..52861d7 100644 --- a/R/render.R +++ b/R/render.R @@ -83,15 +83,15 @@ quarto_render <- function(input = NULL, pandoc_args = NULL, as_job = getOption("quarto.render_as_job", "auto")) { + # get quarto binary + quarto_bin <- find_quarto() + # provide default for input if (is.null(input)) { input <- getwd() } input <- path.expand(input) - # get quarto binary - quarto_bin <- find_quarto() - # see if we need to render as a job if (identical(as_job, "auto")) { as_job <- utils::file_test("-d", input) @@ -179,7 +179,7 @@ quarto_render <- function(input = NULL, } # run quarto - processx::run(quarto_bin, args, echo = TRUE) + quarto_run(args, echo = TRUE, quarto_bin = quarto_bin) # no return value invisible(NULL) From 96dd56bdca05e88e18392afa6da463beb4d66151 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 17:32:22 +0200 Subject: [PATCH 07/19] With latest Quarto this is `quarto_add_extension()` --- DESCRIPTION | 2 + NAMESPACE | 4 +- R/add.R | 65 +++++++++++++++++++++++++++++++++ R/install.R | 43 ---------------------- man/quarto_add_extension.Rd | 37 +++++++++++++++++++ man/quarto_install_extension.Rd | 26 ------------- tests/testthat/test-add.R | 9 +++++ 7 files changed, 116 insertions(+), 70 deletions(-) create mode 100644 R/add.R delete mode 100644 R/install.R create mode 100644 man/quarto_add_extension.Rd delete mode 100644 man/quarto_install_extension.Rd create mode 100644 tests/testthat/test-add.R diff --git a/DESCRIPTION b/DESCRIPTION index 8b49806..2c38f71 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -14,9 +14,11 @@ URL: https://github.com/quarto-dev/quarto-r, https://quarto-dev.github.io/quarto-r/ BugReports: https://github.com/quarto-dev/quarto-r/issues Imports: + cli, jsonlite, later, processx, + rlang, rmarkdown, rsconnect (>= 0.8.26), rstudioapi, diff --git a/NAMESPACE b/NAMESPACE index 2c65638..812b3a2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,7 +1,7 @@ # Generated by roxygen2: do not edit by hand +export(quarto_add_extension) export(quarto_inspect) -export(quarto_install_extension) export(quarto_path) export(quarto_preview) export(quarto_preview_stop) @@ -12,10 +12,12 @@ export(quarto_render) export(quarto_serve) export(quarto_use_template) export(quarto_version) +importFrom(cli,cli_abort) importFrom(jsonlite,fromJSON) importFrom(later,later) importFrom(processx,process) importFrom(processx,run) +importFrom(rlang,is_interactive) importFrom(rmarkdown,relative_to) importFrom(rstudioapi,isAvailable) importFrom(rstudioapi,viewer) diff --git a/R/add.R b/R/add.R new file mode 100644 index 0000000..2e00e05 --- /dev/null +++ b/R/add.R @@ -0,0 +1,65 @@ +#' Quarto Add Extension +#' +#' Add an extension to this folder or project. +#' +#' # Extension Trust +#' +#' Quarto extensions may execute code when documents are rendered. Therefore, if +#' you do not trust the author of an extension, we recommend that you do not +#' install or use the extension. +#' By default `no_prompt = FALSE` which means that +#' the function will ask for explicit approval when used interactively, or +#' disallow installation. +#' +#' @param extension The extension to install, either an archive or a GitHub +#' repository as described in the documentation +#' . +#' @param no_prompt Do not prompt to confirm approval to download external extension. +#' +#' @examples +#' \dontrun{ +#' # Install a template and set up a draft document from a GitHub repository +#' quarto_add_extension("quarto-ext/fontawesome") +#' +#' # Install a template and set up a draft document from a ZIP archive +#' quarto_add_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") +#' } +#' +#' @importFrom rlang is_interactive +#' @importFrom cli cli_abort +#' @export +quarto_add_extension <- function(extension = NULL, no_prompt = FALSE) { + quarto_bin <- find_quarto() + + if (!no_prompt) { + if (!rlang::is_interactive()) { + cli::cli_abort(c( + "Adding an extension requires explicit approval.", + '>' = "Set {.arg no_prompt = TRUE} if you agree.", + i = "See more at {.url https://quarto.org/docs/extensions/managing.html}" + )) + } else { + message( + "Quarto extensions may execute code when documents are rendered. ", + "If you do not trust the authors of the extension, ", + "we recommend that you do not install or use the extension" + ) + prompt_value <- tolower(readline("Do you trust the authors of this extension (Y/n)? ")) + if (!prompt_value %in% "y") { + message("Quarto extension not installed.") + return(invisible(FALSE)) + } + } + } + + args <- c(extension,"--no-prompt") + + quarto_add(args, quarto_bin = quarto_bin, echo = TRUE) + + invisible() +} + +quarto_add <- function(args = character(), ...) { + args <- c("add", args) + quarto_run(args, ...) +} diff --git a/R/install.R b/R/install.R deleted file mode 100644 index 8153a55..0000000 --- a/R/install.R +++ /dev/null @@ -1,43 +0,0 @@ -#' Quarto Install Extension -#' -#' Install an extension into a Quarto project. -#' -#' @param extension The extension to install, either an archive or a GitHub -#' repository as described in the documentation -#' . -#' -#' @examples -#' \dontrun{ -#' # Install a template and set up a draft document from a GitHub repository -#' quarto_install_extension("quarto-ext/fontawesome") -#' -#' # Install a template and set up a draft document from a ZIP archive -#' quarto_install_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") -#' } -#' -#' @export -quarto_install_extension <- function(template = NULL) { - quarto_bin <- find_quarto() - message( - "Quarto extensions may execute code when documents are rendered. ", - "If you do not trust the authors of the extension, ", - "we recommend that you do not install or use the extension" - ) - prompt_value <- tolower(readline("Do you trust the authors of this extension (Y/n)? ")) - if (!prompt_value %in% "y") { - message("Quarto extension not installed.") - return(invisible()) - } - - tryCatch( - system2(quarto_bin, stdout = TRUE, c( - "install", - "extension", - "--no-prompt", - template - )), - error = function(e) e, - warning = function(w) w - ) - invisible() -} diff --git a/man/quarto_add_extension.Rd b/man/quarto_add_extension.Rd new file mode 100644 index 0000000..f03f0a2 --- /dev/null +++ b/man/quarto_add_extension.Rd @@ -0,0 +1,37 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/add.R +\name{quarto_add_extension} +\alias{quarto_add_extension} +\title{Quarto Add Extension} +\usage{ +quarto_add_extension(extension = NULL, no_prompt = FALSE) +} +\arguments{ +\item{extension}{The extension to install, either an archive or a GitHub +repository as described in the documentation +\url{https://quarto.org/docs/extensions/managing.html}.} + +\item{no_prompt}{Do not prompt to confirm approval to download external extension.} +} +\description{ +Add an extension to this folder or project. +} +\section{Extension Trust}{ +Quarto extensions may execute code when documents are rendered. Therefore, if +you do not trust the author of an extension, we recommend that you do not +install or use the extension. +By default \code{no_prompt = FALSE} which means that +the function will ask for explicit approval when used interactively, or +disallow installation. +} + +\examples{ +\dontrun{ +# Install a template and set up a draft document from a GitHub repository +quarto_add_extension("quarto-ext/fontawesome") + +# Install a template and set up a draft document from a ZIP archive +quarto_add_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") +} + +} diff --git a/man/quarto_install_extension.Rd b/man/quarto_install_extension.Rd deleted file mode 100644 index 30d557e..0000000 --- a/man/quarto_install_extension.Rd +++ /dev/null @@ -1,26 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/install.R -\name{quarto_install_extension} -\alias{quarto_install_extension} -\title{Quarto Install Extension} -\usage{ -quarto_install_extension(template = NULL) -} -\arguments{ -\item{extension}{The extension to install, either an archive or a GitHub -repository as described in the documentation -\url{https://quarto.org/docs/extensions/formats.html}.} -} -\description{ -Install an extension into a Quarto project. -} -\examples{ -\dontrun{ -# Install a template and set up a draft document from a GitHub repository -quarto_install_extension("quarto-ext/fontawesome") - -# Install a template and set up a draft document from a ZIP archive -quarto_install_extension("https://github.com/quarto-ext/fontawesome/archive/refs/heads/main.zip") -} - -} diff --git a/tests/testthat/test-add.R b/tests/testthat/test-add.R new file mode 100644 index 0000000..6272c88 --- /dev/null +++ b/tests/testthat/test-add.R @@ -0,0 +1,9 @@ +test_that("Installing an extension", { + skip_if_no_quarto() + skip_if_offline("github.com") + qmd <- local_qmd_file(c("content")) + withr::local_dir(dirname(qmd)) + expect_error(quarto_add_extension("quarto-ext/fontawesome"), "explicit approval") + quarto_add_extension("quarto-ext/fontawesome", no_prompt = TRUE) + expect_true(dir.exists("_extensions/quarto-ext/fontawesome")) +}) From 20764936c84f0edb68e5ec8a1c3f9c7c91315664 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 18:43:24 +0200 Subject: [PATCH 08/19] Catch and rethrow error correctly --- R/quarto.R | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/R/quarto.R b/R/quarto.R index 305fdf6..9bed049 100644 --- a/R/quarto.R +++ b/R/quarto.R @@ -38,8 +38,11 @@ quarto_version <- function() { } #' @importFrom processx run -quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FALSE, ...) { - res <- processx::run(quarto_bin, args = args, echo = FALSE, ...) - # TODO: handle better the outputs +quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FALSE, ..., .call = rlang::caller_env()) { + res <- tryCatch({ + processx::run(quarto_bin, args = args, echo = FALSE, error_on_status = TRUE, ...) + }, + error = function(e) rlang::abort(c("Error running quarto cli:", x = e$stderr), call = .call, parent = e) + ) invisible(res) } From 347ec7ef482c933220f05dbe71e40a4cd25c87e8 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 19:09:36 +0200 Subject: [PATCH 09/19] import rlang --- NAMESPACE | 2 ++ R/aaa.R | 3 +++ R/quarto-package.R | 9 ++++++--- man/quarto-package.Rd | 29 +++++++++++++++++++++++++++++ 4 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 R/aaa.R create mode 100644 man/quarto-package.Rd diff --git a/NAMESPACE b/NAMESPACE index 812b3a2..f24c448 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -12,7 +12,9 @@ export(quarto_render) export(quarto_serve) export(quarto_use_template) export(quarto_version) +import(rlang) importFrom(cli,cli_abort) +importFrom(cli,cli_inform) importFrom(jsonlite,fromJSON) importFrom(later,later) importFrom(processx,process) diff --git a/R/aaa.R b/R/aaa.R new file mode 100644 index 0000000..334a598 --- /dev/null +++ b/R/aaa.R @@ -0,0 +1,3 @@ +#' Internal package state +#' @noRd +quarto <- new.env(parent = emptyenv()) diff --git a/R/quarto-package.R b/R/quarto-package.R index 1f3aab6..d248733 100644 --- a/R/quarto-package.R +++ b/R/quarto-package.R @@ -1,4 +1,7 @@ +#' @keywords internal +"_PACKAGE" -#' Internal package state -#' @noRd -quarto <- new.env(parent = emptyenv()) +## usethis namespace: start +#' @import rlang +## usethis namespace: end +NULL diff --git a/man/quarto-package.Rd b/man/quarto-package.Rd new file mode 100644 index 0000000..eb47183 --- /dev/null +++ b/man/quarto-package.Rd @@ -0,0 +1,29 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/quarto-package.R +\docType{package} +\name{quarto-package} +\alias{quarto} +\alias{quarto-package} +\title{quarto: R Interface to 'Quarto' Markdown Publishing System} +\description{ +Convert R Markdown documents and 'Jupyter' notebooks to a variety of output formats using 'Quarto'. +} +\seealso{ +Useful links: +\itemize{ + \item \url{https://github.com/quarto-dev/quarto-r} + \item \url{https://quarto-dev.github.io/quarto-r/} + \item Report bugs at \url{https://github.com/quarto-dev/quarto-r/issues} +} + +} +\author{ +\strong{Maintainer}: JJ Allaire \email{jj@rstudio.com} (\href{https://orcid.org/0000-0003-0174-9868}{ORCID}) + +Authors: +\itemize{ + \item Christophe Dervieux \email{cderv@posit.co} (\href{https://orcid.org/0000-0003-4474-2498}{ORCID}) +} + +} +\keyword{internal} From 6e3b8badb922d02d136be2a291b2bb8224b0bfb4 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 20:49:11 +0200 Subject: [PATCH 10/19] Move echo_cmd option to main function --- R/inspect.R | 2 +- R/quarto.R | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/R/inspect.R b/R/inspect.R index 691a92d..f5fff4f 100644 --- a/R/inspect.R +++ b/R/inspect.R @@ -38,7 +38,7 @@ quarto_inspect <- function(input = ".", args <- c(args, c("--profile", paste0(profile, collapse = ","))) } - res <- quarto_run(args, echo_cmd = getOption("quarto.echo_cmd", FALSE), quarto_bin = quarto_bin) + res <- quarto_run(args, quarto_bin = quarto_bin) fromJSON(res$stdout) } diff --git a/R/quarto.R b/R/quarto.R index 9bed049..c13d6c6 100644 --- a/R/quarto.R +++ b/R/quarto.R @@ -38,9 +38,9 @@ quarto_version <- function() { } #' @importFrom processx run -quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FALSE, ..., .call = rlang::caller_env()) { +quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FALSE, echo_cmd = getOption("quarto.echo_cmd", FALSE), ..., .call = rlang::caller_env()) { res <- tryCatch({ - processx::run(quarto_bin, args = args, echo = FALSE, error_on_status = TRUE, ...) + processx::run(quarto_bin, args = args, echo = FALSE, error_on_status = TRUE, echo_cmd = echo_cmd, ...) }, error = function(e) rlang::abort(c("Error running quarto cli:", x = e$stderr), call = .call, parent = e) ) From 95983b33d8308729bc612fc7152589cc89733fb2 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 20:50:06 +0200 Subject: [PATCH 11/19] Refactor extension approval --- R/add.R | 22 ++-------------------- R/utils-prompt.R | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 20 deletions(-) create mode 100644 R/utils-prompt.R diff --git a/R/add.R b/R/add.R index 2e00e05..7ab71c5 100644 --- a/R/add.R +++ b/R/add.R @@ -31,26 +31,8 @@ quarto_add_extension <- function(extension = NULL, no_prompt = FALSE) { quarto_bin <- find_quarto() - if (!no_prompt) { - if (!rlang::is_interactive()) { - cli::cli_abort(c( - "Adding an extension requires explicit approval.", - '>' = "Set {.arg no_prompt = TRUE} if you agree.", - i = "See more at {.url https://quarto.org/docs/extensions/managing.html}" - )) - } else { - message( - "Quarto extensions may execute code when documents are rendered. ", - "If you do not trust the authors of the extension, ", - "we recommend that you do not install or use the extension" - ) - prompt_value <- tolower(readline("Do you trust the authors of this extension (Y/n)? ")) - if (!prompt_value %in% "y") { - message("Quarto extension not installed.") - return(invisible(FALSE)) - } - } - } + # This will ask for approval or stop installation + check_extension_approval(no_prompt, "Quarto extensions", "https://quarto.org/docs/extensions/managing.html") args <- c(extension,"--no-prompt") diff --git a/R/utils-prompt.R b/R/utils-prompt.R new file mode 100644 index 0000000..8f7479d --- /dev/null +++ b/R/utils-prompt.R @@ -0,0 +1,24 @@ +#' @importFrom cli cli_inform cli_abort +check_extension_approval <- function(no_prompt = FALSE, what = "Something", see_more_at = NULL) { + if (!no_prompt) { + if (!rlang::is_interactive()) { + cli::cli_abort(c( + "{ what } requires explicit approval.", + '>' = "Set {.arg no_prompt = TRUE} if you agree.", + if (!is.null(see_more_at)) { + c(i = "See more at {.url {see_more_at}}") + } + )) + } else { + cli::cli_inform(c( + "{what} may execute code when documents are rendered. ", + '*' = "If you do not trust the author(s) of this {what}, we recommend that you do not install or use this {what}." + )) + prompt_value <- tolower(readline(sprintf("Do you trust the authors of this %s (Y/n)? ", what))) + if (!prompt_value %in% "y") { + cli::cli_inform("{what} not installed.") + return(invisible(FALSE)) + } + } + } +} From 185c86fa85849c9e37b6669bcc73bf5c03be4a4e Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 20:50:35 +0200 Subject: [PATCH 12/19] Refactor quarto_ builder --- R/add.R | 5 +++-- R/quarto.R | 5 +++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/R/add.R b/R/add.R index 7ab71c5..7c6abbe 100644 --- a/R/add.R +++ b/R/add.R @@ -29,6 +29,8 @@ #' @importFrom cli cli_abort #' @export quarto_add_extension <- function(extension = NULL, no_prompt = FALSE) { + rlang::check_required(extension) + quarto_bin <- find_quarto() # This will ask for approval or stop installation @@ -42,6 +44,5 @@ quarto_add_extension <- function(extension = NULL, no_prompt = FALSE) { } quarto_add <- function(args = character(), ...) { - args <- c("add", args) - quarto_run(args, ...) + quarto_run_what("add", args = args, ...) } diff --git a/R/quarto.R b/R/quarto.R index c13d6c6..2ae5a8f 100644 --- a/R/quarto.R +++ b/R/quarto.R @@ -46,3 +46,8 @@ quarto_run <- function(args = character(), quarto_bin = find_quarto(), echo = FA ) invisible(res) } + +quarto_run_what <- function(what = character(), args = character(), quarto_bin = find_quarto(), echo = FALSE, ..., .call = rlang::caller_env()) { + res <- quarto_run(quarto_bin, args = c(what, args), echo = FALSE, ..., .call = .call) + invisible(res) +} From c9ed4ad2715b29c19a067a1f40304d4ef93a8b88 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 20:51:03 +0200 Subject: [PATCH 13/19] quarto use template helper --- R/use.R | 35 ++++++++++++++--------------------- man/quarto_use_template.Rd | 2 +- tests/testthat/test-use.R | 10 ++++++++++ 3 files changed, 25 insertions(+), 22 deletions(-) create mode 100644 tests/testthat/test-use.R diff --git a/R/use.R b/R/use.R index a6a27cf..cf884c6 100644 --- a/R/use.R +++ b/R/use.R @@ -16,28 +16,21 @@ #' } #' #' @export -quarto_use_template <- function(template = NULL) { +quarto_use_template <- function(template, no_prompt = FALSE) { + rlang::check_required(template) + quarto_bin <- find_quarto() - message( - "Quarto templates may execute code when documents are rendered. ", - "If you do not trust the authors of the template, ", - "we recommend that you do not install or use the template." - ) - prompt_value <- tolower(readline("Do you trust the authors of this template (Y/n)? ")) - if (!prompt_value %in% "y") { - message("Quarto template not installed.") - return(invisible()) - } - tryCatch( - system2(quarto_bin, stdout = TRUE, c( - "use", - "template", - "--no-prompt", - template - )), - error = function(e) e, - warning = function(w) w - ) + # This will ask for approval or stop installation + check_extension_approval(no_prompt, "Quarto templates", "https://quarto.org/docs/extensions/formats.html#distributing-formats") + + args <- c("template", template, "--no-prompt") + + quarto_use(args, quarto_bin = quarto_bin, echo = TRUE) + invisible() } + +quarto_use <- function(args = character(), ...) { + quarto_run_what("use", args = args, ...) +} diff --git a/man/quarto_use_template.Rd b/man/quarto_use_template.Rd index 36c6ca4..83808e2 100644 --- a/man/quarto_use_template.Rd +++ b/man/quarto_use_template.Rd @@ -4,7 +4,7 @@ \alias{quarto_use_template} \title{Quarto Use Template} \usage{ -quarto_use_template(template = NULL) +quarto_use_template(template, no_prompt = FALSE) } \arguments{ \item{template}{The template to install, either an archive or a GitHub diff --git a/tests/testthat/test-use.R b/tests/testthat/test-use.R new file mode 100644 index 0000000..574df3a --- /dev/null +++ b/tests/testthat/test-use.R @@ -0,0 +1,10 @@ +test_that("Installing an extension", { + skip_if_no_quarto() + skip_if_offline("github.com") + dir <- withr::local_tempdir() + withr::local_dir(dir) + expect_error(quarto_use_template("quarto-journals/jss"), "explicit approval") + quarto_use_template("quarto-journals/jss", no_prompt = TRUE) + expect_true(dir.exists("_extensions/quarto-journals/jss")) + expect_length(list.files(pattern = "[.]qmd$"), 1) +}) From 793ff701708c63e5fddfe1bc7b94f331fa58a479 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:16:28 +0200 Subject: [PATCH 14/19] Update documentation --- R/add.R | 1 + R/quarto-package.R | 1 + R/use.R | 2 ++ R/utils-prompt.R | 1 - man/quarto_use_template.Rd | 2 ++ 5 files changed, 6 insertions(+), 1 deletion(-) diff --git a/R/add.R b/R/add.R index 7c6abbe..4d23a0f 100644 --- a/R/add.R +++ b/R/add.R @@ -14,6 +14,7 @@ #' @param extension The extension to install, either an archive or a GitHub #' repository as described in the documentation #' . +#' #' @param no_prompt Do not prompt to confirm approval to download external extension. #' #' @examples diff --git a/R/quarto-package.R b/R/quarto-package.R index d248733..661d072 100644 --- a/R/quarto-package.R +++ b/R/quarto-package.R @@ -3,5 +3,6 @@ ## usethis namespace: start #' @import rlang +#' @importFrom cli cli_inform ## usethis namespace: end NULL diff --git a/R/use.R b/R/use.R index cf884c6..80d4f75 100644 --- a/R/use.R +++ b/R/use.R @@ -2,6 +2,8 @@ #' #' Install and use a template into a Quarto project. #' +#' @inheritParams quarto_add_extension +#' #' @param template The template to install, either an archive or a GitHub #' repository as described in the documentation #' . diff --git a/R/utils-prompt.R b/R/utils-prompt.R index 8f7479d..cbb3453 100644 --- a/R/utils-prompt.R +++ b/R/utils-prompt.R @@ -1,4 +1,3 @@ -#' @importFrom cli cli_inform cli_abort check_extension_approval <- function(no_prompt = FALSE, what = "Something", see_more_at = NULL) { if (!no_prompt) { if (!rlang::is_interactive()) { diff --git a/man/quarto_use_template.Rd b/man/quarto_use_template.Rd index 83808e2..1de1261 100644 --- a/man/quarto_use_template.Rd +++ b/man/quarto_use_template.Rd @@ -10,6 +10,8 @@ quarto_use_template(template, no_prompt = FALSE) \item{template}{The template to install, either an archive or a GitHub repository as described in the documentation \url{https://quarto.org/docs/extensions/formats.html}.} + +\item{no_prompt}{Do not prompt to confirm approval to download external extension.} } \description{ Install and use a template into a Quarto project. From 6f1b5df69b12d4cb6b9a105c2349c861afc831b0 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:35:35 +0200 Subject: [PATCH 15/19] Add new functions to pkgdown website --- _pkgdown.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 178190c..0c1b0eb 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -29,6 +29,14 @@ reference: contents: - quarto_publish_doc +- title: "Extensions" + desc: > + This functions enable you to install extensions and use template from extensions in your folder and projects. + More about Quarto extensions at + contents: + - starts_with("quarto_add") + - starts_with("quarto_use") + - title: "Configuration" desc: > These functions enable you to inspect the Quarto installation as well as the metadata From 5a835df219d3320a5fbd492cf5ab73a98d5a3c66 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:37:59 +0200 Subject: [PATCH 16/19] Adapt title for website --- R/add.R | 4 ++-- R/use.R | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/R/add.R b/R/add.R index 4d23a0f..5917606 100644 --- a/R/add.R +++ b/R/add.R @@ -1,6 +1,6 @@ -#' Quarto Add Extension +#' Install a Quarto extensions #' -#' Add an extension to this folder or project. +#' Add an extension to this folder or project by running `quarto add` #' #' # Extension Trust #' diff --git a/R/use.R b/R/use.R index 80d4f75..2d748a1 100644 --- a/R/use.R +++ b/R/use.R @@ -1,6 +1,6 @@ -#' Quarto Use Template +#' Use acustom format extension template #' -#' Install and use a template into a Quarto project. +#' Install and use a template for Quarto using `quarto use`. #' #' @inheritParams quarto_add_extension #' From 1e06e711c4bd888448b07c39ac97fcc94958fdc6 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:38:18 +0200 Subject: [PATCH 17/19] re-document --- man/quarto_add_extension.Rd | 4 ++-- man/quarto_use_template.Rd | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/man/quarto_add_extension.Rd b/man/quarto_add_extension.Rd index f03f0a2..4e82fec 100644 --- a/man/quarto_add_extension.Rd +++ b/man/quarto_add_extension.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/add.R \name{quarto_add_extension} \alias{quarto_add_extension} -\title{Quarto Add Extension} +\title{Install a Quarto extensions} \usage{ quarto_add_extension(extension = NULL, no_prompt = FALSE) } @@ -14,7 +14,7 @@ repository as described in the documentation \item{no_prompt}{Do not prompt to confirm approval to download external extension.} } \description{ -Add an extension to this folder or project. +Add an extension to this folder or project by running \verb{quarto add} } \section{Extension Trust}{ Quarto extensions may execute code when documents are rendered. Therefore, if diff --git a/man/quarto_use_template.Rd b/man/quarto_use_template.Rd index 1de1261..77b71f7 100644 --- a/man/quarto_use_template.Rd +++ b/man/quarto_use_template.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/use.R \name{quarto_use_template} \alias{quarto_use_template} -\title{Quarto Use Template} +\title{Use acustom format extension template} \usage{ quarto_use_template(template, no_prompt = FALSE) } @@ -14,7 +14,7 @@ repository as described in the documentation \item{no_prompt}{Do not prompt to confirm approval to download external extension.} } \description{ -Install and use a template into a Quarto project. +Install and use a template for Quarto using \verb{quarto use}. } \examples{ \dontrun{ From f529dcd98666946db95c4c64c8ca193fc1bc2157 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:40:01 +0200 Subject: [PATCH 18/19] Typo --- R/use.R | 2 +- man/quarto_use_template.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/use.R b/R/use.R index 2d748a1..86f0752 100644 --- a/R/use.R +++ b/R/use.R @@ -1,4 +1,4 @@ -#' Use acustom format extension template +#' Use a custom format extension template #' #' Install and use a template for Quarto using `quarto use`. #' diff --git a/man/quarto_use_template.Rd b/man/quarto_use_template.Rd index 77b71f7..515c447 100644 --- a/man/quarto_use_template.Rd +++ b/man/quarto_use_template.Rd @@ -2,7 +2,7 @@ % Please edit documentation in R/use.R \name{quarto_use_template} \alias{quarto_use_template} -\title{Use acustom format extension template} +\title{Use a custom format extension template} \usage{ quarto_use_template(template, no_prompt = FALSE) } From ab0af7576fd4f3c9dbe17d3ffd8112c3299b595f Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Fri, 13 Oct 2023 22:46:37 +0200 Subject: [PATCH 19/19] Bump version and update NEWS [skip ci] --- DESCRIPTION | 2 +- NEWS.md | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 2c38f71..122263b 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: quarto Title: R Interface to 'Quarto' Markdown Publishing System -Version: 1.3.3 +Version: 1.3.4 Authors@R: c( person("JJ", "Allaire", , "jj@rstudio.com", role = c("aut", "cre"), comment = c(ORCID = "0000-0003-0174-9868")), diff --git a/NEWS.md b/NEWS.md index f56160e..2fd228d 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,8 +1,6 @@ # quarto (development version) -* Add wrapper to quarto use template ([#42](https://github.com/quarto-dev/quarto-r/issues/42)). - -* Add wrapper to `quarto install extension`. +* Add `quarto_add_extension()` and `quarto_use_template()` to deal with Quarto extensions for a Quarto project. (thanks, @mcanouil, #45, @remlapmot, #42). * Add `profile` arguments to `quarto_render()` and `quarto_inspect()` (thanks, #95, @andrewheiss, #123, @salim-b).