Major Changes: - NEW: Scripts 09 & 10 for KPI calculation and enhanced reporting - NEW: Shell script wrappers (01-10) for easier execution - NEW: R packages flextable and officer for enhanced Word reports - NEW: DEPLOYMENT_README.md with complete deployment guide - RENAMED: Numbered R scripts (02, 03, 04) for clarity - REMOVED: Old package management scripts (using renv only) - UPDATED: Workflow now uses scripts 09->10 instead of 05 Files Changed: 90+ files New Packages: flextable, officer New Scripts: 09_run_calculate_kpis.sh, 10_run_kpi_report.sh Documentation: DEPLOYMENT_README.md, EMAIL_TO_ADMIN.txt See DEPLOYMENT_README.md for full deployment instructions.
201 lines
6.8 KiB
R
201 lines
6.8 KiB
R
#' 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()
|