mkNix2ContainerPublish: add impureBuild + indexMovesLatest modes (cluster #205)
impureBuild: build the consumer's flake attr at run time via nix build --impure --sandbox false, instead of embedding the image closure as an eval-time build dep — required for images that fetch private artifacts with a token at build time (ii-agent). indexMovesLatest: publish-index also moves :latest, for repos that publish each arch on a separate CI agent and converge in a final index-only step. Both opt-in, default-off; existing consumers unchanged. Verified by eval in both modes.
This commit is contained in:
+52
-3
@@ -679,11 +679,44 @@ let
|
||||
registryHost ? "git.oleks.space",
|
||||
registryOwner ? "oleks",
|
||||
passEntry ? "infra/gitea/personal_access_token_packages_rw",
|
||||
# IMPURE-BUILD mode (cluster #205). Default: each `images.<arch>` carries a
|
||||
# `copyTo` derivation referenced as an EVAL-TIME store path (a build dep of
|
||||
# the app) — correct for a pure image. But some images are built IMPURELY
|
||||
# (need a registry token / network / sandbox off at build time, e.g.
|
||||
# ii-agent fetching private wheels), so the closure CANNOT be a build dep
|
||||
# of the app. When `impureBuild = true`, each `images.<arch>` instead
|
||||
# carries `attr` (a flake attribute on the CONSUMER's own flake, e.g.
|
||||
# "frontend-image"), and stage/publish/verify-digest build it at RUN time
|
||||
# via `nix build --impure --option sandbox false ".#<attr>.copyTo"`.
|
||||
impureBuild ? false,
|
||||
# When true, `publish-index` ALSO moves `:latest` (a dev-guarded digest
|
||||
# copy of `:VERSION`) after assembling the index. Default off: `:latest`
|
||||
# is owned by the `publish` app. Repos that publish each arch on a SEPARATE
|
||||
# CI agent and converge in a final index-only step (ii-agent) need the
|
||||
# latest-move to live in `publish-index`. cluster #205.
|
||||
indexMovesLatest ? false,
|
||||
}:
|
||||
let
|
||||
head = preamble { inherit registryHost registryOwner passEntry; };
|
||||
localArches = lib.attrNames images;
|
||||
|
||||
# Resolve one arch's nix2container copy-to wrapper into shell var $1.
|
||||
# Pure: an eval-time store path (build dep of the app). Impure (cluster
|
||||
# #205): build the consumer's own flake attr at RUN time and read the path
|
||||
# back — the impure layers (token/network/sandbox-off) never become a build
|
||||
# dep of the app, which would otherwise fail under the pure sandbox.
|
||||
resolveCopyTo =
|
||||
arch: var:
|
||||
if impureBuild then
|
||||
''
|
||||
IMAGE_TAG="$VERSION-${arch}" nix build --impure --no-link \
|
||||
--option sandbox false ".#${images.${arch}.attr}.copyTo" >/dev/null
|
||||
${var}="$(IMAGE_TAG="$VERSION-${arch}" nix eval --impure --raw \
|
||||
".#${images.${arch}.attr}.copyTo")"
|
||||
''
|
||||
else
|
||||
"${var}=${lib.escapeShellArg "${images.${arch}.copyTo}"}";
|
||||
|
||||
# per-arch stage: realise the image's copy-to closure locally (no push).
|
||||
mkArchStage =
|
||||
arch:
|
||||
@@ -696,7 +729,7 @@ let
|
||||
echo "→ staging ${imageName}:$VERSION-${arch} (build closure only, no push)"
|
||||
d="$(parity_stage_reset ${lib.escapeShellArg arch})"
|
||||
# Realise the nix2container copyTo wrapper (its closure is the image).
|
||||
out=${lib.escapeShellArg "${images.${arch}.copyTo}"}
|
||||
${resolveCopyTo arch "out"}
|
||||
printf 'oci %s %s %s\n' ${lib.escapeShellArg imageName} "$VERSION" "${arch}" >"$d/.parity-meta"
|
||||
printf '%s\n' "$out" >"$d/copy-to-path"
|
||||
echo " staged copyTo: $out"
|
||||
@@ -715,7 +748,8 @@ let
|
||||
digestArch = arch: ''
|
||||
echo "→ ${imageName}:$VERSION-${arch} (local build, no registry contact)"
|
||||
ocidir="$(mktemp -d)"
|
||||
${lib.escapeShellArg "${images.${arch}.copyTo}"}/bin/copy-to "oci:$ocidir:${arch}" >/dev/null
|
||||
${resolveCopyTo arch "copyto"}
|
||||
"$copyto/bin/copy-to" "oci:$ocidir:${arch}" >/dev/null
|
||||
digest="$(skopeo manifest-digest "$ocidir/blobs/sha256/$(
|
||||
jq -r '.manifests[0].digest | sub("sha256:";"")' "$ocidir/index.json"
|
||||
)")"
|
||||
@@ -758,7 +792,10 @@ let
|
||||
tok="$(parity_resolve_token)"
|
||||
parity_registry_preflight
|
||||
creds="$PARITY_REGISTRY_OWNER:$tok"
|
||||
${lib.escapeShellArg "${images.${arch}.copyTo}"}/bin/copy-to \
|
||||
# Read the copy-to path the stage step just wrote (works for both
|
||||
# pure and impure modes — stage already realised/built the closure).
|
||||
copyto="$(cat "$PARITY_STAGE_DIR/${arch}/copy-to-path")"
|
||||
"$copyto/bin/copy-to" \
|
||||
--dest-creds "$creds" \
|
||||
"docker://${imageName}:$VERSION-${arch}"
|
||||
echo "Pushed ${imageName}:$VERSION-${arch}"
|
||||
@@ -809,6 +846,18 @@ let
|
||||
done
|
||||
regctl index create "${imageName}:$VERSION" "''${refs[@]/#/--ref=}"
|
||||
echo "Assembled index ${imageName}:$VERSION"
|
||||
${lib.optionalString indexMovesLatest ''
|
||||
# Repos that converge per-arch legs in this index-only step own the
|
||||
# ':latest' move here (rather than in `publish`). Dev-guarded; a pure
|
||||
# digest copy of the just-assembled ':VERSION', done LAST.
|
||||
case "$VERSION" in
|
||||
*dev*) echo " dev version $VERSION — refusing to move :latest" ;;
|
||||
*)
|
||||
regctl image copy "${imageName}:$VERSION" "${imageName}:latest"
|
||||
echo "→ ${imageName}:$VERSION -> :latest (digest copy)"
|
||||
;;
|
||||
esac
|
||||
''}
|
||||
'';
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user