Mercurial > hg-stable
comparison rust/rhg/src/main.rs @ 46705:33f2d56acc73
rhg: Add a `rhg.on-unsupported` configuration key
For now the two values are:
* `abort-silent`: silently exit with code 252, the previous default behavior
* `abort`: print an error message about what feature
is not supported, then exit with code 252. Now the default.
Differential Revision: https://phab.mercurial-scm.org/D10091
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Mon, 01 Mar 2021 16:18:42 +0100 |
parents | 7284b524b441 |
children | 93e9f448273c |
comparison
equal
deleted
inserted
replaced
46704:7284b524b441 | 46705:33f2d56acc73 |
---|---|
82 | 82 |
83 env_logger::init(); | 83 env_logger::init(); |
84 let ui = ui::Ui::new(); | 84 let ui = ui::Ui::new(); |
85 | 85 |
86 let early_args = EarlyArgs::parse(std::env::args_os()); | 86 let early_args = EarlyArgs::parse(std::env::args_os()); |
87 let non_repo_config = Config::load(early_args.config) | 87 let non_repo_config = |
88 .unwrap_or_else(|error| exit(&ui, Err(error.into()))); | 88 Config::load(early_args.config).unwrap_or_else(|error| { |
89 // Normally this is decided based on config, but we don’t have that | |
90 // available. As of this writing config loading never returns an | |
91 // "unsupported" error but that is not enforced by the type system. | |
92 let on_unsupported = OnUnsupported::Abort; | |
93 | |
94 exit(&ui, on_unsupported, Err(error.into())) | |
95 }); | |
89 | 96 |
90 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes); | 97 let repo_path = early_args.repo.as_deref().map(get_path_from_bytes); |
91 let repo_result = match Repo::find(&non_repo_config, repo_path) { | 98 let repo_result = match Repo::find(&non_repo_config, repo_path) { |
92 Ok(repo) => Ok(repo), | 99 Ok(repo) => Ok(repo), |
93 Err(RepoError::NotFound { at }) if repo_path.is_none() => { | 100 Err(RepoError::NotFound { at }) if repo_path.is_none() => { |
94 // Not finding a repo is not fatal yet, if `-R` was not given | 101 // Not finding a repo is not fatal yet, if `-R` was not given |
95 Err(NoRepoInCwdError { cwd: at }) | 102 Err(NoRepoInCwdError { cwd: at }) |
96 } | 103 } |
97 Err(error) => exit(&ui, Err(error.into())), | 104 Err(error) => exit( |
105 &ui, | |
106 OnUnsupported::from_config(&non_repo_config), | |
107 Err(error.into()), | |
108 ), | |
98 }; | 109 }; |
99 | 110 |
100 let config = if let Ok(repo) = &repo_result { | 111 let config = if let Ok(repo) = &repo_result { |
101 repo.config() | 112 repo.config() |
102 } else { | 113 } else { |
107 &process_start_time, | 118 &process_start_time, |
108 &ui, | 119 &ui, |
109 repo_result.as_ref(), | 120 repo_result.as_ref(), |
110 config, | 121 config, |
111 ); | 122 ); |
112 exit(&ui, result) | 123 exit(&ui, OnUnsupported::from_config(config), result) |
113 } | 124 } |
114 | 125 |
115 fn exit_code(result: &Result<(), CommandError>) -> i32 { | 126 fn exit_code(result: &Result<(), CommandError>) -> i32 { |
116 match result { | 127 match result { |
117 Ok(()) => exitcode::OK, | 128 Ok(()) => exitcode::OK, |
118 Err(CommandError::Abort { .. }) => exitcode::ABORT, | 129 Err(CommandError::Abort { .. }) => exitcode::ABORT, |
119 | 130 |
120 // Exit with a specific code and no error message to let a potential | 131 // Exit with a specific code and no error message to let a potential |
121 // wrapper script fallback to Python-based Mercurial. | 132 // wrapper script fallback to Python-based Mercurial. |
122 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, | 133 Err(CommandError::UnsupportedFeature { .. }) => { |
123 } | 134 exitcode::UNIMPLEMENTED |
124 } | 135 } |
125 | 136 } |
126 fn exit(ui: &Ui, result: Result<(), CommandError>) -> ! { | 137 } |
127 if let Err(CommandError::Abort { message }) = &result { | 138 |
128 if !message.is_empty() { | 139 fn exit( |
129 // Ignore errors when writing to stderr, we’re already exiting | 140 ui: &Ui, |
130 // with failure code so there’s not much more we can do. | 141 on_unsupported: OnUnsupported, |
131 let _ = ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | 142 result: Result<(), CommandError>, |
143 ) -> ! { | |
144 match &result { | |
145 Ok(_) => {} | |
146 Err(CommandError::Abort { message }) => { | |
147 if !message.is_empty() { | |
148 // Ignore errors when writing to stderr, we’re already exiting | |
149 // with failure code so there’s not much more we can do. | |
150 let _ = | |
151 ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | |
152 } | |
153 } | |
154 Err(CommandError::UnsupportedFeature { message }) => { | |
155 match on_unsupported { | |
156 OnUnsupported::Abort => { | |
157 let _ = ui.write_stderr(&format_bytes!( | |
158 b"unsupported feature: {}\n", | |
159 message | |
160 )); | |
161 } | |
162 OnUnsupported::AbortSilent => {} | |
163 } | |
132 } | 164 } |
133 } | 165 } |
134 std::process::exit(exit_code(&result)) | 166 std::process::exit(exit_code(&result)) |
135 } | 167 } |
136 | 168 |
224 } | 256 } |
225 } | 257 } |
226 Self { config, repo } | 258 Self { config, repo } |
227 } | 259 } |
228 } | 260 } |
261 | |
262 /// What to do when encountering some unsupported feature. | |
263 /// | |
264 /// See `HgError::UnsupportedFeature` and `CommandError::UnsupportedFeature`. | |
265 enum OnUnsupported { | |
266 /// Print an error message describing what feature is not supported, | |
267 /// and exit with code 252. | |
268 Abort, | |
269 /// Silently exit with code 252. | |
270 AbortSilent, | |
271 } | |
272 | |
273 impl OnUnsupported { | |
274 fn from_config(config: &Config) -> Self { | |
275 let default = OnUnsupported::Abort; | |
276 match config.get(b"rhg", b"on-unsupported") { | |
277 Some(b"abort") => OnUnsupported::Abort, | |
278 Some(b"abort-silent") => OnUnsupported::AbortSilent, | |
279 None => default, | |
280 Some(_) => { | |
281 // TODO: warn about unknown config value | |
282 default | |
283 } | |
284 } | |
285 } | |
286 } |