# Pure helpers for local/rebuild-missing.R, kept separate so local/tests can # source them without executing a rebuild. # Interleaved slice of the rebuild list. # # The list is alphabetical and build cost clusters by name (Rcpp*, Bioc*, # rstan*), so contiguous thirds would be badly unbalanced. Interleaving also # makes each shard's progress counter representative of the slot as a whole. shard_slice <- function(pkgs, split_into, split_index) { split_into <- as.integer(split_into) split_index <- as.integer(split_index) if (is.na(split_into) || is.na(split_index)) { stop("shard_slice(): split_into and split_index must be integers") } if (split_into < 1L || split_index < 1L || split_index > split_into) { stop(sprintf( "shard_slice(): need 1 <= split_index <= split_into, got %s of %s", split_index, split_into )) } # seq() errors on a descending range, which is what an empty list or a shard # index past the end would produce. if (length(pkgs) < split_index) { return(pkgs[0L]) } pkgs[seq.int(split_index, length(pkgs), by = split_into)] } # Packages that still need building, decided from the bucket rather than from # remembered progress. # # This is bincraft's `check_s3_root_package()` evaluated in bulk: an object # whose ETag equals CRAN's published MD5sum is byte-identical to CRAN's source, # so the build that was supposed to replace it has not happened yet. # # `etag_by_file` named by `_.tar.gz`, values are unquoted ETags # `cran_version` named by package # `cran_md5` named by `_` # # Unknown always means "already a binary", never "rebuild it", so an unreadable # CRAN index or a multipart ETag can never mass-schedule work. outstanding_packages <- function(pkgs, etag_by_file, cran_version, cran_md5) { if (length(pkgs) == 0L) { return(pkgs) } # An empty table indexes to zero length rather than to NA, which would # recycle the whole result away and silently report "nothing to build". lookup <- function(table, key) { if (length(table) == 0L) { return(rep(NA_character_, length(key))) } unname(as.character(table[key])) } version <- lookup(cran_version, pkgs) file <- sprintf("%s_%s.tar.gz", pkgs, version) etag <- lookup(etag_by_file, file) md5 <- lookup(cran_md5, paste(pkgs, version, sep = "_")) # No CRAN version means the package cannot be resolved to a tarball at all; # leave it in and let bincraft report why. unresolved <- is.na(version) # No object at the key: never built, so it is outstanding by definition. absent <- !unresolved & is.na(etag) # A multipart upload carries a compound ETag rather than an MD5. unknown <- !is.na(etag) & grepl("-", etag, fixed = TRUE) is_source <- !unresolved & !is.na(etag) & !unknown & !is.na(md5) & etag == md5 pkgs[unresolved | absent | is_source] } parse_rebuild_args <- function(args) { pos <- args[!startsWith(args, "--")] budget <- as.numeric(pos[3L]) list( split_into = as.integer(pos[1L]), split_index = as.integer(pos[2L]), budget_hours = if (is.na(budget)) 20 else budget ) }