r-lib / pkgdown

Generate static html documentation for an R package
https://pkgdown.r-lib.org/
Other
718 stars 336 forks source link

`pkgdown::build_article()` fails for .qmd files if article is mounted on a different drive than your temp directory #2791

Closed jacpete closed 1 month ago

jacpete commented 1 month ago

I tracked this bug down to https://github.com/quarto-dev/quarto-cli/issues/2671. The actual bug is reproduced there in a minimal reprex, so I'm just going to show an example of what a user of pkgdown may see and provide a workaround that others can use until this is fixed in quarto. Essentially, my project exists on a mounted network drive at /mnt/home/jacob/GitHub/support-onepasswoRd and /tmp is on the local filesystem.

In my project I ran build_articles() and got the following error:

> pkgdown::build_articles()
── Building articles ────────────────────────────────────────────────────────────────────────────────────────────────
Reading vignettes/environmental-variables.qmd
Reading vignettes/onepasswoRd.qmd
Reading vignettes/secrets-in-code.qmd
Reading vignettes/template-injection.qmd
Running `quarto render`
Error in `quarto::quarto_render()`:
✖ Error running quarto cli.
ℹ Rerun with `quiet = FALSE` to see the full error message.
Caused by error:
! System command 'quarto' failed
Run `rlang::last_trace()` to see where the error occurred.

I then narrowed the render to a single article to see if I could get more information and the signature error for the quarto issue popped up:

> pkgdown::build_article(name = 'onepasswoRd', quiet = FALSE)
Reading vignettes/onepasswoRd.qmd
Running `quarto render`

processing file: onepasswoRd.qmd

output file: onepasswoRd.knit.md

pandoc 
  to: html
  output-file: onepasswoRd.html
  template: >-
    /mnt/home/jacob/R/x86_64-pc-linux-gnu-library/4.4/pkgdown/quarto/template.html
  standalone: true
  embed-resources: false
  wrap: none
  default-image-extension: png
  html-math-method: mathml
  section-divs: true
  toc: false
  toc-depth: 3

metadata
  document-css: false
  lang: en
  minimal: true
  theme: none
  citations-hover: true
  link-citations: true
  title: Introduction to onepasswoRd
  description: |
    Learn how to get started with the basics of onepasswoRd
  vignette: |
    %\VignetteIndexEntry{Introduction to onepasswoRd} %\VignetteEngine{quarto::html} %\VignetteEncoding{UTF-8}

ERROR: Invalid cross-device link (os error 18): rename '/mnt/home/jacob/GitHub/support-onepasswoRd/vignettes/onepasswoRd.html' -> '/tmp/Rtmp8drUYZ/pkgdown-quarto-20914103f5df/onepasswoRd.html'

Stack trace:
    at Object.renameSync (ext:deno_fs/30_fs.js:267:3)
    at renderProject (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:78512:22)
    at eventLoopTick (ext:core/01_core.js:153:7)
    at async Command.actionHandler (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:83077:32)
    at async Command.execute (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:8017:13)
    at async Command.parseCommand (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:7907:20)
    at async quarto (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:118224:9)
    at async file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:118244:9
    at async mainRunner (file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:118128:9)
    at async file:///usr/lib/rstudio-server/bin/quarto/bin/quarto.js:118235:5
Error in `quarto::quarto_render()`:
✖ Error running quarto cli.
Caused by error:
! System command 'quarto' failed
Run `rlang::last_trace()` to see where the error occurred.

This line was the indicator for the quarto issue:

ERROR: Invalid cross-device link (os error 18): rename '/mnt/home/jacob/GitHub/support-onepasswoRd/vignettes/onepasswoRd.html' -> '/tmp/Rtmp8drUYZ/pkgdown-quarto-20914103f5df/onepasswoRd.html'

It looks like using the default temporary directory set by the session is hard-coded into this package at: https://github.com/r-lib/pkgdown/blob/0cb9d38d1dc25946f01ee7500be9665985d8784e/R/build-quarto-articles.R#L77-L96 With no option in the command to specify a different one. However, as a workaround, you can set the temp directory location used by withr::local_tempfile() with the TMPDIR environmental variable as described at https://rdrr.io/r/base/tempfile.html, but we have to launch it in a separate process because:

By default, tmpdir will be the directory given by tempdir(). This will be a subdirectory of the per-session temporary directory found by the following rule when the R session is started. The environment variables TMPDIR, TMP and TEMP are checked in turn and the first found which points to a writable directory is used: if none succeeds ‘/tmp’ is used. The path should not contain spaces. Note that setting any of these environment variables in the R session has no effect on tempdir(): the per-session temporary directory is created before the interpreter is started.

Example Workaround

library(fs)
library(processx)
library(pkgdown)

new_temp_dir <- fs::path_wd("tmp")
if (fs::dir_exists(new_temp_dir)) fs::dir_delete(new_temp_dir)
fs::dir_create(new_temp_dir, mode = "ugo=rwx")

Rscript <- fs::path(Sys.getenv('R_HOME'), 'bin', 'Rscript')
env_tmp <- c('current', 'TMPDIR'=new_temp_dir)
# p_output <- processx::run(Rscript, args = c('-e', "tempdir()"), env = env_tmp, stdout = "", stderr = "") #returns the correct directory
# p_output <- processx::run(Rscript, args = c('-e', "pkgdown::build_article(name = 'onepasswoRd', quiet = FALSE)"), env = env_tmp, stdout = "", stderr = "") #successfully builds a single article using the correct temp dir
# p_output <- processx::run(Rscript, args = c('-e', "pkgdown::build_articles()"), env = env_tmp, stdout = "", stderr = "")  #successfully builds all articles using the correct temp dir
p_output <- processx::run(Rscript, args = c('-e', "pkgdown::build_site()"), env = env_tmp, stdout = "", stderr = "") #successfully builds the site using the correct temp dir
#Since we built the site in a separate non-interactive process, we can now call preview site to serve the site for us to view in our browser.
pkgdown::preview_site()
rcannood commented 1 month ago

Just encountered this as well. It indeed helps to set an environment variable TMPDIR beforehand. For example:

export TMPDIR=$HOME/temp
mkdir -p $TMPDIR
R

pkgdown::build_site()

Unfortunately, the error message you get when running pkgdown::build_site() is very unhelpful to say the least.

Could this error message be solved by copying the R package into the tempdir before running the quarto render?

jayhesselberth commented 1 month ago

This looks like a quarto issue, pkgdown should be fine once that is resolved.