From c6bdd63df21aaaab5a4180d60f95f82d8ec465b8 Mon Sep 17 00:00:00 2001 From: Juan Denis Date: Tue, 21 Jul 2026 23:33:48 -0400 Subject: [PATCH] Fix Windows PTY Docker resolution Add a shared `docker_program()` helper and use it for PTY terminal sessions so Windows resolves `docker.exe` instead of Docker Desktop's extensionless `docker` script. This avoids portable-pty launching a non-Win32 executable and fixes terminal startup on Windows. --- src-tauri/src/docker.rs | 32 ++++++++++++++++++++++++++++++++ src-tauri/src/terminal.rs | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/docker.rs b/src-tauri/src/docker.rs index 50d46a6..43fb15a 100644 --- a/src-tauri/src/docker.rs +++ b/src-tauri/src/docker.rs @@ -27,6 +27,38 @@ pub(crate) fn no_window(cmd: &mut Command) -> &mut Command { cmd } +/// The Docker CLI executable to launch, resolved to an absolute path when we +/// can find one. +/// +/// This matters only on Windows, and only for callers that spawn Docker +/// through `portable-pty` (the terminal). Docker Desktop ships *both* a +/// `docker` POSIX shell script and the real `docker.exe` in the same +/// `resources\bin` directory. `std::process::Command` appends `.exe` for us, +/// so the rest of the app resolves the binary correctly — but `portable-pty`'s +/// PATH search tries the bare name `docker` first and picks the script, which +/// `CreateProcessW` rejects with "%1 is not a valid Win32 application" +/// (os error 193). Resolving `docker.exe` ourselves — to an absolute path when +/// it is on PATH — sidesteps that quirk entirely. +pub(crate) fn docker_program() -> std::ffi::OsString { + #[cfg(windows)] + { + // Prefer an absolute `docker.exe` found on PATH; fall back to the bare + // name (`CommandBuilder` searches PATH, and the explicit `.exe` still + // avoids the extension-less script). + return std::env::var_os("PATH") + .into_iter() + .flat_map(|paths| std::env::split_paths(&paths).collect::>()) + .map(|dir| dir.join("docker.exe")) + .find(|candidate| candidate.is_file()) + .map(|path| path.into_os_string()) + .unwrap_or_else(|| "docker.exe".into()); + } + #[cfg(not(windows))] + { + "docker".into() + } +} + #[derive(Debug, Clone, Serialize)] pub struct DockerStatus { pub available: bool, diff --git a/src-tauri/src/terminal.rs b/src-tauri/src/terminal.rs index a569579..5b52dab 100644 --- a/src-tauri/src/terminal.rs +++ b/src-tauri/src/terminal.rs @@ -68,7 +68,7 @@ impl PtyManager { }) .map_err(|e| format!("failed to open PTY: {e}"))?; - let mut cmd = CommandBuilder::new("docker"); + let mut cmd = CommandBuilder::new(crate::docker::docker_program()); cmd.args(["compose", "exec", service, "bash"]); cmd.cwd(site_dir); cmd.env("TERM", "xterm-256color");