1#' Build package vignettes. 2#' 3#' Builds package vignettes using the same algorithm that `R CMD build` 4#' does. This means including non-Sweave vignettes, using makefiles (if 5#' present), and copying over extra files. The files are copied in the 'doc' 6#' directory and an vignette index is created in 'Meta/vignette.rds', as they 7#' would be in a built package. 'doc' and 'Meta' are added to 8#' `.Rbuildignore`, so will not be included in the built package. These 9#' files can be checked into version control, so they can be viewed with 10#' `browseVignettes()` and `vignette()` if the package has been 11#' loaded with `load_all()` without needing to re-build them locally. 12#' 13#' @template devtools 14#' @param quiet If `TRUE`, suppresses most output. Set to `FALSE` 15#' if you need to debug. 16#' @param install If `TRUE`, install the package before building 17#' vignettes. 18#' @param keep_md If `TRUE`, move md intermediates as well as rendered 19#' outputs. Most useful when using the `keep_md` YAML option for Rmarkdown 20#' outputs. See 21#' <https://bookdown.org/yihui/rmarkdown/html-document.html#keeping-markdown>. 22#' @inheritParams tools::buildVignettes 23#' @inheritParams remotes::install_deps 24#' @importFrom stats update 25#' @keywords programming 26#' @seealso [clean_vignettes()] to remove the pdfs in 27#' \file{doc} created from vignettes 28#' @export 29#' @seealso [clean_vignettes()] to remove build tex/pdf files. 30build_vignettes <- function(pkg = ".", 31 dependencies = "VignetteBuilder", 32 clean = TRUE, 33 upgrade = "never", 34 quiet = TRUE, 35 install = TRUE, 36 keep_md = TRUE) { 37 pkg <- as.package(pkg) 38 39 deps <- remotes::dev_package_deps(pkg$path, dependencies) 40 update(deps, upgrade = upgrade) 41 42 vigns <- tools::pkgVignettes(dir = pkg$path) 43 if (length(vigns$docs) == 0) return() 44 45 cli::cli_alert_info("Building {.pkg {pkg$package}} vignettes") 46 47 if (isTRUE(install)) { 48 build <- function(pkg_path, clean, quiet, upgrade) { 49 withr::with_temp_libpaths(action = "prefix", { 50 devtools::install(pkg_path, upgrade = upgrade, reload = FALSE, quiet = quiet) 51 tools::buildVignettes(dir = pkg_path, clean = clean, tangle = TRUE, quiet = quiet) 52 }) 53 } 54 } else { 55 build <- function(pkg_path, clean, quiet, upgrade) { 56 tools::buildVignettes(dir = pkg_path, clean = clean, tangle = TRUE, quiet = quiet) 57 } 58 } 59 60 callr::r( 61 build, 62 args = list(pkg_path = pkg$path, clean = clean, upgrade = upgrade, quiet = quiet), 63 show = !quiet, 64 spinner = FALSE, 65 stderr = "2>&1" 66 ) 67 68 # We need to re-run pkgVignettes now that they are built to get the output 69 # files as well 70 vigns <- tools::pkgVignettes(dir = pkg$path, source = TRUE, output = TRUE) 71 72 copy_vignettes(pkg, keep_md) 73 74 create_vignette_index(pkg, vigns) 75 76 invisible(TRUE) 77} 78 79create_vignette_index <- function(pkg, vigns) { 80 usethis_use_directory(pkg, "Meta", ignore = TRUE) 81 usethis_use_git_ignore(pkg, "/Meta/") 82 83 cli::cli_alert_info("Building vignette index") 84 85 vignette_index <- ("tools" %:::% ".build_vignette_index")(vigns) 86 87 vignette_index_path <- path(pkg$path, "Meta", "vignette.rds") 88 89 saveRDS(vignette_index, vignette_index_path, version = 2L) 90} 91 92#' Clean built vignettes. 93#' 94#' This uses a fairly rudimentary algorithm where any files in \file{doc} 95#' with a name that exists in \file{vignettes} are removed. 96#' 97#' @template devtools 98#' @export 99clean_vignettes <- function(pkg = ".") { 100 pkg <- as.package(pkg) 101 vigns <- tools::pkgVignettes(dir = pkg$path) 102 if (path_file(vigns$dir) != "vignettes") return() 103 104 cli::cli_alert_info("Cleaning built vignettes and index from {.pkg {pkg$package}}") 105 106 doc_path <- path(pkg$path, "doc") 107 108 vig_candidates <- if (dir_exists(doc_path)) dir_ls(doc_path) else character() 109 vig_rm <- vig_candidates[file_name(vig_candidates) %in% file_name(vigns$docs)] 110 111 extra_candidates <- path(doc_path, path_file(find_vignette_extras(pkg))) 112 extra_rm <- extra_candidates[file_exists(extra_candidates)] 113 114 meta_path <- path(pkg$path, "Meta") 115 vig_index_path <- path(meta_path, "vignette.rds") 116 vig_index_rm <- if (file_exists(vig_index_path)) vig_index_path 117 118 to_remove <- c(vig_rm, extra_rm, vig_index_rm) 119 if (length(to_remove) > 0) { 120 cli::cli_alert_warning("Removing {.file {path_file(to_remove)}}") 121 file_delete(to_remove) 122 } 123 124 lapply(c(doc_path, meta_path), dir_delete_if_empty) 125 126 invisible(TRUE) 127} 128 129dir_delete_if_empty <- function(x) { 130 if (dir_exists(x) && rlang::is_empty(dir_ls(x))) { 131 dir_delete(x) 132 cli::cli_alert_warning("Removing {.file {path_file(x)}}") 133 } 134} 135 136file_name <- function(x) { 137 if (length(x) == 0) return(NULL) 138 path_ext_remove(path_file(x)) 139} 140