mirror of
https://github.com/jmcorgan/fips.git
synced 2026-10-05 11:08:25 +00:00
Have the package build name its output instead of searching for it
build-deb-container.sh chose the package to return by listing the output directory for fips_*_*.deb files modified in the last ten minutes and taking the one that sorted last by name. Any package already in that directory that sorted higher, such as one with a larger version left by an earlier run, was returned instead of the package just built, and every caller installed, tested or published that stale file. build-deb.sh now takes --name-file and writes the basename of the package it produced there. The container build passes a fresh per-run directory for that file, reads the name back, and fails if the build did not name a package, if the name is not a package file name, or if the named file does not exist. The last line of stdout is still the package path, so callers are unchanged. The deb-install harness had the same defect in its own fallback build: it listed its cache directory after building and took the first file. It now clears the cache before building, takes the path from the build's last line of stdout, and every scenario installs that path rather than re-listing the directory.
This commit is contained in:
@@ -101,12 +101,22 @@ if [ -n "$FEATURES" ]; then
|
||||
# from the default build of the same commit. It refuses --features with
|
||||
# --no-build for that reason, so the two cases cannot share one command.
|
||||
# The version still comes from the host, because the image has no git.
|
||||
BUILD_CMD="packaging/debian/build-deb.sh --features '$FEATURES' --version '$VERSION' --output-dir /out"
|
||||
BUILD_CMD="packaging/debian/build-deb.sh --features '$FEATURES' --version '$VERSION' --output-dir /out --name-file /name/deb"
|
||||
else
|
||||
BUILD_CMD="cargo build --release --locked
|
||||
packaging/debian/build-deb.sh --no-build --version '$VERSION' --output-dir /out"
|
||||
packaging/debian/build-deb.sh --no-build --version '$VERSION' --output-dir /out --name-file /name/deb"
|
||||
fi
|
||||
|
||||
# The build names the package it produced rather than this script picking one
|
||||
# out of the output directory. The output directory is the caller's and may
|
||||
# already hold packages from earlier runs; a search there by name or by age
|
||||
# could return one of those, and a package that sorts higher by name was
|
||||
# returned in preference to the one just built. The name travels through a
|
||||
# directory of its own, created fresh for this run, so a name left by an
|
||||
# earlier run cannot be read and nothing extra is left in the output directory.
|
||||
NAME_DIR=$(mktemp -d)
|
||||
trap 'rm -rf "$NAME_DIR"' EXIT
|
||||
|
||||
# The source is mounted read-only so a build cannot leave artifacts in the tree.
|
||||
# CARGO_TARGET_DIR and the registry live in named volumes, which is what makes a
|
||||
# second run fast; they are per-base-image so a floor change does not reuse
|
||||
@@ -115,6 +125,7 @@ VOL_SUFFIX="${FIPS_BUILD_IMAGE//[:\/]/-}"
|
||||
docker run --rm \
|
||||
-v "$REPO_ROOT":/src:ro \
|
||||
-v "$DEST_ABS":/out \
|
||||
-v "$NAME_DIR":/name \
|
||||
-v "fips-deb-target-${VOL_SUFFIX}":/target \
|
||||
-v "fips-deb-registry-${VOL_SUFFIX}":/usr/local/cargo/registry \
|
||||
-e CARGO_TARGET_DIR=/target \
|
||||
@@ -123,8 +134,21 @@ docker run --rm \
|
||||
"$IMAGE_TAG" \
|
||||
bash -euo pipefail -c "$BUILD_CMD" >&2
|
||||
|
||||
DEB=$(find "$DEST_ABS" -maxdepth 1 -name "fips_*_*.deb" -newermt '-10 minutes' -print | sort | tail -1)
|
||||
[ -n "$DEB" ] || { echo "build-deb-container: no .deb was produced." >&2; exit 1; }
|
||||
DEB_NAME=""
|
||||
[ -f "$NAME_DIR/deb" ] && DEB_NAME=$(head -n 1 "$NAME_DIR/deb")
|
||||
[ -n "$DEB_NAME" ] || {
|
||||
echo "build-deb-container: the build did not name its package" >&2
|
||||
exit 1
|
||||
}
|
||||
if [[ "$DEB_NAME" == */* || "$DEB_NAME" != fips_*_*.deb ]]; then
|
||||
echo "build-deb-container: the build named '$DEB_NAME', which is not a package file name" >&2
|
||||
exit 1
|
||||
fi
|
||||
DEB="$DEST_ABS/$DEB_NAME"
|
||||
[ -f "$DEB" ] || {
|
||||
echo "build-deb-container: the build named $DEB_NAME but $DEB does not exist" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Check the artifact here rather than in one workflow, so every producer is
|
||||
# gated: the release, the CI job, a local run and packaging/Makefile all reach
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
# Build a .deb package for FIPS using cargo-deb.
|
||||
#
|
||||
# Usage: ./build-deb.sh [--target <triple>] [--version <version>] [--no-build]
|
||||
# [--features <list>]
|
||||
# [--features <list>] [--output-dir <dir>]
|
||||
# [--name-file <path>]
|
||||
#
|
||||
# Prerequisites: cargo-deb (install with: cargo install cargo-deb)
|
||||
# Output: deploy/fips_<version>_<arch>.deb
|
||||
@@ -26,6 +27,10 @@ Options:
|
||||
--output-dir <dir> Where to put the finished .deb. Defaults to deploy/ under
|
||||
the project root. Exists so the container build can write
|
||||
to a mount and leave the source tree read-only.
|
||||
--name-file <path> Also write the finished package's file name (basename
|
||||
only) to <path>. The container build reads it so it
|
||||
never has to guess which .deb in the output directory
|
||||
this run produced.
|
||||
-h, --help Show this help
|
||||
EOF
|
||||
}
|
||||
@@ -35,6 +40,7 @@ VERSION_OVERRIDE=""
|
||||
NO_BUILD=0
|
||||
FEATURES=""
|
||||
DEST_DIR=""
|
||||
NAME_FILE=""
|
||||
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case "$1" in
|
||||
@@ -58,6 +64,10 @@ while [[ $# -gt 0 ]]; do
|
||||
DEST_DIR="${2:?missing value for --output-dir}"
|
||||
shift 2
|
||||
;;
|
||||
--name-file)
|
||||
NAME_FILE="${2:?missing value for --name-file}"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
usage
|
||||
exit 0
|
||||
@@ -182,6 +192,9 @@ fi
|
||||
|
||||
cp "${DEB_FILE}" "${DEST_DIR}/"
|
||||
BASENAME=$(basename "${DEB_FILE}")
|
||||
if [[ -n "${NAME_FILE}" ]]; then
|
||||
printf '%s\n' "${BASENAME}" > "${NAME_FILE}"
|
||||
fi
|
||||
echo "Package built: ${DEST_DIR}/${BASENAME}"
|
||||
echo ""
|
||||
echo "Install with: sudo dpkg -i ${DEST_DIR}/${BASENAME}"
|
||||
|
||||
@@ -58,6 +58,10 @@ SKIP=0
|
||||
# however many scenarios run in one process.
|
||||
SUPPLIED_DEB=""
|
||||
DEB_PREPARED=0
|
||||
# The package the scenarios install, set by build_deb() on every path that
|
||||
# succeeds. Scenarios use it rather than listing the cache directory, so which
|
||||
# file they install never depends on what else happens to be in there.
|
||||
DEB_PATH=""
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
# Helpers
|
||||
@@ -202,6 +206,7 @@ build_deb() {
|
||||
fi
|
||||
rm -f "$DEB_CACHE_DIR"/*.deb
|
||||
cp "$SUPPLIED_DEB" "$DEB_CACHE_DIR/"
|
||||
DEB_PATH="$DEB_CACHE_DIR/$(basename "$SUPPLIED_DEB")"
|
||||
DEB_PREPARED=1
|
||||
log "Installing the supplied package $(basename "$SUPPLIED_DEB")"
|
||||
return 0
|
||||
@@ -218,6 +223,7 @@ build_deb() {
|
||||
local cached_age
|
||||
cached_age=$(stat -c '%Y' "$cached_deb" 2>/dev/null || echo 0)
|
||||
if awk "BEGIN { exit !($cached_age >= $newest_src) }"; then
|
||||
DEB_PATH="$cached_deb"
|
||||
log "Using cached .deb at $cached_deb"
|
||||
return 0
|
||||
fi
|
||||
@@ -233,20 +239,28 @@ build_deb() {
|
||||
# not exhibit a defect that only the release environment produced. It stayed
|
||||
# green through five releases that could not start on two of the five
|
||||
# distributions in its own matrix.
|
||||
#
|
||||
# The cache holds one package at a time. Clearing it first is what keeps the
|
||||
# reuse check above honest, since that check looks at whichever package it
|
||||
# finds; and the package installed is the one the build names on the last
|
||||
# line of its stdout, never one found by listing the directory.
|
||||
log "Building the .deb in the pinned build container (slow on first run)"
|
||||
if ! bash "$REPO_ROOT/packaging/debian/build-deb-container.sh" \
|
||||
--output-dir "$DEB_CACHE_DIR" >&2; then
|
||||
rm -f "$DEB_CACHE_DIR"/*.deb
|
||||
local build_out
|
||||
if ! build_out=$(bash "$REPO_ROOT/packaging/debian/build-deb-container.sh" \
|
||||
--output-dir "$DEB_CACHE_DIR"); then
|
||||
echo " ERROR: container build failed" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
cached_deb=$(ls "$DEB_CACHE_DIR"/fips_*_amd64.deb 2>/dev/null | head -1)
|
||||
if [ -n "$cached_deb" ]; then
|
||||
log "Cached at $cached_deb ($(stat -c %s "$cached_deb") bytes)"
|
||||
else
|
||||
echo " ERROR: no .deb produced by the container build" >&2
|
||||
cached_deb=$(printf '%s\n' "$build_out" | tail -n 1)
|
||||
if [ -z "$cached_deb" ] || [ ! -f "$cached_deb" ]; then
|
||||
echo " ERROR: the container build did not report a package path: '$cached_deb'" >&2
|
||||
return 1
|
||||
fi
|
||||
DEB_PATH="$cached_deb"
|
||||
log "Cached at $cached_deb ($(stat -c %s "$cached_deb") bytes)"
|
||||
return 0
|
||||
}
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
@@ -267,8 +281,7 @@ _run_deb_install_scenario() {
|
||||
|
||||
build_deb || { fail ".deb build failed"; return; }
|
||||
|
||||
local cached_deb
|
||||
cached_deb=$(ls "$DEB_CACHE_DIR"/fips_*_amd64.deb 2>/dev/null | head -1)
|
||||
local cached_deb="$DEB_PATH"
|
||||
if [ -z "$cached_deb" ] || [ ! -f "$cached_deb" ]; then
|
||||
fail "no .deb available at $DEB_CACHE_DIR"
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user