use std::path::Path; use crate::Error; use crate::remote::types::RemoteAuth; pub fn run(repo_path: &Path, args: &[&str]) -> Result { let out = duct::cmd("git", args) .env("GIT_DIR", repo_path) .env("GIT_TERMINAL_PROMPT", "0") .read() .map_err(|e| Error::Other(format!("git command failed: {e}")))?; Ok(out) } pub fn run_bytes(repo_path: &Path, args: &[&str]) -> Result, Error> { let out = duct::cmd("git", args) .env("GIT_DIR", repo_path) .env("GIT_TERMINAL_PROMPT", "0") .stdout_capture() .stderr_capture() .run() .map_err(|e| Error::Other(format!("git command failed: {e}")))?; if !out.status.success() { return Err(Error::Other(format!( "git command failed: {}", String::from_utf8_lossy(&out.stderr) ))); } Ok(out.stdout) } pub fn run_status(repo_path: &Path, args: &[&str]) -> Result { let output = duct::cmd("git", args) .env("GIT_DIR", repo_path) .env("GIT_TERMINAL_PROMPT", "0") .run() .map_err(|e| Error::Other(format!("git command failed: {e}")))?; Ok(output.status.success()) } pub fn run_remote(repo_path: &Path, args: &[&str], auth: &RemoteAuth) -> Result { let mut cmd = duct::cmd("git", args) .env("GIT_DIR", repo_path) .env("GIT_TERMINAL_PROMPT", "0"); let mut askpass = None; match auth { RemoteAuth::None | RemoteAuth::SshKey(_) => {} RemoteAuth::Token(token) => { let helper = write_askpass_helper(token)?; let helper_path = helper.path.clone(); cmd = cmd .env("GIT_ASKPASS", &helper_path) .env("GIT_TERMINAL_PROMPT", "0"); askpass = Some(helper); } } let out = cmd .read() .map_err(|e| Error::Other(format!("git command failed: {e}")))?; if let Some(h) = askpass.as_mut() { let _ = std::fs::remove_file(&h.path); } Ok(out) } struct AskPassHelper { path: std::path::PathBuf, } impl Drop for AskPassHelper { fn drop(&mut self) { let _ = std::fs::remove_file(&self.path); } } fn write_askpass_helper(token: &str) -> Result { let dir = std::env::temp_dir(); let path = dir.join(format!("git-askpass-{}.sh", std::process::id())); let script = format!( "#!/bin/sh\nprintf '%s\\n' '{}'\n", token.replace('\'', "'\\''") ); std::fs::write(&path, script).map_err(|e| Error::Io(e.to_string()))?; #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; let _ = std::fs::set_permissions(&path, std::fs::Permissions::from_mode(0o700)); } Ok(AskPassHelper { path }) }