use super::*;
#[derive(Debug, Clone, Default, PartialEq, Eq)]
pub struct RepoIdent {
pub workdir: Option<PathBuf>,
pub commondir: Option<PathBuf>,
pub remote: Option<String>,
}
impl RepoIdent {
pub fn discover(path: &Path) -> Self {
git2::Repository::discover(path)
.map(|repo| Self::from_repo(&repo))
.unwrap_or_default()
}
pub fn discover_with_repo(path: &Path) -> (Self, Option<git2::Repository>) {
match git2::Repository::discover(path) {
Ok(repo) => {
let ident = Self::from_repo(&repo);
(ident, Some(repo))
}
Err(_) => (Self::default(), None),
}
}
fn from_repo(repo: &git2::Repository) -> Self {
let workdir = repo.workdir().map(trim_trailing_sep);
let commondir = trim_trailing_sep(repo.commondir());
let remote = read_remote_url(&commondir.join("config"));
Self {
workdir,
commondir: Some(commondir),
remote,
}
}
pub fn slug(&self, fallback_path: &Path) -> String {
let input = self
.remote
.clone()
.or_else(|| self.workdir.as_ref().map(|p| path_to_string(p)))
.unwrap_or_else(|| path_to_string(&canonicalize_or_self(fallback_path)));
let digest = Sha256::digest(input.as_bytes());
hex::encode(&digest[..4])
}
pub fn slug_root(&self, fallback_path: &Path) -> PathBuf {
self.workdir
.clone()
.unwrap_or_else(|| canonicalize_or_self(fallback_path))
}
}
fn trim_trailing_sep(p: &Path) -> PathBuf {
match p.to_str() {
Some(s) => PathBuf::from(s.trim_end_matches('/')),
None => p.to_path_buf(),
}
}
fn path_to_string(p: &Path) -> String {
p.to_string_lossy().into_owned()
}
fn canonicalize_or_self(p: &Path) -> PathBuf {
std::fs::canonicalize(p).unwrap_or_else(|_| p.to_path_buf())
}
pub fn derive_slug(repo_root: &Path) -> String {
RepoIdent::discover(repo_root).slug(repo_root)
}
pub fn slug_root(repo_root: &Path) -> PathBuf {
RepoIdent::discover(repo_root).slug_root(repo_root)
}
fn read_remote_url(config_path: &Path) -> Option<String> {
let config = std::fs::read_to_string(config_path).ok()?;
config
.lines()
.find(|l| l.trim_start().starts_with("url ="))
.map(|l| {
l.split_once('=')
.map(|(_, v)| v.trim().to_owned())
.unwrap_or_default()
})
}