use std::path::PathBuf;
use thiserror::Error;
pub use self::audit::{AuditError, AuditResult};
pub use self::changelog::{ChangelogError, ChangelogResult};
pub use self::changes::{ChangesError, ChangesResult};
pub use self::changeset::{ChangesetError, ChangesetResult};
pub use self::config::{ConfigError, ConfigResult};
pub use self::upgrade::{UpgradeError, UpgradeResult};
pub use self::version::{VersionError, VersionResult};
pub use self::context::{ErrorContext, WithContext};
pub use self::recovery::{
ErrorRecoveryManager, LogLevel, RecoveryResult, RecoveryStats, RecoveryStrategy,
};
pub mod audit;
pub mod changelog;
pub mod changes;
pub mod changeset;
pub mod config;
pub mod upgrade;
pub mod version;
pub mod context;
pub mod recovery;
#[cfg(test)]
mod tests;
#[derive(Debug, Error)]
pub enum Error {
#[error("Configuration error: {0}")]
Config(#[from] ConfigError),
#[error("Version error: {0}")]
Version(#[from] VersionError),
#[error("Changeset error: {0}")]
Changeset(#[from] ChangesetError),
#[error("Changes analysis error: {0}")]
Changes(#[from] ChangesError),
#[error("Changelog error: {0}")]
Changelog(#[from] ChangelogError),
#[error("Upgrade error: {0}")]
Upgrade(#[from] UpgradeError),
#[error("Audit error: {0}")]
Audit(#[from] AuditError),
#[error("Filesystem error: {0}")]
FileSystem(String),
#[error("Git error: {0}")]
Git(String),
#[error("I/O error: {0}")]
IO(#[from] std::io::Error),
#[error("JSON error: {0}")]
Json(#[from] serde_json::Error),
}
impl AsRef<str> for Error {
fn as_ref(&self) -> &str {
match self {
Self::Config(e) => e.as_ref(),
Self::Version(e) => e.as_ref(),
Self::Changeset(e) => e.as_ref(),
Self::Changes(e) => e.as_ref(),
Self::Changelog(e) => e.as_ref(),
Self::Upgrade(e) => e.as_ref(),
Self::Audit(e) => e.as_ref(),
Self::FileSystem(_) => "filesystem error",
Self::Git(_) => "git error",
Self::IO(_) => "io error",
Self::Json(_) => "json error",
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
impl From<sublime_standard_tools::error::FileSystemError> for Error {
fn from(error: sublime_standard_tools::error::FileSystemError) -> Self {
Self::FileSystem(error.to_string())
}
}
impl From<sublime_standard_tools::error::ConfigError> for ConfigError {
fn from(error: sublime_standard_tools::error::ConfigError) -> Self {
match error {
sublime_standard_tools::error::ConfigError::FileNotFound { path } => {
ConfigError::NotFound { path }
}
sublime_standard_tools::error::ConfigError::FileReadError { path, message } => {
ConfigError::ParseError { path, reason: message }
}
sublime_standard_tools::error::ConfigError::FileWriteError { path, message } => {
ConfigError::InvalidPath { path, reason: message }
}
sublime_standard_tools::error::ConfigError::ParseError { format, message } => {
ConfigError::InvalidConfig { message: format!("{}: {}", format, message) }
}
sublime_standard_tools::error::ConfigError::SerializeError { format, message } => {
ConfigError::InvalidConfig {
message: format!("serialization {}: {}", format, message),
}
}
sublime_standard_tools::error::ConfigError::ValidationError { message } => {
ConfigError::ValidationFailed { errors: vec![message] }
}
sublime_standard_tools::error::ConfigError::EnvironmentError { message } => {
ConfigError::EnvVarError { var_name: "UNKNOWN".to_string(), reason: message }
}
sublime_standard_tools::error::ConfigError::TypeError { expected, actual } => {
ConfigError::InvalidFieldType { field: "unknown".to_string(), expected, actual }
}
sublime_standard_tools::error::ConfigError::KeyNotFound { key } => {
ConfigError::MissingField { field: key }
}
sublime_standard_tools::error::ConfigError::MergeConflict { message } => {
ConfigError::MergeConflict { field: "unknown".to_string(), reason: message }
}
sublime_standard_tools::error::ConfigError::ProviderError { provider, message } => {
ConfigError::InvalidConfig {
message: format!("provider '{}': {}", provider, message),
}
}
sublime_standard_tools::error::ConfigError::Other(msg) => {
ConfigError::InvalidConfig { message: msg }
}
}
}
}
impl From<sublime_git_tools::RepoError> for Error {
fn from(error: sublime_git_tools::RepoError) -> Self {
Self::Git(error.to_string())
}
}
impl From<sublime_git_tools::RepoError> for ChangesError {
fn from(error: sublime_git_tools::RepoError) -> Self {
ChangesError::GitError { operation: "git operation".to_string(), reason: error.to_string() }
}
}
impl From<sublime_git_tools::RepoError> for ChangelogError {
fn from(error: sublime_git_tools::RepoError) -> Self {
ChangelogError::GitError {
operation: "git operation".to_string(),
reason: error.to_string(),
}
}
}
impl From<sublime_git_tools::RepoError> for ChangesetError {
fn from(error: sublime_git_tools::RepoError) -> Self {
ChangesetError::GitError {
operation: "git operation".to_string(),
reason: error.to_string(),
}
}
}
impl Error {
#[must_use]
pub fn is_transient(&self) -> bool {
match self {
Self::Version(e) => e.is_recoverable(),
Self::Changeset(e) => e.is_transient(),
Self::Changes(e) => e.is_transient(),
Self::Changelog(e) => e.is_transient(),
Self::Upgrade(e) => e.is_transient(),
Self::Audit(e) => e.is_transient(),
Self::FileSystem(_) | Self::Git(_) | Self::IO(_) => true,
Self::Config(_) | Self::Json(_) => false,
}
}
#[must_use]
pub fn filesystem_error(path: PathBuf, reason: &str) -> Self {
Self::FileSystem(format!("Filesystem error at '{}': {}", path.display(), reason))
}
#[must_use]
pub fn git_error(operation: &str, reason: &str) -> Self {
Self::Git(format!("Git operation '{}' failed: {}", operation, reason))
}
}