Show More
@@ -0,0 +1,19 b'' | |||
|
1 | pub type ExitCode = i32; | |
|
2 | ||
|
3 | /// Successful exit | |
|
4 | pub const OK: ExitCode = 0; | |
|
5 | ||
|
6 | /// Generic abort | |
|
7 | pub const ABORT: ExitCode = 255; | |
|
8 | ||
|
9 | // Abort when there is a config related error | |
|
10 | pub const CONFIG_ERROR_ABORT: ExitCode = 30; | |
|
11 | ||
|
12 | // Abort when there is an error while parsing config | |
|
13 | pub const CONFIG_PARSE_ERROR_ABORT: ExitCode = 10; | |
|
14 | ||
|
15 | /// Generic something completed but did not succeed | |
|
16 | pub const UNSUCCESSFUL: ExitCode = 1; | |
|
17 | ||
|
18 | /// Command or feature not implemented by rhg | |
|
19 | pub const UNIMPLEMENTED: ExitCode = 252; |
@@ -8,6 +8,7 b'' | |||
|
8 | 8 | // GNU General Public License version 2 or any later version. |
|
9 | 9 | |
|
10 | 10 | use crate::errors::HgError; |
|
11 | use crate::exit_codes::CONFIG_PARSE_ERROR_ABORT; | |
|
11 | 12 | use crate::utils::files::{get_bytes_from_path, get_path_from_bytes}; |
|
12 | 13 | use format_bytes::{format_bytes, write_bytes, DisplayBytes}; |
|
13 | 14 | use lazy_static::lazy_static; |
@@ -73,11 +74,14 b' impl ConfigLayer {' | |||
|
73 | 74 | if let Some((section, item, value)) = parse_one(arg) { |
|
74 | 75 | layer.add(section, item, value, None); |
|
75 | 76 | } else { |
|
76 |
Err(HgError::abort( |
|
|
77 | "abort: malformed --config option: '{}' \ | |
|
77 | Err(HgError::abort( | |
|
78 | format!( | |
|
79 | "abort: malformed --config option: '{}' \ | |
|
78 | 80 | (use --config section.name=value)", |
|
79 | String::from_utf8_lossy(arg), | |
|
80 |
) |
|
|
81 | String::from_utf8_lossy(arg), | |
|
82 | ), | |
|
83 | CONFIG_PARSE_ERROR_ABORT, | |
|
84 | ))? | |
|
81 | 85 | } |
|
82 | 86 | } |
|
83 | 87 | if layer.sections.is_empty() { |
@@ -1,4 +1,5 b'' | |||
|
1 | 1 | use crate::config::ConfigValueParseError; |
|
2 | use crate::exit_codes; | |
|
2 | 3 | use std::fmt; |
|
3 | 4 | |
|
4 | 5 | /// Common error cases that can happen in many different APIs |
@@ -27,9 +28,12 b' pub enum HgError {' | |||
|
27 | 28 | |
|
28 | 29 | /// Operation cannot proceed for some other reason. |
|
29 | 30 | /// |
|
30 |
/// The |
|
|
31 | /// The message is a short explanation for users, not intended to be | |
|
31 | 32 | /// machine-readable. |
|
32 |
Abort |
|
|
33 | Abort { | |
|
34 | message: String, | |
|
35 | detailed_exit_code: exit_codes::ExitCode, | |
|
36 | }, | |
|
33 | 37 | |
|
34 | 38 | /// A configuration value is not in the expected syntax. |
|
35 | 39 | /// |
@@ -69,8 +73,15 b' impl HgError {' | |||
|
69 | 73 | pub fn unsupported(explanation: impl Into<String>) -> Self { |
|
70 | 74 | HgError::UnsupportedFeature(explanation.into()) |
|
71 | 75 | } |
|
72 | pub fn abort(explanation: impl Into<String>) -> Self { | |
|
73 | HgError::Abort(explanation.into()) | |
|
76 | ||
|
77 | pub fn abort( | |
|
78 | explanation: impl Into<String>, | |
|
79 | exit_code: exit_codes::ExitCode, | |
|
80 | ) -> Self { | |
|
81 | HgError::Abort { | |
|
82 | message: explanation.into(), | |
|
83 | detailed_exit_code: exit_code, | |
|
84 | } | |
|
74 | 85 | } |
|
75 | 86 | } |
|
76 | 87 | |
@@ -78,7 +89,7 b' impl HgError {' | |||
|
78 | 89 | impl fmt::Display for HgError { |
|
79 | 90 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
|
80 | 91 | match self { |
|
81 |
HgError::Abort |
|
|
92 | HgError::Abort { message, .. } => write!(f, "{}", message), | |
|
82 | 93 | HgError::IoError { error, context } => { |
|
83 | 94 | write!(f, "abort: {}: {}", context, error) |
|
84 | 95 | } |
@@ -11,6 +11,7 b' pub use ancestors::{AncestorsIterator, L' | |||
|
11 | 11 | pub mod dirstate; |
|
12 | 12 | pub mod dirstate_tree; |
|
13 | 13 | pub mod discovery; |
|
14 | pub mod exit_codes; | |
|
14 | 15 | pub mod requirements; |
|
15 | 16 | pub mod testing; // unconditionally built, for use from integration tests |
|
16 | 17 | pub use dirstate::{ |
@@ -1,5 +1,6 b'' | |||
|
1 | 1 | use crate::config::{Config, ConfigError, ConfigParseError}; |
|
2 | 2 | use crate::errors::{HgError, IoErrorContext, IoResultExt}; |
|
3 | use crate::exit_codes; | |
|
3 | 4 | use crate::requirements; |
|
4 | 5 | use crate::utils::files::get_path_from_bytes; |
|
5 | 6 | use crate::utils::SliceExt; |
@@ -150,6 +151,7 b' impl Repo {' | |||
|
150 | 151 | Some(b"abort") | None => HgError::abort( |
|
151 | 152 | "abort: share source does not support share-safe requirement\n\ |
|
152 | 153 | (see `hg help config.format.use-share-safe` for more information)", |
|
154 | exit_codes::ABORT, | |
|
153 | 155 | ), |
|
154 | 156 | _ => HgError::unsupported("share-safe downgrade"), |
|
155 | 157 | } |
@@ -161,6 +163,7 b' impl Repo {' | |||
|
161 | 163 | "abort: version mismatch: source uses share-safe \ |
|
162 | 164 | functionality while the current share does not\n\ |
|
163 | 165 | (see `hg help config.format.use-share-safe` for more information)", |
|
166 | exit_codes::ABORT, | |
|
164 | 167 | ), |
|
165 | 168 | _ => HgError::unsupported("share-safe upgrade"), |
|
166 | 169 | } |
@@ -1,10 +1,10 b'' | |||
|
1 | use crate::exitcode; | |
|
2 | 1 |
|
|
3 | 2 | use crate::ui::UiError; |
|
4 | 3 | use crate::NoRepoInCwdError; |
|
5 | 4 | use format_bytes::format_bytes; |
|
6 | 5 | use hg::config::{ConfigError, ConfigParseError, ConfigValueParseError}; |
|
7 | 6 | use hg::errors::HgError; |
|
7 | use hg::exit_codes; | |
|
8 | 8 | use hg::repo::RepoError; |
|
9 | 9 | use hg::revlog::revlog::RevlogError; |
|
10 | 10 | use hg::utils::files::get_bytes_from_path; |
@@ -17,7 +17,7 b' pub enum CommandError {' | |||
|
17 | 17 | /// Exit with an error message and "standard" failure exit code. |
|
18 | 18 | Abort { |
|
19 | 19 | message: Vec<u8>, |
|
20 | detailed_exit_code: exitcode::ExitCode, | |
|
20 | detailed_exit_code: exit_codes::ExitCode, | |
|
21 | 21 | }, |
|
22 | 22 | |
|
23 | 23 | /// Exit with a failure exit code but no message. |
@@ -32,12 +32,12 b' pub enum CommandError {' | |||
|
32 | 32 | |
|
33 | 33 | impl CommandError { |
|
34 | 34 | pub fn abort(message: impl AsRef<str>) -> Self { |
|
35 | CommandError::abort_with_exit_code(message, exitcode::ABORT) | |
|
35 | CommandError::abort_with_exit_code(message, exit_codes::ABORT) | |
|
36 | 36 | } |
|
37 | 37 | |
|
38 | 38 | pub fn abort_with_exit_code( |
|
39 | 39 | message: impl AsRef<str>, |
|
40 | detailed_exit_code: exitcode::ExitCode, | |
|
40 | detailed_exit_code: exit_codes::ExitCode, | |
|
41 | 41 | ) -> Self { |
|
42 | 42 | CommandError::Abort { |
|
43 | 43 | // TODO: bytes-based (instead of Unicode-based) formatting |
@@ -78,7 +78,7 b' impl From<ConfigValueParseError> for Com' | |||
|
78 | 78 | fn from(error: ConfigValueParseError) -> Self { |
|
79 | 79 | CommandError::abort_with_exit_code( |
|
80 | 80 | error.to_string(), |
|
81 | exitcode::CONFIG_ERROR_ABORT, | |
|
81 | exit_codes::CONFIG_ERROR_ABORT, | |
|
82 | 82 | ) |
|
83 | 83 | } |
|
84 | 84 | } |
@@ -100,7 +100,7 b' impl From<RepoError> for CommandError {' | |||
|
100 | 100 | b"abort: repository {} not found", |
|
101 | 101 | get_bytes_from_path(at) |
|
102 | 102 | ), |
|
103 | detailed_exit_code: exitcode::ABORT, | |
|
103 | detailed_exit_code: exit_codes::ABORT, | |
|
104 | 104 | }, |
|
105 | 105 | RepoError::ConfigParseError(error) => error.into(), |
|
106 | 106 | RepoError::Other(error) => error.into(), |
@@ -116,7 +116,7 b" impl<'a> From<&'a NoRepoInCwdError> for " | |||
|
116 | 116 | b"abort: no repository found in '{}' (.hg not found)!", |
|
117 | 117 | get_bytes_from_path(cwd) |
|
118 | 118 | ), |
|
119 | detailed_exit_code: exitcode::ABORT, | |
|
119 | detailed_exit_code: exit_codes::ABORT, | |
|
120 | 120 | } |
|
121 | 121 | } |
|
122 | 122 | } |
@@ -149,7 +149,7 b' impl From<ConfigParseError> for CommandE' | |||
|
149 | 149 | line_message, |
|
150 | 150 | message |
|
151 | 151 | ), |
|
152 | detailed_exit_code: exitcode::CONFIG_ERROR_ABORT, | |
|
152 | detailed_exit_code: exit_codes::CONFIG_ERROR_ABORT, | |
|
153 | 153 | } |
|
154 | 154 | } |
|
155 | 155 | } |
@@ -6,6 +6,7 b' use clap::Arg;' | |||
|
6 | 6 | use clap::ArgMatches; |
|
7 | 7 | use format_bytes::{format_bytes, join}; |
|
8 | 8 | use hg::config::{Config, ConfigSource}; |
|
9 | use hg::exit_codes; | |
|
9 | 10 | use hg::repo::{Repo, RepoError}; |
|
10 | 11 | use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes}; |
|
11 | 12 | use hg::utils::SliceExt; |
@@ -15,7 +16,6 b' use std::process::Command;' | |||
|
15 | 16 | |
|
16 | 17 | mod blackbox; |
|
17 | 18 | mod error; |
|
18 | mod exitcode; | |
|
19 | 19 | mod ui; |
|
20 | 20 | use error::CommandError; |
|
21 | 21 | |
@@ -297,7 +297,7 b' fn exit_code(' | |||
|
297 | 297 | use_detailed_exit_code: bool, |
|
298 | 298 | ) -> i32 { |
|
299 | 299 | match result { |
|
300 | Ok(()) => exitcode::OK, | |
|
300 | Ok(()) => exit_codes::OK, | |
|
301 | 301 | Err(CommandError::Abort { |
|
302 | 302 | message: _, |
|
303 | 303 | detailed_exit_code, |
@@ -305,15 +305,15 b' fn exit_code(' | |||
|
305 | 305 | if use_detailed_exit_code { |
|
306 | 306 | *detailed_exit_code |
|
307 | 307 | } else { |
|
308 | exitcode::ABORT | |
|
308 | exit_codes::ABORT | |
|
309 | 309 | } |
|
310 | 310 | } |
|
311 | Err(CommandError::Unsuccessful) => exitcode::UNSUCCESSFUL, | |
|
311 | Err(CommandError::Unsuccessful) => exit_codes::UNSUCCESSFUL, | |
|
312 | 312 | |
|
313 | 313 | // Exit with a specific code and no error message to let a potential |
|
314 | 314 | // wrapper script fallback to Python-based Mercurial. |
|
315 | 315 | Err(CommandError::UnsupportedFeature { .. }) => { |
|
316 | exitcode::UNIMPLEMENTED | |
|
316 | exit_codes::UNIMPLEMENTED | |
|
317 | 317 | } |
|
318 | 318 | } |
|
319 | 319 | } |
@@ -352,7 +352,7 b' fn exit(' | |||
|
352 | 352 | let result = command.status(); |
|
353 | 353 | match result { |
|
354 | 354 | Ok(status) => std::process::exit( |
|
355 | status.code().unwrap_or(exitcode::ABORT), | |
|
355 | status.code().unwrap_or(exit_codes::ABORT), | |
|
356 | 356 | ), |
|
357 | 357 | Err(error) => { |
|
358 | 358 | let _ = ui.write_stderr(&format_bytes!( |
|
1 | NO CONTENT: file was removed |
General Comments 0
You need to be logged in to leave comments.
Login now