vinxen-git 0.1.1

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

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BranchInfo {
    pub name: String,
    pub is_current: bool,
    pub upstream: Option<String>,
    pub commit_id: Option<String>,
}

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

        if head.is_branch() {
            let name = head
                .name()
                .map(|n| n.strip_prefix("refs/heads/").unwrap_or(n).to_string())
                .unwrap_or_else(|| "HEAD".to_string());

            let commit_id = head.peel_to_commit().ok().map(|c| c.id().to_string());

            return Ok(Some(Self {
                name,
                is_current: true,
                upstream: None,
                commit_id,
            }));
        }

        Ok(None)
    }

    pub fn list(repo: &Repository) -> Result<Vec<Self>> {
        let mut branches = Vec::new();
        let current = Self::current(repo)?;
        let current_name = current.as_ref().map(|b| b.name.clone());

        let branch_names = repo.branches(None)?;
        for branch in branch_names.flatten() {
            if let Ok(Some(name)) = branch.0.name() {
                let name = name.strip_prefix("refs/heads/").unwrap_or(name).to_string();
                let is_current = current_name.as_ref() == Some(&name);
                let commit_id = branch
                    .0
                    .get()
                    .peel_to_commit()
                    .ok()
                    .map(|c| c.id().to_string());

                branches.push(Self {
                    name,
                    is_current,
                    upstream: None,
                    commit_id,
                });
            }
        }

        Ok(branches)
    }
}