main.rs
94 lines
| 2.6 KiB
| application/rls-services+xml
|
RustLexer
|
r46101 | extern crate log; | ||
|
r45593 | use clap::App; | ||
use clap::AppSettings; | ||||
|
r46100 | use clap::ArgMatches; | ||
|
r47174 | use format_bytes::format_bytes; | ||
|
r45593 | |||
|
r45515 | mod error; | ||
|
r45503 | mod exitcode; | ||
|
r45592 | mod ui; | ||
|
r46100 | use error::CommandError; | ||
|
r45503 | |||
fn main() { | ||||
|
r46101 | env_logger::init(); | ||
|
r46100 | let app = App::new("rhg") | ||
|
r45593 | .setting(AppSettings::AllowInvalidUtf8) | ||
.setting(AppSettings::SubcommandRequired) | ||||
.setting(AppSettings::VersionlessSubcommands) | ||||
|
r47230 | .version("0.0.1"); | ||
let app = add_subcommand_args(app); | ||||
|
r45593 | |||
|
r45920 | let ui = ui::Ui::new(); | ||
|
r47230 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { | ||
let _ = ui.writeln_stderr_str(&err.message); | ||||
std::process::exit(exitcode::UNIMPLEMENTED) | ||||
}); | ||||
let (subcommand_name, subcommand_matches) = matches.subcommand(); | ||||
let run = subcommand_run_fn(subcommand_name) | ||||
.expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired"); | ||||
let args = subcommand_matches | ||||
.expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired"); | ||||
|
r45593 | |||
|
r47230 | let result = (|| -> Result<(), CommandError> { | ||
let config = hg::config::Config::load()?; | ||||
run(&ui, &config, args) | ||||
})(); | ||||
let exit_code = match result { | ||||
|
r47174 | Ok(_) => exitcode::OK, | ||
// Exit with a specific code and no error message to let a potential | ||||
// wrapper script fallback to Python-based Mercurial. | ||||
Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, | ||||
Err(CommandError::Abort { message }) => { | ||||
if !message.is_empty() { | ||||
// Ignore errors when writing to stderr, we’re already exiting | ||||
// with failure code so there’s not much more we can do. | ||||
let _ = | ||||
ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | ||||
} | ||||
exitcode::ABORT | ||||
|
r45920 | } | ||
|
r47174 | }; | ||
std::process::exit(exit_code) | ||||
|
r45503 | } | ||
|
r46100 | |||
|
r47230 | macro_rules! subcommands { | ||
($( $command: ident )+) => { | ||||
mod commands { | ||||
$( | ||||
pub mod $command; | ||||
)+ | ||||
} | ||||
fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { | ||||
app | ||||
$( | ||||
.subcommand(commands::$command::args()) | ||||
)+ | ||||
} | ||||
|
r47213 | |||
|
r47230 | fn subcommand_run_fn(name: &str) -> Option<fn( | ||
&ui::Ui, | ||||
&hg::config::Config, | ||||
&ArgMatches, | ||||
) -> Result<(), CommandError>> { | ||||
match name { | ||||
$( | ||||
stringify!($command) => Some(commands::$command::run), | ||||
)+ | ||||
_ => None, | ||||
} | ||||
|
r46113 | } | ||
|
r47230 | }; | ||
|
r46100 | } | ||
|
r47230 | |||
subcommands! { | ||||
cat | ||||
debugdata | ||||
debugrequirements | ||||
files | ||||
root | ||||
} | ||||