use anyhow::Context;
use git2::Repository;
use std::{fmt, path::Path};
pub const GIT_REQUEST_NOT_FOUND: &str = "Git object doesn't exist";
pub struct Repo {
lib_path: String,
namespace: String,
name: String,
repo: Repository,
}
impl fmt::Debug for Repo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"Repo for {}/{} in the library at {}",
self.namespace, self.name, self.lib_path
)
}
}
impl Repo {
pub fn new(lib_path: &Path, namespace: &str, name: &str) -> anyhow::Result<Self> {
let lib_path_str = lib_path.to_string_lossy();
let repo_path = format!("{lib_path_str}/{namespace}/{name}");
Ok(Self {
lib_path: lib_path_str.into(),
namespace: namespace.into(),
name: name.into(),
repo: Repository::open(repo_path)?,
})
}
pub fn get_bytes_at_path(&self, commitish: &str, path: &str) -> anyhow::Result<Vec<u8>> {
let base_revision = format!("{commitish}:{path}");
for postfix in ["", "/index.html", ".html", "index.html"] {
let query = &format!("{base_revision}{postfix}");
let blob = self.find(query);
if blob.is_ok() {
tracing::trace!(query, "Found Git object");
return blob;
}
}
tracing::debug!(base_revision, "Couldn't find requeted Git object");
anyhow::bail!(GIT_REQUEST_NOT_FOUND)
}
fn find(&self, query: &str) -> anyhow::Result<Vec<u8>> {
tracing::trace!(query, "Git reverse parse search");
let obj = self.repo.revparse_single(query)?;
let blob = obj.as_blob().context("Couldn't cast Git object to blob")?;
Ok(blob.content().to_owned())
}
}