use anyhow::{bail, Result};
use std::process::Command;
use std::path::Path;
use super::GitCli;
impl GitCli {
pub fn stage_file(&self, repo_path: &str, file: &str) -> Result<()> {
let output = Command::new("git")
.args(["-C", repo_path, "add", "--", file])
.output()?;
if !output.status.success() {
bail!(
"git add failed (exit {}): {}",
output.status,
String::from_utf8_lossy(&output.stderr)
);
}
Ok(())
}
pub fn unstage_file(&self, repo_path: &str, file: &str) -> Result<()> {
let output = Command::new("git")
.args(["-C", repo_path, "restore", "--staged", "--", file])
.output()?;
if !output.status.success() {
bail!(
"git restore --staged failed (exit {}): {}",
output.status,
String::from_utf8_lossy(&output.stderr)
);
}
Ok(())
}
pub fn diff(
&self,
repo_path: &str,
path: &str,
staged: bool,
context: usize,
) -> Result<String> {
let status_output = Command::new("git")
.args(["-C", repo_path, "status", "--porcelain=v2", "--", path])
.output()?;
let is_untracked = if status_output.status.success() {
String::from_utf8_lossy(&status_output.stdout).trim().starts_with("? ")
} else {
false
};
if is_untracked {
let file_path = Path::new(repo_path).join(path);
if !file_path.exists() {
return Ok(String::new());
}
let ctx = format!("--unified={}", context);
let output = Command::new("git")
.args(["-C", repo_path, "diff", "--no-index", &ctx])
.arg("/dev/null")
.arg(&file_path)
.output()?;
if output.status.code() == Some(1) || output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
} else {
bail!("git diff --no-index failed: {}", String::from_utf8_lossy(&output.stderr));
}
} else {
let mut cmd = Command::new("git");
cmd.args(["-C", repo_path, "diff"]);
if staged {
cmd.arg("--cached");
}
cmd.arg(format!("--unified={}", context));
cmd.arg("--").arg(path);
let output = cmd.output()?;
if !output.status.success() {
bail!("git diff failed: {}", String::from_utf8_lossy(&output.stderr));
}
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
}
}
}