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.
138 lines
3.2 KiB
Rust
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(())
|
|
}
|
|
}
|