Repository navigation
Phase D: packaging, release gates and CI for the 2.0 catch-up - #84
Merged
Merged
Conversation
…g backend 2.0 replaced the Linux-only jeepney pin with an unconditional keyboard pin. FTHR_UI never imports keyboard; only FTHR.spec names it as a hidden import, so it gets a win32 marker and jeepney (GlobalShortcuts portal) comes back with its non-Windows marker. Restore keyboard's licence text, which the merge lost because the linux branch had dropped the package. keyring resolves its Secret Service backend through SecretStorage and jeepney on Linux. Pin both with linux markers in requirements-uploader.txt so the frozen uploader is reproducible, and add their licence texts to the optional-uploader inventory. Every pin has a manylinux_2_34-or-older wheel for CPython 3.12 and 3.14, inside the glibc 2.35 baseline.
… builders 2.0's _write_core_manifest regenerates uploader_bundle_manifest.py wholesale, which erased EXPECTED_UPLOADER_LINUX_BUNDLE_SHA256 on every Windows build, while build_linux_uploader.py still sealed the 1.1.0 plugin against the 2026-08-24 terms. build_optional_uploaders.py is now the one source of the plugin version, legal versions, licence inventory and binding format: render_core_manifest() regenerates the file from those constants and carries the other platform's hash over, and the Linux builder imports it. Both builders now refuse to freeze when requirements-uploader.txt is not satisfied. PyInstaller otherwise builds an executable without paramiko and the sealed package only fails when it runs, which is why "Test built optional upload packages" fails on Windows. The Linux builder also embeds the optional-uploader licences like the Windows package, names sftp_provider and keyring's Secret Service backend as hidden imports, drops the FTHR_Hardware_ID path 2.0 removed, and unpacks the ELF members of its one-file payload so the glibc gate can inspect them.
The 2.0 editor renders the clip preview and snapshots in QQuickWidget scenes (ui/qml/*.qml importing QtQuick and QtMultimedia, with a precompiled color.frag.qsb), so FTHR_linux.spec stops excluding QtQuick/QtQml, collects ui/qml, gatze.png and ui/capture_card_process.py, and names the Quick modules as hidden imports. Every other new 2.0 module is imported statically; the build's PYZ table confirms it is collected. Like FTHR.spec, the Qt hooks' output is filtered: only the QtQml, QtQml/Models, QtQml/WorkerScript, QtQuick and QtMultimedia import directories, only Qt libraries listed in qt_runtime_manifest.json, and no qmltooling plugins (QML debugger; one links the GPL-only Quick 3D). The filter is anchored to the wheel's qml/ destination so it cannot drop the application's own ui/qml files. The manifest gains 2.0's Windows Quick modules and licence sources, and QmlCore, QuickWidgets and MultimediaQuick for Linux. A local build ships 25 Qt modules, every libQt6 NEEDED entry resolves inside the bundle, and both scenes load with only the bundled QML import tree on the import path.
The licence gate failed on linux-2.0 because the kept linux asset manifest did not know 2.0's new assets (Oswald Regular/SemiBold, gatze.png, 24 SVG icons, the Ko-fi symbol, the polished installer artwork) and still listed .github/social_preview.png, which upstream deleted. Take 2.0's manifest, keep the linux entries for shared files and the AppDir icon, and give every Windows-distributed new asset the same _internal/assets path in the AppImage, where FTHR_linux.spec puts it. generate_release_assets.py stops expecting the deleted social preview so its --check passes again.
The merge took 2.0's THIRD_PARTY_NOTICES.md, which removed every Linux entry (Linux FFmpeg, jeepney, Wayland protocols, PipeWire/D-Bus headers, the AppImage runtime) although the AppImage still ships or uses them. Start from the linux notices and add what 2.0 brought: the Windows-only keyboard package, the Qt Quick/QML modules the editor bundles, the optional uploader's dependencies (paramiko LGPL-2.1+, the Linux SecretStorage and jeepney backend), and the new Oswald, SVG, user-provided and Ko-fi assets.
The merge took 2.0's pyproject.toml, which drops pythonpath, the linux_only marker (--strict-markers turns its uses into errors) and the FTHRcapture_linux/AppDir ruff excludes. Keep those and 2.0's new backup directory excludes.
"Test built optional upload packages" failed on Windows with "No module named 'paramiko'": no job installed requirements-uploader.txt, so the sealed executable was frozen without its SFTP stack. The Windows engine, AppImage and Python jobs now install it (tests/test_sftp_provider.py imports paramiko too). The AppImage job and build_linux.sh pass the unpacked uploader payload to the glibc gate; the one-file executable inside the .fthrplugin was invisible to it. From 2.0: bash as the default shell (the MSBuild step moves to pwsh explicitly) and the no-secrets comment. Kept from linux: every Linux job, the PyInstaller exit-code check, ubuntu release verification and the narrow "test_built_" run on Windows, since the python matrix already runs the rest of the plugin boundary tests. The CI contract tests get back the Linux engine job check and a check for the uploader lock installs.
FTHR.spec's QML filter matched any destination containing '/qml/'. The application's own scenes are bundled at ui/qml/, so VideoPreview.qml, Snapshot.qml and color.frag.qsb failed the "allowed QML module" test and were dropped: the packaged editor loses the GPU preview (it silently falls back to the CPU path) and snapshot scenes fail to load. Anchor the filter to the PySide6 wheel's QML tree as PyInstaller's Qt hooks lay it out (pyside6_library_info.qt_rel_dir: 'PySide6' on Windows, so 'PySide6/qml/'), as FTHR_linux.spec already does. The licence gate now also requires the three files in --windows-dist, --appdir and --all artifacts, byte-identical to FTHR_UI/ui/qml, so a filter regression fails the release instead of shipping a degraded editor.
The Linux pytest row ignored test_linux_appimage_report.py, test_linux_runtime.py, test_linux_tools.py and test_capture_backend_detection.py, and the Windows row ignores them too, so they ran nowhere. The commit that added the ignores gives no reason, and all four pass headless: the report test only runs the shell script against a fake image, and the backend test uses the engine "Prepare Linux test artifacts" already builds with the pinned FFmpeg on LD_LIBRARY_PATH (the one case that needs a real Wayland session skips itself). A CI contract test keeps them in the Linux row.
The glibc gate saw the ELF members unpacked from the uploader's one-file payload but not the executable that carries them: its PyInstaller bootloader is what the host loader runs first. Pass it as a target in build_linux.sh and in the AppImage CI job (it needs GLIBC_2.14 locally).
SecretStorage and jeepney are bundled into the Linux uploader so keyring's Secret Service backend is available, but sftp_provider still saves passwords only through Windows Credential Manager; the Linux wiring is the next UI change. Say so in the notices, docs/linux.md and the uploader lock.
kalopsia-space
force-pushed
the
port/linux-2.0-packaging
branch
from
October 17, 2026 14:03
a2be00b to
03fdc3c
Compare
test_frozen_extension_connects_to_real_sftp activates the sealed Windows uploader package, which only the Windows engine job builds. In the python matrix it failed with "bundle is missing" as soon as paramiko was installed and the module could be collected. Skip it when the package is absent and run it in "Test built optional upload packages" after the build.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase D of docs/linux-2.0-catch-up.md.
What changes
keyboardis Windows-only (FTHR_UI never imports it; only FTHR.spec names it),jeepneyis back for the portal, and keyring's Linux backend (SecretStorage 3.5.0, jeepney 0.9.0) is pinned inrequirements-uploader.txtwith licence texts. Every uploader pin has a manylinux_2_34-or-older wheel for CPython 3.12 and 3.14.build_optional_uploaders.pyis the one source of plugin version, terms/privacy versions, licence inventory and the Core binding format. Each builder regeneratesuploader_bundle_manifest.pyand keeps the other platform's hash, so a Windows build no longer erases the Linux hash. Both builders refuse to run whenrequirements-uploader.txtis not satisfied. The Linux builder moves to 1.4.0/v3, embeds the licences, includessftp_providerand the Secret Service backend, drops FTHR_Hardware_ID, and unpacks its payload ELFs for the glibc gate.ui/qml(with the .qsb),gatze.pngandui/capture_card_process.py. The filter mirrors FTHR.spec: it keeps the 5 QML import directories and only the Qt libraries in the manifest, and drops qmltooling.generate_release_assets.py --checkno longer expects that preview.requirements-uploader.txt. The AppImage glibc check covers the uploader payload. From 2.0: the bash default shell and pwsh for MSBuild. All Linux jobs, the PyInstaller exit-code check and ubuntu release verification stay.Verification (local, Arch)
verify_release_licenses.py --tree .passes (177 checks);--appdiron a fresh AppDir passes (190 checks).verify_version_consistency.py,verify_engine_response_contract.py,verify_exception_handling.pyandscan_repo_hygiene.pypass, and so doesruff check ..verify_shared_memory_contract.pyfails on the Linux layout becausecapture_bridgestill has the 2.0 wchar layout. That is Phase B work. CI never reached this step before, because the licence step failed first.bash build_linux.shgets through the engine, the uploader (71 payload ELFs unpacked), PyInstaller, the licence gate and appimagetool. It stops at the glibc 2.35 gate, as expected for an Arch build. That gate now also reports the uploader payload.Snapshot.qmlandVideoPreview.qmlload as Ready.