lix-installer/src/error.rs
Ana Hobden 8bb37f1bcf
Uninstall shouldn't fail fast (#382)
* Uninstall shouldn't fail fast

* wip

* wip

* No longer fails fast

* Tidy up error handling

* Touchup post merge

* Refactor nix tests

* Some minor fixes

* Uninstall fail tests

* Fiddle with messaging

* nixfmt

* Tweak display a bit

* fix docs

* Fix Mac

* Revert setting I was testing

* Reflect feedback about a log level
2023-04-05 15:12:38 +00:00

114 lines
3.7 KiB
Rust

use std::{error::Error, path::PathBuf};
use crate::{action::ActionError, planner::PlannerError, settings::InstallSettingsError};
/// An error occurring during a call defined in this crate
#[non_exhaustive]
#[derive(thiserror::Error, Debug, strum::IntoStaticStr)]
pub enum NixInstallerError {
/// An error originating from an [`Action`](crate::action::Action)
#[error("Error executing action")]
Action(#[source] ActionError),
/// An error originating from an [`Action`](crate::action::Action) while reverting
#[error("Error reverting\n{}", .0.iter().map(|err| {
if let Some(source) = err.source() {
format!("{err}\n{source}\n")
} else {
format!("{err}\n")
}
}).collect::<Vec<_>>().join("\n"))]
ActionRevert(Vec<ActionError>),
/// An error while writing the [`InstallPlan`](crate::InstallPlan)
#[error("Recording install receipt")]
RecordingReceipt(PathBuf, #[source] std::io::Error),
/// An error while writing copying the binary into the `/nix` folder
#[error("Copying `nix-installer` binary into `/nix`")]
CopyingSelf(
#[source]
#[from]
std::io::Error,
),
/// An error while serializing the [`InstallPlan`](crate::InstallPlan)
#[error("Serializing receipt")]
SerializingReceipt(
#[from]
#[source]
serde_json::Error,
),
/// An error occurring when a signal is issued along [`InstallPlan::install`](crate::InstallPlan::install)'s `cancel_channel` argument
#[error("Cancelled by user")]
Cancelled,
/// Semver error
#[error("Semantic Versioning error")]
SemVer(
#[from]
#[source]
semver::Error,
),
/// Planner error
#[error("Planner error")]
Planner(
#[from]
#[source]
PlannerError,
),
/// Install setting error
#[error("Install setting error")]
InstallSettings(
#[from]
#[source]
InstallSettingsError,
),
#[cfg(feature = "diagnostics")]
/// Diagnostic error
#[error("Diagnostic error")]
Diagnostic(
#[from]
#[source]
crate::diagnostics::DiagnosticError,
),
}
pub(crate) trait HasExpectedErrors: std::error::Error + Sized + Send + Sync {
fn expected<'a>(&'a self) -> Option<Box<dyn std::error::Error + 'a>>;
}
impl HasExpectedErrors for NixInstallerError {
fn expected<'a>(&'a self) -> Option<Box<dyn std::error::Error + 'a>> {
match self {
NixInstallerError::Action(action_error) => action_error.kind().expected(),
NixInstallerError::ActionRevert(_) => None,
NixInstallerError::RecordingReceipt(_, _) => None,
NixInstallerError::CopyingSelf(_) => None,
NixInstallerError::SerializingReceipt(_) => None,
this @ NixInstallerError::Cancelled => Some(Box::new(this)),
NixInstallerError::SemVer(_) => None,
NixInstallerError::Planner(planner_error) => planner_error.expected(),
NixInstallerError::InstallSettings(_) => None,
#[cfg(feature = "diagnostics")]
NixInstallerError::Diagnostic(_) => None,
}
}
}
#[cfg(feature = "diagnostics")]
impl crate::diagnostics::ErrorDiagnostic for NixInstallerError {
fn diagnostic(&self) -> String {
let static_str: &'static str = (self).into();
let context = match self {
Self::Action(action_error) => vec![action_error.action_tag().to_string()],
_ => vec![],
};
return format!(
"{}({})",
static_str,
context
.iter()
.map(|v| format!("\"{v}\""))
.collect::<Vec<_>>()
.join(", ")
);
}
}