use std::path::PathBuf;
#[non_exhaustive]
#[derive(Debug)]
pub enum Error {
NotARepository(PathBuf),
OpenRepository(String),
ResolveRef {
reference: String,
reason: String,
},
Walk(String),
Diff(String),
Mailmap(String),
InvalidBotPattern(String),
InvalidWindow(String),
InvalidTimestamp(String),
InvalidFormula(String),
InvalidFileTypeScope(String),
InvalidBusFactorThreshold(String),
InvalidAuthorHashKey(String),
InvalidTrend(String),
Blame(String),
InvalidDiff(String),
Cache(String),
}
macro_rules! classify_error_variants {
(
client_input { $($client:pat_param => $sample:expr),+ $(,)? }
environment { $($environment:pat),+ $(,)? }
) => {
impl Error {
#[must_use]
pub fn is_client_input(&self) -> bool {
match self {
$($client => true,)+
$($environment => false,)+
}
}
#[doc(hidden)]
#[must_use]
pub fn client_input_samples() -> Vec<Self> {
vec![$($sample),+]
}
}
};
}
classify_error_variants! {
client_input {
Self::NotARepository(_) => Self::NotARepository(PathBuf::from("/not-a-repository")),
Self::ResolveRef { .. } => Self::ResolveRef {
reference: "HEAD".to_owned(),
reason: "unborn branch".to_owned(),
},
Self::InvalidBotPattern(_) => Self::InvalidBotPattern("[".to_owned()),
Self::InvalidWindow(_) => Self::InvalidWindow("banana".to_owned()),
Self::InvalidTimestamp(_) => Self::InvalidTimestamp("yesterday".to_owned()),
Self::InvalidFormula(_) => Self::InvalidFormula("astrology".to_owned()),
Self::InvalidFileTypeScope(_) => Self::InvalidFileTypeScope(String::new()),
Self::InvalidBusFactorThreshold(_) => Self::InvalidBusFactorThreshold("1.5".to_owned()),
Self::InvalidAuthorHashKey(_) => Self::InvalidAuthorHashKey("hunter2".to_owned()),
Self::InvalidTrend(_) => Self::InvalidTrend("1".to_owned()),
Self::InvalidDiff(_) => Self::InvalidDiff("not a unified diff".to_owned()),
}
environment {
Self::OpenRepository(_),
Self::Walk(_),
Self::Diff(_),
Self::Mailmap(_),
Self::Blame(_),
Self::Cache(_),
}
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::NotARepository(path) => {
write!(
f,
"{} is not inside a supported version-control working tree",
path.display()
)
}
Self::OpenRepository(reason) => write!(f, "failed to open repository: {reason}"),
Self::ResolveRef { reference, reason } => {
write!(f, "failed to resolve revision {reference:?}: {reason}")
}
Self::Walk(reason) => write!(f, "failed to walk commit history: {reason}"),
Self::Diff(reason) => write!(f, "failed to compute diff: {reason}"),
Self::Mailmap(reason) => write!(f, "failed to apply .mailmap: {reason}"),
Self::InvalidBotPattern(reason) => write!(f, "invalid bot pattern: {reason}"),
Self::InvalidWindow(reason) => write!(f, "invalid time window: {reason}"),
Self::InvalidTimestamp(reason) => write!(f, "invalid timestamp: {reason}"),
Self::InvalidFormula(name) => write!(
f,
"unknown risk formula {name:?} (expected `weighted` or `percentile`)"
),
Self::InvalidFileTypeScope(reason) => write!(f, "invalid file-type scope: {reason}"),
Self::InvalidBusFactorThreshold(reason) => {
write!(f, "invalid bus-factor threshold: {reason}")
}
Self::InvalidAuthorHashKey(reason) => {
write!(f, "invalid author-hash key: {reason}")
}
Self::InvalidTrend(reason) => write!(f, "invalid trend parameters: {reason}"),
Self::Blame(reason) => write!(f, "failed to blame file: {reason}"),
Self::InvalidDiff(reason) => write!(f, "invalid unified diff: {reason}"),
Self::Cache(reason) => write!(f, "history cache error: {reason}"),
}
}
}
impl std::error::Error for Error {}
#[cfg(test)]
#[path = "error_tests.rs"]
mod tests;