use std::path::Path;
use std::process::{Command, Stdio};
use crate::error::{Error, Result};
const BIN: &str = "git";
#[must_use]
pub fn is_repo(dir: &Path) -> bool {
dir.join(".git").exists()
}
pub fn init(dir: &Path) -> Result<()> {
std::fs::create_dir_all(dir)?;
run(dir, &["init", "--initial-branch=main"])?;
let gitattributes = dir.join(".gitattributes");
if !gitattributes.exists() {
std::fs::write(
&gitattributes,
"*.age binary -diff -merge\n.recipients text\n",
)?;
}
Ok(())
}
pub fn add_all(dir: &Path) -> Result<()> {
run(dir, &["add", "-A"])?;
Ok(())
}
pub fn commit(dir: &Path, message: &str) -> Result<()> {
let output = command(dir, &["commit", "-m", message])
.output()
.map_err(Error::Io)?;
if output.status.success() {
return Ok(());
}
let combined = format!(
"{}{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
if combined.contains("nothing to commit") || combined.contains("no changes added") {
return Ok(());
}
Err(Error::Command {
cmd: format!("git commit -m {message:?}"),
status: output.status.code().unwrap_or(-1),
stderr: combined,
})
}
pub fn pull_rebase(dir: &Path) -> Result<()> {
run(dir, &["pull", "--rebase", "--autostash"])?;
Ok(())
}
pub fn push(dir: &Path) -> Result<()> {
run(dir, &["push"])?;
Ok(())
}
pub fn status(dir: &Path) -> Result<String> {
run(dir, &["status", "-sb"])
}
pub fn log(dir: &Path, n: usize) -> Result<String> {
let limit = format!("-n{n}");
run(dir, &["log", "--oneline", &limit])
}
fn run(dir: &Path, args: &[&str]) -> Result<String> {
let output = command(dir, args).output().map_err(Error::Io)?;
if output.status.success() {
Ok(String::from_utf8_lossy(&output.stdout).into_owned())
} else {
Err(Error::Command {
cmd: format!("git {}", args.join(" ")),
status: output.status.code().unwrap_or(-1),
stderr: String::from_utf8_lossy(&output.stderr).into_owned(),
})
}
}
fn command(dir: &Path, args: &[&str]) -> Command {
let mut cmd = Command::new(BIN);
cmd.current_dir(dir)
.args(args)
.stdin(Stdio::null())
.stdout(Stdio::piped())
.stderr(Stdio::piped());
cmd
}