use std::io::Write;
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::sync::LazyLock;
use assert_cmd::Command;
use tempfile::NamedTempFile;
pub(crate) static GIT_EXISTS: LazyLock<bool> =
LazyLock::new(|| Command::new("git").arg("-v").ok().is_ok());
pub(crate) struct GitRepo(git2::Repository);
impl GitRepo {
pub(crate) fn init<P: AsRef<Path>>(path: P) -> pkgcruft_git::Result<Self> {
let mut opts = git2::RepositoryInitOptions::new();
opts.bare(false)
.external_template(false)
.initial_head("main");
Ok(Self(git2::Repository::init_opts(path, &opts)?))
}
pub(crate) fn init_bare<P: AsRef<Path>>(path: P) -> pkgcruft_git::Result<Self> {
let mut opts = git2::RepositoryInitOptions::new();
opts.bare(true)
.external_template(false)
.initial_head("main");
Ok(Self(git2::Repository::init_opts(path, &opts)?))
}
pub(crate) fn stage(&self, paths: &[&str]) -> pkgcruft_git::Result<git2::Oid> {
let mut index = self.0.index().unwrap();
index.add_all(paths, git2::IndexAddOption::DEFAULT, None)?;
index.write()?;
let oid = index.write_tree()?;
Ok(oid)
}
pub(crate) fn commit(&self, oid: git2::Oid, msg: &str) -> pkgcruft_git::Result<()> {
let tree = self.0.find_tree(oid)?;
let sig = git2::Signature::new("test", "test@test.test", &git2::Time::new(0, 0))?;
self.0.commit(Some("HEAD"), &sig, &sig, msg, &tree, &[])?;
Ok(())
}
}
impl Deref for GitRepo {
type Target = git2::Repository;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for GitRepo {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
pub(crate) struct GitCmd {
cmd: Command,
_config: NamedTempFile,
}
impl Deref for GitCmd {
type Target = Command;
fn deref(&self) -> &Self::Target {
&self.cmd
}
}
impl DerefMut for GitCmd {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.cmd
}
}
impl GitCmd {
pub(crate) fn new<S: AsRef<str>>(cmd: S) -> Self {
let args: Vec<_> = cmd.as_ref().split_whitespace().collect();
let mut cmd = Command::new("git");
cmd.args(&args);
let data = indoc::indoc! {"
[user]
name = Pkgcruft Git
email = pkgcruft-git@pkgcruft.pkgcraft
"};
let mut config = NamedTempFile::new().unwrap();
config.write_all(data.as_bytes()).unwrap();
let config_path = config.path().to_str().unwrap();
cmd.env("GIT_CONFIG_SYSTEM", "/dev/null");
cmd.env("GIT_CONFIG_GLOBAL", config_path);
Self { cmd, _config: config }
}
}
#[macro_export]
macro_rules! git {
($cmd:expr) => {
if *$crate::git::GIT_EXISTS {
$crate::git::GitCmd::new($cmd)
} else {
return;
}
};
}
pub(crate) use git;