Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
jacpete opened this issue Oct 4, 2024 · 2 comments

Comments

@jacpete
Copy link

jacpete commented Oct 4, 2024

I tracked this bug down to quarto-dev/quarto-cli#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:

quarto_render <- function(pkg, path, quiet = TRUE, frame = caller_env()) {
# Override default quarto format
metadata_path <- withr::local_tempfile(
fileext = ".yml",
pattern = "pkgdown-quarto-metadata-",
)
write_yaml(quarto_format(pkg), metadata_path)
output_dir <- withr::local_tempdir("pkgdown-quarto-", .local_envir = frame)
quarto::quarto_render(
path,
metadata_file = metadata_path,
execute_dir = output_dir,
quarto_args = c("--output-dir", output_dir),
quiet = quiet,
as_job = FALSE
)
output_dir
}

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
Copy link
Contributor

rcannood commented Oct 8, 2024

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
Copy link
Collaborator

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

@hadley hadley closed this as completed Oct 9, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants