use std::{
env,
io::{self, Write},
path::PathBuf,
process::ExitCode,
};
use weavatrix_git::{HistoryOptions, Repository};
fn main() -> ExitCode {
match run(env::args().skip(1).collect()) {
Ok(()) => ExitCode::SUCCESS,
Err(error) => {
eprintln!("weavatrix-git: {error}");
ExitCode::FAILURE
}
}
}
fn run(mut args: Vec<String>) -> Result<(), Box<dyn std::error::Error>> {
let mut repository = PathBuf::from(".");
if args.first().is_some_and(|value| value == "-C") {
if args.len() < 3 {
return Err("usage: -C requires a repository path and command".into());
}
repository = PathBuf::from(args.remove(1));
args.remove(0);
}
let command = args.first().map_or("head", String::as_str);
let repo = Repository::open(repository)?;
match command {
"head" => {
let head = repo.head()?;
if let Some(id) = head.target {
println!("{id}");
} else {
println!("unborn");
}
}
"cat" => {
let spec = args.get(1).ok_or("usage: cat <object>")?;
let object = repo.object(repo.resolve(spec)?)?;
println!("{} {}", object.kind.as_str(), object.data.len());
io::stdout().write_all(&object.data)?;
}
"log" => {
let spec = args.get(1).map_or("HEAD", String::as_str);
let max_commits = args
.get(2)
.map(|value| value.parse())
.transpose()?
.unwrap_or(100);
let options = HistoryOptions {
max_commits,
..HistoryOptions::default()
};
for record in repo.history(repo.resolve(spec)?, options)? {
let time = record
.commit
.committer
.as_ref()
.map_or(0, |signature| signature.timestamp);
println!(
"{}\t{}\t{}",
record.id,
time,
record.commit.summary_lossy().replace('\t', " ")
);
}
}
"diff" => {
let old = args.get(1).ok_or("usage: diff <old> <new>")?;
let new = args.get(2).ok_or("usage: diff <old> <new>")?;
for change in repo.diff_commits(repo.resolve(old)?, repo.resolve(new)?)? {
println!(
"{:?}\t{}",
change.kind,
String::from_utf8_lossy(&change.path)
);
}
}
_ => return Err(format!("unknown command {command:?}").into()),
}
Ok(())
}