use super::LogInfos;
use simple_error::SimpleError;
use log::trace;
use std::{
io::{Result, Error, ErrorKind},
process::Command,
ffi::OsStr,
};
fn extract_remote(line: &str) -> Option<(String, String)> {
if !line.ends_with(" (fetch)") {
return None;
}
let mut parts = line.split_whitespace().map(|s| s.trim());
let name = parts.next().map(String::from);
let url = parts.next().map(String::from);
match (name, url) {
(Some(name), Some(url)) => Some((name, url)),
_ => None,
}
}
pub(in super::super) struct GitFetcher;
impl GitFetcher {
pub(in super::super) fn new() -> Result<Self> {
Ok(GitFetcher)
}
fn run_command(&self, args: Vec<&str>) -> Result<String> {
trace!("Running Git command: git {}", args.join(" "));
let res = Command::new("git").args(args.into_iter().map(OsStr::new)).output()?;
if !res.status.success() {
let out = String::from_utf8_lossy(res.stdout.as_slice());
let err = String::from_utf8_lossy(res.stderr.as_slice());
let msg = format!(
"GIT command return code {}\nSTDOUT: {:?}\nSTDERR: {:?}",
res.status, out, err
);
return Err(Error::new(ErrorKind::Other, SimpleError::new(msg)));
}
match String::from_utf8(res.stdout) {
Ok(v) => Ok(v),
Err(err) => Err(Error::new(ErrorKind::Other, err)),
}
}
pub(in super::super) fn get_branch(&self) -> Result<Option<String>> {
let res = self
.run_command(vec!["rev-parse", "--abbrev-ref", "HEAD"])?
.trim()
.to_string();
Ok((!res.is_empty()).then_some(res))
}
pub(in super::super) fn get_log(&self) -> Result<LogInfos> {
let res = self.run_command(vec![
"--no-pager",
"log",
"-1",
"--pretty=format:%H%n%aN%n%ae%n%cN%n%ce%n%s",
])?;
let mut fields = res.split('\n').map(|s| {
let s = s.trim();
(!s.is_empty()).then(|| s.to_string())
});
Ok(LogInfos::new(
fields.next().flatten(),
fields.next().flatten(),
fields.next().flatten(),
fields.next().flatten(),
fields.next().flatten(),
fields.next().flatten(),
))
}
pub(in super::super) fn get_remotes(&self) -> Result<Option<Vec<(String, String)>>> {
let res = self
.run_command(vec!["remote", "-v"])?
.trim()
.lines()
.filter_map(extract_remote)
.collect::<Vec<_>>();
Ok((!res.is_empty()).then_some(res))
}
}