Mercurial > public > mercurial-scm > hg
diff rust/rhg/src/error.rs @ 46445:ca3f73cc3cf4
rhg: Simplify CommandError based on its use
Differential Revision: https://phab.mercurial-scm.org/D9905
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Thu, 28 Jan 2021 19:13:55 +0100 |
parents | 43d63979a75e |
children | 1dcd9c9975ed |
line wrap: on
line diff
--- a/rust/rhg/src/error.rs Thu Jan 28 19:21:57 2021 +0100 +++ b/rust/rhg/src/error.rs Thu Jan 28 19:13:55 2021 +0100 @@ -1,101 +1,65 @@ -use crate::exitcode; use crate::ui::utf8_to_local; use crate::ui::UiError; -use format_bytes::format_bytes; -use hg::errors::HgError; +use hg::errors::{HgError, IoErrorContext}; use hg::operations::FindRootError; use hg::revlog::revlog::RevlogError; -use hg::utils::files::get_bytes_from_path; use std::convert::From; -use std::path::PathBuf; /// The kind of command error -#[derive(Debug, derive_more::From)] +#[derive(Debug)] pub enum CommandError { - /// The root of the repository cannot be found - RootNotFound(PathBuf), - /// The current directory cannot be found - CurrentDirNotFound(std::io::Error), - /// The standard output stream cannot be written to - StdoutError, - /// The standard error stream cannot be written to - StderrError, - /// The command aborted - Abort(Option<Vec<u8>>), + /// Exit with an error message and "standard" failure exit code. + Abort { message: Vec<u8> }, + /// A mercurial capability as not been implemented. + /// + /// There is no error message printed in this case. + /// Instead, we exit with a specic status code and a wrapper script may + /// fallback to Python-based Mercurial. Unimplemented, - /// Common cases - #[from] - Other(HgError), } impl CommandError { - pub fn get_exit_code(&self) -> exitcode::ExitCode { - match self { - CommandError::RootNotFound(_) => exitcode::ABORT, - CommandError::CurrentDirNotFound(_) => exitcode::ABORT, - CommandError::StdoutError => exitcode::ABORT, - CommandError::StderrError => exitcode::ABORT, - CommandError::Abort(_) => exitcode::ABORT, - CommandError::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, - CommandError::Other(HgError::UnsupportedFeature(_)) => { - exitcode::UNIMPLEMENTED_COMMAND - } - CommandError::Other(_) => exitcode::ABORT, + pub fn abort(message: impl AsRef<str>) -> Self { + CommandError::Abort { + // TODO: bytes-based (instead of Unicode-based) formatting + // of error messages to handle non-UTF-8 filenames etc: + // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output + message: utf8_to_local(message.as_ref()).into(), } } +} - /// Return the message corresponding to the error if any - pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { - match self { - CommandError::RootNotFound(path) => { - let bytes = get_bytes_from_path(path); - Some(format_bytes!( - b"abort: no repository found in '{}' (.hg not found)!\n", - bytes.as_slice() - )) - } - CommandError::CurrentDirNotFound(e) => Some(format_bytes!( - b"abort: error getting current working directory: {}\n", - e.to_string().as_bytes(), - )), - CommandError::Abort(message) => message.to_owned(), - - CommandError::StdoutError - | CommandError::StderrError - | CommandError::Unimplemented - | CommandError::Other(HgError::UnsupportedFeature(_)) => None, - - CommandError::Other(e) => { - Some(format_bytes!(b"{}\n", e.to_string().as_bytes())) - } +impl From<HgError> for CommandError { + fn from(error: HgError) -> Self { + match error { + HgError::UnsupportedFeature(_) => CommandError::Unimplemented, + _ => CommandError::abort(error.to_string()), } } - - /// Exist the process with the corresponding exit code. - pub fn exit(&self) { - std::process::exit(self.get_exit_code()) - } } impl From<UiError> for CommandError { - fn from(error: UiError) -> Self { - match error { - UiError::StdoutError(_) => CommandError::StdoutError, - UiError::StderrError(_) => CommandError::StderrError, - } + fn from(_error: UiError) -> Self { + // If we already failed writing to stdout or stderr, + // writing an error message to stderr about it would be likely to fail + // too. + CommandError::abort("") } } impl From<FindRootError> for CommandError { fn from(err: FindRootError) -> Self { match err { - FindRootError::RootNotFound(path) => { - CommandError::RootNotFound(path) + FindRootError::RootNotFound(path) => CommandError::abort(format!( + "no repository found in '{}' (.hg not found)!", + path.display() + )), + FindRootError::GetCurrentDirError(error) => HgError::IoError { + error, + context: IoErrorContext::CurrentDir, } - FindRootError::GetCurrentDirError(e) => { - CommandError::CurrentDirNotFound(e) - } + .into(), } } } @@ -103,21 +67,15 @@ impl From<(RevlogError, &str)> for CommandError { fn from((err, rev): (RevlogError, &str)) -> CommandError { match err { - RevlogError::InvalidRevision => CommandError::Abort(Some( - utf8_to_local(&format!( - "abort: invalid revision identifier {}\n", - rev - )) - .into(), + RevlogError::InvalidRevision => CommandError::abort(format!( + "invalid revision identifier {}", + rev )), - RevlogError::AmbiguousPrefix => CommandError::Abort(Some( - utf8_to_local(&format!( - "abort: ambiguous revision identifier {}\n", - rev - )) - .into(), + RevlogError::AmbiguousPrefix => CommandError::abort(format!( + "ambiguous revision identifier {}", + rev )), - RevlogError::Other(err) => CommandError::Other(err), + RevlogError::Other(error) => error.into(), } } }