### # Scope: List Packages for which the most recent CRAN release is not available ### library(furrr) library(cli) library(dplyr) library(data.table) last_versions_cran <- available.packages("https://cloud.r-project.org/src/contrib")[, c("Package", "Version")] arch <- c("amd64", "arm64") os_ids <- c("rhel8", "rhel9", "noble", "jammy", "alpine320") grid <- tidyr::expand_grid(arch = arch, os_ids = os_ids) # Define the function to check for missing packages check_package <- function(pkg_name, available_pkgs, version_cran, arch, os_id) { if (pkg_name %in% available_pkgs$Package) { version_devxy <- available_pkgs %>% filter(Package == pkg_name) %>% pull(Version) if (is.na(version_devxy) || version_cran != version_devxy) { # Package is missing or version mismatch return(data.frame(pkg_name = pkg_name, arch = arch, ID = os_id)) } } else { # Package completely missing in devxy return(data.frame(pkg_name = pkg_name, arch = arch, ID = os_id)) } return(NULL) # No mismatch, no entry added } # Run the mapping with parallel processing for each (arch, os_id) combination future::plan("multisession", workers = 5) pkgs_missing <- future_map2(grid$arch, grid$os_ids, ~ { # Prepare the URL and fetch available packages only once per (arch, os_id) repo_url <- sprintf("https://cran.devxy.io/%s/%s/latest/src/contrib", .x, .y) available_pkgs <- as.data.table(available.packages(contriburl = repo_url)[, c("Package", "Version")]) # Define the packages to check once cran_pkgs <- as.data.table(last_versions_cran) # Accumulate results in a list pkg_entries <- list() # Loop through each package name and check if it's missing for (pkg_name in cran_pkgs$Package) { version_cran <- cran_pkgs[Package == pkg_name, Version] result <- check_package(pkg_name, available_pkgs, version_cran, .x, .y) if (!is.null(result)) { pkg_entries[[length(pkg_entries) + 1]] <- result } } # Combine results for the current (arch, os_id) if (length(pkg_entries) > 0) { return(rbindlist(pkg_entries)) } else { return(data.table(pkg_name = character(), arch = character(), ID = character())) } }) df_missing_pkgs <- rbindlist(pkgs_missing, fill = TRUE) # Group and count missing packages by architecture and ID df_summary <- df_missing_pkgs %>% group_by(arch, ID) %>% arrange(arch, ID) %>% count() # Extract and copy missing package names for each architecture and ID combination extract_and_copy_pkgs <- function(df, arch, id, clip = FALSE) { pkgs <- df %>% filter(arch == arch, ID == id) %>% pull(pkg_name) # Print and copy to clipboard if needed formatted_pkgs <- gsub('"', "'", capture.output(dput(pkgs[1:300]))) cat(formatted_pkgs, "\n", sep = "") if (clip) { clipr::write_clip(formatted_pkgs) } return(pkgs) } # Usage for different architecture and ID combinations pkgs_missing_amd64_rhel8 <- extract_and_copy_pkgs(df_missing_pkgs, "amd64", "rhel8", clip = TRUE) pkgs_missing_amd64_rhel9 <- extract_and_copy_pkgs(df_missing_pkgs, "amd64", "rhel9", clip = TRUE) pkgs_missing_amd64_jammy <- extract_and_copy_pkgs(df_missing_pkgs, "amd64", "jammy", clip = TRUE) pkgs_missing_amd64_noble <- extract_and_copy_pkgs(df_missing_pkgs, "amd64", "noble", clip = TRUE) pkgs_missing_amd64_alpine320 <- extract_and_copy_pkgs(df_missing_pkgs, "amd64", "alpine320", clip = TRUE) pkgs_missing_arm64_rhel8 <- extract_and_copy_pkgs(df_missing_pkgs, "arm64", "rhel8", clip = TRUE) pkgs_missing_arm64_rhel9 <- extract_and_copy_pkgs(df_missing_pkgs, "arm64", "rhel9", clip = TRUE) pkgs_missing_arm64_jammy <- extract_and_copy_pkgs(df_missing_pkgs, "arm64", "jammy", clip = TRUE) pkgs_missing_arm64_noble <- extract_and_copy_pkgs(df_missing_pkgs, "arm64", "noble", clip = TRUE) pkgs_missing_arm64_alpine320 <- extract_and_copy_pkgs(df_missing_pkgs, "arm64", "alpine320", clip = TRUE)