use std::io::{BufRead, BufReader, Read};
use std::{fs::File, path::PathBuf, process::Command};
mod command;
mod git;
mod git_cmd;
mod line;
mod parser;
mod status;
pub use parser::parse;
use Subcommand::*;
const VERSION: Option<&str> = option_env!("CARGO_PKG_VERSION");
#[derive(Debug, PartialEq)]
pub enum Subcommand {
Status(bool),
Number,
Version,
Unset,
}
#[derive(Debug)]
pub struct App {
subcommand: Subcommand,
cwd: PathBuf,
cmd: Command,
pargs: Vec<String>,
cache: Vec<String>,
}
impl App {
fn cache_path(&self) -> Option<PathBuf> {
git::git_dir(&self.pargs).map(|v| self.cwd.join(v).join("gitnu.txt"))
}
pub fn cache(&self, create: bool) -> Option<File> {
self.cache_path().and_then(|v| match create {
true => File::create(v).ok(),
false => File::open(v).ok(),
})
}
pub fn read_cache(&mut self) {
std::mem::swap(&mut self.cache, &mut vec!["0".to_string()]);
self.cache(false).map(|f| lines(f).for_each(|v| self.cache.push(v)));
}
pub fn set_once(&mut self, sc: Subcommand) {
match (&self.subcommand, &sc) {
(Unset, _) => self.subcommand = sc,
(Status(true), Status(false)) => self.subcommand = sc,
_ => (),
}
}
pub fn push_arg(&mut self, arg: &str) {
self.cmd.arg(arg);
if self.subcommand == Unset {
self.pargs.push(arg.to_string());
}
}
pub fn new(cwd: PathBuf) -> Self {
let mut cmd = Command::new("git");
if atty::is(atty::Stream::Stdout) {
cmd.args(["-c", "color.ui=always"]);
}
cmd.current_dir(&cwd);
Self { cwd, subcommand: Unset, pargs: vec![], cache: vec![], cmd }
}
pub fn run(&mut self) {
use command::CommandOps;
match self.subcommand {
Status(is_normal) => status::status(self, is_normal),
Version => {
self.cmd.run();
println!("gitnu version {}", VERSION.unwrap_or("unknown"));
}
_ => self.cmd.run(),
}
}
}
fn lines<R: Read>(src: R) -> impl Iterator<Item = String> {
BufReader::new(src).lines().filter_map(|v| v.ok())
}
#[cfg(test)]
mod tests;