ramnathv / htmlwidgets

HTML Widgets for R
http://htmlwidgets.org
Other
792 stars 205 forks source link

saveWidget does not correctly remove dependency folder when selfcontained=TRUE #296

Open mac471 opened 6 years ago

mac471 commented 6 years ago

When selfcontained=TRUE in saveWidget, the folder created with all of the dependent files is not removed when the path of the file is not the same as the current working directory.

In the code fragment below, note that libdir is the base name of file plus _files appended. The path has been removed. If the current working directory is not the same as the path to file, this command unlink(libdir, recursive = TRUE) fails.

  # form a path for dependenent files
  if (is.null(libdir)){
    libdir <- paste(tools::file_path_sans_ext(basename(file)), "_files",
                    sep = "")
  }

  # make it self-contained if requested
  if (selfcontained) {

    # Save the file
    # Include a title; pandoc 2.0 complains if you don't have one
    pandoc_save_markdown(html, file = file, libdir = libdir,
                         background = background, title = title)

    if (!pandoc_available()) {
      stop("Saving a widget with selfcontained = TRUE requires pandoc. For details see:\n",
           "https://github.com/rstudio/rmarkdown/blob/master/PANDOC.md")
    }

    pandoc_self_contained_html(file, file)
    unlink(libdir, recursive = TRUE)
  } else {
    # no pandoc needed if not selfcontained
    html <- tagList(tags$head(tags$title(title)), html)
    htmltools::save_html(html, file = file, libdir = libdir, background = background)
  }

To make this more robust, suggest the following change to the unlink function call:

  unlink(file.path(dirname(file),libdir))

Thanks. Keep up the great work!

ParsaAkbari commented 6 years ago

I'm also having this issue, currently removing the additional generated files manually R 3.3.0 htmlwidgets 0.9

pooranis commented 6 years ago

Yes, saveWidget seems to expect the working directory to be the same directory as the output html file, but both pandoc_save_markdown and pandoc_self_contained_html (or pandoc_convert) set the working directory back to the original state on.exit.

This could potentially be bad news if you happened to have a directory named libdir in your original working directory. For now, it might be prudent to pass the full path to the libdir instead of using default NULL.

chrisholbrook commented 6 years ago

note that if you pass an incorrect or incomplete path to libdir, then it will delete all files in that path.

gregrs-uk commented 3 years ago

As mentioned in my comment https://github.com/ramnathv/htmlwidgets/issues/299#issuecomment-869012044, this is still the case. Here's a reprex illustrating the issue with the latest CRAN version of htmlwidgets (1.5.3):

library(plotly)
#> Loading required package: ggplot2
#> 
#> Attaching package: 'plotly'
#> The following object is masked from 'package:ggplot2':
#> 
#>     last_plot
#> The following object is masked from 'package:stats':
#> 
#>     filter
#> The following object is masked from 'package:graphics':
#> 
#>     layout
library(htmlwidgets)

p <- plot_ly(
  mtcars,
  x = ~wt,
  y = ~mpg,
  type = "scatter",
  mode = "markers"
)

# This works as expected
saveWidget(
  p,
  "mtcars.html", # in the current working directory
  selfcontained = TRUE # which is the default anyway
)
dir.exists("mtcars-files")
#> [1] FALSE

# When saving to a relative path, an unnecessary temporary directory remains
dir.create("my-dir")
saveWidget(
  p,
  file.path("my-dir", "mtcars.html"), # in the directory just created
  selfcontained = TRUE # which is the default anyway
)
dir.exists(file.path("my-dir", "mtcars_files"))
#> [1] TRUE

Created on 2021-07-15 by the reprex package (v2.0.0)

