Skip to content

Commit

Permalink
Enable freeze functionality for quarto_website (#262)
Browse files Browse the repository at this point in the history
* Improve `quarto` rendering with `freeze`

- Add `output-dir` to avoid needing to copy files after running `quarto_render`
- Avoid making `_quarto/docs/` folder when rendering. This is needed
  to use `_freeze/` folder correctly since that lives within `_quarto/`.
- Add `execute:\n\tfreeze: auto` to `setup_docs` default `yml` file

The transition to this would be any users to add `  output-dir: ../docs/` under
`project` in their `quarto_website.yml`.

* If `freeze == FALSE`, delete the `_freeze` folder which forces recomputation

* Remove unnecessary `dir_exists` for `dir_create`

* Use `verbatim_logical` to fix `: yes/no` issue with `yaml`

* Simplify code for deleting files

* fix styling issues

* Add documentation for `freeze` option
  • Loading branch information
kylebutts authored Mar 21, 2024
1 parent 6bb4e5b commit 8824669
Show file tree
Hide file tree
Showing 9 changed files with 83 additions and 69 deletions.
20 changes: 20 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
# News

## dev

### Breaking changes

* Simplified rendering for Quarto websites. Previously, the website was rendered into `_quarto/_site` and manually copied over to `docs/`. The new version removes this logic and instead uses the `output-dir` project option. To transition, change `quarto_website.yml` to:
``` yml
project:
output-dir: ../docs/
```
### New features
* `render_docs(freeze = TRUE)` now works correctly when output is `"quarto_website"`. Freezing a document needs to be set either at a project or per-file level. To do so, add to either `quarto_website.yml` or the frontmatter of a file:
``` yml
execute:
freeze: auto
```



## 0.3.0

All functions have changed so any change listed below technically is a breaking
Expand Down
2 changes: 1 addition & 1 deletion R/altdoc_variables.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
for (vn in files) {
fn <- fs::path_join(c(.doc_path(path), vn))
regex <- sprintf("\\$ALTDOC_%s", fs::path_ext_remove(basename(vn)))
if (fs::file_exists(fn) || fs::file_exists(fs::path_join(c(path, "_quarto/docs", vn)))) {
if (fs::file_exists(fn) || fs::file_exists(fs::path_join(c(path, "_quarto", vn)))) {
if (tool == "docute") {
new <- paste0("/", vn)
} else {
Expand Down
4 changes: 1 addition & 3 deletions R/import_vignettes.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,7 @@

# target directory
tar_dir <- fs::path_join(c(tar_dir, "vignettes"))
if (!dir.exists(tar_dir)) {
fs::dir_create(tar_dir)
}
fs::dir_create(tar_dir)

# source files
# docute can't open PDF in external tab because it adds ".md" after all files
Expand Down
30 changes: 17 additions & 13 deletions R/render_docs.R
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
#' @return NULL
#' @template altdoc_variables
#' @template altdoc_preambles
#' @template altdoc_freeze
#'
#' @examples
#' if (interactive()) {
Expand All @@ -56,24 +57,27 @@ render_docs <- function(path = ".", verbose = FALSE, parallel = FALSE, freeze =
# build quarto in a separate folder to use the built-in freeze functionality
# and to allow moving the _site folder to docs/
if (tool == "quarto_website") {
docs_parent <- fs::path_join(c(path, "_quarto"))
# avoid collisions
if (fs::dir_exists(docs_parent)) {
fs::dir_delete(docs_parent)
docs_dir <- fs::path_join(c(path, "_quarto"))

# Delete everything in `_quarto/` besides `_freeze/`
if (fs::dir_exists(docs_dir)) {
docs_files <- fs::dir_ls(docs_dir)
if (freeze == TRUE) {
docs_files <- Filter(function(f) basename(f) != "_freeze", docs_files)
}
fs::file_delete(docs_files)
}
.add_gitignore("^_quarto$", path = path)
} else {
docs_parent <- path
}

# create docs/
docs_dir <- fs::path_join(c(docs_parent, "docs"))
if (!fs::dir_exists(docs_dir)) {
fs::dir_create(docs_dir)
.add_gitignore("_quarto/", path = path)
.add_gitignore("!_quarto/_freeze/", path = path)
} else {
docs_dir <- fs::path_join(c(path, "docs"))
}

cli::cli_h1("Basic files")
# create `docs_dir/`
fs::dir_create(docs_dir)

cli::cli_h1("Basic files")
basics <- c("NEWS", "CHANGELOG", "ChangeLog", "CODE_OF_CONDUCT", "LICENSE", "LICENCE")
for (b in basics) {
.import_basic(src_dir = path, tar_dir = docs_dir, name = b)
Expand Down
4 changes: 2 additions & 2 deletions R/settings.R
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

# docs/* files are mutable and should be overwritten
if (grepl("^quarto", tool)) {
tar_dir <- fs::path_join(c(path, "_quarto/docs"))
tar_dir <- fs::path_join(c(path, "_quarto"))
} else {
tar_dir <- .doc_path(path)
}
Expand Down Expand Up @@ -58,4 +58,4 @@
settings <- finalize(settings, path, verbose, freeze)

cli::cli_alert_success("HTML updated.")
}
}
68 changes: 23 additions & 45 deletions R/settings_quarto_website.R
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,12 @@

# drop empty lines
settings <- settings[!grepl("^\\w*$", settings)]

fn <- fs::path_join(c(path, "_quarto", "_quarto.yml"))
yaml::write_yaml(settings, fn, indent.mapping.sequence = TRUE)

# yaml::write_yaml converts true to yes, but quarto complains
settings <- .readlines(fn)
settings <- gsub(": yes$", ": true", settings)
settings <- gsub(": no$", ": false", settings)
writeLines(settings, fn)

tmp <- fs::path_join(c(path, "_quarto", "docs"))
fs::dir_copy(tmp, fs::path_join(c(path, "_quarto")), overwrite = TRUE)
fs::dir_delete(tmp)
settings <- yaml::as.yaml(
settings, indent.mapping.sequence = TRUE,
handler = list(logical = yaml::verbatim_logical)
)
settings <- strsplit(settings, "\\n")[[1]]
writeLines(settings, fs::path_join(c(path, "_quarto", "_quarto.yml")))

# index.md breaks rendering
fn <- fs::path_join(c(path, "_quarto", "index.md"))
Expand All @@ -33,59 +26,44 @@
fs::file_delete(b)
}

quarto::quarto_render(
input = fs::path_join(c(path, "_quarto")),
quiet = !verbose,
as_job = FALSE,
use_freezer = freeze)

# move _quarto/_site to docs/
# allow book
for (x in c("_site", "_book")) {
tmp <- fs::path_join(c(path, "_quarto", x))
if (fs::file_exists(tmp)) {
src <- tmp
}
}

tar <- .doc_path(path)

# make sure docs/ exists
if (!fs::dir_exists(tar)) {
fs::dir_create(tar)
}
fs::dir_create(tar)

# CNAME is used by Github and other providers to redirect to a custom domain
files <- fs::dir_ls(tar)
for (f in files) {
if (basename(f) != "CNAME") {
if (fs::is_dir(f)) fs::dir_delete(f)
if (fs::is_file(f)) fs::file_delete(f)
}
}
files <- Filter(function(f) basename(f) != "CNAME", fs::dir_ls(tar))
# Clear out `tar`
fs::file_delete(files)

fs::file_move(fs::dir_ls(src), tar)
# render to `output-dir: ../docs/`
quarto::quarto_render(
input = fs::path_join(c(path, "_quarto")),
quiet = !verbose,
as_job = FALSE,
use_freezer = freeze
)

# copy the content of altdoc/ to docs/. This is important because the
# process above rendered the site in a completely different directory, so
# did not have the static files, and we want the static files in altdoc/ to
# be served on the website. This a core feature of altdoc: users can store
# files in altdoc/ and those will be copied to the root of the website

# this can be done automatically with `project:` > `resources: ../altdoc/`
fs::dir_copy(fs::path_join(c(path, "altdoc")), tar, overwrite = TRUE)

}


.sidebar_vignettes_quarto_website <- function(sidebar, path) {
fn_vignettes <- list.files(
fs::path_join(c(path, "_quarto/docs/vignettes")),
fs::path_join(c(path, "_quarto/vignettes")),
pattern = "\\.qmd$|\\.Rmd|\\.pdf$", full.names = TRUE)
fn_man <- list.files(
fs::path_join(c(path, "_quarto/docs/man")),
fs::path_join(c(path, "_quarto/man")),
pattern = "\\.qmd$", full.names = TRUE)

fn_man <- gsub(".*_quarto.docs.", "", fn_man)
fn_vignettes <- gsub(".*_quarto.docs.", "", fn_vignettes)
fn_man <- gsub(".*_quarto.", "", fn_man)
fn_vignettes <- gsub(".*_quarto.", "", fn_vignettes)

yml <- paste(sidebar, collapse = "\n")
yml <- yaml::yaml.load(yml)
Expand Down
5 changes: 1 addition & 4 deletions R/setup_github_actions.R
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,7 @@
setup_github_actions <- function(path = ".") {

path <- .convert_path(path)

if (!fs::dir_exists(fs::path_join(c(path, ".github/workflows")))) {
fs::dir_create(fs::path_join(c(path, ".github/workflows")))
}
fs::dir_create(fs::path_join(c(path, ".github/workflows")))
if (fs::file_exists(fs::path_join(c(path, ".github/workflows/altdoc.yaml")))) {
cli::cli_abort("{.file .github/workflows/altdoc.yaml} already exists.")
}
Expand Down
7 changes: 6 additions & 1 deletion inst/quarto_website/quarto_website.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
project:
type: website
output-dir: ../docs/

# Note: freeze functionality can be set at a project level or for individual .qmd files
# execute:
# freeze: false

website:
title: "$ALTDOC_PACKAGE_NAME"
Expand Down Expand Up @@ -32,4 +37,4 @@ website:
# format:
# html:
# theme: cosmo
# number-sections: false
# number-sections: false
12 changes: 12 additions & 0 deletions man-roxygen/altdoc_freeze.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#' @section Freeze
#'
#' When working on a package, running `render_docs()` to preview changes can be a time-consuming road block. The argument `freeze = TRUE` tries to improve the experience by preventing rerendering of files that have not changed since the last time `render_docs()` was ran. Note that changes to package internals will not cause a rerender, so rerendering the entire docs can still be necessary.
#'
#' For non-Quarto formats, this is done by creating a `freeze.rds` file in `altdoc/` that is able to determine which documentation files have changed.
#'
#' For the Quarto format, we rely on the [Quarto freeze](https://quarto.org/docs/projects/code-execution.html#freeze) feature. Freezing a document needs to be set either at a project or per-file level. Freezing a document needs to be set either at a project or per-file level. To do so, add to either `quarto_website.yml` or the frontmatter of a file:
#' ``` yml
#' execute:
#' freeze: auto
#' ```
#'

0 comments on commit 8824669

Please sign in to comment.