My personal project and infrastructure archive
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
nomicon/apps/servers/octopus/supergit/src/repo.rs

114 lines
2.9 KiB

//! Raw representation wrappers for libgit2
use crate::branch::Branch;
use git2::{self, Oid};
use std::{fmt, sync::Arc};
pub type GitResult<T> = Result<T, GitError>;
/// The hex ID of a commit
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct HashId(String);
impl fmt::Display for HashId {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl HashId {
pub fn to_oid(&self) -> Oid {
self.clone().into()
}
pub fn to_string(&self) -> String {
self.0.clone()
}
}
impl From<Oid> for HashId {
fn from(o: Oid) -> Self {
Self(o.to_string())
}
}
impl From<HashId> for Oid {
fn from(hid: HashId) -> Self {
Oid::from_str(hid.0.as_str()).expect(&format!(
"Tried turning an invalid HashId variant into an Oid: {:?}",
hid
))
}
}
impl<'any> From<&'any HashId> for Oid {
fn from(hid: &'any HashId) -> Self {
Oid::from_str(hid.0.as_str()).expect(&format!(
"Tried turning an invalid HashId variant into an Oid: {:?}",
hid
))
}
}
/// An error abstraction for raw git operations
#[derive(Debug)]
pub enum GitError {
AllBad,
}
impl From<git2::Error> for GitError {
fn from(_: git2::Error) -> Self {
Self::AllBad
}
}
/// Represents a git repository with lazy data loading
#[derive(Clone)]
pub struct Repository {
inner: Arc<git2::Repository>,
}
impl Repository {
/// Open a repository read-only at a specific path
pub fn open(path: &str) -> GitResult<Self> {
Ok(Self {
inner: Arc::new(git2::Repository::open(path)?),
})
}
/// Parse branch data from repository
///
/// If you only care about a single branch, you can also use the
/// convenience function `get_branch()`.
///
/// ## Panics
///
/// This function can panic when branch metadata is missing.
pub fn branches(&self) -> GitResult<Vec<Branch>> {
Ok(self
.inner
.branches(None)?
.into_iter()
.filter_map(|e| e.ok())
.map(|(branch, _)| {
let name = branch.name().unwrap().unwrap().into();
let head = branch.get().peel_to_commit().unwrap().id().into();
Branch::new(&self.inner, name, head)
})
.collect())
}
/// Get a single branch by name
///
/// This function will enumerate all branches, and then select the
/// desired one. If you want to make repeated queries onto the
/// branch set, it's recommended you call `branches()`, and cache
/// the data yourself.
pub fn branch(&self, name: String) -> Option<Branch> {
self.branches().ok().and_then(|ok| {
ok.into_iter()
.filter(|b| b.name().is_some())
.find(|b| &b.name().unwrap() == &name)
})
}
}