##// END OF EJS Templates
dirstate-tree: Give to `status()` mutable access to the `DirstateMap`...
dirstate-tree: Give to `status()` mutable access to the `DirstateMap` Differential Revision: https://phab.mercurial-scm.org/D10546

File last commit:

r47555:bcdcb442 default
r47882:d5956136 default
Show More
errors.rs
183 lines | 6.0 KiB | application/rls-services+xml | RustLexer
Simon Sapin
rust: Add a `ConfigValueParseError` variant to common errors...
r47340 use crate::config::ConfigValueParseError;
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 use std::fmt;
/// Common error cases that can happen in many different APIs
Simon Sapin
rust: Add a `ConfigValueParseError` variant to common errors...
r47340 #[derive(Debug, derive_more::From)]
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 pub enum HgError {
IoError {
error: std::io::Error,
context: IoErrorContext,
},
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 /// A file under `.hg/` normally only written by Mercurial is not in the
/// expected format. This indicates a bug in Mercurial, filesystem
/// corruption, or hardware failure.
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 ///
/// The given string is a short explanation for users, not intended to be
/// machine-readable.
CorruptedRepository(String),
/// The respository or requested operation involves a feature not
/// supported by the Rust implementation. Falling back to the Python
/// implementation may or may not work.
///
/// The given string is a short explanation for users, not intended to be
/// machine-readable.
UnsupportedFeature(String),
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214
/// Operation cannot proceed for some other reason.
///
/// The given string is a short explanation for users, not intended to be
/// machine-readable.
Abort(String),
Simon Sapin
rust: Add a `ConfigValueParseError` variant to common errors...
r47340
/// A configuration value is not in the expected syntax.
///
/// These errors can happen in many places in the code because values are
/// parsed lazily as the file-level parser does not know the expected type
/// and syntax of each value.
#[from]
ConfigValueParseError(ConfigValueParseError),
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
/// Details about where an I/O error happened
Simon Sapin
rust: Add a log file rotation utility...
r47341 #[derive(Debug)]
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 pub enum IoErrorContext {
Simon Sapin
rust: Add a log file rotation utility...
r47341 ReadingFile(std::path::PathBuf),
WritingFile(std::path::PathBuf),
RemovingFile(std::path::PathBuf),
RenamingFile {
from: std::path::PathBuf,
to: std::path::PathBuf,
},
Simon Sapin
rhg: Don’t make repository path absolute too early...
r47474 /// `std::fs::canonicalize`
CanonicalizingPath(std::path::PathBuf),
Simon Sapin
rust: Parse system and user configuration...
r47212 /// `std::env::current_dir`
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 CurrentDir,
Simon Sapin
rust: Parse system and user configuration...
r47212 /// `std::env::current_exe`
CurrentExe,
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
impl HgError {
pub fn corrupted(explanation: impl Into<String>) -> Self {
Simon Sapin
rust: use HgError in RevlogError and Vfs...
r47172 // TODO: capture a backtrace here and keep it in the error value
// to aid debugging?
// https://doc.rust-lang.org/std/backtrace/struct.Backtrace.html
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 HgError::CorruptedRepository(explanation.into())
}
Simon Sapin
rhg: initial support for shared repositories...
r47190
pub fn unsupported(explanation: impl Into<String>) -> Self {
HgError::UnsupportedFeature(explanation.into())
}
Simon Sapin
rhg: Abort based on config on share-safe mismatch...
r47214 pub fn abort(explanation: impl Into<String>) -> Self {
HgError::Abort(explanation.into())
}
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
// TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
impl fmt::Display for HgError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Simon Sapin
rust: Add a `ConfigValueParseError` variant to common errors...
r47340 HgError::Abort(explanation) => write!(f, "{}", explanation),
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 HgError::IoError { error, context } => {
Simon Sapin
rhg: Align config file parse error formatting with Python...
r47465 write!(f, "abort: {}: {}", context, error)
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
HgError::CorruptedRepository(explanation) => {
Simon Sapin
rhg: Align with Python on some more error messages...
r47469 write!(f, "abort: {}", explanation)
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
HgError::UnsupportedFeature(explanation) => {
write!(f, "unsupported feature: {}", explanation)
}
Simon Sapin
rhg: Add more conversions between error types...
r47555 HgError::ConfigValueParseError(error) => error.fmt(f),
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
}
}
// TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
impl fmt::Display for IoErrorContext {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Simon Sapin
rust: Add a log file rotation utility...
r47341 IoErrorContext::ReadingFile(path) => {
write!(f, "when reading {}", path.display())
}
IoErrorContext::WritingFile(path) => {
write!(f, "when writing {}", path.display())
}
IoErrorContext::RemovingFile(path) => {
write!(f, "when removing {}", path.display())
}
IoErrorContext::RenamingFile { from, to } => write!(
f,
"when renaming {} to {}",
from.display(),
to.display()
),
Simon Sapin
rhg: Don’t make repository path absolute too early...
r47474 IoErrorContext::CanonicalizingPath(path) => {
write!(f, "when canonicalizing {}", path.display())
}
Simon Sapin
rhg: Align config file parse error formatting with Python...
r47465 IoErrorContext::CurrentDir => {
write!(f, "error getting current working directory")
}
IoErrorContext::CurrentExe => {
write!(f, "error getting current executable")
}
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
}
}
pub trait IoResultExt<T> {
Simon Sapin
rust: Add a log file rotation utility...
r47341 /// Annotate a possible I/O error as related to a reading a file at the
/// given path.
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 ///
Simon Sapin
rust: Add a log file rotation utility...
r47341 /// This allows printing something like “File not found when reading
/// example.txt” instead of just “File not found”.
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 ///
/// Converts a `Result` with `std::io::Error` into one with `HgError`.
Simon Sapin
rust: Add a log file rotation utility...
r47341 fn when_reading_file(self, path: &std::path::Path) -> Result<T, HgError>;
fn with_context(
self,
context: impl FnOnce() -> IoErrorContext,
) -> Result<T, HgError>;
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 }
impl<T> IoResultExt<T> for std::io::Result<T> {
Simon Sapin
rust: Add a log file rotation utility...
r47341 fn when_reading_file(self, path: &std::path::Path) -> Result<T, HgError> {
self.with_context(|| IoErrorContext::ReadingFile(path.to_owned()))
}
fn with_context(
self,
context: impl FnOnce() -> IoErrorContext,
) -> Result<T, HgError> {
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 self.map_err(|error| HgError::IoError {
error,
Simon Sapin
rust: Add a log file rotation utility...
r47341 context: context(),
Simon Sapin
rust: Introduce an `HgError` enum for common error cases...
r47167 })
}
}
pub trait HgResultExt<T> {
/// Handle missing files separately from other I/O error cases.
///
/// Wraps the `Ok` type in an `Option`:
///
/// * `Ok(x)` becomes `Ok(Some(x))`
/// * An I/O "not found" error becomes `Ok(None)`
/// * Other errors are unchanged
fn io_not_found_as_none(self) -> Result<Option<T>, HgError>;
}
impl<T> HgResultExt<T> for Result<T, HgError> {
fn io_not_found_as_none(self) -> Result<Option<T>, HgError> {
match self {
Ok(x) => Ok(Some(x)),
Err(HgError::IoError { error, .. })
if error.kind() == std::io::ErrorKind::NotFound =>
{
Ok(None)
}
Err(other_error) => Err(other_error),
}
}
}