supergit/
repo.rs

1//! Raw representation wrappers for libgit2
2
3use crate::branch::Branch;
4use git2::{self, Oid};
5use std::{fmt, sync::Arc};
6
7pub type GitResult<T> = Result<T, GitError>;
8
9/// The hex ID of a commit
10#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct HashId(String);
12
13impl fmt::Display for HashId {
14    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
15        write!(f, "{}", self.0)
16    }
17}
18
19impl HashId {
20    pub fn to_oid(&self) -> Oid {
21        self.clone().into()
22    }
23
24    pub fn to_string(&self) -> String {
25        self.0.clone()
26    }
27}
28
29impl From<Oid> for HashId {
30    fn from(o: Oid) -> Self {
31        Self(o.to_string())
32    }
33}
34
35impl From<HashId> for Oid {
36    fn from(hid: HashId) -> Self {
37        Oid::from_str(hid.0.as_str()).expect(&format!(
38            "Tried turning an invalid HashId variant into an Oid: {:?}",
39            hid
40        ))
41    }
42}
43
44impl<'any> From<&'any HashId> for Oid {
45    fn from(hid: &'any HashId) -> Self {
46        Oid::from_str(hid.0.as_str()).expect(&format!(
47            "Tried turning an invalid HashId variant into an Oid: {:?}",
48            hid
49        ))
50    }
51}
52
53/// An error abstraction for raw git operations
54#[derive(Debug)]
55pub enum GitError {
56    AllBad,
57}
58
59impl From<git2::Error> for GitError {
60    fn from(_: git2::Error) -> Self {
61        Self::AllBad
62    }
63}
64
65/// Represents a git repository with lazy data loading
66#[derive(Clone)]
67pub struct Repository {
68    inner: Arc<git2::Repository>,
69}
70
71impl Repository {
72    /// Open a repository read-only at a specific path
73    pub fn open(path: &str) -> GitResult<Self> {
74        Ok(Self {
75            inner: Arc::new(git2::Repository::open(path)?),
76        })
77    }
78
79    /// Parse branch data from repository
80    ///
81    /// If you only care about a single branch, you can also use the
82    /// convenience function `get_branch()`.
83    ///
84    /// ## Panics
85    ///
86    /// This function can panic when branch metadata is missing.
87    pub fn branches(&self) -> GitResult<Vec<Branch>> {
88        Ok(self
89            .inner
90            .branches(None)?
91            .into_iter()
92            .filter_map(|e| e.ok())
93            .map(|(branch, _)| {
94                let name = branch.name().unwrap().unwrap().into();
95                let head = branch.get().peel_to_commit().unwrap().id().into();
96                Branch::new(&self.inner, name, head)
97            })
98            .collect())
99    }
100
101    /// Get a single branch by name
102    ///
103    /// This function will enumerate all branches, and then select the
104    /// desired one.  If you want to make repeated queries onto the
105    /// branch set, it's recommended you call `branches()`, and cache
106    /// the data yourself.
107    pub fn branch(&self, name: String) -> Option<Branch> {
108        self.branches().ok().and_then(|ok| {
109            ok.into_iter()
110                .filter(|b| b.name().is_some())
111                .find(|b| &b.name().unwrap() == &name)
112        })
113    }
114}