logos-blockchain-testing/scripts/build/build_test_image.sh

262 lines
9.1 KiB
Bash
Raw Normal View History

#!/usr/bin/env bash
set -euo pipefail
if [ -z "${BASH_VERSION:-}" ]; then
exec bash "$0" "$@"
fi
# shellcheck disable=SC1091
. "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../lib/common.sh"
build_test_image::usage() {
cat <<'USAGE'
Usage: scripts/build/build_test_image.sh [options]
2026-01-26 08:26:15 +01:00
Builds the compose/k8s test image (bakes in binaries).
Options:
--tag TAG Docker image tag (default: logos-blockchain-testing:local; or env IMAGE_TAG)
2026-01-26 08:26:15 +01:00
--version VERSION Bundle version tag (default: versions.env VERSION)
2026-02-02 07:19:22 +01:00
--dockerfile PATH Dockerfile path (default: logos/infra/assets/stack/Dockerfile.runtime)
2025-12-18 09:58:47 +01:00
--base-tag TAG Base image tag (default: logos-blockchain-testing:base)
2026-01-26 16:36:51 +01:00
--bundle-tar PATH Bundle tar containing artifacts/{nomos-*} (default: .tmp/nomos-binaries-linux-<version>.tar.gz; or env LOGOS_BLOCKCHAIN_BINARIES_TAR)
2026-01-26 08:26:15 +01:00
--no-restore Do not restore binaries from bundle tar (forces Dockerfile to build/download as needed)
--print-config Print resolved configuration and exit
-h, --help Show this help and exit
Env (legacy/compatible):
2026-01-26 16:36:51 +01:00
IMAGE_TAG, VERSION, LOGOS_BLOCKCHAIN_BINARIES_TAR
USAGE
}
build_test_image::fail() {
common::die "$1"
}
build_test_image::load_env() {
if [ -n "${ROOT_DIR:-}" ] && [ -f "${ROOT_DIR}/versions.env" ]; then
: # Use provided ROOT_DIR.
else
ROOT_DIR="$(common::repo_root)"
fi
export ROOT_DIR
common::require_file "${ROOT_DIR}/versions.env"
# shellcheck disable=SC1091
. "${ROOT_DIR}/versions.env"
common::maybe_source "${ROOT_DIR}/paths.env"
2026-02-02 07:19:22 +01:00
DOCKERFILE_PATH_DEFAULT="${ROOT_DIR}/logos/infra/assets/stack/Dockerfile.runtime"
BASE_DOCKERFILE_PATH_DEFAULT="${ROOT_DIR}/logos/infra/assets/stack/Dockerfile.base"
IMAGE_TAG_DEFAULT="logos-blockchain-testing:local"
2025-12-18 09:58:47 +01:00
BASE_IMAGE_TAG_DEFAULT="logos-blockchain-testing:base"
VERSION_DEFAULT="${VERSION:?Missing VERSION in versions.env}"
2026-01-26 16:36:51 +01:00
LOGOS_BLOCKCHAIN_NODE_REV="${LOGOS_BLOCKCHAIN_NODE_REV:?Missing LOGOS_BLOCKCHAIN_NODE_REV in versions.env}"
}
build_test_image::parse_args() {
IMAGE_TAG="${IMAGE_TAG:-${IMAGE_TAG_DEFAULT}}"
VERSION_OVERRIDE=""
DOCKERFILE_PATH="${DOCKERFILE_PATH_DEFAULT}"
2025-12-18 09:58:47 +01:00
BASE_DOCKERFILE_PATH="${BASE_DOCKERFILE_PATH_DEFAULT}"
BASE_IMAGE_TAG="${BASE_IMAGE_TAG:-${BASE_IMAGE_TAG_DEFAULT}}"
2026-01-26 16:36:51 +01:00
BUNDLE_TAR_PATH="${LOGOS_BLOCKCHAIN_BINARIES_TAR:-}"
NO_RESTORE=0
PRINT_CONFIG=0
while [ "$#" -gt 0 ]; do
case "$1" in
-h|--help) build_test_image::usage; exit 0 ;;
--tag=*) IMAGE_TAG="${1#*=}"; shift ;;
--tag) IMAGE_TAG="${2:-}"; shift 2 ;;
--version=*) VERSION_OVERRIDE="${1#*=}"; shift ;;
--version) VERSION_OVERRIDE="${2:-}"; shift 2 ;;
--dockerfile=*) DOCKERFILE_PATH="${1#*=}"; shift ;;
--dockerfile) DOCKERFILE_PATH="${2:-}"; shift 2 ;;
2025-12-18 09:58:47 +01:00
--base-tag=*) BASE_IMAGE_TAG="${1#*=}"; shift ;;
--base-tag) BASE_IMAGE_TAG="${2:-}"; shift 2 ;;
--bundle-tar=*) BUNDLE_TAR_PATH="${1#*=}"; shift ;;
--bundle-tar) BUNDLE_TAR_PATH="${2:-}"; shift 2 ;;
--no-restore) NO_RESTORE=1; shift ;;
--print-config) PRINT_CONFIG=1; shift ;;
*) build_test_image::fail "Unknown argument: $1" ;;
esac
done
if [ -n "${VERSION_OVERRIDE}" ]; then
VERSION="${VERSION_OVERRIDE}"
else
VERSION="${VERSION_DEFAULT}"
fi
2026-02-02 07:19:22 +01:00
BIN_DST="${ROOT_DIR}/logos/infra/assets/stack/bin"
DEFAULT_LINUX_TAR="${ROOT_DIR}/.tmp/nomos-binaries-linux-${VERSION}.tar.gz"
TAR_PATH="${BUNDLE_TAR_PATH:-${DEFAULT_LINUX_TAR}}"
2026-02-02 07:19:22 +01:00
LOGOS_BLOCKCHAIN_NODE_PATH="${LOGOS_BLOCKCHAIN_NODE_PATH:-}"
if [ -z "${LOGOS_BLOCKCHAIN_NODE_PATH}" ]; then
# Prefer local checkout when available: this repo currently depends on
# lb-framework from nomos-node/tests/testing_framework.
local sibling_node_path="${ROOT_DIR}/../nomos-node"
if [ -d "${sibling_node_path}/tests/testing_framework" ]; then
LOGOS_BLOCKCHAIN_NODE_PATH="${sibling_node_path}"
fi
fi
if [ -n "${LOGOS_BLOCKCHAIN_NODE_PATH}" ] && [ ! -d "${LOGOS_BLOCKCHAIN_NODE_PATH}" ]; then
build_test_image::fail "LOGOS_BLOCKCHAIN_NODE_PATH does not exist: ${LOGOS_BLOCKCHAIN_NODE_PATH}"
fi
}
build_test_image::print_config() {
echo "Workspace root: ${ROOT_DIR}"
echo "Image tag: ${IMAGE_TAG}"
echo "Dockerfile: ${DOCKERFILE_PATH}"
2025-12-18 09:58:47 +01:00
echo "Base image tag: ${BASE_IMAGE_TAG}"
echo "Base Dockerfile: ${BASE_DOCKERFILE_PATH}"
2026-01-26 16:36:51 +01:00
echo "Logos node rev: ${LOGOS_BLOCKCHAIN_NODE_REV}"
2026-02-02 07:19:22 +01:00
echo "Logos node path: ${LOGOS_BLOCKCHAIN_NODE_PATH:-<unset>}"
echo "Binaries dir: ${BIN_DST}"
echo "Bundle tar (if used): ${TAR_PATH}"
echo "Restore from tar: $([ "${NO_RESTORE}" -eq 1 ] && echo "disabled" || echo "enabled")"
}
build_test_image::have_host_binaries() {
# Preserve existing behavior: only require node on the host.
[ -x "${BIN_DST}/logos-blockchain-node" ]
}
build_test_image::restore_from_bundle() {
[ -f "${TAR_PATH}" ] || build_test_image::fail "Prebuilt binaries missing and bundle tar not found at ${TAR_PATH}"
2026-01-26 08:26:15 +01:00
echo "==> Restoring binaries from ${TAR_PATH}"
local tmp_extract
tmp_extract="$(common::tmpdir nomos-bundle-extract.XXXXXX)"
trap "rm -rf -- '${tmp_extract}'" RETURN
tar -xzf "${TAR_PATH}" -C "${tmp_extract}"
local artifacts="${tmp_extract}/artifacts"
2026-01-26 08:26:15 +01:00
[ -f "${artifacts}/logos-blockchain-node" ] || build_test_image::fail \
"Bundle ${TAR_PATH} missing artifacts/logos-blockchain-node"
mkdir -p "${BIN_DST}"
2026-01-26 08:26:15 +01:00
cp "${artifacts}/logos-blockchain-node" "${BIN_DST}/"
chmod +x "${BIN_DST}/logos-blockchain-node" || true
}
build_test_image::maybe_restore_assets() {
if [ "${NO_RESTORE}" -eq 1 ]; then
return 0
fi
if build_test_image::have_host_binaries; then
return 0
fi
build_test_image::restore_from_bundle
}
build_test_image::docker_build() {
command -v docker >/dev/null 2>&1 || build_test_image::fail "docker not found in PATH"
[ -f "${DOCKERFILE_PATH}" ] || build_test_image::fail "Dockerfile not found: ${DOCKERFILE_PATH}"
2025-12-18 09:58:47 +01:00
[ -f "${BASE_DOCKERFILE_PATH}" ] || build_test_image::fail "Base Dockerfile not found: ${BASE_DOCKERFILE_PATH}"
local host_platform=""
local target_platform=""
case "$(uname -m)" in
x86_64) host_platform="linux/amd64" ;;
arm64|aarch64) host_platform="linux/arm64" ;;
esac
2026-01-26 08:26:15 +01:00
if [ -n "${DOCKER_PLATFORM:-}" ]; then
target_platform="${DOCKER_PLATFORM}"
elif [ -n "${COMPOSE_CIRCUITS_PLATFORM:-}" ] || [ -n "${CIRCUITS_PLATFORM:-}" ]; then
case "${COMPOSE_CIRCUITS_PLATFORM:-${CIRCUITS_PLATFORM}}" in
linux-x86_64) target_platform="linux/amd64" ;;
linux-aarch64) target_platform="linux/arm64" ;;
esac
fi
2026-02-02 07:19:22 +01:00
if [ -z "${target_platform}" ] && [ -n "${host_platform}" ]; then
# Prefer native builds to avoid emulation issues in rapidsnark/prover.
target_platform="${host_platform}"
fi
2025-12-18 09:58:47 +01:00
local -a base_build_args=(
-f "${BASE_DOCKERFILE_PATH}"
-t "${BASE_IMAGE_TAG}"
2026-01-26 16:36:51 +01:00
--build-arg "LOGOS_BLOCKCHAIN_NODE_REV=${LOGOS_BLOCKCHAIN_NODE_REV}"
2026-02-02 07:19:22 +01:00
--build-arg "LOGOS_BLOCKCHAIN_NODE_USE_LOCAL_CONTEXT=$([ -n "${LOGOS_BLOCKCHAIN_NODE_PATH}" ] && echo 1 || echo 0)"
--build-arg "VERSION=${VERSION}"
)
2026-02-02 07:19:22 +01:00
local node_context_path="${LOGOS_BLOCKCHAIN_NODE_PATH:-${ROOT_DIR}}"
base_build_args+=(--build-context "nomos_node=${node_context_path}")
if [ -n "${LOGOS_BLOCKCHAIN_FORCE_BUILD:-}" ]; then
base_build_args+=(--build-arg "LOGOS_BLOCKCHAIN_FORCE_BUILD=${LOGOS_BLOCKCHAIN_FORCE_BUILD}")
fi
if [ -n "${host_platform}" ] && [ -n "${target_platform}" ] && [ "${host_platform}" != "${target_platform}" ]; then
base_build_args+=(--platform "${target_platform}")
fi
2026-02-02 07:19:22 +01:00
base_build_args+=("${ROOT_DIR}")
printf "Running:"
2025-12-18 09:58:47 +01:00
printf " %q" docker build "${base_build_args[@]}"
echo
2026-02-02 07:19:22 +01:00
build_test_image::docker_build_with_retry "${base_build_args[@]}"
2025-12-18 09:58:47 +01:00
local -a final_build_args=(
-f "${DOCKERFILE_PATH}"
-t "${IMAGE_TAG}"
--build-arg "BASE_IMAGE=${BASE_IMAGE_TAG}"
"${ROOT_DIR}"
)
if [ -n "${host_platform}" ] && [ -n "${target_platform}" ] && [ "${host_platform}" != "${target_platform}" ]; then
final_build_args+=(--platform "${target_platform}")
fi
2025-12-18 09:58:47 +01:00
printf "Running:"
printf " %q" docker build "${final_build_args[@]}"
echo
2026-02-02 07:19:22 +01:00
build_test_image::docker_build_with_retry "${final_build_args[@]}"
}
build_test_image::docker_build_with_retry() {
local max_attempts=3
local attempt
for attempt in $(seq 1 "${max_attempts}"); do
if docker build "$@"; then
return 0
fi
if [ "${attempt}" -lt "${max_attempts}" ]; then
local backoff=$((attempt * 5))
echo "docker build failed (attempt ${attempt}/${max_attempts}); retrying in ${backoff}s..."
sleep "${backoff}"
fi
done
build_test_image::fail "docker build failed after ${max_attempts} attempts"
}
build_test_image::main() {
build_test_image::load_env
build_test_image::parse_args "$@"
if [ "${PRINT_CONFIG}" -eq 1 ]; then
build_test_image::print_config
exit 0
fi
build_test_image::print_config
build_test_image::maybe_restore_assets
build_test_image::docker_build
cat <<EOF
Build complete.
2026-01-26 16:36:51 +01:00
- Use this image in k8s/compose by exporting LOGOS_BLOCKCHAIN_TESTNET_IMAGE=${IMAGE_TAG}
EOF
}
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
build_test_image::main "$@"
fi