#!/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" 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 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" 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 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