rhg: Simplify CommandError based on its use
Differential Revision: https://phab.mercurial-scm.org/D9905
use crate::ui::utf8_to_local;
use crate::ui::UiError;
use hg::errors::{HgError, IoErrorContext};
use hg::operations::FindRootError;
use hg::revlog::revlog::RevlogError;
use std::convert::From;
/// The kind of command error
#[derive(Debug)]
pub enum CommandError {
/// 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,
}
impl CommandError {
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(),
}
}
}
impl From<HgError> for CommandError {
fn from(error: HgError) -> Self {
match error {
HgError::UnsupportedFeature(_) => CommandError::Unimplemented,
_ => CommandError::abort(error.to_string()),
}
}
}
impl From<UiError> for CommandError {
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::abort(format!(
"no repository found in '{}' (.hg not found)!",
path.display()
)),
FindRootError::GetCurrentDirError(error) => HgError::IoError {
error,
context: IoErrorContext::CurrentDir,
}
.into(),
}
}
}
impl From<(RevlogError, &str)> for CommandError {
fn from((err, rev): (RevlogError, &str)) -> CommandError {
match err {
RevlogError::InvalidRevision => CommandError::abort(format!(
"invalid revision identifier {}",
rev
)),
RevlogError::AmbiguousPrefix => CommandError::abort(format!(
"ambiguous revision identifier {}",
rev
)),
RevlogError::Other(error) => error.into(),
}
}
}