vinxen-git 0.1.0

Git operations for Vinxen CLI
Documentation
use crate::Result;
use git2::Repository;
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CommitInfo {
    pub id: String,
    pub short_id: String,
    pub message: String,
    pub author: String,
    pub email: String,
    pub timestamp: i64,
}

impl CommitInfo {
    pub fn head(repo: &Repository) -> Result<Option<Self>> {
        let head = match repo.head() {
            Ok(h) => h,
            Err(_) => return Ok(None),
        };

        let commit = match head.peel_to_commit() {
            Ok(c) => c,
            Err(_) => return Ok(None),
        };

        Ok(Some(Self::from_commit(&commit)?))
    }

    pub fn recent(repo: &Repository, count: usize) -> Result<Vec<Self>> {
        let mut commits = Vec::new();

        let head = match repo.head() {
            Ok(h) => h,
            Err(_) => return Ok(commits),
        };

        let commit = match head.peel_to_commit() {
            Ok(c) => c,
            Err(_) => return Ok(commits),
        };

        let mut current = Some(commit);
        let mut remaining = count;

        while let Some(c) = current {
            if remaining == 0 {
                break;
            }

            commits.push(Self::from_commit(&c)?);
            remaining -= 1;

            current = c.parent(0).ok();
        }

        Ok(commits)
    }

    fn from_commit(commit: &git2::Commit) -> Result<Self> {
        let id = commit.id().to_string();
        let short_id = id.chars().take(7).collect();

        let message = commit.message().map(|m| m.to_string()).unwrap_or_default();

        let author = commit.author();
        let name = author.name().unwrap_or("").to_string();
        let email = author.email().unwrap_or("").to_string();
        let timestamp = author.when().seconds();

        Ok(Self {
            id,
            short_id,
            message,
            author: name,
            email,
            timestamp,
        })
    }
}