Skip to content

Commit

Permalink
Prevent execution when modules are not verified
Browse files Browse the repository at this point in the history
  • Loading branch information
anthonysena committed Dec 13, 2023
1 parent 9a98c44 commit fb092b7
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 33 deletions.
5 changes: 4 additions & 1 deletion R/Execution.R
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ execute <- function(analysisSpecifications,
)
}
modules <- ensureAllModulesInstantiated(analysisSpecifications)
if (isFALSE(modules$allModulesInstalled)) {
stop("Stopping execution due to module issues")
}

if (is.null(executionScriptFolder)) {
executionScriptFolder <- tempfile("strategusTempSettings")
Expand All @@ -79,7 +82,7 @@ execute <- function(analysisSpecifications,
keyringName = keyringName
)
}
dependencies <- extractDependencies(modules)
dependencies <- extractDependencies(modules$modules)


fileName <- generateTargetsScript(
Expand Down
66 changes: 48 additions & 18 deletions R/ModuleInstantiation.R
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,15 @@
#'
#' @template AnalysisSpecifications
#'
#' @template forceVerification
#'
#' @return
#' A tibble listing the instantiated modules.
#' A list containing the install status of all modules
#' (TRUE if all are installed properly) and a tibble listing
#' the instantiated modules.
#'
#' @export
ensureAllModulesInstantiated <- function(analysisSpecifications) {
ensureAllModulesInstantiated <- function(analysisSpecifications, force = FALSE) {
modules <- getModuleTable(analysisSpecifications, distinct = TRUE)

# Verify only one version per module:
Expand Down Expand Up @@ -78,13 +82,30 @@ ensureAllModulesInstantiated <- function(analysisSpecifications) {
for (i in 1:nrow(modules)) {
status <- verifyModuleInstallation(
module = modules$module[i],
version = modules$version[i]
version = modules$version[i],
forceVerification = forceVerification
)
moduleInstallStatus <- append(status, moduleInstallStatus)
moduleInstallStatus[[length(moduleInstallStatus) + 1]] <- status
}
attr(modules, 'moduleInstallStatus') <- moduleInstallStatus

return(modules)
installStatus <- unlist(lapply(moduleInstallStatus, FUN = function(x) { x$moduleInstalled }))
if (!all(installStatus)) {
problemModules <- status[!installStatus]
message("There were ", length(problemModules), " issue(s) found with your Strategus modules!")
for (i in seq_along(problemModules)) {
message("Issue #", i, ": Module ", problemModules[[i]]$moduleFolder, " could not install the following R packages:")
print(problemModules[[i]]$issues)
}
message("To fix these issues, open the module project at the path specified above and re-run \"renv::restore()\" and correct all issues")
}

return(
list(
allModulesInstalled = all(installStatus),
modules = modules
)
)
}


Expand All @@ -110,17 +131,15 @@ ensureAllModulesInstantiated <- function(analysisSpecifications) {
#'
#' @param version The version of the module to verify (i.e. "0.2.1")
#'
#' @param forceVerification When set to TRUE, the verification process is forced
#' to re-evaluate if the module is properly installed. The default is FALSE
#' since if the module is successfully validated by this function, it will cache
#' the hash value of the module's renv.lock file in the file system so it can
#' by-pass running this check every time.
#' @param silent When TRUE output of this verification process is suppressed
#'
#' @template forceVerification
#'
#' @return
#' A list with the output of the consistency check
#'
#' @export
verifyModuleInstallation <- function(module, version, forceVerification = FALSE) {
verifyModuleInstallation <- function(module, version, silent = FALSE, forceVerification = FALSE) {
# Internal helper function
verifyModuleInstallationReturnValue <- function(moduleFolder, moduleInstalled, issues = NULL) {
returnVal <- list(
Expand All @@ -133,7 +152,9 @@ verifyModuleInstallation <- function(module, version, forceVerification = FALSE)

moduleFolder <- getModuleFolder(module, version)
if (!dir.exists(moduleFolder)) {
warn("Module ", module, ", Version: ", version, " not found at: ", moduleFolder, ". This means the module was never installed.")
if (!silent) {
warn("Module ", module, ", Version: ", version, " not found at: ", moduleFolder, ". This means the module was never installed.")
}
return(
verifyModuleInstallationReturnValue(
moduleFolder = moduleFolder,
Expand All @@ -142,14 +163,17 @@ verifyModuleInstallation <- function(module, version, forceVerification = FALSE)
)
}

message("Verifying module: ", module, ", (", version, ") at ", moduleFolder, "...", appendLF = F)

if (!silent) {
message("Verifying module: ", module, ", (", version, ") at ", moduleFolder, "...", appendLF = F)
}
moduleStatusFileName <- "moduleStatus.txt"
renvLockFileName <- "renv.lock"

# If the lock file doesn't exist, we're not sure if we're dealing with a module.
if (!file.exists(file.path(moduleFolder, renvLockFileName))) {
message("ERROR - renv.lock file missing.")
if (!silent) {
message("ERROR - renv.lock file missing.")
}
return(
verifyModuleInstallationReturnValue(
moduleFolder = moduleFolder,
Expand All @@ -176,7 +200,9 @@ verifyModuleInstallation <- function(module, version, forceVerification = FALSE)
# If the values match, the module is installed correctly
# return and exit
if (lockfileHashFromModuleStatusFile == lockfileHash) {
message("MODULE READY!")
if (!silent) {
message("MODULE READY!")
}
return(
verifyModuleInstallationReturnValue(
moduleFolder = moduleFolder,
Expand Down Expand Up @@ -253,7 +279,9 @@ verifyModuleInstallation <- function(module, version, forceVerification = FALSE)
moduleInstalled <- nrow(issues) == 0

if (isTRUE(moduleInstalled)) {
message("MODULE READY!")
if (!silent) {
message("MODULE READY!")
}
# Write the contents of the md5 hash of the module's
# renv.lock file to the file system to note that the
# module's install status was successful and verified
Expand All @@ -262,7 +290,9 @@ verifyModuleInstallation <- function(module, version, forceVerification = FALSE)
targetFile = file.path(moduleFolder, "moduleStatus.txt")
)
} else {
message("MODULE HAS ISSUES!")
if (!silent) {
message("MODULE HAS ISSUES!")
}
}

return(
Expand Down
3 changes: 3 additions & 0 deletions R/ResultModelCreation.R
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ createResultDataModels <- function(analysisSpecifications,
checkmate::reportAssertions(collection = errorMessages)

modules <- ensureAllModulesInstantiated(analysisSpecifications)
if (isFALSE(modules$allModulesInstalled)) {
stop("Stopping execution due to module issues")
}


if (is.null(executionScriptFolder)) {
Expand Down
5 changes: 5 additions & 0 deletions man-roxygen/forceVerification.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#' @param forceVerification When set to TRUE, the verification process is forced
#' to re-evaluate if a module is properly installed. The default is FALSE
#' since if a module is successfully validated, the module will contain
#' the hash value of the module's renv.lock file in the file system so it can
#' by-pass running this check every time.
12 changes: 10 additions & 2 deletions man/ensureAllModulesInstantiated.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 11 additions & 5 deletions man/verifyModuleInstallation.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions tests/testthat/setup.R
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,17 @@ if (dir.exists(Sys.getenv("DATABASECONNECTOR_JAR_FOLDER"))) {
tableSuffix <- paste0(substr(.Platform$OS.type, 1, 3), format(Sys.time(), "%y%m%d%H%M%S"), sample(1:100, 1))
tableSuffix <- abs(digest::digest2int(tableSuffix))

tempDir <- "C:/TEMP/strategus_test" #tempfile()
tempDir <- tempfile()
tempDir <- gsub("\\\\", "/", tempDir) # Correct windows path
renvCachePath <- file.path(tempDir, "strategus/renv")
moduleFolder <- file.path(tempDir, "strategus/modules")
Sys.setenv("INSTANTIATED_MODULES_FOLDER" = moduleFolder)
# withr::defer(
# {
# unlink(c(tempDir, renvCachePath, moduleFolder), recursive = TRUE, force = TRUE)
# },
# testthat::teardown_env()
# )
withr::defer(
{
unlink(c(tempDir, renvCachePath, moduleFolder), recursive = TRUE, force = TRUE)
},
testthat::teardown_env()
)

# Assemble a list of connectionDetails for the tests -----------
connectionDetailsList <- list()
Expand Down

0 comments on commit fb092b7

Please sign in to comment.