#!/usr/bin/env bash # Build the offline APT repository bundle that is committed to git. # # Input : /*.deb reviewed packages accepted by add-packages.sh # Output: /pool/*.deb copy of every package # /Packages APT index of the pool (apt-ftparchive) # /Packages.gz gzip of the index, timestamp free # /packages.lock.tsv SBOM: package/version/architecture/sha256/source # /SHA256SUMS digests of the three index files # /repo-manifest.yaml repository record (release, arch, sizes, packages) # # The bundle layout is exactly what scripts/install/blueforce-install.sh --offline # validates in /opt/blueforce/offline-repo, so the device that installs from it # never needs a package source of its own. # # Guarantees: # * nothing is downloaded and no dependency is resolved from a remote source, # * every manifest pin must be satisfied by a pool package with the exact # version, otherwise no bundle is written and the gaps are listed in Turkish, # * the index is written in a canonical order and gzip carries no timestamp, so # re-running over the same pool leaves the bundle byte-identical (the bundle # is committed, so a stable rebuild keeps git diffs empty), # * an existing output directory is only replaced when it holds a previous # bundle of ours and no foreign file, # * the result is verified with `sha256sum -c SHA256SUMS` before it is reported. # # User-facing output is Turkish; code and comments are English. set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" PACKAGES_DIR="$SCRIPT_DIR/packages" OUTPUT="$SCRIPT_DIR/built" # BF_MANIFEST_DIR points a test run at a fixture directory; a real build always # reads the reviewed manifests next to this script. MANIFEST_DIR="${BF_MANIFEST_DIR:-$SCRIPT_DIR/manifests}" # The repository record belongs to the build it describes, so it is written # inside the output directory by default, resolved once OUTPUT is final (see the # guard below). It deliberately does NOT default to the shipped # repo-manifest.yaml next to this script: that file is the reviewed contract # template (state: UNBUILT, packages: []) which documents the schema and which # the static suite asserts on, and a default-path write silently replaced it with # BUILT rows twice. Keeping the two paths distinct is what makes it safe; # --manifest-out still overrides the destination explicitly. MANIFEST_OUT='' TARGET_ARCH='amd64' ALLOWED_ARCH_RE='^(amd64|all)$' PACKAGE_NAME_RE='^[a-z0-9][a-z0-9+.-]*$' PIN_RE='^[a-z0-9][a-z0-9+.-]*=[^[:space:]]+$' PIN_PLACEHOLDER_RE='(placeholder|replace|todo|tbd|fixme|changeme|fillme|example)' LOCK_HEADER="$(printf 'package\tversion\tarchitecture\tsha256\tsource')" UNPINNED='UNPINNED' SCHEMA_VERSION=1 # Entries an output directory may hold without being treated as foreign. ALLOWED_ENTRIES='pool Packages Packages.gz packages.lock.tsv SHA256SUMS .gitkeep' usage() { cat <<'EOF' Kullanım: build-index.sh [seçenekler] packages/ altındaki .deb dosyalarından git'e girecek offline APT deposunu üretir. Seçenekler: --packages DIZIN Kaynak paket dizini (varsayılan: