#!/usr/bin/env Rscript # Validate local/patches/registry.json: schema, referenced patch files, and # ambiguous overlaps. Exits 1 on any problem. Used by pre-commit and CI. # # Defaults to local/patches/registry.json. To validate a candidate registry # without touching the real one (e.g. from the patch proposer), set: # PATCH_DIR directory patch-file paths resolve against (default local/patches) # REGISTRY_FILE registry.json to validate (default /registry.json) dir <- Sys.getenv("PATCH_DIR", unset = "local/patches") registry_file <- Sys.getenv( "REGISTRY_FILE", unset = file.path(dir, "registry.json") ) if (!file.exists(registry_file)) { cat("No registry.json found; nothing to validate.\n") quit(status = 0L) } or_q <- function(x) if (is.null(x)) "?" else x reg <- jsonlite::fromJSON(registry_file, simplifyVector = FALSE) required <- c("package", "versions", "platforms", "reason") errs <- character(0L) for (i in seq_along(reg)) { e <- reg[[i]] missing <- setdiff(required, names(e)) if (length(missing) > 0L) { errs <- c( errs, sprintf( "entry %d (%s): missing %s", i, if (is.null(e$package)) "?" else e$package, toString(missing) ) ) } if (!is.null(e$patch)) { p <- file.path(dir, e$patch) if (!file.exists(p)) { errs <- c( errs, sprintf("entry %d (%s): patch file '%s' missing", i, e$package, p) ) } } } # Ambiguous overlap: two entries for the same package with identical platforms # and versions. keys <- vapply( reg, function(e) { sprintf( "%s|%s|%s", or_q(e$package), paste(sort(as.character(unlist(e$platforms))), collapse = ","), or_q(e$versions) ) }, character(1L) ) dups <- keys[duplicated(keys)] if (length(dups) > 0L) { errs <- c( errs, sprintf("ambiguous duplicate entries: %s", toString(unique(dups))) ) } if (length(errs) > 0L) { cat("Patch registry validation FAILED:\n") cat(paste0(" - ", errs, "\n")) quit(status = 1L) } cat(sprintf( "Patch registry OK (%d %s).\n", length(reg), if (length(reg) == 1L) "entry" else "entries" ))