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

479 mirai lockfile@main #1263

Merged
merged 100 commits into from
Sep 23, 2024
Merged
Show file tree
Hide file tree
Changes from 99 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 Jul 1, 2024
d1efcc7
fix tests
m7pr Jul 1, 2024
9bd9944
cleanup the old approach
m7pr Jul 1, 2024
5911bd3
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 1, 2024
e46337c
do not assign renv output to anything
m7pr Jul 1, 2024
f0ee2fd
no need to capture renv::snapshot output as nothing gets printed out …
m7pr Jul 1, 2024
b90e1ef
Merge branch '479_callr_lockfile@main' of https://github.com/insights…
m7pr Jul 1, 2024
3650a9d
pass options and renv objects
m7pr Jul 2, 2024
0689000
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 2, 2024
b40417e
add comments
m7pr Jul 2, 2024
f4b51d6
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 2, 2024
e04fff1
bring back logging
m7pr Jul 2, 2024
13d965a
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 2, 2024
23df7ca
prefixes
m7pr Jul 2, 2024
746690f
merge
m7pr Jul 2, 2024
b717558
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 2, 2024
9208909
Update R/teal_lockfile.R
m7pr Jul 2, 2024
f7fbc87
Update tests/testthat/test-utils.R
m7pr Jul 2, 2024
03c2dce
Merge branch 'main' into 479_callr_lockfile@main
m7pr Jul 3, 2024
d400570
test for a lockfile in init
m7pr Jul 3, 2024
e7c7c7b
less capture.output is needed
m7pr Jul 3, 2024
6b1c0df
expose env = NULL and unify documentation
m7pr Jul 3, 2024
0114333
bring create_renv_lockfile_2 for testing
m7pr Jul 3, 2024
58a9e8d
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 3, 2024
2632e5c
append the name to the counter for the test function
m7pr Jul 3, 2024
db24fbd
merge
m7pr Jul 3, 2024
027faee
store r_bg process to a variable to prevent from killing the process
m7pr Jul 4, 2024
4467cd2
prototype of the reactivePoll
m7pr Jul 4, 2024
86403e8
[skip style] [skip vbump] Restyle files
github-actions[bot] Jul 4, 2024
d6a82e4
styler check
m7pr Jul 10, 2024
a7f0666
Merge branch '479_callr_lockfile@main' of https://github.com/insights…
m7pr Jul 10, 2024
3c480a7
lockfile_status_tracker
m7pr Jul 10, 2024
d2b0d8b
use showNotification to publish information about lofkcile creation
m7pr Jul 11, 2024
6010c4f
start lockfile download handler as hidden, and only display when lock…
m7pr Jul 11, 2024
209538e
assert
gogonzo Jul 11, 2024
82d1048
WIP tests
gogonzo Jul 12, 2024
f5cc36b
setwd
gogonzo Jul 12, 2024
3c3d1c3
setwd, todos
gogonzo Jul 12, 2024
42aad86
tight up
gogonzo Jul 15, 2024
8431ef9
fixes
gogonzo Jul 15, 2024
af2c6a3
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] Jul 15, 2024
aa8a669
Update R/teal_lockfile.R
m7pr Jul 16, 2024
1f09428
udpate comment
m7pr Jul 16, 2024
d77f486
run_mirai as function
m7pr Jul 16, 2024
10a517d
cleanup names for new run_renv_mirai function
m7pr Jul 16, 2024
667b751
remove comments
m7pr Jul 17, 2024
7849e40
remove whiteline
m7pr Jul 17, 2024
323d8ae
Update R/teal_lockfile.R
m7pr Jul 17, 2024
5087163
let's try with teal:::renv_lockfile
m7pr Jul 17, 2024
38e4e17
get back to the previous version of exeuciton of ExtendedTask, but pa…
m7pr Jul 17, 2024
043d673
suppress socket warning
m7pr Jul 17, 2024
4b26fb8
styler
m7pr Jul 17, 2024
717bad2
remove prefix
m7pr Jul 17, 2024
c6ccbb5
479 mirai pr (#1272)
pawelru Jul 29, 2024
45a0ec8
Merge branch 'main' into 479_mirai_lockfile@main
gogonzo Aug 13, 2024
f746bd6
duplicated test - there is one in init already
gogonzo Aug 14, 2024
5a8089c
fix condition
gogonzo Aug 14, 2024
ee55fa8
fix r cmd check
gogonzo Aug 14, 2024
198ae35
encapsulate everything in one module
gogonzo Aug 14, 2024
39cfa53
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] Aug 14, 2024
5312d61
- no shinyjs in utility functions
gogonzo Aug 14, 2024
6d0409f
- don't make a "teal_app.renv" when the app is interrupted during asy…
gogonzo Aug 14, 2024
5a991e4
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo Aug 14, 2024
e59c5c3
remove future and promises from verdepcheck
gogonzo Aug 14, 2024
4171c46
Merge branch 'main' into 479_mirai_lockfile@main
gogonzo Aug 15, 2024
8c72bca
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo Aug 19, 2024
bcc115e
WIP
gogonzo Aug 19, 2024
5fab6ce
switch to Joe's Cheng example as one can't just create mirai object a…
gogonzo Aug 19, 2024
4834f4e
turnoff renv in tests
gogonzo Aug 20, 2024
cfbeda8
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
gogonzo Sep 2, 2024
df91de6
some spelling fixes
gogonzo Sep 2, 2024
7b6f822
fix verdepcheck
gogonzo Sep 2, 2024
3f61fb6
Merge branch 'main' into 479_mirai_lockfile@main
dependabot-preview[bot] Sep 5, 2024
6f01409
wow
dependabot-preview[bot] Sep 5, 2024
b6a1dc8
disable lockfile creation when no packages
dependabot-preview[bot] Sep 5, 2024
debc4ce
- disable and warn when mirai or renv not available
dependabot-preview[bot] Sep 5, 2024
d1c9735
- change options to follow `teal.lockfile.` pattern
dependabot-preview[bot] Sep 6, 2024
c0378c8
make code more readible
dependabot-preview[bot] Sep 10, 2024
82ed188
Merge remote-tracking branch 'origin/main' into 479_mirai_lockfile@main
dependabot-preview[bot] Sep 11, 2024
ec73a04
- remove `teal_app.lock` occurrence from the docs
dependabot-preview[bot] Sep 17, 2024
65aca47
Merge branch 'main' into 479_mirai_lockfile@main
m7pr Sep 17, 2024
db11af5
Merge branch 'main' into 479_mirai_lockfile@main
m7pr Sep 18, 2024
82bb3fb
documentation updates
m7pr Sep 18, 2024
761dd68
disable lockfile generation in `callr`, `testthat::tests` and `R CMD …
m7pr Sep 19, 2024
240cbb6
[skip style] [skip vbump] Restyle files
github-actions[bot] Sep 19, 2024
41ba2cb
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] Sep 19, 2024
f76a30f
empty
dependabot-preview[bot] Sep 19, 2024
f4e268f
introduce teal.lockfile.mode
m7pr Sep 19, 2024
dfbcfca
[skip style] [skip vbump] Restyle files
github-actions[bot] Sep 19, 2024
392437d
[skip roxygen] [skip vbump] Roxygen Man Pages Auto Update
dependabot-preview[bot] Sep 19, 2024
dc9687d
Update tests/testthat/test-module_teal.R
m7pr Sep 19, 2024
5bdd79c
@pawelru and @gogonzo suggestions
m7pr Sep 19, 2024
0effb51
typo
m7pr Sep 19, 2024
139890a
move user_lockfile_path under "user" condition
m7pr Sep 19, 2024
eeb6d1a
remove user option for lockfile creation
m7pr Sep 20, 2024
13c62a0
[skip style] [skip vbump] Restyle files
github-actions[bot] Sep 20, 2024
9653aa4
rename teal.lockfile.mode to "enabled" and "disabled"
m7pr Sep 20, 2024
ee89fdb
Merge branch '479_mirai_lockfile@main' of https://github.com/insights…
m7pr Sep 20, 2024
ab77120
remove section about user-specified lockfile from module_teal_lockfil…
m7pr Sep 20, 2024
3ffc3de
rephrase vignette wording
m7pr Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,13 @@ repos:
additional_dependencies:
- davidgohel/flextable # Error: package 'flextable' is not available
- davidgohel/gdtools # for flextable
- mirai
- checkmate
- future
- jsonlite
- lifecycle
- logger
- magrittr
- methods
gogonzo marked this conversation as resolved.
Show resolved Hide resolved
- promises
- renv
- rlang
- shiny
Expand Down
12 changes: 6 additions & 6 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,10 @@ Depends:
teal.slice (>= 0.5.1.9009)
Imports:
checkmate (>= 2.1.0),
future (>= 1.33.2),
jsonlite,
lifecycle (>= 0.2.0),
logger (>= 0.2.0),
methods,
promises (>= 1.3.0),
renv (>= 1.0.7),
rlang (>= 1.0.0),
shinyjs,
stats,
Expand All @@ -59,8 +56,10 @@ Imports:
Suggests:
bslib,
knitr (>= 1.42),
mirai (>= 1.1.1),
MultiAssayExperiment,
R6,
renv (>= 1.0.7),
rmarkdown (>= 2.23),
rvest,
shinytest2,
Expand All @@ -74,8 +73,9 @@ RdMacros:
lifecycle
Config/Needs/verdepcheck: rstudio/shiny, insightsengineering/teal.data,
insightsengineering/teal.slice, mllg/checkmate,
HenrikBengtsson/future, jeroen/jsonlite, r-lib/lifecycle,
daroczig/logger, rstudio/promises, rstudio/renv, r-lib/rlang,
jeroen/jsonlite, r-lib/lifecycle,
daroczig/logger, shikokuchuo/mirai, shikokuchuo/nanonext,
rstudio/renv, r-lib/rlang,
daattali/shinyjs, insightsengineering/teal.code,
insightsengineering/teal.logger, insightsengineering/teal.reporter,
insightsengineering/teal.widgets, rstudio/bslib, yihui/knitr,
Expand Down Expand Up @@ -106,6 +106,7 @@ Collate:
'module_snapshot_manager.R'
'module_teal.R'
'module_teal_data.R'
'module_teal_lockfile.R'
'module_teal_with_splash.R'
'module_transform_data.R'
'reporter_previewer_module.R'
Expand All @@ -116,7 +117,6 @@ Collate:
'teal_data_module-eval_code.R'
'teal_data_module-within.R'
'teal_data_utils.R'
'teal_lockfile.R'
'teal_reporter.R'
'teal_slices-store.R'
'teal_slices.R'
Expand Down
3 changes: 0 additions & 3 deletions R/init.R
Original file line number Diff line number Diff line change
Expand Up @@ -153,9 +153,6 @@ init <- function(data,
# log
teal.logger::log_system_info()

# invoke lockfile creation
teal_lockfile()

# argument transformations
## `modules` - landing module
landing <- extract_module(modules, "teal_module_landing")
Expand Down
6 changes: 3 additions & 3 deletions R/module_teal.R
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ ui_teal <- function(id,
footer,
teal.widgets::verbatim_popup_ui(ns("sessionInfo"), "Session Info", type = "link"),
br(),
downloadLink(ns("lockFile"), "Download .lock file"),
ui_teal_lockfile(ns("lockfile")),
textOutput(ns("identifier"))
)
)
Expand All @@ -156,6 +156,8 @@ srv_teal <- function(id, data, modules, filter = teal_slices()) {
moduleServer(id, function(input, output, session) {
logger::log_debug("srv_teal initializing.")

srv_teal_lockfile("lockfile")

output$identifier <- renderText(
paste0("Pid:", Sys.getpid(), " Token:", substr(session$token, 25, 32))
)
Expand All @@ -166,8 +168,6 @@ srv_teal <- function(id, data, modules, filter = teal_slices()) {
title = "SessionInfo"
)

output$lockFile <- teal_lockfile_downloadhandler()

# `JavaScript` code
run_js_files(files = "init.js")

Expand Down
201 changes: 201 additions & 0 deletions R/module_teal_lockfile.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,201 @@
#' 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.
#'
#' - **Working directory lockfile**: `teal`, by default, will 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::hide("lockFileLink")
}

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 = "")

if (!(mode %in% c("auto", "enabled", "disabled"))) {
stop("'teal.lockfile.mode' option can only be one of \"auto\", \"disabled\" or \"disabled\". ")
}

m7pr marked this conversation as resolved.
Show resolved Hide resolved
if (mode == "disabled") {
logger::log_debug("'teal.lockfile.mode' option is set to 'disabled'. 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 == "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 (!.is_lockfile_deps_installed()) {
warning("Automatic lockfile creation disabled. `mirai` and `renv` packages must be installed.")
shinyjs::hide("lockFileLink")
return(NULL)
}

# - 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
}
Loading
Loading