fix(packaging): derive the Flatpak and AUR dependency sets from the lock (#819)

* fix(packaging): derive the Flatpak and AUR dependency sets from the lock

* test(packaging): add return annotations on new packaging tests

Greptile asked for -> None on the new tests, matching AGENTS.md.

* test(packaging): type parametrized Flatpak source arguments

Greptile asked for type hints on the source parameter, matching AGENTS.md.

---------

Co-authored-by: jatinkrmalik <jatinkrmalik@gmail.com>
This commit is contained in:
Sergey
2026-09-12 12:41:06 -07:00
committed by GitHub
co-authored by jatinkrmalik
parent 4d8c58f536
commit 1fac26ff07
11 changed files with 796 additions and 58 deletions
+28 -9
View File
@@ -74,19 +74,38 @@ flatpak-builder --run build-dir packaging/flatpak/com.vocalinux.Vocalinux.yml \
## Python Dependencies
`python3-dependencies.yaml` is generated with `flatpak-pip-generator` (offline
builds). Regenerate when `pyproject.toml` deps change:
`python3-dependencies.yaml` is generated from `requirements/runtime.txt`, the
hash-pinned export `just lock` writes out of `uv.lock`. Refresh it whenever the
dependency set changes:
```bash
pipx run flatpak-pip-generator \
--runtime org.gnome.Sdk//50 \
--yaml \
--ignore-pkg 'vosk>=0.3.45' "PyGObject; sys_platform == 'linux'" \
--output packaging/flatpak/python3-dependencies \
pywhispercpp pydub pynput evdev requests tqdm numpy pyaudio python-xlib psutil lxml \
meson-python pyproject-metadata
just flatpak-deps # rewrite the manifest (needs PyPI)
just flatpak-deps-check # report drift, change nothing
```
`just lock` runs the first of those itself, so a normal dependency change needs
no extra step.
The script resolves each package's URL by looking up the digest uv already
recorded, so the bytes this build downloads are the bytes in `uv.lock`, not
merely the same version number. It takes a universal wheel where one exists and
the sdist otherwise; an ABI-tagged wheel would pin the build to one SDK Python.
This replaced a `flatpak-pip-generator` invocation whose package list was typed
out on the command line. Nothing regenerated it and no test compared it to
anything, so it drifted: by 2026-09-10 ten of its fifteen shared packages were
behind the lock, `pydub` and `lxml` were still built four months after #705
deleted them for having no imports, and pywhispercpp sat at 1.4.1 under the
project's own `>=1.5.0`. The project is installed here with
`pip3 install --no-deps`, so nothing inside the build could notice.
`tests/test_flatpak_packaging.py` is what notices now, and it runs offline.
Two things in that file are hand-written and the script preserves them, because
no generator produces them: pywhispercpp's Vulkan build, which injects a version
into `setup.py` (the sdist ships no `version.txt`, `setup()` takes no `version=`
argument, and setuptools-scm has no git tree to read in the sandbox), and the
symlinking of whisper.cpp's shared libraries onto the loader path.
`python3-build-dependencies.yaml` is a small hand-maintained helper so
`--no-build-isolation` builds can import `mesonpy` before NumPy is built.
@@ -7,7 +7,7 @@ command: vocalinux
build-options:
env:
NO_REPAIR: "1"
PYWHISPERCPP_VERSION: "1.4.1"
PYWHISPERCPP_VERSION: "1.5.0"
finish-args:
# Download speech-recognition models on first run.
+38 -43
View File
@@ -1,4 +1,12 @@
# Generated with flatpak-pip-generator --runtime org.gnome.Sdk//50 --yaml --ignore-pkg vosk>=0.3.45 PyGObject; sys_platform == 'linux' --output /tmp/vocalinux-flatpak-gen3/python3-dependencies pywhispercpp pydub pynput evdev requests tqdm numpy pyaudio python-xlib psutil lxml meson-python pyproject-metadata
# Generated by scripts/sync_flatpak_deps.py from requirements/runtime.txt, the
# hash-pinned export `just lock` writes out of uv.lock. Run `just flatpak-deps`
# after any dependency change; `just flatpak-deps-check` and
# tests/test_flatpak_packaging.py fail when this file falls behind.
#
# Do not hand-edit the url/sha256 pairs. Every other line is hand-written and
# the script preserves it: pywhispercpp needs a Vulkan build, a version
# injected into setup.py, and whisper.cpp's shared libraries symlinked onto
# the loader path, none of which a generator produces.
name: python3-dependencies
buildsystem: simple
build-commands: []
@@ -10,10 +18,15 @@ modules:
# the offline Flatpak build, so inject the version explicitly. --no-same-owner
# stops GNU tar from trying to restore the archive's uid inside the build
# sandbox (where chown to an arbitrary uid is not permitted).
- tar --no-same-owner -xzf pywhispercpp-1.4.1.tar.gz
- python3 -c "from pathlib import Path; p = Path('pywhispercpp-1.4.1/setup.py'); s = p.read_text(); p.write_text(s.replace('setup(\\n name=\"pywhispercpp\",', 'setup(\\n name=\"pywhispercpp\",\\n version=\"1.4.1\",'))"
- tar --owner=0 --group=0 -czf pywhispercpp-1.4.1.tar.gz pywhispercpp-1.4.1
- PYWHISPERCPP_VERSION=1.4.1 NO_REPAIR=1 GGML_VULKAN=1 pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
- tar --no-same-owner -xzf pywhispercpp-1.5.0.tar.gz
# The build runs under --no-build-isolation, where setuptools-scm is absent,
# so a replace that matched nothing would not fail -- it would produce a wheel
# carrying version 0.0.0. recognition_manager.py reads that metadata and
# degrades GPU context_params below the floor in pyproject.toml, silently.
# Assert the shape instead.
- python3 -c "from pathlib import Path; p = Path('pywhispercpp-1.5.0/setup.py'); s = p.read_text(); n = 'setup(\\n name=\"pywhispercpp\",'; assert n in s, 'pywhispercpp setup.py no longer matches the injection point'; p.write_text(s.replace(n, n + '\\n version=\"1.5.0\",'))"
- tar --owner=0 --group=0 -czf pywhispercpp-1.5.0.tar.gz pywhispercpp-1.5.0
- PYWHISPERCPP_VERSION=1.5.0 NO_REPAIR=1 GGML_VULKAN=1 pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
--prefix=${FLATPAK_DEST} "pywhispercpp" --no-build-isolation
# whisper.cpp installs its shared libraries next to the extension module.
# Symlink them onto the default loader path so the extension resolves them
@@ -29,47 +42,38 @@ modules:
sources:
- &id002
type: file
url: https://files.pythonhosted.org/packages/22/30/7cd8fdcdfbc5b869528b079bfb76dcdf6056b1a2097a662e5e8c04f42965/certifi-2026.4.22-py3-none-any.whl
sha256: 3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a
url: https://files.pythonhosted.org/packages/0b/a7/71ac2cff56fec219ed242bb11b8efb69fcc4bec75db06fb7bfe35de520e6/certifi-2026.7.22-py3-none-any.whl
sha256: 62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775
- &id003
type: file
url: https://files.pythonhosted.org/packages/db/8f/61959034484a4a7c527811f4721e75d02d653a35afb0b6054474d8185d4c/charset_normalizer-3.4.7-py3-none-any.whl
sha256: 3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d
url: https://files.pythonhosted.org/packages/cc/61/d01fc49b8dea277640b55a9e15960dbca9fdc8c9fde18e572d39c59f4019/charset_normalizer-3.5.1-py3-none-any.whl
sha256: 6df0ec430f9a831772c23ca5a224cba36517a58a84bb32c32bb59a9fa67c47f6
- &id004
type: file
url: https://files.pythonhosted.org/packages/5d/13/ad7d7ca3808a898b4612b6fe93cde56b53f3034dcde235acb1f0e1df24c6/idna-3.13-py3-none-any.whl
sha256: 892ea0cde124a99ce773decba204c5552b69c3c67ffd5f232eb7696135bc8bb3
url: https://files.pythonhosted.org/packages/57/b0/0e52c878c53f245edd3a11020f20979b3f490f245af532c7cae3027754b5/idna-3.19-py3-none-any.whl
sha256: 815e7be7a7806d54abb586dc943addc79e8b2ee16915059658cbeff4b1b43bf4
- &id008
type: file
url: https://files.pythonhosted.org/packages/d7/9f/b8cef5bffa569759033adda9481211426f12f53299629b410340795c2514/numpy-2.4.4.tar.gz
sha256: 2d390634c5182175533585cc89f3608a4682ccb173cc9bb940b2881c8d6f8fa0
url: https://files.pythonhosted.org/packages/9a/80/db0b4559e57ec36362bedbb05530a87fafbcb6067708c946967a41d449e7/numpy-2.5.2.tar.gz
sha256: d482d171c406ae88c5b19cad3b6a1c4c5209f886ab74bc44c2c865c23f52d860
- type: file
url: https://files.pythonhosted.org/packages/75/a6/a0a304dc33b49145b21f4808d763822111e67d1c3a32b524a1baf947b6e1/platformdirs-4.9.6-py3-none-any.whl
sha256: e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917
url: https://files.pythonhosted.org/packages/19/a9/c34aebedd3a4c9afe5101b1b8713710b3fec18087c8a36c35d2f909861bd/platformdirs-4.11.3-py3-none-any.whl
sha256: 5ed065d443751de711da036041a7a214122efc4a4de393b3f4137ba5576540e7
- type: file
url: https://files.pythonhosted.org/packages/f6/7d/fe4b2b190d6cdcf0d5e4ca2b946d73bc449a586606a24d25ff50ffec5a5c/pywhispercpp-1.4.1.tar.gz
sha256: 520ce9275bb6fc81e0daa2e08144a80ee006b117a18058a77860c5b1c9c122f4
url: https://files.pythonhosted.org/packages/1c/43/8778f0685a4d32d74efdfa78fc5f745ca9998d96f8121dbf7793db2da5d3/pywhispercpp-1.5.0.tar.gz
sha256: 5aa54c73ec96617d97aa519dbbf817e44255eddd9bd52ee1243be61028dbd018
- &id005
type: file
url: https://files.pythonhosted.org/packages/d7/8e/7540e8a2036f79a125c1d2ebadf69ed7901608859186c856fa0388ef4197/requests-2.33.1-py3-none-any.whl
sha256: 4e6d1ef462f3626a1f0a0a9c42dd93c63bad33f9f1c1937509b8c5c8718ab56a
url: https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl
sha256: 2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0
- &id007
type: file
url: https://files.pythonhosted.org/packages/16/e1/3079a9ff9b8e11b846c6ac5c8b5bfb7ff225eee721825310c91b3b50304f/tqdm-4.67.3-py3-none-any.whl
sha256: ee1e4c0e59148062281c49d80b25b67771a127c85fc9676d3be5f243206826bf
url: https://files.pythonhosted.org/packages/f9/1c/01bfd571a64e7f270e6bab5e33777debe0edc56759233ce84f27dec92d14/tqdm-4.70.0-py3-none-any.whl
sha256: 7f585706bfddbdebf89daac705b2dfcc16890130727d3197ca62c732b4310953
- &id006
type: file
url: https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl
sha256: bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4
- name: python3-pydub
buildsystem: simple
build-commands:
- pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
--prefix=${FLATPAK_DEST} "pydub" --no-build-isolation
sources:
- type: file
url: https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl
sha256: 65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6
url: https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl
sha256: 9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897
- name: python3-pynput
buildsystem: simple
build-commands:
@@ -81,8 +85,8 @@ modules:
url: https://files.pythonhosted.org/packages/a5/f5/397b61091120a9ca5001041dd7bf76c385b3bfd67a0e5bcb74b852bd22a4/evdev-1.9.3.tar.gz
sha256: 2c140e01ac8437758fa23fe5c871397412461f42d421aa20241dc8fe8cfccbc9
- type: file
url: https://files.pythonhosted.org/packages/59/4f/ac3fa906ae8a375a536b12794128c5efacade9eaa917a35dfd27ce0c7400/pynput-1.8.1-py2.py3-none-any.whl
sha256: 42dfcf27404459ca16ca889c8fb8ffe42a9fe54f722fd1a3e130728e59e768d2
url: https://files.pythonhosted.org/packages/6d/98/bbeb760852adb27f166ce1617f0e51aabb15f21b1e60ea703f2aed3c78ac/pynput-1.8.2-py2.py3-none-any.whl
sha256: 8cc38cf13a6ab2749cb375678be8a0fd705d7ce49c8001ff5db4007a723bbef1
- &id009
type: file
url: https://files.pythonhosted.org/packages/fc/b8/ff33610932e0ee81ae7f1269c890f697d56ff74b9f5b2ee5d9b7fa2c5355/python_xlib-0.33-py2.py3-none-any.whl
@@ -149,15 +153,6 @@ modules:
- type: file
url: https://files.pythonhosted.org/packages/aa/c6/d1ddf4abb55e93cebc4f2ed8b5d6dbad109ecb8d63748dd2b20ab5e57ebe/psutil-7.2.2.tar.gz
sha256: 0746f5f8d406af344fd547f1c8daa5f5c33dbc293bb8d6a16d80b4bb88f59372
- name: python3-lxml
buildsystem: simple
build-commands:
- pip3 install --verbose --exists-action=i --no-index --find-links="file://${PWD}"
--prefix=${FLATPAK_DEST} "lxml" --no-build-isolation
sources:
- type: file
url: https://files.pythonhosted.org/packages/28/30/9abc9e34c657c33834eaf6cd02124c61bdf5944d802aa48e69be8da3585d/lxml-6.1.0.tar.gz
sha256: bfd57d8008c4965709a919c3e9a98f76c2c7cb319086b3d26858250620023b13
- name: python3-meson-python
buildsystem: simple
build-commands: