You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
malachite/src/info.rs

138 lines
3.2 KiB
Rust

use std::fmt::{Display, Formatter};
use std::path::PathBuf;
use crate::builders::{GitFetchBuilder, GitStatusBuilder};
use tabled::Tabled;
use crate::errors::AppResult;
use crate::git::GitRepository;
pub const BOLD: &str = "\x1b[1m";
pub const CLEAN: &str = "\x1b[34m";
pub const DIRTY: &str = "\x1b[33m";
pub const UNKNOWN: &str = "\x1b[37m";
pub const RESET: &str = "\x1b[0m";
#[derive(Debug, Clone, Tabled)]
pub enum GitStatus {
Clean,
Dirty,
Unknown,
}
impl GitStatus {
fn color(&self) -> String {
match self {
Self::Clean => format!("{BOLD}{CLEAN}"),
Self::Dirty => format!("{BOLD}{DIRTY}"),
Self::Unknown => format!("{BOLD}{UNKNOWN}"),
}
}
}
impl Display for GitStatus {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
Self::Clean => write!(f, "✔"),
Self::Dirty => write!(f, "✘"),
Self::Unknown => write!(f, "?"),
}
}
}
#[derive(Debug, Clone)]
pub struct RichInfo {
output: String,
pub push: GitStatus,
pub pull: GitStatus,
pub dirty: GitStatus,
}
impl Display for RichInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}↑ {}↓ {}*{}",
self.push.color(),
self.pull.color(),
self.dirty.color(),
RESET
)
}
}
#[derive(Debug, Clone, Tabled)]
pub struct GitInfo {
#[tabled(skip)]
pub path: PathBuf,
#[tabled(rename = "Repository")]
pub name: String,
#[tabled(rename = "Rich Info")]
pub rich: RichInfo,
#[tabled(rename = "Commit")]
pub commit: String,
}
impl GitInfo {
pub fn new(path: PathBuf) -> AppResult<Self> {
let output = GitStatusBuilder::new(path.clone()).status()?.output()?;
let output = String::from_utf8(output.stdout)?;
GitFetchBuilder::new(path.clone())
.fetch()?
.arg("--all")
.silent()?;
let mut repo = Self {
path: path.clone(),
name: path.file_name().unwrap().to_string_lossy().to_string(),
rich: RichInfo {
output,
push: GitStatus::Unknown,
pull: GitStatus::Unknown,
dirty: GitStatus::Unknown,
},
commit: GitRepository::new(path).hash()?,
};
repo.push()?;
repo.pull()?;
repo.dirty()?;
Ok(repo)
}
fn push(&mut self) -> AppResult<()> {
self.rich.push = if self.rich.output.contains("ahead") {
GitStatus::Dirty
} else {
GitStatus::Clean
};
Ok(())
}
fn pull(&mut self) -> AppResult<()> {
self.rich.pull = if self.rich.output.contains("behind") {
GitStatus::Dirty
} else {
GitStatus::Clean
};
Ok(())
}
fn dirty(&mut self) -> AppResult<()> {
self.rich.dirty = if self.rich.output.contains("Untracked files")
|| self.rich.output.contains("Changes not staged for commit")
|| self.rich.output.contains("Changes to be committed")
{
GitStatus::Dirty
} else {
GitStatus::Clean
};
Ok(())
}
}