use std::{
fmt::{self, Debug},
process::{ExitCode, Termination},
};
use thiserror::Error;
use tokio::{io, task::JoinError};
use crate::exec::{Output, StatusCode};
use crate::print;
pub type Result<T, E = Error> = std::result::Result<T, E>;
#[derive(Debug, Error)]
#[non_exhaustive]
pub enum Error {
#[error("Failed to parse arguments: {msg}")]
#[allow(missing_docs)]
ArgParseError { msg: String },
#[error("Failed to parse config: {0}")]
ConfigError(#[from] figment::Error),
#[error("Failed to get exit code of subprocess: {0}")]
CmdJoinError(JoinError),
#[error("Failed to spawn subprocess: {0}")]
CmdSpawnError(io::Error),
#[error("Subprocess didn't have a handle to {handle}")]
#[allow(missing_docs)]
CmdNoHandleError { handle: String },
#[error("Subprocess failed while running: {0}")]
CmdWaitError(io::Error),
#[error("Subprocess exited with code {code}")]
#[allow(missing_docs)]
CmdStatusCodeError { code: StatusCode, output: Output },
#[error("Subprocess interrupted by signal")]
CmdInterruptedError,
#[error(transparent)]
FromUtf8Error(#[from] std::string::FromUtf8Error),
#[error(transparent)]
DialogError(#[from] dialoguer::Error),
#[error(transparent)]
IoError(#[from] io::Error),
#[error("Operation `{op}` is unimplemented for `{pm}`")]
#[allow(missing_docs)]
OperationUnimplementedError { op: String, pm: String },
#[error("{0}")]
OtherError(String),
}
#[allow(clippy::module_name_repetitions)]
pub struct MainError(Error);
impl From<Error> for MainError {
fn from(e: Error) -> Self {
Self(e)
}
}
impl Debug for MainError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "\r")?;
print::write(f, &*print::prompt::ERROR, &self.0)
}
}
impl Termination for MainError {
fn report(self) -> ExitCode {
#[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)]
match self.0 {
Error::CmdStatusCodeError { code, .. } => code as u8,
_ => 1,
}
.into()
}
}