error.rs
143 lines
| 4.3 KiB
| application/rls-services+xml
|
RustLexer
|
r47165 | use crate::ui::utf8_to_local; | ||
|
r45592 | use crate::ui::UiError; | ||
|
r47335 | use crate::NoRepoInCwdError; | ||
|
r47175 | use format_bytes::format_bytes; | ||
|
r47213 | use hg::config::{ConfigError, ConfigParseError}; | ||
|
r47175 | use hg::errors::HgError; | ||
|
r47215 | use hg::repo::RepoError; | ||
|
r47166 | use hg::revlog::revlog::RevlogError; | ||
|
r47175 | use hg::utils::files::get_bytes_from_path; | ||
|
r45592 | use std::convert::From; | ||
/// The kind of command error | ||||
|
r47174 | #[derive(Debug)] | ||
|
r47163 | pub enum CommandError { | ||
|
r47174 | /// Exit with an error message and "standard" failure exit code. | ||
Abort { message: Vec<u8> }, | ||||
|
r47424 | /// Encountered something (such as a CLI argument, repository layout, …) | ||
/// not supported by this version of `rhg`. Depending on configuration | ||||
/// `rhg` may attempt to silently fall back to Python-based `hg`, which | ||||
/// may or may not support this feature. | ||||
UnsupportedFeature { message: Vec<u8> }, | ||||
|
r45592 | } | ||
|
r47163 | impl CommandError { | ||
|
r47174 | 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(), | ||||
|
r45592 | } | ||
} | ||||
|
r47424 | |||
pub fn unsupported(message: impl AsRef<str>) -> Self { | ||||
CommandError::UnsupportedFeature { | ||||
message: utf8_to_local(message.as_ref()).into(), | ||||
} | ||||
} | ||||
|
r47174 | } | ||
|
r45920 | |||
|
r47333 | /// For now we don’t differenciate between invalid CLI args and valid for `hg` | ||
/// but not supported yet by `rhg`. | ||||
impl From<clap::Error> for CommandError { | ||||
|
r47424 | fn from(error: clap::Error) -> Self { | ||
CommandError::unsupported(error.to_string()) | ||||
|
r47333 | } | ||
} | ||||
|
r47174 | impl From<HgError> for CommandError { | ||
fn from(error: HgError) -> Self { | ||||
match error { | ||||
|
r47424 | HgError::UnsupportedFeature(message) => { | ||
CommandError::unsupported(message) | ||||
} | ||||
|
r47174 | _ => CommandError::abort(error.to_string()), | ||
|
r45920 | } | ||
} | ||||
|
r45592 | } | ||
impl From<UiError> for CommandError { | ||||
|
r47174 | 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("") | ||||
|
r45592 | } | ||
} | ||||
|
r45922 | |||
|
r47215 | impl From<RepoError> for CommandError { | ||
fn from(error: RepoError) -> Self { | ||||
|
r47175 | match error { | ||
|
r47253 | RepoError::NotFound { at } => CommandError::Abort { | ||
|
r47175 | message: format_bytes!( | ||
|
r47335 | b"repository {} not found", | ||
|
r47253 | get_bytes_from_path(at) | ||
|
r47175 | ), | ||
}, | ||||
|
r47215 | RepoError::ConfigParseError(error) => error.into(), | ||
RepoError::Other(error) => error.into(), | ||||
|
r45922 | } | ||
} | ||||
} | ||||
|
r47165 | |||
|
r47335 | impl<'a> From<&'a NoRepoInCwdError> for CommandError { | ||
fn from(error: &'a NoRepoInCwdError) -> Self { | ||||
let NoRepoInCwdError { cwd } = error; | ||||
CommandError::Abort { | ||||
message: format_bytes!( | ||||
|
r47465 | b"abort: no repository found in '{}' (.hg not found)!", | ||
|
r47335 | get_bytes_from_path(cwd) | ||
), | ||||
} | ||||
} | ||||
} | ||||
|
r47213 | impl From<ConfigError> for CommandError { | ||
fn from(error: ConfigError) -> Self { | ||||
match error { | ||||
|
r47215 | ConfigError::Parse(error) => error.into(), | ||
|
r47213 | ConfigError::Other(error) => error.into(), | ||
} | ||||
} | ||||
} | ||||
|
r47215 | impl From<ConfigParseError> for CommandError { | ||
fn from(error: ConfigParseError) -> Self { | ||||
let ConfigParseError { | ||||
origin, | ||||
line, | ||||
|
r47465 | message, | ||
|
r47215 | } = error; | ||
let line_message = if let Some(line_number) = line { | ||||
|
r47465 | format_bytes!(b":{}", line_number.to_string().into_bytes()) | ||
|
r47215 | } else { | ||
Vec::new() | ||||
}; | ||||
CommandError::Abort { | ||||
message: format_bytes!( | ||||
|
r47465 | b"config error at {}{}: {}", | ||
|
r47249 | origin, | ||
|
r47215 | line_message, | ||
|
r47465 | message | ||
|
r47215 | ), | ||
} | ||||
} | ||||
} | ||||
|
r47166 | impl From<(RevlogError, &str)> for CommandError { | ||
fn from((err, rev): (RevlogError, &str)) -> CommandError { | ||||
|
r47165 | match err { | ||
|
r47174 | RevlogError::InvalidRevision => CommandError::abort(format!( | ||
|
r47465 | "abort: invalid revision identifier: {}", | ||
|
r47174 | rev | ||
|
r47165 | )), | ||
|
r47174 | RevlogError::AmbiguousPrefix => CommandError::abort(format!( | ||
|
r47465 | "abort: ambiguous revision identifier: {}", | ||
|
r47174 | rev | ||
|
r47165 | )), | ||
|
r47174 | RevlogError::Other(error) => error.into(), | ||
|
r47165 | } | ||
} | ||||
} | ||||