aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorOgulcan Celik <ogulcancelik@gmail.com>2026-07-16 21:23:53 +0300
committerOgulcan Celik <ogulcancelik@gmail.com>2026-07-16 21:23:53 +0300
commit616d1dd8125ece4a9102b231864cb4fc4b761497 (patch)
tree24647750130d05dcf4a0a262a1976b6bdd0fcee8 /src
parent76a4e3ccb0958ff54badfa65ba4d224d6b0c29a1 (diff)
fix(windows): suppress noninteractive process windows
refs #1468
Diffstat (limited to 'src')
-rw-r--r--src/detect/manifest_update.rs6
-rw-r--r--src/main.rs1
-rw-r--r--src/noninteractive_process.rs12
-rw-r--r--src/plugin_command.rs27
-rw-r--r--src/remote/unix.rs4
-rw-r--r--src/update.rs6
-rw-r--r--src/workspace/git/discovery.rs2
-rw-r--r--src/workspace/git/status.rs2
8 files changed, 46 insertions, 14 deletions
diff --git a/src/detect/manifest_update.rs b/src/detect/manifest_update.rs
index 02efa3bc..8c5fc339 100644
--- a/src/detect/manifest_update.rs
+++ b/src/detect/manifest_update.rs
@@ -4,7 +4,7 @@ use std::{
fmt, fs,
io::{Read, Write},
path::{Path, PathBuf},
- process::{Command, Stdio},
+ process::Stdio,
time::{SystemTime, UNIX_EPOCH},
};
@@ -470,9 +470,7 @@ fn catalog_url() -> String {
fn fetch_text(url: &str) -> Result<String, String> {
let max_fetch_bytes = MAX_FETCH_BYTES.to_string();
- let mut command = Command::new("curl");
- crate::platform::configure_background_command(&mut command);
- let mut child = command
+ let mut child = crate::noninteractive_process::curl_command()
.args([
"-sfL",
"--retry",
diff --git a/src/main.rs b/src/main.rs
index c48951c6..d7746f57 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -74,6 +74,7 @@ mod kitty_graphics;
mod layout;
mod logging;
mod metadata_tokens;
+mod noninteractive_process;
mod pane;
mod persist;
mod platform;
diff --git a/src/noninteractive_process.rs b/src/noninteractive_process.rs
new file mode 100644
index 00000000..98198dce
--- /dev/null
+++ b/src/noninteractive_process.rs
@@ -0,0 +1,12 @@
+use std::{ffi::OsStr, process::Command};
+
+/// Builds a subprocess whose stdio is controlled by the caller and which never opens a Windows console.
+pub(crate) fn command(program: impl AsRef<OsStr>) -> Command {
+ let mut command = Command::new(program);
+ crate::platform::configure_background_command(&mut command);
+ command
+}
+
+pub(crate) fn curl_command() -> Command {
+ command("curl")
+}
diff --git a/src/plugin_command.rs b/src/plugin_command.rs
index ba0a1422..a0f71894 100644
--- a/src/plugin_command.rs
+++ b/src/plugin_command.rs
@@ -12,7 +12,7 @@ pub(crate) fn command_for_argv(program: &str, args: &[String]) -> Command {
#[cfg(not(windows))]
fn command_for_program(program: &str) -> Command {
- Command::new(program)
+ crate::noninteractive_process::command(program)
}
#[cfg(windows)]
@@ -29,11 +29,11 @@ fn command_for_program(program: &str) -> Command {
{
let shell =
std::env::var_os("ComSpec").unwrap_or_else(|| r"C:\Windows\System32\cmd.exe".into());
- let mut command = Command::new(shell);
+ let mut command = crate::noninteractive_process::command(shell);
command.arg("/d").arg("/c").arg(command_program);
command
} else {
- Command::new(command_program)
+ crate::noninteractive_process::command(command_program)
}
}
@@ -126,4 +126,25 @@ mod tests {
assert!(!is_windows_batch_file_name("node.exe"));
assert!(!is_windows_batch_file_name("node"));
}
+
+ #[cfg(windows)]
+ #[test]
+ fn windows_batch_command_captures_output() {
+ let path = std::env::temp_dir().join(format!(
+ "herdr-plugin-command-output-{}.cmd",
+ std::process::id()
+ ));
+ std::fs::write(&path, "@echo off\r\necho plugin-%1\r\n").expect("write batch fixture");
+
+ let output = command_for_argv(&path.display().to_string(), &["ready".to_string()])
+ .output()
+ .expect("run batch fixture");
+ let _ = std::fs::remove_file(&path);
+
+ assert!(output.status.success(), "{output:?}");
+ assert_eq!(
+ String::from_utf8_lossy(&output.stdout).trim(),
+ "plugin-ready"
+ );
+ }
}
diff --git a/src/remote/unix.rs b/src/remote/unix.rs
index 7544585f..40e8bb45 100644
--- a/src/remote/unix.rs
+++ b/src/remote/unix.rs
@@ -1449,7 +1449,7 @@ fn download_release_asset(platform: &RemotePlatform) -> io::Result<InstallSource
let dir = private_download_dir(&asset_key)?;
let path = dir.join("herdr.tmp");
- let status = Command::new("curl")
+ let status = crate::noninteractive_process::curl_command()
.args(["-sfL", "--max-time", "120", "-o"])
.arg(&path)
.arg(&asset.url)
@@ -1473,7 +1473,7 @@ fn download_release_asset(platform: &RemotePlatform) -> io::Result<InstallSource
}
fn fetch_remote_manifest(url: &str) -> io::Result<Vec<u8>> {
- let output = Command::new("curl")
+ let output = crate::noninteractive_process::curl_command()
.args([
"-sfL",
"--retry",
diff --git a/src/update.rs b/src/update.rs
index 8ef77840..eac917bf 100644
--- a/src/update.rs
+++ b/src/update.rs
@@ -294,7 +294,7 @@ fn fetch_json_manifest<T>(url: &str) -> Result<T, String>
where
T: serde::de::DeserializeOwned,
{
- let output = Command::new("curl")
+ let output = crate::noninteractive_process::curl_command()
.args([
"-sfL",
"--retry",
@@ -508,7 +508,7 @@ fn homebrew_update_from_formula_json(
fn check_homebrew_latest() -> Result<Option<Version>, String> {
let current = Version::current();
- let output = Command::new("curl")
+ let output = crate::noninteractive_process::curl_command()
.args([
"-sfL",
"--retry",
@@ -571,7 +571,7 @@ fn download_update(release: &ReleaseInfo) -> Result<DownloadedUpdate, String> {
let tmp_path = parent.join(format!(".herdr-update-{}.tmp", std::process::id()));
// Download the exact asset URL (pinned to the release we checked)
- let status = Command::new("curl")
+ let status = crate::noninteractive_process::curl_command()
.args(["-sfL", "--max-time", "120", "-o"])
.arg(&tmp_path)
.arg(&release.download_url)
diff --git a/src/workspace/git/discovery.rs b/src/workspace/git/discovery.rs
index 9aa351b2..4edfcbc2 100644
--- a/src/workspace/git/discovery.rs
+++ b/src/workspace/git/discovery.rs
@@ -216,7 +216,7 @@ fn strip_git_config_comment(value: &str) -> &str {
}
fn git_trimmed_stdout(repo_root: &Path, args: &[&str]) -> Option<String> {
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.arg("-C")
.arg(repo_root)
.args(args)
diff --git a/src/workspace/git/status.rs b/src/workspace/git/status.rs
index 024ffdde..d9c3123a 100644
--- a/src/workspace/git/status.rs
+++ b/src/workspace/git/status.rs
@@ -218,7 +218,7 @@ fn git_ahead_behind_between(
upstream_oid: &str,
) -> Option<(usize, usize)> {
let range = format!("{head_oid}...{upstream_oid}");
- let output = std::process::Command::new("git")
+ let output = crate::noninteractive_process::command("git")
.arg("-C")
.arg(cwd)
.args(["rev-list", "--left-right", "--count", &range])