diff --git a/R/sysreqs.R b/R/sysreqs.R index 4e5b283f58..ef16fad334 100644 --- a/R/sysreqs.R +++ b/R/sysreqs.R @@ -40,19 +40,77 @@ sysreqs_db_list <- function(sysreqs_platform = NULL) { ) } +check_sysreqs_enabled <- function() { + sysreqs_enabled <- remote( + function() { + config <- pkgdepends::current_config() + config$get("sysreqs") + } + ) + + if (!sysreqs_enabled) { + cli::cli_alert_info( + "System requirements checking is disabled in the config." + ) + cli::cli_alert_info( + "Use {.code Sys.setenv('PKG_SYSREQS' = 'TRUE')} + or {.code options(pkg.sysreqs = TRUE)}." + ) + + # Return an empty data frame with the expected structure + result <- data.frame( + system_package = character(0), + installed = logical(0), + packages = I(list()), + pre_install = I(list()), + post_install = I(list()) + ) + class(result) <- c("pkg_sysreqs_check_result", class(result)) + return(pak_preformat(result)) + } + + return(NULL) +} + sysreqs_check_installed <- function(packages = NULL, library = .libPaths()[1]) { load_extra("pillar") - remote( + + # Check if sysreqs is enabled, return early if disabled + disabled_result <- check_sysreqs_enabled() + if (!is.null(disabled_result)) { + return(invisible(disabled_result)) + } + + result <- remote( function(...) { ret <- pkgdepends::sysreqs_check_installed(...) asNamespace("pak")$pak_preformat(ret) }, list(packages = packages, library = library) ) + + # Inform about detection method + if (nrow(result) > 0) { + cli::cli_alert_info( + "System packages checked via system package manager only." + ) + cli::cli_alert_info( + "Software in non-standard locations may not be detected." + ) + } + + result } sysreqs_fix_installed <- function(packages = NULL, library = .libPaths()[1]) { load_extra("pillar") + + # Check if sysreqs is enabled, return early if disabled + disabled_result <- check_sysreqs_enabled() + if (!is.null(disabled_result)) { + return(invisible(disabled_result)) + } + invisible(remote( function(...) { ret <- pkgdepends::sysreqs_fix_installed(...) @@ -62,6 +120,7 @@ sysreqs_fix_installed <- function(packages = NULL, library = .libPaths()[1]) { )) } + #' Calculate system requirements of one of more packages #' #' @inheritParams pkg_install @@ -110,7 +169,15 @@ pkg_sysreqs <- function( sysreqs_platform = NULL ) { load_extra("pillar") - remote( + # Check if sysreqs support is enabled + sysreqs_enabled <- remote( + function() { + config <- pkgdepends::current_config() + config$get("sysreqs") + } + ) + + result <- remote( function(...) { get("pkg_sysreqs_internal", asNamespace("pak"))(...) }, @@ -121,6 +188,26 @@ pkg_sysreqs <- function( sysreqs_platform = sysreqs_platform ) ) + + # Add informational message if results are shown + if (sysreqs_enabled && length(result$install_scripts) > 0) { + cli::cli_alert_info( + "System packages detected via system package manager only." + ) + cli::cli_alert_info( + "Software in non-standard locations may require manual verification." + ) + } else if (!sysreqs_enabled) { + cli::cli_alert_info( + "System requirements lookup is disabled." + ) + cli::cli_alert_info( + "Enable with {.code Sys.setenv('PKG_SYSREQS' = 'TRUE')} + or {.code options(pkg.sysreqs = TRUE)}." + ) + } + + result } pkg_sysreqs_internal <- function( @@ -180,6 +267,17 @@ format.pak_sysreqs <- function(x, ...) { out } + # Add warning message about detection limitations + warning_msg <- c( + "", + cli$rule(left = "System package detection", col = "yellow"), + paste( + cli$col_yellow(cli$symbol$warning), + "System packages are detected via the system package manager only." + ), + "Software installed in non-standard locations may not be detected." + ) + c( cli$rule(left = "Install scripts", right = label), x$pre_install, @@ -195,7 +293,8 @@ format.pak_sysreqs <- function(x, ...) { " ", vcapply(pkgs, function(x) paste(cisort(x), collapse = ", ")) ) - } + }, + warning_msg ) } diff --git a/R/sysreqsdocs.R b/R/sysreqsdocs.R index eb2585d2f6..f8ab5d1f37 100644 --- a/R/sysreqsdocs.R +++ b/R/sysreqsdocs.R @@ -205,3 +205,39 @@ sysreqs_fix_installed <- sysreqs_fix_installed #' sysreqs_list_system_packages()[1:10,] sysreqs_list_system_packages + +#' System requirements detection limitations +#' +#' @description +#' System requirements detection in pak only considers packages installed via the system package manager. +#' Supported package managers include: +#' * `apt` on Debian/Ubuntu systems +#' * `yum`/`dnf` on RedHat/CentOS/Fedora systems +#' * `zypper` on openSUSE/SUSE systems +#' * `apk` on Alpine systems +#' +#' pak does **not** detect software installed via: +#' * Environment modules (e.g., lmod, environment modules) +#' * Custom compilation from source +#' * Alternative package managers (e.g., conda, spack, nix, homebrew) +#' * User-space installations +#' * Software loaded via environment variables +#' +#' If your system has software installed in non-standard locations, you may need to: +#' * Install the required system packages via your system package manager +#' * Disable system requirements checking with `PKG_SYSREQS=FALSE` +#' * Use `options(pkg.sysreqs = FALSE)` to disable system requirements globally +#' +#' Use [sysreqs_status()] to check your current configuration. +#' +#' @name sysreqs_detection_limitations +#' @family system requirements functions +#' @keywords internal +#' @examplesIf Sys.getenv("IN_PKGDOWN") == "true" +#' # Check current system requirements status +#' sysreqs_status() +#' +#' # Disable system requirements globally +#' options(pkg.sysreqs = FALSE) + +check_sysreqs_enabled diff --git a/R/utils.R b/R/utils.R index 8b13c3baf3..fcb6077405 100644 --- a/R/utils.R +++ b/R/utils.R @@ -359,3 +359,68 @@ rbind_expand <- function(..., .list = list()) { cisort <- function(x) { x[order(tolower(x))] } + +sysreqs_status <- function() { + config_info <- remote( + function() { + config <- pkgdepends::current_config() + list( + enabled = config$get("sysreqs"), + platform = config$get("sysreqs_platform"), + supported = pkgdepends::sysreqs_is_supported() + ) + } + ) + + # Check source of configuration + env_sysreqs <- Sys.getenv("PKG_SYSREQS", "") + opt_sysreqs <- getOption("pkg.sysreqs", NULL) + + config_source <- if (nzchar(env_sysreqs)) { + "environment variable PKG_SYSREQS" + } else if (!is.null(opt_sysreqs)) { + "option pkg.sysreqs" + } else { + "default" + } + + cli::cli_h2("System Requirements Configuration") + + if (config_info$enabled) { + cli::cli_alert_success( + "System requirements: {.strong enabled} (via {config_source})" + ) + + cli::cli_alert_info( + "Platform: {.val {config_info$platform}}" + ) + cli::cli_alert_info( + "Platform supported: {.val {config_info$supported}}" + ) + cli::cli_alert_warning( + "Detection method: {.strong system package manager only}" + ) + cli::cli_text("") + cli::cli_text( + " + Software in non-standard locations will {.strong not} be detected:" + ) + cli::cli_ul(c( + "Environment modules (lmod)", + "Custom compilation from source", + "Alternative package managers (conda, spack, nix)", + "User-space installations" + )) + } else { + cli::cli_alert_info( + "System requirements: {.strong disabled} (via {config_source})" + ) + cli::cli_text("") + cli::cli_text("To enable system requirements:") + cli::cli_code("Sys.setenv('PKG_SYSREQS' = 'TRUE')") + cli::cli_text("or") + cli::cli_code("options(pkg.sysreqs = TRUE)") + } + + invisible(config_info) +}