Most people who want MeshTerm have a radio and a terminal, not a Python toolchain. This is the install for them: one file, download it, run it. `packaging/meshterm.spec` freezes the app with PyInstaller in console mode — which is not a detail, since a windowed build of a terminal program starts with nowhere to draw and exits. The assets land at `meshterm/assets` inside the bundle so that `Path(__file__).parent.parent / "assets"` keeps resolving exactly as it does in a checkout, and bleak's per-platform backends are named as hidden imports because nothing static ever sees the one that actually gets used. UPX is off: a few megabytes are not worth being flagged by antivirus on a first release. The build was run here rather than only written. The Windows executable comes out at 14 MB, runs from a directory with no source tree in sight, and draws the specimen card — which is the real test, because the specimen reads the asset files. `installers.yml` does the same on five machines, because frozen builds cannot be cross-compiled. Windows, macOS on both Apple silicon and Intel (plenty of people still have one, and an arm64 build will not run for them), and Linux on x64 and ARM64 — the last for the uConsole. Each leg runs the binary from a temporary directory before uploading it, so a build that only works beside its own source fails on the runner instead of on somebody's laptop, and each one gets a checksum written beside it. It publishes nothing; attaching these to a release stays a separate decision. Also here: `meshterm --help` now opens with the same sentence as the package summary, rather than a fourth description of the project written in its own way. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
68 lines
2.1 KiB
RPMSpec
68 lines
2.1 KiB
RPMSpec
# PyInstaller spec for the downloadable builds. Run from the repository root:
|
|
#
|
|
# pyinstaller packaging/meshterm.spec
|
|
#
|
|
# One file, console mode. Console is not a detail: MeshTerm *is* a terminal program, and
|
|
# a windowed build would start with nowhere to draw and exit immediately.
|
|
#
|
|
# Built on the machine it targets. There is no cross-compiling here — the Windows build
|
|
# comes off a Windows runner, the macOS one off macOS. That is what the workflow is for.
|
|
|
|
from PyInstaller.utils.hooks import collect_submodules
|
|
|
|
# The assets have to land at `meshterm/assets`, because `ui/about.py` finds them with
|
|
# `Path(__file__).parent.parent / "assets"` and that path has to keep resolving inside
|
|
# the bundle exactly as it does in a checkout.
|
|
datas = [
|
|
("../meshterm/assets", "meshterm/assets"),
|
|
]
|
|
|
|
hiddenimports = [
|
|
# bleak picks its backend at runtime by platform, so static analysis never sees the
|
|
# one that actually gets used. Collect all of them and let the unused ones sit.
|
|
*collect_submodules("bleak.backends"),
|
|
# Same story for the companion library's transports.
|
|
*collect_submodules("meshcore"),
|
|
# Rich and prompt_toolkit both reach for things dynamically.
|
|
"rich.console",
|
|
"prompt_toolkit.output.win32",
|
|
"prompt_toolkit.output.vt100",
|
|
]
|
|
|
|
a = Analysis(
|
|
["entry.py"],
|
|
pathex=[".."],
|
|
binaries=[],
|
|
datas=datas,
|
|
hiddenimports=hiddenimports,
|
|
hookspath=[],
|
|
hooksconfig={},
|
|
runtime_hooks=[],
|
|
# Nothing here is used, and each one drags in a GUI toolkit or a test framework.
|
|
excludes=["tkinter", "pytest", "IPython", "matplotlib", "numpy", "PIL"],
|
|
noarchive=False,
|
|
)
|
|
|
|
pyz = PYZ(a.pure)
|
|
|
|
exe = EXE(
|
|
pyz,
|
|
a.scripts,
|
|
a.binaries,
|
|
a.datas,
|
|
[],
|
|
name="meshterm",
|
|
debug=False,
|
|
bootloader_ignore_signals=False,
|
|
strip=False,
|
|
# UPX is off deliberately: it saves a few megabytes and gets the result flagged by
|
|
# antivirus often enough that it is not a trade worth making for a first release.
|
|
upx=False,
|
|
console=True,
|
|
disable_windowed_traceback=False,
|
|
argv_emulation=False,
|
|
target_arch=None,
|
|
codesign_identity=None,
|
|
entitlements_file=None,
|
|
)
|