1pub mod info;
2pub mod ops;
3pub mod worktree;
4
5use std::path::Path;
6use std::process::Command;
7
8pub fn git_cmd(repo: &Path) -> Command {
13 let mut cmd = Command::new("git");
14 cmd.arg("-C")
15 .arg(repo)
16 .stdin(std::process::Stdio::null())
17 .env("GIT_TERMINAL_PROMPT", "0")
18 .env(
19 "GIT_SSH_COMMAND",
20 "ssh -o BatchMode=yes -o ConnectTimeout=5",
21 );
22 cmd
23}
24
25pub fn output_with_timeout(
29 cmd: &mut Command,
30 timeout: std::time::Duration,
31) -> std::io::Result<std::process::Output> {
32 use std::io::Read;
33 use std::os::unix::process::CommandExt;
34 use std::process::Stdio;
35
36 cmd.process_group(0);
38 let mut child = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
39 let child_pgid = child.id() as libc::pid_t;
40
41 let stdout = child.stdout.take();
42 let stderr = child.stderr.take();
43
44 let stdout_thread = std::thread::spawn(move || {
45 let mut buf = Vec::new();
46 if let Some(mut r) = stdout {
47 let _ = r.read_to_end(&mut buf);
48 }
49 buf
50 });
51 let stderr_thread = std::thread::spawn(move || {
52 let mut buf = Vec::new();
53 if let Some(mut r) = stderr {
54 let _ = r.read_to_end(&mut buf);
55 }
56 buf
57 });
58
59 let start = std::time::Instant::now();
60 loop {
61 match child.try_wait() {
62 Ok(Some(status)) => {
63 let stdout = stdout_thread.join().unwrap_or_default();
64 let stderr = stderr_thread.join().unwrap_or_default();
65 return Ok(std::process::Output {
66 status,
67 stdout,
68 stderr,
69 });
70 }
71 Ok(None) => {
72 if start.elapsed() >= timeout {
73 if let Ok(Some(status)) = child.try_wait() {
74 let stdout = stdout_thread.join().unwrap_or_default();
75 let stderr = stderr_thread.join().unwrap_or_default();
76 return Ok(std::process::Output {
77 status,
78 stdout,
79 stderr,
80 });
81 }
82 unsafe { libc::killpg(child_pgid, libc::SIGKILL) };
84 let _ = child.wait();
85 let _ = stdout_thread.join();
87 let _ = stderr_thread.join();
88 return Err(std::io::Error::new(
89 std::io::ErrorKind::TimedOut,
90 "git command timed out",
91 ));
92 }
93 std::thread::sleep(std::time::Duration::from_millis(5));
94 }
95 Err(e) => return Err(e),
96 }
97 }
98}