use git2::{Repository, Status};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GitStatus {
pub path: Option<String>,
#[serde(serialize_with = "serialize_status")]
#[serde(deserialize_with = "deserialize_status")]
pub status: Status,
}
fn deserialize_status<'de, D>(deserializer: D) -> Result<Status, D::Error>
where
D: Deserializer<'de>,
{
let value: &str = Deserialize::deserialize(deserializer)?;
match value {
"CURRENT" => Ok(Status::CURRENT),
"INDEX_NEW" => Ok(Status::INDEX_NEW),
"INDEX_MODIFIED" => Ok(Status::INDEX_MODIFIED),
"INDEX_DELETED" => Ok(Status::INDEX_DELETED),
"INDEX_RENAMED" => Ok(Status::INDEX_RENAMED),
"INDEX_TYPECHANGE" => Ok(Status::INDEX_TYPECHANGE),
"WT_NEW" => Ok(Status::WT_NEW),
"WT_MODIFIED" => Ok(Status::WT_MODIFIED),
"WT_DELETED" => Ok(Status::WT_DELETED),
"WT_TYPECHANGE" => Ok(Status::WT_TYPECHANGE),
"WT_RENAMED" => Ok(Status::WT_RENAMED),
"IGNORED" => Ok(Status::IGNORED),
"CONFLICTED" => Ok(Status::CONFLICTED),
_ => Err(serde::de::Error::custom("invalid status")),
}
}
fn serialize_status<S>(status: &Status, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(match *status {
Status::CURRENT => "CURRENT",
Status::INDEX_NEW => "INDEX_NEW",
Status::INDEX_MODIFIED => "INDEX_MODIFIED",
Status::INDEX_DELETED => "INDEX_DELETED",
Status::INDEX_RENAMED => "INDEX_RENAMED",
Status::INDEX_TYPECHANGE => "INDEX_TYPECHANGE",
Status::WT_NEW => "WT_NEW",
Status::WT_MODIFIED => "WT_MODIFIED",
Status::WT_DELETED => "WT_DELETED",
Status::WT_TYPECHANGE => "WT_TYPECHANGE",
Status::WT_RENAMED => "WT_RENAMED",
Status::IGNORED => "IGNORED",
Status::CONFLICTED => "CONFLICTED",
_ => "other",
})
}
pub fn git_status(repo: &Repository) -> anyhow::Result<Vec<GitStatus>> {
let statuses = repo.statuses(None)?;
let mut r = vec![];
for x in statuses.iter() {
let path = x.path().and_then(|r| Some(String::from(r)));
let status = GitStatus {
path,
status: x.status(),
};
r.push(status);
}
Ok(r)
}