thoughts_tool/git/
shell_fetch.rs1use anyhow::Context;
2use anyhow::Result;
3use anyhow::bail;
4use std::path::Path;
5use std::process::Command;
6use std::process::Stdio;
7
8pub fn build_fetch_command(repo_path: &Path, remote: &str) -> Command {
10 let mut cmd = Command::new("git");
11 cmd.current_dir(repo_path).arg("fetch").arg(remote);
12 cmd
13}
14
15pub fn fetch(repo_path: &Path, remote: &str) -> Result<()> {
17 which::which("git").context("git executable not found in PATH")?;
18
19 let mut cmd = build_fetch_command(repo_path, remote);
20 let status = cmd
21 .stdout(Stdio::null())
22 .stderr(Stdio::inherit())
23 .status()
24 .with_context(|| {
25 format!(
26 "Failed to spawn git fetch for remote '{}' in '{}'",
27 remote,
28 repo_path.display()
29 )
30 })?;
31
32 if !status.success() {
33 bail!(
34 "git fetch failed for remote '{}' in '{}' with exit code {:?}",
35 remote,
36 repo_path.display(),
37 status.code()
38 );
39 }
40 Ok(())
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46 use std::path::Path;
47
48 #[test]
49 fn build_fetch_cmd_has_expected_args() {
50 let cmd = build_fetch_command(Path::new("/tmp/repo"), "origin");
51 let args: Vec<String> = cmd
52 .get_args()
53 .map(|s| s.to_string_lossy().into_owned())
54 .collect();
55 assert_eq!(args, vec!["fetch", "origin"]);
56 assert_eq!(cmd.get_current_dir(), Some(Path::new("/tmp/repo")));
57 }
58}