Mercurial > hg
comparison rust/rhg/src/main.rs @ 46601:755c31a1caf9
rhg: Add support for the blackbox extension
Only `command` and `commandfinish` events are logged.
The `dirty`, `logsource`, `track` and `ignore` configuration items
are not supported yet.
To indicate commands executed without Python, a `(rust) ` prefix is added
in corresponding log messages.
Differential Revision: https://phab.mercurial-scm.org/D10012
author | Simon Sapin <simon.sapin@octobus.net> |
---|---|
date | Tue, 16 Feb 2021 13:08:37 +0100 |
parents | d2e61f00ee9d |
children | 4e4c70401028 |
comparison
equal
deleted
inserted
replaced
46600:36f3a64846c8 | 46601:755c31a1caf9 |
---|---|
7 use format_bytes::format_bytes; | 7 use format_bytes::format_bytes; |
8 use hg::config::Config; | 8 use hg::config::Config; |
9 use hg::repo::{Repo, RepoError}; | 9 use hg::repo::{Repo, RepoError}; |
10 use std::path::{Path, PathBuf}; | 10 use std::path::{Path, PathBuf}; |
11 | 11 |
12 mod blackbox; | |
12 mod error; | 13 mod error; |
13 mod exitcode; | 14 mod exitcode; |
14 mod ui; | 15 mod ui; |
15 use error::CommandError; | 16 use error::CommandError; |
16 | 17 |
34 // Not ok: `--config section.key1=val section.key2=val2` | 35 // Not ok: `--config section.key1=val section.key2=val2` |
35 .number_of_values(1), | 36 .number_of_values(1), |
36 ) | 37 ) |
37 } | 38 } |
38 | 39 |
39 fn main_with_result(ui: &ui::Ui) -> Result<(), CommandError> { | 40 fn main_with_result( |
41 ui: &ui::Ui, | |
42 process_start_time: &blackbox::ProcessStartTime, | |
43 ) -> Result<(), CommandError> { | |
40 env_logger::init(); | 44 env_logger::init(); |
41 let app = App::new("rhg") | 45 let app = App::new("rhg") |
42 .setting(AppSettings::AllowInvalidUtf8) | 46 .setting(AppSettings::AllowInvalidUtf8) |
43 .setting(AppSettings::SubcommandRequired) | 47 .setting(AppSettings::SubcommandRequired) |
44 .setting(AppSettings::VersionlessSubcommands) | 48 .setting(AppSettings::VersionlessSubcommands) |
81 Err(NoRepoInCwdError { cwd: at }) | 85 Err(NoRepoInCwdError { cwd: at }) |
82 } | 86 } |
83 Err(error) => return Err(error.into()), | 87 Err(error) => return Err(error.into()), |
84 }; | 88 }; |
85 | 89 |
86 run(&CliInvocation { | 90 let invocation = CliInvocation { |
87 ui, | 91 ui, |
88 subcommand_args, | 92 subcommand_args, |
89 non_repo_config, | 93 non_repo_config, |
90 repo: repo.as_ref(), | 94 repo: repo.as_ref(), |
91 }) | 95 }; |
96 let blackbox = blackbox::Blackbox::new(&invocation, process_start_time)?; | |
97 blackbox.log_command_start(); | |
98 let result = run(&invocation); | |
99 blackbox.log_command_end(exit_code(&result)); | |
100 result | |
92 } | 101 } |
93 | 102 |
94 fn main() { | 103 fn main() { |
104 // Run this first, before we find out if the blackbox extension is even | |
105 // enabled, in order to include everything in-between in the duration | |
106 // measurements. Reading config files can be slow if they’re on NFS. | |
107 let process_start_time = blackbox::ProcessStartTime::now(); | |
108 | |
95 let ui = ui::Ui::new(); | 109 let ui = ui::Ui::new(); |
96 | 110 |
97 let exit_code = match main_with_result(&ui) { | 111 let result = main_with_result(&ui, &process_start_time); |
112 if let Err(CommandError::Abort { message }) = &result { | |
113 if !message.is_empty() { | |
114 // Ignore errors when writing to stderr, we’re already exiting | |
115 // with failure code so there’s not much more we can do. | |
116 let _ = ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | |
117 } | |
118 } | |
119 std::process::exit(exit_code(&result)) | |
120 } | |
121 | |
122 fn exit_code(result: &Result<(), CommandError>) -> i32 { | |
123 match result { | |
98 Ok(()) => exitcode::OK, | 124 Ok(()) => exitcode::OK, |
125 Err(CommandError::Abort { .. }) => exitcode::ABORT, | |
99 | 126 |
100 // Exit with a specific code and no error message to let a potential | 127 // Exit with a specific code and no error message to let a potential |
101 // wrapper script fallback to Python-based Mercurial. | 128 // wrapper script fallback to Python-based Mercurial. |
102 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, | 129 Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, |
103 | 130 } |
104 Err(CommandError::Abort { message }) => { | |
105 if !message.is_empty() { | |
106 // Ignore errors when writing to stderr, we’re already exiting | |
107 // with failure code so there’s not much more we can do. | |
108 let _ = | |
109 ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | |
110 } | |
111 exitcode::ABORT | |
112 } | |
113 }; | |
114 std::process::exit(exit_code) | |
115 } | 131 } |
116 | 132 |
117 macro_rules! subcommands { | 133 macro_rules! subcommands { |
118 ($( $command: ident )+) => { | 134 ($( $command: ident )+) => { |
119 mod commands { | 135 mod commands { |