Skip to content

feat(linux): native tray app, Rust core and AppImage releases - #112

Closed
productdevbook wants to merge 1 commit into
mainfrom
feat/linux-support
Closed

feat(linux): native tray app, Rust core and AppImage releases#112
productdevbook wants to merge 1 commit into
mainfrom
feat/linux-support

Conversation

@productdevbook

Copy link
Copy Markdown
Owner

Adds Linux support: a GTK 3 system tray app, the Rust scanning core, CI, and an AppImage attached to each release.

Supersedes #111. That PR targeted feat/rust-cross-platform-backend, which is 57 commits behind main, so nothing in it reached users. This rebuilds the work on current main and keeps only the Linux parts.

Credit to @raine1120 for the original implementation.

Scope

Deliberately not included:

  • portkiller-core's macOS and Windows backends, and the windows crate dependency. Those platforms have native Swift and .NET apps that don't use this crate, so shipping their Rust implementations would be dead code. scanner/mod.rs and process/mod.rs are now Linux-only, and the crate compile_error!s elsewhere.
  • portkiller-ffi.

platforms/linux/ is self-contained Python and doesn't depend on the Rust core today. Worth deciding later whether it should bind to it through FFI rather than keeping two scanner implementations.

CI — .github/workflows/ci-linux.yml

  • Rust: cargo build/test/clippy -D warnings/fmt --check on Ubuntu, with procps iproute2 lsof installed — without them the integration tests fail instead of exercising the real paths. This code is cfg-gated, so the existing macOS/Windows jobs never compiled it.
  • Python: parser tests on 3.9 and 3.12, plus shellcheck on install.sh.
  • Smoke: imports every module under a real GTK stack via xvfb. The parser tests never load the UI modules, so a broken import there would otherwise slip through.

Release — build-linux job

Builds an AppImage and attaches it to the release.

The GTK stack is taken from the host rather than bundled. PyGObject binds tightly to the system GLib/GTK, and bundling those breaks on distros whose versions differ from the build image. The launcher checks for the bindings up front and prints per-distro install hints if they're missing. The job then extracts the AppImage it just built and asserts the entry point, src/ and AppRun are all present.

Verification

Everything below was run on Linux in Docker, not just on macOS:

  • cargo build + cargo test — 20 tests + 2 doc-tests pass (with procps/iproute2/lsof present)
  • cargo clippy -- -D warnings and cargo fmt --check — clean
  • Python suite — 26 tests pass on 3.x
  • shellcheck install.sh — clean
  • AppImage — built end to end (959K) and verified by extraction

Two things the verification caught and fixed: a manual_strip clippy failure, and install.sh looking for the icon at a root Resources/ directory that only existed on the old branch.

Included from the #111 review

The review fixes are all carried over — most notably pkill -f "kubectl.*port-forward" (which matched unrelated processes) replaced with signalling only scanned PIDs, window.py wired up instead of sitting dead, scanning moved off the GTK main thread, the SIGTERM→SIGKILL sequence honoured, and the UTF-8 mangling in decode_escaped.

Adds Linux support: a GTK 3 system tray application, the Rust scanning
core it is built around, CI, and an AppImage published on each release.

Originally contributed by @raine1120 in #111, which targeted the stale
feat/rust-cross-platform-backend branch (57 commits behind main). This
rebuilds that work on top of current main and drops everything that was
not Linux-related.

Scope:
- portkiller-core carries only the Linux backends. The macOS and Windows
  implementations are omitted along with the Windows crate dependency —
  those platforms have native Swift and .NET apps that do not use this
  crate. portkiller-ffi is not included.
- platforms/linux/ is self-contained Python and does not depend on the
  Rust core today.

CI (.github/workflows/ci-linux.yml):
- cargo build/test/clippy/fmt on Ubuntu. The Linux code is cfg-gated, so
  it was never compiled by the existing macOS and Windows jobs.
- Python parser tests on 3.9 and 3.12, plus shellcheck on install.sh.
- A GTK import smoke test, since the parser tests never load the UI
  modules and would not catch a broken import there.

Release (build-linux job):
- Builds a self-contained AppImage and attaches it to the release.
- The GTK stack is taken from the host rather than bundled: PyGObject
  binds tightly to the system GLib/GTK and bundling it breaks on distros
  whose versions differ from the build image. The launcher checks for the
  bindings and prints per-distro install hints if they are missing.
- Verified end to end: the job extracts the built AppImage and asserts
  the entry point, sources and AppRun are present.

Also fixes install.sh, which looked for the icon at a root Resources/
directory that only existed on the old branch.

Co-Authored-By: Raine Sanchez <raine1120@users.noreply.github.com>
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
productdevbook pushed a commit that referenced this pull request Jul 24, 2026
Adds Linux support: a GTK 3 system tray application, the Rust scanning
core, CI, and an AppImage published on each release.

Scope:
- portkiller-core carries only the Linux backends. The macOS and Windows
  implementations are omitted along with the Windows crate dependency —
  those platforms have native Swift and .NET apps that do not use this
  crate. portkiller-ffi is not included.
- platforms/linux/ is self-contained Python and does not depend on the
  Rust core today.

CI (.github/workflows/ci-linux.yml):
- cargo build/test/clippy/fmt on Ubuntu. The Linux code is cfg-gated, so
  it was never compiled by the existing macOS and Windows jobs.
- Python parser tests on 3.9 and 3.12, plus shellcheck on install.sh.
- A GTK import smoke test, since the parser tests never load the UI
  modules and would not catch a broken import there.

Release (build-linux job):
- Builds a self-contained AppImage and attaches it to the release.
- The GTK stack is taken from the host rather than bundled: PyGObject
  binds tightly to the system GLib/GTK and bundling it breaks on distros
  whose versions differ from the build image. The launcher checks for the
  bindings and prints per-distro install hints if they are missing.
- The job extracts the built AppImage and asserts the entry point,
  sources and AppRun are present.

Also fixes install.sh, which looked for the icon at a root Resources/
directory that does not exist in this tree.
@productdevbook

Copy link
Copy Markdown
Owner Author

Merged into main as fcfdb5a. Squashed and pushed directly so the commit is authored by @raine1120, who wrote the implementation. The tree is byte-identical to this PR's head — all four CI jobs passed here before merge.

@productdevbook
productdevbook deleted the feat/linux-support branch July 24, 2026 21:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant