bandsaunter/packaging/build-deb.sh
The Dust Council 8ed01f991f Cover every option in the help, the manual and the readme, and say what to install
An audit rather than a feature, prompted by wanting this fit to hand to
somebody else.

Five options had no command-line flag written down in the table the manual
is generated from -- location, hold, schedules, tile_url and speed_unit --
so five flags that exist were missing from the manual.  Four of them did
exist under other names and are now recorded; hold had no flag at all and
has one.

Four switches could be turned off from the command line and not back on:
--no-lookup, --no-basemap, --no-airports and --no-labels had no positive
halves, so an option turned off in the saved settings could not be turned on
again for one run.  All four now have both.

And adsb, which opens the window and draws a map when it stops, could not be
given any of the settings that decide what those look like: no --at, no
--radius, no --tiles, no --map-brightness, no --width, --fps, --trail,
--fade, --stale, --airports or --labels.  It takes all of them now.

The manual had no list of the aircraft options at all -- the ADS-B sections
were hand-written prose -- so five of them appeared nowhere in it.  It now
generates an AIRCRAFT OPTIONS section from the same table the menu and the
flags come from, and the readme carries a table of all thirty-four with
their flags and defaults.  Three tests hold the three of them together: one
that every option records its flag, one that every flag the table claims
actually exists on a command, and one that the readme names them all.

The installing instructions now list every dependency rather than only the
optional ones: the four Python packages with their names in Debian, Fedora
and Arch, and librtlsdr, which is a C library and therefore the one thing
pip cannot bring and a virtual environment cannot supply.  What reaches a
network is written down too -- which host, when, and which file it is cached
in -- since somebody installing this on a metered or air-gapped machine has
to be able to see that nothing is fetched behind their back.  build-repo.sh
needs dpkg-dev and apt-utils, which a minimal system does not have, and now
says so.

Verified rather than asserted: a clean virtual environment, pip install from
this tree, and a real log read back through the installed command.  It pulls
seven wheels rather than the four the page claimed, the other three being
what Rich brings with it.

Also: matplotlib is gone from the readme's dependency table, nothing having
imported it; ffmpeg and Qt are in it, both having been missing; ffmpeg is a
Suggests on the package; and resume.sh is ignored.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016PsWPTweCT6pwxKngvVxcg
2026-09-06 14:12:33 -07:00

142 lines
5.4 KiB
Bash
Executable file

