#' Version Extractor for SmartCane Project #' #' This script scans your R scripts to find all used packages and extracts #' the currently installed versions. Use this to populate the package_manager.R #' with your actual working versions. #' #' Usage: #' source("extract_current_versions.R") #' #' Author: SmartCane Team #' Date: 2025-06-24 # ============================================================================= # PACKAGE DISCOVERY # ============================================================================= #' Extract packages from R scripts extract_packages_from_scripts <- function(script_dir = ".") { # Find all R files r_files <- list.files(script_dir, pattern = "\\.(R|Rmd)$", recursive = TRUE, full.names = TRUE) packages <- c() for (file in r_files) { cat("Scanning:", file, "\n") tryCatch({ content <- readLines(file, warn = FALSE) # Find library() calls library_matches <- regmatches(content, regexpr('library\\(["\']?([^"\'\\)]+)["\']?\\)', content)) library_packages <- gsub('library\\(["\']?([^"\'\\)]+)["\']?\\)', '\\1', library_matches) library_packages <- library_packages[library_packages != ""] # Find require() calls require_matches <- regmatches(content, regexpr('require\\(["\']?([^"\'\\)]+)["\']?\\)', content)) require_packages <- gsub('require\\(["\']?([^"\'\\)]+)["\']?\\)', '\\1', require_matches) require_packages <- require_packages[require_packages != ""] # Find package::function calls namespace_matches <- regmatches(content, gregexpr('[a-zA-Z][a-zA-Z0-9.]*::', content)) namespace_packages <- unique(unlist(lapply(namespace_matches, function(x) gsub('::', '', x)))) namespace_packages <- namespace_packages[namespace_packages != ""] packages <- c(packages, library_packages, require_packages, namespace_packages) }, error = function(e) { cat("Error reading", file, ":", e$message, "\n") }) } # Clean and deduplicate packages <- unique(packages) packages <- packages[!packages %in% c("", "base", "stats", "utils", "graphics", "grDevices")] return(sort(packages)) } #' Get current version of installed packages get_current_versions <- function(packages) { versions <- list() cat("\nChecking installed versions...\n") cat("===============================\n") for (pkg in packages) { if (pkg %in% rownames(installed.packages())) { version <- as.character(packageVersion(pkg)) versions[[pkg]] <- version cat(sprintf("āœ“ %-20s %s\n", pkg, version)) } else { cat(sprintf("āœ— %-20s NOT INSTALLED\n", pkg)) } } return(versions) } #' Generate package manager configuration generate_package_config <- function(versions) { cat("\n\nGenerating REQUIRED_PACKAGES configuration...\n") cat("=============================================\n\n") config_lines <- c( "# Package requirements with your current working versions", "REQUIRED_PACKAGES <- list(" ) # Group packages by category categories <- list( "Core data manipulation" = c("here", "dplyr", "tidyr", "readr", "readxl", "magrittr", "lubridate", "stringr"), "Spatial data" = c("sf", "terra", "exactextractr", "raster", "sp", "sf", "rgdal", "rgeos"), "Visualization" = c("tmap", "ggplot2", "RColorBrewer", "viridis", "scales"), "Statistical analysis" = c("lme4", "nlme", "mgcv", "survival", "cluster"), "Reporting" = c("knitr", "rmarkdown", "officedown", "officer", "flextable"), "Tidyverse" = c("tidyverse", "purrr", "forcats", "tibble"), "Other packages" = c() ) # Categorize packages categorized <- list() uncategorized <- names(versions) for (category in names(categories)) { cat_packages <- intersect(names(versions), categories[[category]]) if (length(cat_packages) > 0) { categorized[[category]] <- cat_packages uncategorized <- setdiff(uncategorized, cat_packages) } } # Add uncategorized packages if (length(uncategorized) > 0) { categorized[["Other packages"]] <- uncategorized } # Generate config for (category in names(categorized)) { config_lines <- c(config_lines, paste0(" # ", category)) packages_in_cat <- categorized[[category]] for (i in seq_along(packages_in_cat)) { pkg <- packages_in_cat[i] version <- versions[[pkg]] comma <- if (i == length(packages_in_cat) && category == names(categorized)[length(categorized)]) "" else "," # Add special comment for critical packages comment <- "" if (pkg == "tmap") comment <- " # CRITICAL: for tm_scale_continuous() syntax" if (pkg == "terra") comment <- " # CRITICAL: for raster processing" config_lines <- c(config_lines, sprintf(' "%s" = "%s"%s%s', pkg, version, comma, comment)) } if (category != names(categorized)[length(categorized)]) { config_lines <- c(config_lines, "") } } config_lines <- c(config_lines, ")") # Print to console cat(paste(config_lines, collapse = "\n")) # Save to file writeLines(config_lines, "generated_package_config.R") cat("\n\nšŸ“ Configuration saved to: generated_package_config.R\n") return(config_lines) } # ============================================================================= # MAIN EXECUTION # ============================================================================= main <- function() { cat("šŸ” SmartCane Package Version Extractor\n") cat("======================================\n\n") # Step 1: Find all packages used in scripts cat("Step 1: Scanning R scripts for package usage...\n") packages <- extract_packages_from_scripts() cat("\nFound packages:\n") cat(paste(packages, collapse = ", "), "\n") cat("\nTotal packages found:", length(packages), "\n") # Step 2: Get current versions cat("\nStep 2: Checking installed versions...\n") versions <- get_current_versions(packages) installed_count <- length(versions) missing_count <- length(packages) - installed_count cat(sprintf("\nšŸ“Š Summary: %d installed, %d missing\n", installed_count, missing_count)) if (missing_count > 0) { missing_packages <- setdiff(packages, names(versions)) cat("\nāš ļø Missing packages:\n") cat(paste(missing_packages, collapse = ", "), "\n") cat("\nYou may want to install these first, then re-run this script.\n") } # Step 3: Generate configuration if (length(versions) > 0) { cat("\nStep 3: Generating package manager configuration...\n") config <- generate_package_config(versions) cat("\nāœ… Next steps:\n") cat("1. Review generated_package_config.R\n") cat("2. Copy the REQUIRED_PACKAGES list to package_manager.R\n") cat("3. Adjust any versions as needed\n") cat("4. Run package_manager.R\n") } else { cat("\nāŒ No installed packages found. Install packages first.\n") } } # Run the extraction main()