fix: keep native HoloLake entry responsive
This commit is contained in:
parent
3ff80d583a
commit
7a985a3761
9 changed files with 143 additions and 36 deletions
|
|
@ -20,12 +20,13 @@ mod status;
|
|||
mod upstream;
|
||||
|
||||
use std::ffi::{OsStr, OsString};
|
||||
use std::io;
|
||||
use std::io::{self, Read};
|
||||
#[cfg(unix)]
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
use std::process::{Command, Output, Stdio};
|
||||
use std::sync::OnceLock;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
#[cfg(test)]
|
||||
use std::cell::RefCell;
|
||||
|
|
@ -98,6 +99,8 @@ const GIT_SHELL_ENV_NAMES: [EnvName<'static>; 8] = [
|
|||
EnvName::trusted("EMAIL"),
|
||||
];
|
||||
|
||||
const GIT_WORK_TREE_PROBE_TIMEOUT: Duration = Duration::from_secs(2);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct GitLaunchConfig {
|
||||
program: OsString,
|
||||
|
|
@ -166,15 +169,52 @@ pub fn is_inside_work_tree(path: impl AsRef<Path>) -> bool {
|
|||
return false;
|
||||
}
|
||||
|
||||
let Ok(output) = git_command_at(path).and_then(|mut command| {
|
||||
command
|
||||
.args(["rev-parse", "--is-inside-work-tree"])
|
||||
.output()
|
||||
}) else {
|
||||
let Ok(mut command) = git_command_at(path) else {
|
||||
return false;
|
||||
};
|
||||
command
|
||||
.args(["rev-parse", "--is-inside-work-tree", "--show-toplevel"])
|
||||
.stdout(Stdio::null())
|
||||
.stderr(Stdio::null());
|
||||
|
||||
output.status.success() && String::from_utf8_lossy(&output.stdout).trim() == "true"
|
||||
command_output_with_timeout(&mut command, GIT_WORK_TREE_PROBE_TIMEOUT)
|
||||
.is_some_and(|output| output.status.success())
|
||||
}
|
||||
|
||||
pub(crate) fn command_output_with_timeout(
|
||||
command: &mut Command,
|
||||
timeout: Duration,
|
||||
) -> Option<Output> {
|
||||
let mut child = command
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped())
|
||||
.spawn()
|
||||
.ok()?;
|
||||
let deadline = Instant::now() + timeout;
|
||||
|
||||
loop {
|
||||
match child.try_wait() {
|
||||
Ok(Some(status)) => {
|
||||
let mut stdout = Vec::new();
|
||||
let mut stderr = Vec::new();
|
||||
child.stdout.take()?.read_to_end(&mut stdout).ok()?;
|
||||
child.stderr.take()?.read_to_end(&mut stderr).ok()?;
|
||||
return Some(Output {
|
||||
status,
|
||||
stdout,
|
||||
stderr,
|
||||
});
|
||||
}
|
||||
Ok(None) if Instant::now() < deadline => {
|
||||
std::thread::sleep(Duration::from_millis(10));
|
||||
}
|
||||
Ok(None) | Err(_) => {
|
||||
let _ = child.kill();
|
||||
let _ = child.wait();
|
||||
return None;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_git_shell_env(command: &mut Command) {
|
||||
|
|
@ -1147,4 +1187,18 @@ mod tests {
|
|||
assert_repo_path("https://gitlab.com/owner/repo.git", None);
|
||||
assert_repo_path("owner/repo", None);
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test]
|
||||
fn test_wait_for_command_kills_a_hung_process_at_the_deadline() {
|
||||
let mut command = Command::new("sh");
|
||||
command.args(["-c", "sleep 5"]);
|
||||
let started = std::time::Instant::now();
|
||||
|
||||
let status =
|
||||
command_output_with_timeout(&mut command, std::time::Duration::from_millis(40));
|
||||
|
||||
assert!(status.is_none());
|
||||
assert!(started.elapsed() < std::time::Duration::from_secs(2));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue