R/model_deps.R

Defines functions install_model_deps model_deps

Documented in model_deps

#' Report optional model dependencies (no installation performed)
#'
#' Reports optional packages from the package
#' `Suggests` field, including model, documentation, and testing packages.
#' This function **never installs** packages. It reports
#' which packages are required and which are currently missing, and prints
#' a ready-to-copy command you can run to install the missing ones manually.
#'
#' You can add to the discovered packages for testing or CI with
#' `options(writeAlizer.required_pkgs = c("pkgA", "pkgB (>= 1.2.3)"))`.
#' Any version qualifiers you include are preserved in the `required` output,
#' but stripped for the availability check in `missing`. Installed versions are
#' not compared against those qualifiers.
#'
#' @return
#' A named list:
#' \describe{
#'   \item{required}{Character vector of discovered package tokens (may include version qualifiers),
#'     e.g. \code{c("glmnet (>= 4.1)", "ranger")}. This is the union of the package
#'     \emph{Suggests} field and the optional \code{writeAlizer.required_pkgs} override.}
#'   \item{missing}{Character vector of base package names that are not installed,
#'     e.g. \code{c("glmnet", "ranger")}.}
#' }
#'
#' The function also emits a message. If nothing is missing, it reports that all
#' required packages are installed. Otherwise, it lists the missing packages and
#' prints a copy-paste \code{install.packages()} command.
#'
#' @examples
#' md <- model_deps()
#' md$missing
#'
#' @importFrom utils packageDescription
#' @import cli
#' @export
model_deps <- function() {
  # helpers
  parse_suggests <- function(x) {
    if (is.null(x) || length(x) == 0L || is.na(x)) return(character(0))
    x <- gsub("[\r\n]+", " ", x)
    tokens <- trimws(unlist(strsplit(x, ",", fixed = TRUE), use.names = FALSE))
    unique(tokens[nzchar(tokens)])
  }
  strip_qualifier <- function(x) sub("\\s*\\(.*\\)$", "", x)
  is_available <- function(pkg) isTRUE(requireNamespace(pkg, quietly = TRUE))

  # read Suggests from installed DESCRIPTION
  suggests <- utils::packageDescription("writeAlizer", fields = "Suggests")
  pkgs_raw <- parse_suggests(suggests)

  # optional test/CI hook: allow callers to inject/override required packages
  extra <- getOption("writeAlizer.required_pkgs", character(0))
  if (is.null(extra)) {
    extra <- character(0)
  } else {
    extra <- trimws(as.character(extra))
    extra <- extra[!is.na(extra) & nzchar(extra)]
  }

  # union (preserve qualifiers), then unique
  pkgs_raw <- unique(c(pkgs_raw, extra))

  if (length(pkgs_raw) == 0L) {
    cli::cli_alert_info("No optional model dependencies discovered.")
    return(list(required = character(0), missing = character(0)))
  }

  base_names <- unique(strip_qualifier(pkgs_raw))
  have <- vapply(base_names, is_available, logical(1))
  missing <- base_names[!have]

  if (length(missing) == 0L) {
    cli::cli_alert_success("All required packages are installed: {paste(base_names, collapse = ', ')}")
  } else {
    cli::cli_alert_danger("Missing required packages:")
    cli::cli_ul(missing)
    cmd <- sprintf('install.packages(c("%s"))', paste(missing, collapse = '", "'))
    cli::cli_code(cmd)
  }

  list(required = pkgs_raw, missing = missing)
}

#' @keywords internal
#' @noRd
install_model_deps <- function(...) {
  .Deprecated("model_deps", package = "writeAlizer",
              msg = "install_model_deps() was removed. Use model_deps().")
  model_deps()
}

Try the writeAlizer package in your browser

Any scripts or data that you put into this service are public.

writeAlizer documentation built on Sept. 17, 2026, 1:08 a.m.