annotate rust/hg-core/src/errors.rs @ 46485:f031fe1c6ede

rhg: Abort based on config on share-safe mismatch Differential Revision: https://phab.mercurial-scm.org/D9963
author Simon Sapin <simon.sapin@octobus.net>
date Thu, 04 Feb 2021 14:29:47 +0100
parents 2845892dd489
children bc08c2331f99
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
1 use std::fmt;
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
2
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
3 /// Common error cases that can happen in many different APIs
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
4 #[derive(Debug)]
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
5 pub enum HgError {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
6 IoError {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
7 error: std::io::Error,
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
8 context: IoErrorContext,
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
9 },
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
10
46485
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
11 /// A file under `.hg/` normally only written by Mercurial is not in the
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
12 /// expected format. This indicates a bug in Mercurial, filesystem
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
13 /// corruption, or hardware failure.
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
14 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
15 /// The given string is a short explanation for users, not intended to be
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
16 /// machine-readable.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
17 CorruptedRepository(String),
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
18
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
19 /// The respository or requested operation involves a feature not
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
20 /// supported by the Rust implementation. Falling back to the Python
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
21 /// implementation may or may not work.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
22 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
23 /// The given string is a short explanation for users, not intended to be
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
24 /// machine-readable.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
25 UnsupportedFeature(String),
46485
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
26
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
27 /// Operation cannot proceed for some other reason.
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
28 ///
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
29 /// The given string is a short explanation for users, not intended to be
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
30 /// machine-readable.
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
31 Abort(String),
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
32 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
33
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
34 /// Details about where an I/O error happened
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
35 #[derive(Debug, derive_more::From)]
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
36 pub enum IoErrorContext {
46483
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
37 /// A filesystem operation for the given file
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
38 #[from]
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
39 File(std::path::PathBuf),
46483
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
40 /// `std::env::current_dir`
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
41 CurrentDir,
46483
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
42 /// `std::env::current_exe`
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
43 CurrentExe,
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
44 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
45
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
46 impl HgError {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
47 pub fn corrupted(explanation: impl Into<String>) -> Self {
46443
43d63979a75e rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents: 46438
diff changeset
48 // TODO: capture a backtrace here and keep it in the error value
43d63979a75e rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents: 46438
diff changeset
49 // to aid debugging?
43d63979a75e rust: use HgError in RevlogError and Vfs
Simon Sapin <simon.sapin@octobus.net>
parents: 46438
diff changeset
50 // https://doc.rust-lang.org/std/backtrace/struct.Backtrace.html
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
51 HgError::CorruptedRepository(explanation.into())
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
52 }
46462
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
53
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
54 pub fn unsupported(explanation: impl Into<String>) -> Self {
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
55 HgError::UnsupportedFeature(explanation.into())
d03b0601e0eb rhg: initial support for shared repositories
Simon Sapin <simon.sapin@octobus.net>
parents: 46443
diff changeset
56 }
46485
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
57 pub fn abort(explanation: impl Into<String>) -> Self {
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
58 HgError::Abort(explanation.into())
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
59 }
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
60 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
61
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
62 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
63 impl fmt::Display for HgError {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
65 match self {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
66 HgError::IoError { error, context } => {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
67 write!(f, "{}: {}", error, context)
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
68 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
69 HgError::CorruptedRepository(explanation) => {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
70 write!(f, "corrupted repository: {}", explanation)
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
71 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
72 HgError::UnsupportedFeature(explanation) => {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
73 write!(f, "unsupported feature: {}", explanation)
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
74 }
46485
f031fe1c6ede rhg: Abort based on config on share-safe mismatch
Simon Sapin <simon.sapin@octobus.net>
parents: 46483
diff changeset
75 HgError::Abort(explanation) => explanation.fmt(f),
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
76 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
77 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
78 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
79
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
80 // TODO: use `DisplayBytes` instead to show non-Unicode filenames losslessly?
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
81 impl fmt::Display for IoErrorContext {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
83 match self {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
84 IoErrorContext::File(path) => path.display().fmt(f),
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
85 IoErrorContext::CurrentDir => f.write_str("current directory"),
46483
2845892dd489 rust: Parse system and user configuration
Simon Sapin <simon.sapin@octobus.net>
parents: 46462
diff changeset
86 IoErrorContext::CurrentExe => f.write_str("current executable"),
46438
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
87 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
88 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
89 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
90
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
91 pub trait IoResultExt<T> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
92 /// Annotate a possible I/O error as related to a file at the given path.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
93 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
94 /// This allows printing something like “File not found: example.txt”
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
95 /// instead of just “File not found”.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
96 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
97 /// Converts a `Result` with `std::io::Error` into one with `HgError`.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
98 fn for_file(self, path: &std::path::Path) -> Result<T, HgError>;
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
99 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
100
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
101 impl<T> IoResultExt<T> for std::io::Result<T> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
102 fn for_file(self, path: &std::path::Path) -> Result<T, HgError> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
103 self.map_err(|error| HgError::IoError {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
104 error,
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
105 context: IoErrorContext::File(path.to_owned()),
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
106 })
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
107 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
108 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
109
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
110 pub trait HgResultExt<T> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
111 /// Handle missing files separately from other I/O error cases.
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
112 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
113 /// Wraps the `Ok` type in an `Option`:
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
114 ///
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
115 /// * `Ok(x)` becomes `Ok(Some(x))`
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
116 /// * An I/O "not found" error becomes `Ok(None)`
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
117 /// * Other errors are unchanged
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
118 fn io_not_found_as_none(self) -> Result<Option<T>, HgError>;
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
119 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
120
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
121 impl<T> HgResultExt<T> for Result<T, HgError> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
122 fn io_not_found_as_none(self) -> Result<Option<T>, HgError> {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
123 match self {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
124 Ok(x) => Ok(Some(x)),
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
125 Err(HgError::IoError { error, .. })
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
126 if error.kind() == std::io::ErrorKind::NotFound =>
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
127 {
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
128 Ok(None)
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
129 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
130 Err(other_error) => Err(other_error),
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
131 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
132 }
39e9407820ac rust: Introduce an `HgError` enum for common error cases
Simon Sapin <simon.sapin@octobus.net>
parents:
diff changeset
133 }