comparison rust/rhg/src/error.rs @ 49488:9f14126cfc4c

rust: add support for hints in error messages This will be used by the narrow support code in the next commit.
author Raphaël Gomès <rgomes@octobus.net>
date Tue, 19 Jul 2022 17:07:09 +0200
parents ffd4b1f1c9cb
children 7c93e38a0bbd
comparison
equal deleted inserted replaced
49487:e8481625c582 49488:9f14126cfc4c
18 pub enum CommandError { 18 pub enum CommandError {
19 /// Exit with an error message and "standard" failure exit code. 19 /// Exit with an error message and "standard" failure exit code.
20 Abort { 20 Abort {
21 message: Vec<u8>, 21 message: Vec<u8>,
22 detailed_exit_code: exit_codes::ExitCode, 22 detailed_exit_code: exit_codes::ExitCode,
23 hint: Option<Vec<u8>>,
23 }, 24 },
24 25
25 /// Exit with a failure exit code but no message. 26 /// Exit with a failure exit code but no message.
26 Unsuccessful, 27 Unsuccessful,
27 28
48 // TODO: bytes-based (instead of Unicode-based) formatting 49 // TODO: bytes-based (instead of Unicode-based) formatting
49 // of error messages to handle non-UTF-8 filenames etc: 50 // of error messages to handle non-UTF-8 filenames etc:
50 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output 51 // https://www.mercurial-scm.org/wiki/EncodingStrategy#Mixing_output
51 message: utf8_to_local(message.as_ref()).into(), 52 message: utf8_to_local(message.as_ref()).into(),
52 detailed_exit_code: detailed_exit_code, 53 detailed_exit_code: detailed_exit_code,
54 hint: None,
55 }
56 }
57
58 pub fn abort_with_exit_code_and_hint(
59 message: impl AsRef<str>,
60 detailed_exit_code: exit_codes::ExitCode,
61 hint: Option<impl AsRef<str>>,
62 ) -> Self {
63 CommandError::Abort {
64 message: utf8_to_local(message.as_ref()).into(),
65 detailed_exit_code,
66 hint: hint.map(|h| utf8_to_local(h.as_ref()).into()),
53 } 67 }
54 } 68 }
55 69
56 pub fn abort_with_exit_code_bytes( 70 pub fn abort_with_exit_code_bytes(
57 message: impl AsRef<[u8]>, 71 message: impl AsRef<[u8]>,
60 // TODO: use this everywhere it makes sense instead of the string 74 // TODO: use this everywhere it makes sense instead of the string
61 // version. 75 // version.
62 CommandError::Abort { 76 CommandError::Abort {
63 message: message.as_ref().into(), 77 message: message.as_ref().into(),
64 detailed_exit_code, 78 detailed_exit_code,
79 hint: None,
65 } 80 }
66 } 81 }
67 82
68 pub fn unsupported(message: impl AsRef<str>) -> Self { 83 pub fn unsupported(message: impl AsRef<str>) -> Self {
69 CommandError::UnsupportedFeature { 84 CommandError::UnsupportedFeature {
90 CommandError::unsupported("Encountered a censored node") 105 CommandError::unsupported("Encountered a censored node")
91 } 106 }
92 HgError::Abort { 107 HgError::Abort {
93 message, 108 message,
94 detailed_exit_code, 109 detailed_exit_code,
95 } => { 110 hint,
96 CommandError::abort_with_exit_code(message, detailed_exit_code) 111 } => CommandError::abort_with_exit_code_and_hint(
97 } 112 message,
113 detailed_exit_code,
114 hint,
115 ),
98 _ => CommandError::abort(error.to_string()), 116 _ => CommandError::abort(error.to_string()),
99 } 117 }
100 } 118 }
101 } 119 }
102 120
119 } 137 }
120 138
121 impl From<RepoError> for CommandError { 139 impl From<RepoError> for CommandError {
122 fn from(error: RepoError) -> Self { 140 fn from(error: RepoError) -> Self {
123 match error { 141 match error {
124 RepoError::NotFound { at } => CommandError::Abort { 142 RepoError::NotFound { at } => {
125 message: format_bytes!( 143 CommandError::abort_with_exit_code_bytes(
126 b"abort: repository {} not found", 144 format_bytes!(
127 get_bytes_from_path(at) 145 b"abort: repository {} not found",
128 ), 146 get_bytes_from_path(at)
129 detailed_exit_code: exit_codes::ABORT, 147 ),
130 }, 148 exit_codes::ABORT,
149 )
150 }
131 RepoError::ConfigParseError(error) => error.into(), 151 RepoError::ConfigParseError(error) => error.into(),
132 RepoError::Other(error) => error.into(), 152 RepoError::Other(error) => error.into(),
133 } 153 }
134 } 154 }
135 } 155 }
136 156
137 impl<'a> From<&'a NoRepoInCwdError> for CommandError { 157 impl<'a> From<&'a NoRepoInCwdError> for CommandError {
138 fn from(error: &'a NoRepoInCwdError) -> Self { 158 fn from(error: &'a NoRepoInCwdError) -> Self {
139 let NoRepoInCwdError { cwd } = error; 159 let NoRepoInCwdError { cwd } = error;
140 CommandError::Abort { 160 CommandError::abort_with_exit_code_bytes(
141 message: format_bytes!( 161 format_bytes!(
142 b"abort: no repository found in '{}' (.hg not found)!", 162 b"abort: no repository found in '{}' (.hg not found)!",
143 get_bytes_from_path(cwd) 163 get_bytes_from_path(cwd)
144 ), 164 ),
145 detailed_exit_code: exit_codes::ABORT, 165 exit_codes::ABORT,
146 } 166 )
147 } 167 }
148 } 168 }
149 169
150 impl From<ConfigError> for CommandError { 170 impl From<ConfigError> for CommandError {
151 fn from(error: ConfigError) -> Self { 171 fn from(error: ConfigError) -> Self {
166 let line_message = if let Some(line_number) = line { 186 let line_message = if let Some(line_number) = line {
167 format_bytes!(b":{}", line_number.to_string().into_bytes()) 187 format_bytes!(b":{}", line_number.to_string().into_bytes())
168 } else { 188 } else {
169 Vec::new() 189 Vec::new()
170 }; 190 };
171 CommandError::Abort { 191 CommandError::abort_with_exit_code_bytes(
172 message: format_bytes!( 192 format_bytes!(
173 b"config error at {}{}: {}", 193 b"config error at {}{}: {}",
174 origin, 194 origin,
175 line_message, 195 line_message,
176 message 196 message
177 ), 197 ),
178 detailed_exit_code: exit_codes::CONFIG_ERROR_ABORT, 198 exit_codes::CONFIG_ERROR_ABORT,
179 } 199 )
180 } 200 }
181 } 201 }
182 202
183 impl From<(RevlogError, &str)> for CommandError { 203 impl From<(RevlogError, &str)> for CommandError {
184 fn from((err, rev): (RevlogError, &str)) -> CommandError { 204 fn from((err, rev): (RevlogError, &str)) -> CommandError {