main.rs
194 lines
| 6.3 KiB
| application/rls-services+xml
|
RustLexer
Antoine Cezar
|
r46101 | extern crate log; | ||
Antoine Cezar
|
r45593 | use clap::App; | ||
use clap::AppSettings; | ||||
Antoine Cezar
|
r46100 | use clap::Arg; | ||
use clap::ArgGroup; | ||||
use clap::ArgMatches; | ||||
Antoine Cezar
|
r45593 | use clap::SubCommand; | ||
Simon Sapin
|
r47174 | use format_bytes::format_bytes; | ||
Antoine Cezar
|
r46100 | use hg::operations::DebugDataKind; | ||
use std::convert::TryFrom; | ||||
Antoine Cezar
|
r45593 | |||
Antoine Cezar
|
r45515 | mod commands; | ||
mod error; | ||||
Antoine Cezar
|
r45503 | mod exitcode; | ||
Antoine Cezar
|
r45592 | mod ui; | ||
Antoine Cezar
|
r45593 | use commands::Command; | ||
Antoine Cezar
|
r46100 | use error::CommandError; | ||
Antoine Cezar
|
r45503 | |||
fn main() { | ||||
Antoine Cezar
|
r46101 | env_logger::init(); | ||
Antoine Cezar
|
r46100 | let app = App::new("rhg") | ||
Antoine Cezar
|
r45593 | .setting(AppSettings::AllowInvalidUtf8) | ||
.setting(AppSettings::SubcommandRequired) | ||||
.setting(AppSettings::VersionlessSubcommands) | ||||
.version("0.0.1") | ||||
.subcommand( | ||||
SubCommand::with_name("root").about(commands::root::HELP_TEXT), | ||||
Antoine Cezar
|
r45924 | ) | ||
.subcommand( | ||||
Antoine Cezar
|
r46108 | SubCommand::with_name("files") | ||
.arg( | ||||
Arg::with_name("rev") | ||||
.help("search the repository as it is in REV") | ||||
.short("-r") | ||||
.long("--revision") | ||||
.value_name("REV") | ||||
.takes_value(true), | ||||
) | ||||
.about(commands::files::HELP_TEXT), | ||||
Antoine Cezar
|
r46100 | ) | ||
.subcommand( | ||||
Antoine Cezar
|
r46113 | SubCommand::with_name("cat") | ||
.arg( | ||||
Arg::with_name("rev") | ||||
.help("search the repository as it is in REV") | ||||
.short("-r") | ||||
.long("--revision") | ||||
.value_name("REV") | ||||
.takes_value(true), | ||||
) | ||||
.arg( | ||||
clap::Arg::with_name("files") | ||||
.required(true) | ||||
.multiple(true) | ||||
.empty_values(false) | ||||
.value_name("FILE") | ||||
.help("Activity to start: activity@category"), | ||||
) | ||||
.about(commands::cat::HELP_TEXT), | ||||
) | ||||
.subcommand( | ||||
Antoine Cezar
|
r46100 | SubCommand::with_name("debugdata") | ||
.about(commands::debugdata::HELP_TEXT) | ||||
.arg( | ||||
Arg::with_name("changelog") | ||||
.help("open changelog") | ||||
.short("-c") | ||||
.long("--changelog"), | ||||
) | ||||
.arg( | ||||
Arg::with_name("manifest") | ||||
.help("open manifest") | ||||
.short("-m") | ||||
.long("--manifest"), | ||||
) | ||||
.group( | ||||
ArgGroup::with_name("") | ||||
.args(&["changelog", "manifest"]) | ||||
.required(true), | ||||
) | ||||
.arg( | ||||
Arg::with_name("rev") | ||||
.help("revision") | ||||
.required(true) | ||||
.value_name("REV"), | ||||
), | ||||
Simon Sapin
|
r46535 | ) | ||
.subcommand( | ||||
SubCommand::with_name("debugrequirements") | ||||
.about(commands::debugrequirements::HELP_TEXT), | ||||
Antoine Cezar
|
r45593 | ); | ||
Antoine Cezar
|
r46011 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { | ||
let _ = ui::Ui::new().writeln_stderr_str(&err.message); | ||||
Simon Sapin
|
r47174 | std::process::exit(exitcode::UNIMPLEMENTED) | ||
Antoine Cezar
|
r45593 | }); | ||
Antoine Cezar
|
r45920 | let ui = ui::Ui::new(); | ||
Antoine Cezar
|
r46100 | let command_result = match_subcommand(matches, &ui); | ||
Antoine Cezar
|
r45593 | |||
Simon Sapin
|
r47174 | let exit_code = match command_result { | ||
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 | ||||
Antoine Cezar
|
r45920 | } | ||
Simon Sapin
|
r47174 | }; | ||
std::process::exit(exit_code) | ||||
Antoine Cezar
|
r45503 | } | ||
Antoine Cezar
|
r46100 | |||
fn match_subcommand( | ||||
matches: ArgMatches, | ||||
ui: &ui::Ui, | ||||
) -> Result<(), CommandError> { | ||||
Simon Sapin
|
r47213 | let config = hg::config::Config::load()?; | ||
Antoine Cezar
|
r46100 | match matches.subcommand() { | ||
Simon Sapin
|
r47213 | ("root", _) => commands::root::RootCommand::new().run(&ui, &config), | ||
Antoine Cezar
|
r46108 | ("files", Some(matches)) => { | ||
Simon Sapin
|
r47213 | commands::files::FilesCommand::try_from(matches)?.run(&ui, &config) | ||
Antoine Cezar
|
r46108 | } | ||
Antoine Cezar
|
r46113 | ("cat", Some(matches)) => { | ||
Simon Sapin
|
r47213 | commands::cat::CatCommand::try_from(matches)?.run(&ui, &config) | ||
Antoine Cezar
|
r46113 | } | ||
Antoine Cezar
|
r46100 | ("debugdata", Some(matches)) => { | ||
Simon Sapin
|
r47213 | commands::debugdata::DebugDataCommand::try_from(matches)? | ||
.run(&ui, &config) | ||||
Antoine Cezar
|
r46100 | } | ||
Simon Sapin
|
r46535 | ("debugrequirements", _) => { | ||
commands::debugrequirements::DebugRequirementsCommand::new() | ||||
Simon Sapin
|
r47213 | .run(&ui, &config) | ||
Simon Sapin
|
r46535 | } | ||
Antoine Cezar
|
r46100 | _ => unreachable!(), // Because of AppSettings::SubcommandRequired, | ||
} | ||||
} | ||||
Antoine Cezar
|
r46108 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { | ||
type Error = CommandError; | ||||
fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | ||||
let rev = args.value_of("rev"); | ||||
Ok(commands::files::FilesCommand::new(rev)) | ||||
} | ||||
} | ||||
Antoine Cezar
|
r46113 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { | ||
type Error = CommandError; | ||||
fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | ||||
let rev = args.value_of("rev"); | ||||
let files = match args.values_of("files") { | ||||
Some(files) => files.collect(), | ||||
None => vec![], | ||||
}; | ||||
Ok(commands::cat::CatCommand::new(rev, files)) | ||||
} | ||||
} | ||||
Antoine Cezar
|
r46100 | impl<'a> TryFrom<&'a ArgMatches<'_>> | ||
for commands::debugdata::DebugDataCommand<'a> | ||||
{ | ||||
type Error = CommandError; | ||||
fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | ||||
let rev = args | ||||
.value_of("rev") | ||||
.expect("rev should be a required argument"); | ||||
let kind = match ( | ||||
args.is_present("changelog"), | ||||
args.is_present("manifest"), | ||||
) { | ||||
(true, false) => DebugDataKind::Changelog, | ||||
(false, true) => DebugDataKind::Manifest, | ||||
(true, true) => { | ||||
unreachable!("Should not happen since options are exclusive") | ||||
} | ||||
(false, false) => { | ||||
unreachable!("Should not happen since options are required") | ||||
} | ||||
}; | ||||
Ok(commands::debugdata::DebugDataCommand::new(rev, kind)) | ||||
} | ||||
} | ||||