#!/bin/sh # Build every package and an apt repository to serve them from. # # Produces three packages: # bandsaunter the application itself # bandsaunter-transcribe the speech recogniser, which Debian does not # package, vendored into a private directory # bandsaunter-model- the recogniser's model, so a machine never # has to reach the network # # The result is a flat apt repository: point a machine at it and # "apt install bandsaunter" brings the lot, offline from then on. set -eu here=$(cd "$(dirname "$0")/.." && pwd) out=${1:-$here/dist/repo} model=${MODEL:-base.en} hf_repo=${HF_REPO:-Systran/faster-whisper-$model} revision=${DEB_REVISION:-1} version=$(cd "$here" && python3 -c 'import bandsaunter; print(bandsaunter.debian_version())') # Compiled wheels tie this to one architecture. amd64 only, by design. arch=amd64 mkdir -p "$out" stage=$(mktemp -d) trap 'rm -rf "$stage"' EXIT say() { printf '%s\n' "$*" >&2; } # --------------------------------------------------------------------------- say "building bandsaunter ${version}-${revision}" "$here/packaging/build-deb.sh" "$out" >/dev/null # --------------------------------------------------------------------------- say "collecting the speech recogniser (this downloads from PyPI once)" wheels="$stage/wheels" mkdir -p "$wheels" pip download --quiet --only-binary=:all: --dest "$wheels" faster-whisper >&2 pkg="$stage/bandsaunter-transcribe_${version}-${revision}_${arch}" vendor="$pkg/usr/lib/bandsaunter/vendor" mkdir -p "$vendor" "$pkg/DEBIAN" "$pkg/usr/share/doc/bandsaunter-transcribe" for w in "$wheels"/*.whl; do python3 -m zipfile -e "$w" "$vendor/" done # Debian already provides these and they win on sys.path anyway, so shipping # them would be dead weight. rm -rf "$vendor"/numpy "$vendor"/numpy-* "$vendor"/yaml "$vendor"/PyYAML-* \ "$vendor"/setuptools "$vendor"/setuptools-* "$vendor"/pkg_resources \ "$vendor"/_yaml "$vendor"/_distutils_hack "$vendor"/numpy.libs # A .pth file only runs inside a real site directory; here it is dead weight. rm -f "$vendor"/*.pth find "$vendor" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null || true # The packaging is this project's; the wheels inside keep their own terms. { echo "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" echo "Upstream-Name: bandsaunter" echo echo "Files: *" echo "Copyright: 2026 The Dust Council" echo "License: GPL-3.0-or-later" echo " The packaging in this file is under the GNU General Public License," echo " version 3 or later, whose full text is in the bandsaunter package at" echo " /usr/share/doc/bandsaunter/copyright. The Python wheels vendored" echo " under /usr/lib/bandsaunter/vendor are third-party works distributed" echo " under their own licences, each carried in that package's own" echo " dist-info directory beside it." } > "$pkg/usr/share/doc/bandsaunter-transcribe/copyright" cat > "$pkg/DEBIAN/control" </dev/null # --------------------------------------------------------------------------- say "collecting the $model model" modelpkg="$stage/bandsaunter-model-$(echo "$model" | tr '._' '--')_${version}-${revision}_all" modeldir="$modelpkg/usr/share/bandsaunter/models/$model" mkdir -p "$modeldir" "$modelpkg/DEBIAN" modeldoc="$modelpkg/usr/share/doc/bandsaunter-model-$(echo "$model" | tr '._' '--')" mkdir -p "$modeldoc" PYTHONPATH="$stage/wheels-unused" python3 - "$hf_repo" "$modeldir" <<'PY' >&2 import shutil, sys from pathlib import Path from huggingface_hub import snapshot_download src = Path(snapshot_download(sys.argv[1])) dst = Path(sys.argv[2]) for item in src.iterdir(): if item.name.startswith("."): continue target = dst / item.name # Resolve the cache's symlinks so the package holds real files. shutil.copy2(item.resolve(), target) PY { echo "Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/" echo "Upstream-Name: bandsaunter" echo echo "Files: *" echo "Copyright: 2026 The Dust Council" echo "License: GPL-3.0-or-later" echo " The packaging is under the GNU General Public License, version 3 or" echo " later, whose full text is in the bandsaunter package at" echo " /usr/share/doc/bandsaunter/copyright. The model weights under" echo " /usr/share/bandsaunter/models are a third-party work, redistributed" echo " under the terms the model was published with." } > "$modeldoc/copyright" cat > "$modelpkg/DEBIAN/control" </dev/null # --------------------------------------------------------------------------- say "indexing the repository" ( cd "$out" && dpkg-scanpackages --multiversion . /dev/null > Packages 2>/dev/null gzip -9kfn Packages apt-ftparchive -o APT::FTPArchive::Release::Suite=stable \ -o APT::FTPArchive::Release::Codename=bandsaunter \ release . > Release ) say "" say "repository ready: $out" ls -1sh "$out"/*.deb >&2