fix(linux): run an "Open application" target instead of xdg-opening it - #839
fix(linux): run an "Open application" target instead of xdg-opening it#8394ni1ak wants to merge 3 commits into
Conversation
Greptile SummaryThe PR changes Linux application-target handling so executable paths and commands found on PATH are spawned directly, while URLs, documents, directories, and desktop entries continue through the desktop opener.
Confidence Score: 4/5The PR is not yet safe to merge because non-permission spawn failures still repeat the failed executable launch through the desktop opener. A target that passes the execute-bit check but fails to spawn for reasons other than permission denial is still passed unchanged to the opener, which does not run executable files and therefore leaves the Actions Ring slot inert. Files Needing Attention: crates/openlogi-inject/src/inject/linux.rs, crates/openlogi-inject/src/inject.rs
|
| Filename | Overview |
|---|---|
| crates/openlogi-inject/src/inject.rs | Routes Linux OpenApplication targets through launch_program before retaining the existing desktop-opener fallback. |
| crates/openlogi-inject/src/inject/linux.rs | Adds executable classification and direct spawning, but non-permission spawn failures still send the unchanged executable to the opener, leaving the previously reported fallback defect outstanding. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[OpenApplication target] --> B{Linux target classification}
B -->|URL, document, directory, desktop entry| C[Desktop opener]
B -->|Executable path or PATH command| D[Command spawn]
D -->|Success| E[Detached child wait]
D -->|Permission denied| F[Log and report handled]
D -->|Other spawn error| C
Reviews (5): Last reviewed commit: "fix(linux): don't hand an unexecutable p..." | Re-trigger Greptile
70a1fd7 to
19a9ab7
Compare
`Action::OpenApplication` handed its target straight to `opener::open`, which on Linux is `xdg-open` — and xdg-open *opens* a file. Given `/usr/bin/nautilus` it looks for a handler claiming `application/x-executable`, finds none, and does nothing at all, so the Actions Ring slot appeared dead. On Linux, classify the target first: an executable file path or a bare command name resolved on `PATH` is spawned as a program; URLs, folders, documents, and `.desktop` entries stay with the opener — a desktop entry especially, since xdg-open reads its `Exec=` and honours `Terminal=` and `StartupNotify=`, none of which spawning the file would. macOS and Windows keep going through the opener, where `open`/`ShellExecute` already run `.app` bundles and `.exe`s. The child is waited on from a detached thread so a long-lived app does not sit as a zombie for the agent's lifetime. The decision table takes its two filesystem probes as parameters, so it is tested with fakes; one further test pins the real probes against `sh` on `PATH`. Fixes AprilNEA#775
`is_executable` is a mode check, so a regular file carrying an execute bit for another user classified as a program. The spawn then failed inside the detached thread, after `launch_program` had already reported the target handled, so the opener fallback was skipped and activating the slot did nothing at all. Run the spawn on the calling thread and let its result decide the return value; only the wait stays detached, which is all it was ever needed for. `Command::spawn` reports a refused `exec` rather than succeeding and failing later, so a target this user cannot run — or one that is not a loadable binary, or vanished between the check and the call — now falls through to the desktop opener like any other file. The mode check stays as the classification heuristic and says so: the exec is the authority, and this is the layer that defers to it. Found by the Greptile review on this PR.
The previous fallback treated every refused spawn the same and passed the target to `xdg-open`. That helps when the mode bit was misleading — a data file with the bit set, a script with no interpreter — but not when the exec was refused for permissions: the opener cannot run it either, and its best case is a binary opened in a text editor. Split on the error. `PermissionDenied` is reported handled, with a warning saying the target is not executable by this user; everything else still falls through, because those really are the opener's business. Found by the Greptile review on this PR.
1d69177 to
290242b
Compare
Summary
An Actions Ring slot configured with an application did nothing on Linux.
Split out of #802 at your request.
Fixes #775
Changes
Action::OpenApplicationhanded its target straight toopener::open, which onLinux is
xdg-open— and xdg-open opens a file. Given/usr/bin/nautilusitlooks for a handler claiming
application/x-executable, finds none, and doesnothing, so the slot looked dead.
On Linux the target is now classified first:
PATH, is spawnedas a program;
.desktopentries stay with the opener — adesktop entry especially, since xdg-open reads its
Exec=and honoursTerminal=andStartupNotify=, none of which spawning the file would.macOS and Windows keep going through the opener, where
openandShellExecutealready run.appbundles and.exes.The child is waited on from a detached thread, so a long-lived GUI app is not
left as a zombie for the agent's lifetime. The decision table takes its two
filesystem probes as parameters, so it is unit-tested with fakes rather than
against the host.
Testing
Linux, x86_64, Rust 1.98.0:
All green. New tests:
executables_are_run_and_everything_else_goes_to_the_opener,an_executable_desktop_entry_still_goes_to_the_opener, andthe_real_probes_resolve_a_shell_on_path, which pins the two real filesystemprobes against
shonPATHrather than only the fakes.Not run on this host:
tests (macos),cargo-deny, macOS clippy — no macOSSDK here. The Windows cross-lint covers the non-Linux side of the one
#[cfg(target_os = "linux")]statement added toinject.rs.Not runtime-tested. To verify: configure
/usr/bin/nautilusand barenautilusin an Actions Ring slot — both should launch the file manager — andconfirm a folder path and an
https://URL still open as before.