Some checks failed
ci/crow/cron/process-updates/2 Pipeline was successful
ci/crow/cron/process-updates/11 Pipeline was successful
ci/crow/cron/process-updates/9 Pipeline was successful
ci/crow/cron/process-updates/16 Pipeline was successful
ci/crow/cron/process-updates/15 Pipeline was successful
ci/crow/cron/process-updates/8 Pipeline was successful
ci/crow/cron/process-updates/13 Pipeline was successful
ci/crow/cron/process-updates/12 Pipeline was successful
ci/crow/cron/process-updates/10 Pipeline was successful
ci/crow/cron/process-updates/14 Pipeline was successful
ci/crow/cron/process-updates/4 Pipeline was successful
ci/crow/cron/auto-apply-patches Pipeline failed
ci/crow/cron/weekly-audit-missing/1 Pipeline was successful
ci/crow/cron/weekly-audit-missing/2 Pipeline was successful
ci/crow/cron/weekly-audit-missing/4 Pipeline was successful
ci/crow/cron/weekly-audit-missing/5 Pipeline was successful
ci/crow/cron/weekly-audit-missing/6 Pipeline was successful
ci/crow/cron/process-updates/3 Pipeline was successful
ci/crow/cron/process-updates/5 Pipeline was successful
ci/crow/cron/process-updates/7 Pipeline was successful
ci/crow/cron/process-updates/6 Pipeline failed
ci/crow/cron/process-updates/1 Pipeline failed
Step 1 of rpkgs/bincraft#211: pass the metadata database explicitly so bincraft can drop its implicit production defaults. ## Changes - Pass `metadata_db_*` explicitly to every per-minor `upload_package_index()` call in `reindex.yaml`, `process-updates.yaml`, `weekly-rebuild-reindex.yaml`, `build-all-versions.yaml` and `prune-stale-flat-binaries.yaml`. - Replace `|| true` in those per-minor loops with a list of failed minors: every minor is still attempted, then the step exits 1 naming the ones that failed. - Give the "Upload package indexes" step of `build-all-versions.yaml` the `PGPASS` secret. It never had it, so its per-minor reindexes always aborted and `|| true` hid that. - Run the CDN purge in `process-updates.yaml` and `prune-stale-flat-binaries.yaml` even when a reindex failed, as `reindex.yaml` and `weekly-rebuild-reindex.yaml` already do, because the generic index was still replaced. - `local/repair-built-stamp.R` passes the database too, and fails once all minors are tried instead of only printing the error. The generic (non-per-minor) calls are unchanged: they never read the database. ## Behaviour change A per-minor reindex that fails now turns the pipeline red instead of passing silently. Expect build-all-versions runs to start reindexing per-minor slots for real, since they now have the password. ## Ordering Merge this before rpkgs/bincraft's companion PR is released: `local/install-bincraft.R` installs the latest bincraft tag, and the explicit arguments work with both the current and the next release. Reviewed-on: #234
194 lines
5.6 KiB
R
194 lines
5.6 KiB
R
### Rebuild one shard of a slot's missing-binary list.
|
|
#
|
|
# Usage: Rscript local/rebuild-missing.R <split_into> <split_index> [budget_hours]
|
|
#
|
|
# The list itself comes from local/fetch-rebuild-packages-from-issue.R, which
|
|
# writes $REBUILD_PKG_LIST (default /tmp/rebuild_pkgs.txt).
|
|
#
|
|
# Two properties matter here and are the reason this is a script rather than an
|
|
# `R -q -e` argument in the pipeline:
|
|
#
|
|
# * it is restartable. The outstanding set is re-derived from the bucket on
|
|
# every start, so a shard that died resumes where it stopped without any
|
|
# progress file, and without replaying thousands of per-package HEADs.
|
|
# * it terminates. A wall-clock budget stops the loop cleanly instead of the
|
|
# run having to be killed, which is what previously skipped the re-index and
|
|
# CDN purge and left rebuilt binaries hidden behind stale edge copies.
|
|
|
|
options(error = function() {
|
|
cat("ERROR:", geterrmessage(), "\n", file = stdout())
|
|
traceback(2)
|
|
q(status = 1)
|
|
})
|
|
|
|
library(bincraft, quietly = TRUE)
|
|
|
|
source(file.path("local", "rebuild-missing-helpers.R"))
|
|
|
|
args <- parse_rebuild_args(commandArgs(trailingOnly = TRUE))
|
|
if (is.na(args$split_into) || is.na(args$split_index)) {
|
|
stop("usage: rebuild-missing.R <split_into> <split_index> [budget_hours]")
|
|
}
|
|
|
|
list_file <- Sys.getenv("REBUILD_PKG_LIST", "/tmp/rebuild_pkgs.txt")
|
|
pkgs <- if (file.exists(list_file)) readLines(list_file) else character(0)
|
|
pkgs <- pkgs[nzchar(pkgs)]
|
|
if (length(pkgs) == 0L) {
|
|
cat("Nothing to rebuild\n")
|
|
q("no")
|
|
}
|
|
|
|
excluded <- jsonlite::fromJSON("local/excluded-packages.json")[["package"]]
|
|
pkgs <- setdiff(pkgs, excluded)
|
|
|
|
mine <- shard_slice(pkgs, args$split_into, args$split_index)
|
|
cat(sprintf(
|
|
"Shard %s/%s: %s of %s listed packages\n",
|
|
args$split_index,
|
|
args$split_into,
|
|
length(mine),
|
|
length(pkgs)
|
|
))
|
|
|
|
### Resume: ask the bucket what is still outstanding
|
|
|
|
codename <- bincraft::set_codename(NULL)
|
|
local_machine <- Sys.info()[["machine"]]
|
|
arch <- if (grepl("arm64|aarch64", local_machine)) "arm64" else "amd64"
|
|
slot_dir <- sprintf(
|
|
"devxy-rpkgs-binaries/%s/%s/latest/src/contrib",
|
|
arch,
|
|
codename
|
|
)
|
|
|
|
s3fs::s3_file_system(
|
|
aws_access_key_id = Sys.getenv("B2_S3_ACCESS_KEY"),
|
|
aws_secret_access_key = Sys.getenv("B2_S3_SECRET_KEY"),
|
|
endpoint = "https://s3.eu-central-003.backblazeb2.com",
|
|
region_name = "eu-central-003",
|
|
refresh = TRUE
|
|
)
|
|
|
|
# One paginated listing instead of a HEAD per package. Not recursed: the
|
|
# rebuild passes no `is_r_minor_sensitive`, so it only ever targets the flat
|
|
# path, and the resume filter matches that scope deliberately.
|
|
info <- tryCatch(s3fs::s3_dir_info(slot_dir), error = function(e) NULL)
|
|
etag_by_file <- if (is.null(info) || nrow(info) == 0L) {
|
|
cat(sprintf(
|
|
"WARNING: could not list %s; building the whole shard\n",
|
|
slot_dir
|
|
))
|
|
stats::setNames(character(), character())
|
|
} else {
|
|
stats::setNames(
|
|
gsub('^"|"$', "", as.character(info$etag)),
|
|
basename(as.character(info$uri))
|
|
)
|
|
}
|
|
|
|
cran <- tryCatch(
|
|
{
|
|
con <- gzcon(url(
|
|
"https://cloud.r-project.org/src/contrib/PACKAGES.gz",
|
|
open = "rb"
|
|
))
|
|
on.exit(close(con), add = TRUE)
|
|
read.dcf(con, fields = c("Package", "Version", "MD5sum"))
|
|
},
|
|
error = function(e) {
|
|
cat(sprintf(
|
|
"WARNING: could not read CRAN's index (%s)\n",
|
|
conditionMessage(e)
|
|
))
|
|
NULL
|
|
}
|
|
)
|
|
cran_version <- stats::setNames(character(), character())
|
|
cran_md5 <- stats::setNames(character(), character())
|
|
if (!is.null(cran)) {
|
|
cran_version <- stats::setNames(
|
|
as.character(cran[, "Version"]),
|
|
as.character(cran[, "Package"])
|
|
)
|
|
keep <- !is.na(cran[, "MD5sum"])
|
|
cran_md5 <- stats::setNames(
|
|
as.character(cran[keep, "MD5sum"]),
|
|
paste(cran[keep, "Package"], cran[keep, "Version"], sep = "_")
|
|
)
|
|
}
|
|
|
|
before <- length(mine)
|
|
mine <- outstanding_packages(mine, etag_by_file, cran_version, cran_md5)
|
|
cat(sprintf(
|
|
"Resume: %s of %s already carry a binary; %s outstanding\n",
|
|
before - length(mine),
|
|
before,
|
|
length(mine)
|
|
))
|
|
|
|
if (length(mine) == 0L) {
|
|
cat("Nothing outstanding for this shard\n")
|
|
q("no")
|
|
}
|
|
|
|
### Build
|
|
|
|
options(
|
|
crayon.enabled = TRUE,
|
|
Ncpus = as.integer(Sys.getenv("NCPUS", "2")),
|
|
future.globals.onReference = NULL
|
|
)
|
|
|
|
started <- Sys.time()
|
|
n <- length(mine)
|
|
completed <- 0L
|
|
for (i in seq_along(mine)) {
|
|
elapsed <- as.numeric(difftime(Sys.time(), started, units = "hours"))
|
|
if (elapsed > args$budget_hours) {
|
|
cat(sprintf(
|
|
"Budget of %sh reached after %d/%d packages; stopping cleanly. The next run resumes from the bucket.\n",
|
|
args$budget_hours,
|
|
completed,
|
|
n
|
|
))
|
|
break
|
|
}
|
|
|
|
x <- mine[i]
|
|
cat(sprintf("[%d/%d] %s\n", i, n, x))
|
|
tryCatch(
|
|
bincraft::build_binary_package(
|
|
x,
|
|
tag_limit = 1L,
|
|
patches = "local/patches",
|
|
s3_endpoint = "https://s3.eu-central-003.backblazeb2.com",
|
|
s3_region = "eu-central-003",
|
|
s3_bucket = "devxy-rpkgs-binaries",
|
|
s3_access_key_id = Sys.getenv("B2_S3_ACCESS_KEY"),
|
|
s3_secret_access_key = Sys.getenv("B2_S3_SECRET_KEY"),
|
|
metadata_db_host = "r-binaries.devxy.io",
|
|
metadata_db_name = "build_metadata",
|
|
metadata_db_table = "single_builds",
|
|
metadata_db_user = "rpkgs",
|
|
metadata_db_password = Sys.getenv("PGPASS"),
|
|
metadata_db_sslmode = "verify-full",
|
|
metadata_db_port = 15432,
|
|
archive = TRUE,
|
|
upload = TRUE,
|
|
store_build_metadata = TRUE
|
|
),
|
|
error = function(e) {
|
|
cat(sprintf("ERROR building %s - %s\n", x, conditionMessage(e)))
|
|
}
|
|
)
|
|
completed <- completed + 1L
|
|
}
|
|
|
|
cat(sprintf(
|
|
"Shard %s/%s finished: %d/%d packages processed in %.1fh\n",
|
|
args$split_index,
|
|
args$split_into,
|
|
completed,
|
|
n,
|
|
as.numeric(difftime(Sys.time(), started, units = "hours"))
|
|
))
|