diff options
Diffstat (limited to 'vendor/xshell/src/error.rs')
-rw-r--r-- | vendor/xshell/src/error.rs | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/vendor/xshell/src/error.rs b/vendor/xshell/src/error.rs new file mode 100644 index 000000000..3e0f5dc3f --- /dev/null +++ b/vendor/xshell/src/error.rs @@ -0,0 +1,177 @@ +use std::{env, ffi::OsString, fmt, io, path::PathBuf, process::ExitStatus, string::FromUtf8Error}; + +use crate::{Cmd, CmdData}; + +/// `Result` from std, with the error type defaulting to xshell's [`Error`]. +pub type Result<T, E = Error> = std::result::Result<T, E>; + +/// An error returned by an `xshell` operation. +pub struct Error { + kind: Box<ErrorKind>, +} + +/// Note: this is intentionally not public. +enum ErrorKind { + CurrentDir { err: io::Error }, + Var { err: env::VarError, var: OsString }, + ReadFile { err: io::Error, path: PathBuf }, + ReadDir { err: io::Error, path: PathBuf }, + WriteFile { err: io::Error, path: PathBuf }, + CopyFile { err: io::Error, src: PathBuf, dst: PathBuf }, + HardLink { err: io::Error, src: PathBuf, dst: PathBuf }, + CreateDir { err: io::Error, path: PathBuf }, + RemovePath { err: io::Error, path: PathBuf }, + CmdStatus { cmd: CmdData, status: ExitStatus }, + CmdIo { err: io::Error, cmd: CmdData }, + CmdUtf8 { err: FromUtf8Error, cmd: CmdData }, + CmdStdin { err: io::Error, cmd: CmdData }, +} + +impl From<ErrorKind> for Error { + fn from(kind: ErrorKind) -> Error { + let kind = Box::new(kind); + Error { kind } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &*self.kind { + ErrorKind::CurrentDir { err } => write!(f, "failed to get current directory: {err}"), + ErrorKind::Var { err, var } => { + let var = var.to_string_lossy(); + write!(f, "failed to get environment variable `{var}`: {err}") + } + ErrorKind::ReadFile { err, path } => { + let path = path.display(); + write!(f, "failed to read file `{path}`: {err}") + } + ErrorKind::ReadDir { err, path } => { + let path = path.display(); + write!(f, "failed read directory `{path}`: {err}") + } + ErrorKind::WriteFile { err, path } => { + let path = path.display(); + write!(f, "failed to write file `{path}`: {err}") + } + ErrorKind::CopyFile { err, src, dst } => { + let src = src.display(); + let dst = dst.display(); + write!(f, "failed to copy `{src}` to `{dst}`: {err}") + } + ErrorKind::HardLink { err, src, dst } => { + let src = src.display(); + let dst = dst.display(); + write!(f, "failed hard link `{src}` to `{dst}`: {err}") + } + ErrorKind::CreateDir { err, path } => { + let path = path.display(); + write!(f, "failed to create directory `{path}`: {err}") + } + ErrorKind::RemovePath { err, path } => { + let path = path.display(); + write!(f, "failed to remove path `{path}`: {err}") + } + ErrorKind::CmdStatus { cmd, status } => match status.code() { + Some(code) => write!(f, "command exited with non-zero code `{cmd}`: {code}"), + #[cfg(unix)] + None => { + use std::os::unix::process::ExitStatusExt; + match status.signal() { + Some(sig) => write!(f, "command was terminated by a signal `{cmd}`: {sig}"), + None => write!(f, "command was terminated by a signal `{cmd}`"), + } + } + #[cfg(not(unix))] + None => write!(f, "command was terminated by a signal `{cmd}`"), + }, + ErrorKind::CmdIo { err, cmd } => { + if err.kind() == io::ErrorKind::NotFound { + let prog = cmd.prog.display(); + write!(f, "command not found: `{prog}`") + } else { + write!(f, "io error when running command `{cmd}`: {err}") + } + } + ErrorKind::CmdUtf8 { err, cmd } => { + write!(f, "failed to decode output of command `{cmd}`: {err}") + } + ErrorKind::CmdStdin { err, cmd } => { + write!(f, "failed to write to stdin of command `{cmd}`: {err}") + } + }?; + Ok(()) + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(self, f) + } +} +impl std::error::Error for Error {} + +/// `pub(crate)` constructors, visible only in this crate. +impl Error { + pub(crate) fn new_current_dir(err: io::Error) -> Error { + ErrorKind::CurrentDir { err }.into() + } + + pub(crate) fn new_var(err: env::VarError, var: OsString) -> Error { + ErrorKind::Var { err, var }.into() + } + + pub(crate) fn new_read_file(err: io::Error, path: PathBuf) -> Error { + ErrorKind::ReadFile { err, path }.into() + } + + pub(crate) fn new_read_dir(err: io::Error, path: PathBuf) -> Error { + ErrorKind::ReadDir { err, path }.into() + } + + pub(crate) fn new_write_file(err: io::Error, path: PathBuf) -> Error { + ErrorKind::WriteFile { err, path }.into() + } + + pub(crate) fn new_copy_file(err: io::Error, src: PathBuf, dst: PathBuf) -> Error { + ErrorKind::CopyFile { err, src, dst }.into() + } + + pub(crate) fn new_hard_link(err: io::Error, src: PathBuf, dst: PathBuf) -> Error { + ErrorKind::HardLink { err, src, dst }.into() + } + + pub(crate) fn new_create_dir(err: io::Error, path: PathBuf) -> Error { + ErrorKind::CreateDir { err, path }.into() + } + + pub(crate) fn new_remove_path(err: io::Error, path: PathBuf) -> Error { + ErrorKind::RemovePath { err, path }.into() + } + + pub(crate) fn new_cmd_status(cmd: &Cmd<'_>, status: ExitStatus) -> Error { + let cmd = cmd.data.clone(); + ErrorKind::CmdStatus { cmd, status }.into() + } + + pub(crate) fn new_cmd_io(cmd: &Cmd<'_>, err: io::Error) -> Error { + let cmd = cmd.data.clone(); + ErrorKind::CmdIo { err, cmd }.into() + } + + pub(crate) fn new_cmd_utf8(cmd: &Cmd<'_>, err: FromUtf8Error) -> Error { + let cmd = cmd.data.clone(); + ErrorKind::CmdUtf8 { err, cmd }.into() + } + + pub(crate) fn new_cmd_stdin(cmd: &Cmd<'_>, err: io::Error) -> Error { + let cmd = cmd.data.clone(); + ErrorKind::CmdStdin { err, cmd }.into() + } +} + +#[test] +fn error_send_sync() { + fn f<T: Send + Sync>() {} + f::<Error>(); +} |