-
-
Notifications
You must be signed in to change notification settings - Fork 42
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
479 add
renv::snapshot()
for .lockfile
with future
+ `shiny::Ex…
…tendedTask` (#1232) Fixes insightsengineering/coredev-tasks#479 Alternative for #1224 This PR includes new imports - `{renv}` - so that we can use a function that creates a `.lockfile` for future reproducibility - `{future}` - so that we can run `renv::snapshot()` as a `shiny::ExtendedTask()$new` in a parallel process to the shiny session Tested with ```r # pass your own .lockfile # options(teal.renv.lockfile = "session.lock") # allow to create the .lockfile based on DESCRIPTION file # renv::settings$snapshot.type("explicit") app <- init( data = teal_data(iris = iris), modules = example_module(label = "example teal module") ) if (interactive()) { shinyApp(app$ui, app$server) } ``` --------- Signed-off-by: Marcin <[email protected]> Co-authored-by: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: 27856297+dependabot-preview[bot]@users.noreply.github.com <27856297+dependabot-preview[bot]@users.noreply.github.com> Co-authored-by: kartikeya kirar <[email protected]> Co-authored-by: André Veríssimo <[email protected]> Co-authored-by: Pawel Rucki <[email protected]>
- Loading branch information
1 parent
7da5d29
commit 04825a1
Showing
13 changed files
with
214 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
#' Generate lockfile for application reproducibility | ||
#' | ||
#' This function is invoked during [teal::init] to create `renv`-compatible lockfile for use within the application. | ||
#' | ||
#' The function leverages [renv::snapshot()], which offers multiple methods for lockfile creation. | ||
#' | ||
#' - User-specified: | ||
#' - **Pre-computed lockfile**: Users can provide their own pre-computed lockfile by specifying the path via | ||
#' `teal.renv.lockfile` option. Automatic lockfile computation is skipped in such case. | ||
#' - Automatically computed: | ||
#' - **Working directory lockfile**: If `teal.renv.lockfile` is not set, `teal` will, by default, create an | ||
#' `implicit` type lockfile that uses `renv::dependencies()` to detect all R packages in the current project's | ||
#' working directory. | ||
#' - **`DESCRIPTION`-based lockfile**: To generate a lockfile based on a `DESCRIPTION` file in your working | ||
#' directory, set `renv::settings$snapshot.type("explicit")`. The naming convention for `type` follows | ||
#' `renv::snapshot()`. For the `"explicit"` type, refer to `renv::settings$package.dependency.fields()` for the | ||
#' `DESCRIPTION` fields included in the lockfile. | ||
#' - **Custom files-based lockfile**: To specify custom files as the basis for the lockfile, set | ||
#' `renv::settings$snapshot.type("custom")` and configure the `renv.snapshot.filter` option. | ||
#' | ||
#' @section lockfile usage: | ||
#' After creating the lockfile, you can restore the application environment using `renv::restore()`. | ||
#' | ||
#' @seealso [renv::snapshot()], [renv::restore()]. | ||
#' | ||
#' @return Nothing. This function is executed for its side effect of creating a lockfile used in the `teal` application. | ||
#' | ||
#' @keywords internal | ||
teal_lockfile <- function() { | ||
lockfile_path <- "teal_app.lock" | ||
# If user has setup the file, there is no need to compute a new one. | ||
user_lockfile <- getOption("teal.renv.lockfile", "") | ||
if (!identical(user_lockfile, "")) { | ||
if (file.exists(user_lockfile)) { | ||
file.copy(user_lockfile, lockfile_path) | ||
return(invisible(NULL)) | ||
} else { | ||
stop("lockfile provided through options('teal.renv.lockfile') does not exist.") | ||
} | ||
} | ||
|
||
if (!(is_in_test() || is_r_cmd_check())) { | ||
old_plan <- future::plan() | ||
# If there is already a parallel (non-sequential) backend, reuse it. | ||
if (inherits(old_plan, "sequential")) { | ||
future::plan(future::multisession, workers = 2) | ||
} | ||
|
||
lockfile_task <- ExtendedTask$new(create_renv_lockfile) | ||
lockfile_task$invoke(close = inherits(old_plan, "sequential"), lockfile_path) | ||
logger::log_trace("lockfile creation invoked.") | ||
} | ||
} | ||
|
||
create_renv_lockfile <- function(close = FALSE, lockfile_path = NULL) { | ||
checkmate::assert_flag(close) | ||
checkmate::assert_string(lockfile_path, na.ok = TRUE) | ||
promise <- promises::future_promise({ | ||
# Below we can not use a file created in tempdir() directory. | ||
# If a file is created in tempdir(), it gets deleted on 'then(onFulfilled' part. | ||
shiny::onStop(function() file.remove(lockfile_path)) | ||
|
||
renv_logs <- utils::capture.output( | ||
renv::snapshot( | ||
lockfile = lockfile_path, | ||
prompt = FALSE, | ||
force = TRUE | ||
# type = is taken from renv::settings$snapshot.type() | ||
) | ||
) | ||
if (any(grepl("Lockfile written", renv_logs))) { | ||
logger::log_trace("lockfile created successfully.") | ||
} else { | ||
logger::log_trace("lockfile created with issues.") | ||
} | ||
|
||
lockfile_path | ||
}) | ||
if (close) { | ||
# If the initial backend was only sequential, bring it back. | ||
promises::then(promise, onFulfilled = function() { | ||
future::plan(future::sequential) | ||
}) | ||
} | ||
promise | ||
} | ||
|
||
teal_lockfile_downloadhandler <- function() { | ||
downloadHandler( | ||
filename = function() { | ||
"renv.lock" | ||
}, | ||
content = function(file) { | ||
teal_lockfile <- "teal_app.lock" | ||
iter <- 1 | ||
while (!file.exists(teal_lockfile) && iter <= 100) { | ||
logger::log_trace("lockfile not created yet, retrying...") | ||
Sys.sleep(0.25) | ||
iter <- iter + 1 # max wait time is 25 seconds | ||
} | ||
file.copy(teal_lockfile, file) | ||
file | ||
}, | ||
contentType = "application/json" | ||
) | ||
} | ||
|
||
is_r_cmd_check <- function() { | ||
("CheckExEnv" %in% search()) || any(c("_R_CHECK_TIMINGS_", "_R_CHECK_LICENSE_") %in% names(Sys.getenv())) | ||
} | ||
|
||
is_in_test <- function() { | ||
identical(Sys.getenv("TESTTHAT"), "true") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -26,3 +26,4 @@ tabsetted | |
themer | ||
theming | ||
uncheck | ||
lockfile |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters