use std::path::Path;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct BlobRef {
pub path: String,
pub oid: String,
}
#[derive(Debug, thiserror::Error)]
pub enum GitError {
#[error("git error: {0}")]
Git(String),
#[error("non-utf8 path in tree: {0:?}")]
NonUtf8Path(Vec<u8>),
}
fn ge<E: std::fmt::Display>(e: E) -> GitError {
GitError::Git(e.to_string())
}
pub struct Repo {
inner: gix::Repository,
}
impl Repo {
pub fn discover(path: &Path) -> Result<Self, GitError> {
Ok(Self {
inner: gix::discover(path).map_err(ge)?,
})
}
#[must_use]
pub fn common_dir(&self) -> &Path {
self.inner.common_dir()
}
#[must_use]
pub fn git_dir(&self) -> &Path {
self.inner.git_dir()
}
pub fn head_tree_id(&self) -> Result<String, GitError> {
let tree = self.inner.head_tree().map_err(ge)?;
Ok(tree.id().to_hex().to_string())
}
pub fn walk_blobs(&self) -> Result<Vec<BlobRef>, GitError> {
let tree = self.inner.head_tree().map_err(ge)?;
let mut recorder = gix::traverse::tree::Recorder::default();
tree.traverse().breadthfirst(&mut recorder).map_err(ge)?;
let mut out = Vec::new();
for entry in recorder.records {
if !entry.mode.is_blob() {
continue;
}
let path = String::from_utf8(entry.filepath.into())
.map_err(|e| GitError::NonUtf8Path(e.into_bytes()))?;
out.push(BlobRef {
path,
oid: entry.oid.to_hex().to_string(),
});
}
Ok(out)
}
pub fn read_blob(&self, oid: &str) -> Result<Vec<u8>, GitError> {
let id = gix::ObjectId::from_hex(oid.as_bytes()).map_err(ge)?;
Ok(self.inner.find_object(id).map_err(ge)?.detach().data)
}
}