aboutsummaryrefslogtreecommitdiffstats
path: root/image-builder/build-sbo-testbuild.sh
blob: 0d1e07bcc0efa8b55353810f06acd7704314fe06 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/bin/bash
#
# Copyright (C) 2026 Danilo M. <danix@danix.xyz>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# build-sbo-testbuild.sh — sbo-testbuild:{ver} FROM sbo-full:{ver}.
# Adds sbopkg + sbo-maintainer-tools from prebuilt .txz in PKGDIR.
# Rebuilds when the full image OR the .txz set changes.
set -euo pipefail
PROJECT_VERSION="1.0.0"   # bump via sed across all scripts; see CLAUDE.md Releases
HERE="$(cd "$(dirname "$0")" && pwd)"
source "${HERE}/config"
LOG_TAG=testbuild
source "${HERE}/lib.sh"

FULL_IMAGE="${REGISTRY}/sbo-full"
TB_IMAGE="${REGISTRY}/sbo-testbuild"
DIGEST_LABEL="sbo.testbuild.full-digest"
PKGS_LABEL="sbo.testbuild.pkgs-hash"

FORCE=false
OPT_VERSION=""
while [[ $# -gt 0 ]]; do
    case "$1" in
        -V)        echo "build-sbo-testbuild.sh $PROJECT_VERSION"; exit 0 ;;
        --version) OPT_VERSION="$2"; shift 2 ;;
        --force)   FORCE=true;       shift   ;;
        *) _err "unknown argument: $1" ;;
    esac
done
if [[ -n "${OPT_VERSION}" ]]; then
    BUILD_VARIANTS=("${OPT_VERSION}")
else
    BUILD_VARIANTS=("${VARIANTS[@]}")
fi

# Verify the required packages (*.t?z) are present before doing anything.
require_pkgs() {
    [[ -d "${PKGDIR}" ]] || _err "PKGDIR missing: ${PKGDIR}"
    compgen -G "${PKGDIR}/sbopkg-*.t?z" >/dev/null \
        || _err "no sbopkg-*.t?z in ${PKGDIR}"
    compgen -G "${PKGDIR}/sbo-maintainer-tools-*.t?z" >/dev/null \
        || _err "no sbo-maintainer-tools-*.t?z in ${PKGDIR}"
}

# needs_rebuild FULL_TAG TB_TAG PKGS_HASH -> 0 if rebuild needed
needs_rebuild() {
    local full_tag="$1" tb_tag="$2" pkgs_hash="$3"
    [[ "${FORCE}" == "true" ]] && { _log "  --force."; return 0; }

    local full_digest
    full_digest=$(docker inspect --format '{{index .RepoDigests 0}}' \
        "${full_tag}" 2>/dev/null || echo "")
    [[ -n "${full_digest}" ]] || { _warn "  no full digest; rebuilding."; return 0; }

    local rec_digest rec_pkgs
    rec_digest=$(docker inspect \
        --format "{{index .Config.Labels \"${DIGEST_LABEL}\"}}" \
        "${tb_tag}" 2>/dev/null || echo "")
    rec_pkgs=$(docker inspect \
        --format "{{index .Config.Labels \"${PKGS_LABEL}\"}}" \
        "${tb_tag}" 2>/dev/null || echo "")

    if [[ "${full_digest}" == "${rec_digest}" && "${pkgs_hash}" == "${rec_pkgs}" ]]; then
        _log "  full image and .txz set unchanged; skipping."
        return 1
    fi
    _log "  full image or .txz set changed; rebuilding."
    return 0
}

build_variant() {
    local VERSION="$1"
    local FULL_TAG="${FULL_IMAGE}:${VERSION}"
    local TB_TAG="${TB_IMAGE}:${VERSION}"
    _log "=== ${TB_TAG} ==="

    _log "  Pulling ${FULL_TAG}..."
    docker pull "${FULL_TAG}"

    local PKGS_HASH; PKGS_HASH="$(txz_hash "${PKGDIR}")"

    if ! needs_rebuild "${FULL_TAG}" "${TB_TAG}" "${PKGS_HASH}"; then
        return 0
    fi

    local FULL_DIGEST
    FULL_DIGEST=$(docker inspect --format '{{index .RepoDigests 0}}' "${FULL_TAG}" 2>/dev/null || echo "")

    local WORKDIR; WORKDIR="$(mktemp -d /tmp/sbo-testbuild.XXXXXX)"
    # shellcheck disable=SC2064
    trap "rm -rf '${WORKDIR}'" EXIT
    mkdir -p "${WORKDIR}/pkgs"
    cp "${PKGDIR}"/sbopkg-*.t?z "${PKGDIR}"/sbo-maintainer-tools-*.t?z "${WORKDIR}/pkgs/"

    cat > "${WORKDIR}/Dockerfile" <<DOCKERFILE
FROM ${FULL_TAG}
LABEL maintainer="danix <danix@danix.xyz>"
COPY pkgs/ /tmp/pkgs/
RUN installpkg /tmp/pkgs/* && rm -rf /tmp/pkgs
RUN /sbin/ldconfig
LABEL org.opencontainers.image.created="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
LABEL org.opencontainers.image.title="SBo test-build env ${VERSION} (x86_64)"
LABEL org.opencontainers.image.description="Slackware ${VERSION} full + sbopkg + sbo-maintainer-tools"
LABEL slackware.version="${VERSION}"
LABEL ${DIGEST_LABEL}="${FULL_DIGEST}"
LABEL ${PKGS_LABEL}="${PKGS_HASH}"
CMD ["/bin/bash"]
DOCKERFILE

    local BUILD_FLAGS=()
    [[ "${FORCE}" == "true" ]] && BUILD_FLAGS+=(--no-cache)
    # Explicit exit checks: build_variant runs in an `if ! (...)` condition
    # (see Main), which suppresses `set -e` in this subshell, so a failed build
    # would otherwise push a nonexistent tag and log "Done".
    _log "  Building ${TB_TAG}..."
    if ! docker build "${BUILD_FLAGS[@]}" -t "${TB_TAG}" "${WORKDIR}"; then
        _warn "  build failed for ${TB_TAG}; not pushing."
        return 1
    fi
    _log "  Pushing ${TB_TAG}..."
    if ! docker push "${TB_TAG}"; then
        _warn "  push failed for ${TB_TAG}."
        return 1
    fi
    _log "=== Done: ${TB_TAG} ==="
}

require_pkgs
rc=0
for VERSION in "${BUILD_VARIANTS[@]}"; do
    if ! ( build_variant "${VERSION}" ); then
        _warn "variant ${VERSION} failed; continuing."
        rc=1
    fi
done
exit "${rc}"