use std::fmt::Debug;
use command_error::CommandExt;
use command_error::OutputContext;
use miette::miette;
use miette::IntoDiagnostic;
use tracing::instrument;
use utf8_command::Utf8Output;
use super::Git;
#[repr(transparent)]
pub struct GitConfig<'a>(&'a Git);
impl Debug for GitConfig<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Debug::fmt(self.0, f)
}
}
impl<'a> GitConfig<'a> {
pub fn new(git: &'a Git) -> Self {
Self(git)
}
pub fn get_and<R>(
&self,
key: &str,
parser: impl Fn(OutputContext<Utf8Output>, Option<String>) -> Result<R, command_error::Error>,
) -> miette::Result<R> {
self.0
.command()
.args(["config", "get", "--null", key])
.output_checked_as(|context: OutputContext<Utf8Output>| {
if context.status().success() {
match context.output().stdout.as_str().split_once('\0') {
Some((value, rest)) => {
if !rest.is_empty() {
tracing::warn!(
%key,
data=rest,
"Trailing data in `git config` output"
);
}
let value = value.to_owned();
parser(context, Some(value))
}
None => Err(context.error_msg("Output didn't contain any null bytes")),
}
} else if let Some(1) = context.status().code() {
parser(context, None)
} else {
Err(context.error())
}
})
.into_diagnostic()
}
#[instrument(level = "trace")]
pub fn get(&self, key: &str) -> miette::Result<Option<String>> {
self.get_and(key, |_, value| Ok(value))
}
#[instrument(level = "trace")]
pub fn is_bare(&self) -> miette::Result<bool> {
self.get_and("core.bare", |context, value| {
match value {
None => {
Ok(false)
}
Some(value) => match value.as_str() {
"true" => Ok(true),
"false" => Ok(false),
_ => Err(context.error_msg(miette!(
"Unexpected Git config value for `core.bare`: {value}"
))),
},
}
})
}
#[instrument(level = "trace")]
pub fn set(&self, key: &str, value: &str) -> miette::Result<()> {
self.0
.command()
.args(["config", "set", key, value])
.output_checked_utf8()
.into_diagnostic()?;
Ok(())
}
}