Session info ``` r sessioninfo::session_info() #> ─ Session info ─────────────────────────────────────────────────────────────── #> setting value #> version R version 4.1.0 (2021-05-18) #> os macOS Big Sur 10.16 #> system x86_64, darwin17.0 #> ui X11 #> language (EN) #> collate en_GB.UTF-8 #> ctype en_GB.UTF-8 #> tz Europe/London #> date 2021-07-15 #> #> ─ Packages ─────────────────────────────────────────────────────────────────── #> package * version date lib source #> assertthat 0.2.1 2019-03-21 [1] CRAN (R 4.1.0) #> cli 2.5.0 2021-04-26 [1] CRAN (R 4.1.0) #> colorspace 2.0-1 2021-05-04 [1] CRAN (R 4.1.0) #> crayon 1.4.1 2021-02-08 [1] CRAN (R 4.1.0) #> crosstalk 1.1.1 2021-01-12 [1] CRAN (R 4.1.0) #> data.table 1.14.0 2021-02-21 [1] CRAN (R 4.1.0) #> DBI 1.1.1 2021-01-15 [1] CRAN (R 4.1.0) #> digest 0.6.27 2020-10-24 [1] CRAN (R 4.1.0) #> dplyr 1.0.6 2021-05-05 [1] CRAN (R 4.1.0) #> ellipsis 0.3.2 2021-04-29 [1] CRAN (R 4.1.0) #> evaluate 0.14 2019-05-28 [1] CRAN (R 4.1.0) #> fansi 0.4.2 2021-01-15 [1] CRAN (R 4.1.0) #> fs 1.5.0 2020-07-31 [1] CRAN (R 4.1.0) #> generics 0.1.0 2020-10-31 [1] CRAN (R 4.1.0) #> ggplot2 * 3.3.3 2020-12-30 [1] CRAN (R 4.1.0) #> glue 1.4.2 2020-08-27 [1] CRAN (R 4.1.0) #> gtable 0.3.0 2019-03-25 [1] CRAN (R 4.1.0) #> highr 0.9 2021-04-16 [1] CRAN (R 4.1.0) #> htmltools 0.5.1.1 2021-01-22 [1] CRAN (R 4.1.0) #> htmlwidgets * 1.5.3 2020-12-10 [1] CRAN (R 4.1.0) #> httr 1.4.2 2020-07-20 [1] CRAN (R 4.1.0) #> jsonlite 1.7.2 2020-12-09 [1] CRAN (R 4.1.0) #> knitr 1.33 2021-04-24 [1] CRAN (R 4.1.0) #> lazyeval 0.2.2 2019-03-15 [1] CRAN (R 4.1.0) #> lifecycle 1.0.0 2021-02-15 [1] CRAN (R 4.1.0) #> magrittr 2.0.1 2020-11-17 [1] CRAN (R 4.1.0) #> munsell 0.5.0 2018-06-12 [1] CRAN (R 4.1.0) #> pillar 1.6.1 2021-05-16 [1] CRAN (R 4.1.0) #> pkgconfig 2.0.3 2019-09-22 [1] CRAN (R 4.1.0) #> plotly * 4.9.3 2021-01-10 [1] CRAN (R 4.1.0) #> purrr 0.3.4 2020-04-17 [1] CRAN (R 4.1.0) #> R6 2.5.0 2020-10-28 [1] CRAN (R 4.1.0) #> reprex 2.0.0 2021-04-02 [1] CRAN (R 4.1.0) #> rlang 0.4.11 2021-04-30 [1] CRAN (R 4.1.0) #> rmarkdown 2.8 2021-05-07 [1] CRAN (R 4.1.0) #> rstudioapi 0.13 2020-11-12 [1] CRAN (R 4.1.0) #> scales 1.1.1 2020-05-11 [1] CRAN (R 4.1.0) #> sessioninfo 1.1.1 2018-11-05 [1] CRAN (R 4.1.0) #> stringi 1.6.2 2021-05-17 [1] CRAN (R 4.1.0) #> stringr 1.4.0 2019-02-10 [1] CRAN (R 4.1.0) #> tibble 3.1.2 2021-05-16 [1] CRAN (R 4.1.0) #> tidyr 1.1.3 2021-03-03 [1] CRAN (R 4.1.0) #> tidyselect 1.1.1 2021-04-30 [1] CRAN (R 4.1.0) #> utf8 1.2.1 2021-03-12 [1] CRAN (R 4.1.0) #> vctrs 0.3.8 2021-04-29 [1] CRAN (R 4.1.0) #> viridisLite 0.4.0 2021-04-13 [1] CRAN (R 4.1.0) #> withr 2.4.2 2021-04-18 [1] CRAN (R 4.1.0) #> xfun 0.23 2021-05-15 [1] CRAN (R 4.1.0) #> yaml 2.2.1 2020-02-01 [1] CRAN (R 4.1.0) #> #> [1] /Library/Frameworks/R.framework/Versions/4.1/Resources/library ```
zickyls commented 2 years ago

I used a temporary solution: save it in working directory and move it afterwards.

htmlwidgets::saveWidget(widget = as_widget(p), file = "tmp.html", selfcontained = TRUE) file.rename("tmp.html", "target_dir/target.html"))

py9mrg commented 1 year ago

Same for me, and also affecting packages that use this under the hood (e.g., in my case, reactablefmtr::save_reactable()).

DanChaltiel commented 1 year ago

In the meantime, you can use the following workaround:

saveWidget2 = function(widget, file, ...){
  wd = setwd(dirname(file))
  on.exit(setwd(wd))
  htmlwidgets::saveWidget(widget, file=basename(file), ...)
}