#!/bin/sh
# Build a .deb that pulls in every dependency through apt.
#
# Deliberately plain dpkg-deb rather than debhelper: everything this package
# needs is already in Debian, the payload is pure Python with no compiled
# parts, and this way the build needs nothing installed beyond dpkg itself.
set -eu
here=$(cd "$(dirname "$0")/.." && pwd)
version=$(cd "$here" && python3 -c 'import bandsaunter; print(bandsaunter.debian_version())')
revision=${DEB_REVISION:-1}
arch=all
stage=$(mktemp -d)
trap 'rm -rf "$stage"' EXIT
pkgdir="$stage/bandsaunter_${version}-${revision}_${arch}"
site="$pkgdir/usr/lib/python3/dist-packages"
mkdir -p "$site/bandsaunter" "$pkgdir/usr/bin" "$pkgdir/DEBIAN" \
"$pkgdir/usr/share/doc/bandsaunter"
cp "$here"/bandsaunter/*.py "$site/bandsaunter/"
cp "$here/README.md" "$here/INSTALL.md" "$pkgdir/usr/share/doc/bandsaunter/"
gzip -9n "$pkgdir/usr/share/doc/bandsaunter/README.md"
gzip -9n "$pkgdir/usr/share/doc/bandsaunter/INSTALL.md"
# Debian Policy requires the licence verbatim, at this exact path, in every
# package. The header above it is the machine-readable format apt tools read.
{
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
echo "License: GPL-3.0-or-later"
sed 's/^$/./; s/^/ /' "$here/LICENSE"
} > "$pkgdir/usr/share/doc/bandsaunter/copyright"
# Regenerated from the settings table rather than copied, so the manual
# cannot describe a version of the settings that no longer exists.
mkdir -p "$pkgdir/usr/share/man/man1"
python3 "$here/packaging/make-man.py" "$pkgdir/usr/share/man/man1/bandsaunter.1" \
>/dev/null
python3 "$here/packaging/make-browse-man.py" \
"$pkgdir/usr/share/man/man1/saunterbrowse.1" >/dev/null
gzip -9n "$pkgdir/usr/share/man/man1/bandsaunter.1"
gzip -9n "$pkgdir/usr/share/man/man1/saunterbrowse.1"
cat > "$pkgdir/usr/bin/bandsaunter" <<'EOF'
#!/usr/bin/python3
import sys
from bandsaunter.cli import main
sys.exit(main())
EOF
chmod 755 "$pkgdir/usr/bin/bandsaunter"
cat > "$pkgdir/usr/bin/saunterbrowse" <<'EOF'
#!/usr/bin/python3
import sys
from bandsaunter.browse import main
sys.exit(main())
EOF
chmod 755 "$pkgdir/usr/bin/saunterbrowse"
# Every one of these is in Debian, so apt resolves the lot. No speech
# recogniser is packaged for Debian, so that part ships as its own package
# (built by build-repo.sh) and is recommended rather than depended on: apt
# pulls it in from the repository, and a bare "dpkg -i" of this file still
# installs, without transcription.
cat > "$pkgdir/DEBIAN/control" <<EOF
Package: bandsaunter
Version: ${version}-${revision}
Section: hamradio
Priority: optional
Architecture: ${arch}
Depends: python3 (>= 3.10), python3-numpy, python3-scipy, python3-rich,
python3-yaml, librtlsdr0
Recommends: bandsaunter-transcribe, espeak-ng
Suggests: rtl-sdr, python3-pyqt6, ffmpeg
Maintainer: bandsaunter
Installed-Size: $(du -ks "$pkgdir" | cut -f1)
Description: signal scanner and recorder for RTL-SDR receivers
Sweeps any set of frequency ranges, or presets from a built-in US band plan,
records what it finds and works out what kind of signal it was.
.
Captures are kept only if they carry voice, decodable CW or an identified
digital keying scheme, so static and interference are discarded rather than
filling the disk. CW is decoded to text, and speech can be transcribed when
a recogniser is installed.
EOF
cat > "$pkgdir/DEBIAN/postinst" <<'EOF'
#!/bin/sh
set -e
if [ "$1" = configure ]; then
# The DVB-T driver claims the dongle on sight and has to be kept off it.
if [ ! -e /etc/modprobe.d/blacklist-rtlsdr.conf ]; then
echo 'blacklist dvb_usb_rtl28xxu' > /etc/modprobe.d/blacklist-rtlsdr.conf
echo 'bandsaunter: blacklisted dvb_usb_rtl28xxu; unplug and replug the'
echo ' receiver, or run: sudo rmmod dvb_usb_rtl28xxu'
fi
# Said once, at install time, only when there is genuinely nothing to
# transcribe with -- otherwise the recogniser package has already
# arrived and there is nothing to explain.
if ! python3 -c 'import importlib.util as u, sys
sys.path.append("/usr/lib/bandsaunter/vendor")
try:
found = any(u.find_spec(m) for m in
("faster_whisper", "whisper", "vosk", "pocketsphinx"))
except Exception:
found = True # something is there, however unhappy; say nothing
sys.exit(0 if found else 1)' \
2>/dev/null; then
echo 'bandsaunter: speech transcription is unavailable -- no recogniser'
echo ' is installed. Scanning, recording and CW decoding all'
echo ' work without one. To add transcription, either:'
echo ' apt install bandsaunter-transcribe'
echo ' (from the repository this package came from), or'
echo ' pip install --break-system-packages faster-whisper'
echo ' Then: bandsaunter transcribe --engines'
fi
fi
exit 0
EOF
chmod 755 "$pkgdir/DEBIAN/postinst"
cat > "$pkgdir/DEBIAN/prerm" <<'EOF'
#!/bin/sh
set -e
if [ "$1" = remove ] || [ "$1" = purge ]; then
rm -f /etc/modprobe.d/blacklist-rtlsdr.conf
fi
exit 0
EOF
chmod 755 "$pkgdir/DEBIAN/prerm"
out=${1:-$here/dist}
mkdir -p "$out"
fakeroot dpkg-deb --build "$pkgdir" "$out" >/dev/null
echo "$out/bandsaunter_${version}-${revision}_${arch}.deb"