-
-
Notifications
You must be signed in to change notification settings - Fork 50
479 mirai lockfile@main #1263
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
Merged
Merged
479 mirai lockfile@main #1263
Changes from 91 commits
Commits
Show all changes
100 commits
Select commit
Hold shift + click to select a range
249390c
substitute future::promises lockfile creation with callr::r_bg
m7pr d1efcc7
fix tests
m7pr 9bd9944
cleanup the old approach
m7pr 5911bd3
[skip style] [skip vbump] Restyle files
github-actions[bot] e46337c
do not assign renv output to anything
m7pr f0ee2fd
no need to capture renv::snapshot output as nothing gets printed out …
m7pr b90e1ef
Merge branch '479_callr_lockfile@main' of https://github.com/insights…
m7pr 3650a9d
pass options and renv objects
m7pr 0689000
[skip style] [skip vbump] Restyle files
github-actions[bot] b40417e
add comments
m7pr f4b51d6
[skip style] [skip vbump] Restyle files
github-actions[bot] e04fff1
bring back logging
m7pr 13d965a
[skip style] [skip vbump] Restyle files
github-actions[bot] 23df7ca
prefixes
m7pr 746690f
merge
m7pr b717558
[skip style] [skip vbump] Restyle files
github-actions[bot] 9208909
Update R/teal_lockfile.R
m7pr f7fbc87
Update tests/testthat/test-utils.R
m7pr 03c2dce
Merge branch 'main' into 479_callr_lockfile@main
m7pr d400570
test for a lockfile in init
m7pr e7c7c7b
less capture.output is needed
m7pr 6b1c0df
expose env = NULL and unify documentation
m7pr 0114333
bring create_renv_lockfile_2 for testing
m7pr 58a9e8d
[skip style] [skip vbump] Restyle files
github-actions[bot] 2632e5c
append the name to the counter for the test function
m7pr db24fbd
merge
m7pr 027faee
store r_bg process to a variable to prevent from killing the process
m7pr 4467cd2
prototype of the reactivePoll
m7pr 86403e8
[skip style] [skip vbump] Restyle files
github-actions[bot] d6a82e4
styler check
m7pr a7f0666
Merge branch '479_callr_lockfile@main' of https://github.com/insights…
m7pr 3c480a7
lockfile_status_tracker
m7pr d2b0d8b
use showNotification to publish information about lofkcile creation
m7pr 6010c4f
start lockfile download handler as hidden, and only display when lock…
m7pr 209538e
assert
gogonzo 82d1048
WIP tests
gogonzo f5cc36b
setwd
gogonzo 3c3d1c3
setwd, todos
gogonzo 42aad86
tight up
gogonzo 8431ef9
fixes
gogonzo af2c6a3
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] aa8a669
Update R/teal_lockfile.R
m7pr 1f09428
udpate comment
m7pr d77f486
run_mirai as function
m7pr 10a517d
cleanup names for new run_renv_mirai function
m7pr 667b751
remove comments
m7pr 7849e40
remove whiteline
m7pr 323d8ae
Update R/teal_lockfile.R
m7pr 5087163
let's try with teal:::renv_lockfile
m7pr 38e4e17
get back to the previous version of exeuciton of ExtendedTask, but pa…
m7pr 043d673
suppress socket warning
m7pr 4b26fb8
styler
m7pr 717bad2
remove prefix
m7pr c6ccbb5
479 mirai pr (#1272)
pawelru 45a0ec8
Merge branch 'main' into 479_mirai_lockfile@main
gogonzo f746bd6
duplicated test - there is one in init already
gogonzo 5a8089c
fix condition
gogonzo ee55fa8
fix r cmd check
gogonzo 198ae35
encapsulate everything in one module
gogonzo 39cfa53
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] 5312d61
- no shinyjs in utility functions
gogonzo 6d0409f
- don't make a "teal_app.renv" when the app is interrupted during asy…
gogonzo 5a991e4
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo e59c5c3
remove future and promises from verdepcheck
gogonzo 4171c46
Merge branch 'main' into 479_mirai_lockfile@main
gogonzo 8c72bca
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo bcc115e
WIP
gogonzo 5fab6ce
switch to Joe's Cheng example as one can't just create mirai object a…
gogonzo 4834f4e
turnoff renv in tests
gogonzo cfbeda8
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo df91de6
some spelling fixes
gogonzo 7b6f822
fix verdepcheck
gogonzo 3f61fb6
Merge branch 'main' into 479_mirai_lockfile@main
dependabot-preview[bot] 6f01409
wow
dependabot-preview[bot] b6a1dc8
disable lockfile creation when no packages
dependabot-preview[bot] debc4ce
- disable and warn when mirai or renv not available
dependabot-preview[bot] d1c9735
- change options to follow `teal.lockfile.` pattern
dependabot-preview[bot] c0378c8
make code more readible
dependabot-preview[bot] 82ed188
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
dependabot-preview[bot] ec73a04
- remove `teal_app.lock` occurrence from the docs
dependabot-preview[bot] 65aca47
Merge branch 'main' into 479_mirai_lockfile@main
m7pr db11af5
Merge branch 'main' into 479_mirai_lockfile@main
m7pr 82bb3fb
documentation updates
m7pr 761dd68
disable lockfile generation in `callr`, `testthat::tests` and `R CMD …
m7pr 240cbb6
[skip style] [skip vbump] Restyle files
github-actions[bot] 41ba2cb
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] f76a30f
empty
dependabot-preview[bot] f4e268f
introduce teal.lockfile.mode
m7pr dfbcfca
[skip style] [skip vbump] Restyle files
github-actions[bot] 392437d
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] dc9687d
Update tests/testthat/test-module_teal.R
m7pr 5bdd79c
@pawelru and @gogonzo suggestions
m7pr 0effb51
typo
m7pr 139890a
move user_lockfile_path under "user" condition
m7pr eeb6d1a
remove user option for lockfile creation
m7pr 13c62a0
[skip style] [skip vbump] Restyle files
github-actions[bot] 9653aa4
rename teal.lockfile.mode to "enabled" and "disabled"
m7pr ee89fdb
Merge branch '479_mirai_lockfile@main' of https://github.com/insights…
m7pr ab77120
remove section about user-specified lockfile from module_teal_lockfil…
m7pr 3ffc3de
rephrase vignette wording
m7pr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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 hidden or 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 hidden or 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 hidden or 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 hidden or 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,219 @@ | ||
| #' Generate lockfile for application's environment reproducibility | ||
| #' | ||
| #' @param lockfile_path (`character`) path to the lockfile. | ||
| #' | ||
| #' @section Different ways of creating lockfile: | ||
| #' `teal` 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.lockfile.path` option. Automatic lockfile computation is skipped in such case. | ||
| #' - Automatically computed: | ||
| #' - **Working directory lockfile**: If `teal.lockfile.path` 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's environment using `renv::restore()`. | ||
| #' | ||
| #' @seealso [renv::snapshot()], [renv::restore()]. | ||
| #' | ||
| #' @return `NULL` | ||
| #' | ||
| #' @name module_teal_lockfile | ||
| #' @rdname module_teal_lockfile | ||
| #' | ||
| #' @keywords internal | ||
| NULL | ||
|
|
||
| #' @rdname module_teal_lockfile | ||
| ui_teal_lockfile <- function(id) { | ||
| ns <- NS(id) | ||
| shiny::tagList( | ||
| tags$span("", id = ns("lockFileStatus")), | ||
| shinyjs::disabled(downloadLink(ns("lockFileLink"), "Download lockfile")) | ||
| ) | ||
| } | ||
|
|
||
| #' @rdname module_teal_lockfile | ||
| srv_teal_lockfile <- function(id) { | ||
| moduleServer(id, function(input, output, session) { | ||
| logger::log_debug("Initialize srv_teal_lockfile.") | ||
| enable_lockfile_download <- function() { | ||
| shinyjs::html("lockFileStatus", "Application lockfile ready.") | ||
| shinyjs::hide("lockFileStatus", anim = TRUE) | ||
| shinyjs::enable("lockFileLink") | ||
| output$lockFileLink <- shiny::downloadHandler( | ||
| filename = function() { | ||
| "renv.lock" | ||
| }, | ||
| content = function(file) { | ||
| file.copy(lockfile_path, file) | ||
| file | ||
| }, | ||
| contentType = "application/json" | ||
| ) | ||
| } | ||
| disable_lockfile_download <- function() { | ||
| warning("Lockfile creation failed.", call. = FALSE) | ||
| shinyjs::html("lockFileStatus", "Lockfile creation failed.") | ||
| shinyjs::disable("lockFileLink") | ||
m7pr marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| shiny::onStop(function() { | ||
| if (file.exists(lockfile_path) && !shiny::isRunning()) { | ||
| logger::log_debug("Removing lockfile after shutting down the app") | ||
| file.remove(lockfile_path) | ||
| } | ||
| }) | ||
|
|
||
| lockfile_path <- "teal_app.lock" | ||
| mode <- getOption("teal.lockfile.mode", default = "") | ||
| user_lockfile_path <- getOption("teal.lockfile.path", default = "") | ||
|
|
||
| if (!(mode %in% c("auto", "true", "false", "user"))) { | ||
gogonzo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| stop("'teal.lockfile.mode' option can only be one of \"auto\", \"true\", \"false\", or \"user\". ") | ||
| } | ||
|
|
||
m7pr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (mode == "false") { | ||
| logger::log_debug("'teal.lockfile.mode' option is set to 'false'. Hiding lockfile download button.") | ||
| shinyjs::hide("lockFileLink") | ||
| return(NULL) | ||
| } | ||
|
|
||
| if (file.exists(lockfile_path)) { | ||
| logger::log_debug("Lockfile has already been created for this app - skipping automatic creation.") | ||
| enable_lockfile_download() | ||
| return(NULL) | ||
| } | ||
gogonzo marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
|
||
| if (mode %in% c("auto", "true") && !.is_lockfile_deps_installed()) { | ||
m7pr marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| warning("Automatic lockfile creation disabled. `mirai` and `renv` packages must be installed.") | ||
| shinyjs::hide("lockFileLink") | ||
| return(NULL) | ||
| } | ||
|
|
||
| if (mode == "auto" && .is_disabled_lockfile_scenario()) { | ||
m7pr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| logger::log_debug( | ||
| "Automatic lockfile creation disabled. Execution scenario satisfies teal:::.is_disabled_lockfile_scenario()." | ||
| ) | ||
| shinyjs::hide("lockFileLink") | ||
| return(NULL) | ||
| } | ||
|
|
||
| if (mode == "user") { | ||
| if (file.exists(user_lockfile_path)) { | ||
| file.copy(user_lockfile_path, lockfile_path) | ||
| logger::log_debug('Lockfile set using option "teal.lockfile.path" - skipping automatic creation.') | ||
| enable_lockfile_download() | ||
| } else { | ||
| warning("Lockfile provided through options('teal.lockfile.path') does not exist.", call. = FALSE) | ||
| shinyjs::hide("lockFileLink") | ||
| } | ||
| return(NULL) | ||
| } | ||
m7pr marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| # - Will be run only if the lockfile doesn't exist (see the if-s above) | ||
| # - We render to the tempfile because the process might last after session is closed and we don't | ||
| # want to make a "teal_app.renv" then. This is why we copy only during active session. | ||
| process <- .teal_lockfile_process_invoke(lockfile_path) | ||
| observeEvent(process$status(), { | ||
| if (process$status() %in% c("initial", "running")) { | ||
| shinyjs::html("lockFileStatus", "Creating lockfile...") | ||
| } else if (process$status() == "success") { | ||
| result <- process$result() | ||
| if (any(grepl("Lockfile written to", result$out))) { | ||
| logger::log_debug("Lockfile containing { length(result$res$Packages) } packages created.") | ||
| if (any(grepl("(WARNING|ERROR):", result$out))) { | ||
| warning("Lockfile created with warning(s) or error(s):", call. = FALSE) | ||
| for (i in result$out) { | ||
| warning(i, call. = FALSE) | ||
| } | ||
| } | ||
| enable_lockfile_download() | ||
| } else { | ||
| disable_lockfile_download() | ||
| } | ||
| } else if (process$status() == "error") { | ||
| disable_lockfile_download() | ||
| } | ||
| }) | ||
|
|
||
| NULL | ||
| }) | ||
| } | ||
|
|
||
| utils::globalVariables(c("opts", "sysenv", "libpaths", "wd", "lockfilepath", "run")) # needed for mirai call | ||
| #' @rdname module_teal_lockfile | ||
m7pr marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .teal_lockfile_process_invoke <- function(lockfile_path) { | ||
| mirai_obj <- NULL | ||
| process <- shiny::ExtendedTask$new(function() { | ||
| m <- mirai::mirai( | ||
| { | ||
| options(opts) | ||
| do.call(Sys.setenv, sysenv) | ||
| .libPaths(libpaths) | ||
| setwd(wd) | ||
| run(lockfile_path = lockfile_path) | ||
| }, | ||
| run = .renv_snapshot, | ||
| lockfile_path = lockfile_path, | ||
| opts = options(), | ||
| libpaths = .libPaths(), | ||
| sysenv = as.list(Sys.getenv()), | ||
| wd = getwd() | ||
| ) | ||
| mirai_obj <<- m | ||
| m | ||
| }) | ||
|
|
||
| shiny::onStop(function() { | ||
| if (mirai::unresolved(mirai_obj)) { | ||
| logger::log_debug("Terminating a running lockfile process...") | ||
| mirai::stop_mirai(mirai_obj) # this doesn't stop running - renv will be created even if session is closed | ||
| } | ||
| }) | ||
|
|
||
| suppressWarnings({ # 'package:stats' may not be available when loading | ||
| process$invoke() | ||
| }) | ||
|
|
||
| logger::log_debug("Lockfile creation started based on { getwd() }.") | ||
|
|
||
| process | ||
| } | ||
|
|
||
| #' @rdname module_teal_lockfile | ||
| .renv_snapshot <- function(lockfile_path) { | ||
| out <- utils::capture.output( | ||
| res <- renv::snapshot( | ||
| lockfile = lockfile_path, | ||
| prompt = FALSE, | ||
| force = TRUE, | ||
| type = renv::settings$snapshot.type() # see the section "Different ways of creating lockfile" above here | ||
| ) | ||
| ) | ||
|
|
||
| list(out = out, res = res) | ||
| } | ||
|
|
||
| #' @rdname module_teal_lockfile | ||
| .is_lockfile_deps_installed <- function() { | ||
| requireNamespace("mirai", quietly = TRUE) && requireNamespace("renv", quietly = TRUE) | ||
| } | ||
|
|
||
| #' @rdname module_teal_lockfile | ||
| .is_disabled_lockfile_scenario <- function() { | ||
| identical(Sys.getenv("CALLR_IS_RUNNING"), "true") || # inside callr process | ||
| identical(Sys.getenv("TESTTHAT"), "true") || # inside devtools::test | ||
| !identical(Sys.getenv("QUARTO_PROJECT_ROOT"), "") || # inside Quarto process | ||
| ( | ||
| ("CheckExEnv" %in% search()) || any(c("_R_CHECK_TIMINGS_", "_R_CHECK_LICENSE_") %in% names(Sys.getenv())) | ||
| ) # inside R CMD CHECK | ||
| } | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.