1 extern crate log; |
1 extern crate log; |
2 use clap::App; |
2 use clap::App; |
3 use clap::AppSettings; |
3 use clap::AppSettings; |
|
4 use clap::Arg; |
4 use clap::ArgMatches; |
5 use clap::ArgMatches; |
5 use format_bytes::format_bytes; |
6 use format_bytes::format_bytes; |
|
7 use std::path::Path; |
6 |
8 |
7 mod error; |
9 mod error; |
8 mod exitcode; |
10 mod exitcode; |
9 mod ui; |
11 mod ui; |
10 use error::CommandError; |
12 use error::CommandError; |
|
13 |
|
14 fn add_global_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { |
|
15 app.arg( |
|
16 Arg::with_name("repository") |
|
17 .help("repository root directory") |
|
18 .short("-R") |
|
19 .long("--repository") |
|
20 .value_name("REPO") |
|
21 .takes_value(true), |
|
22 ) |
|
23 } |
11 |
24 |
12 fn main() { |
25 fn main() { |
13 env_logger::init(); |
26 env_logger::init(); |
14 let app = App::new("rhg") |
27 let app = App::new("rhg") |
15 .setting(AppSettings::AllowInvalidUtf8) |
28 .setting(AppSettings::AllowInvalidUtf8) |
16 .setting(AppSettings::SubcommandRequired) |
29 .setting(AppSettings::SubcommandRequired) |
17 .setting(AppSettings::VersionlessSubcommands) |
30 .setting(AppSettings::VersionlessSubcommands) |
18 .version("0.0.1"); |
31 .version("0.0.1"); |
|
32 let app = add_global_args(app); |
19 let app = add_subcommand_args(app); |
33 let app = add_subcommand_args(app); |
20 |
34 |
21 let ui = ui::Ui::new(); |
35 let ui = ui::Ui::new(); |
22 |
36 |
23 let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { |
37 let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { |
24 let _ = ui.writeln_stderr_str(&err.message); |
38 let _ = ui.writeln_stderr_str(&err.message); |
25 std::process::exit(exitcode::UNIMPLEMENTED) |
39 std::process::exit(exitcode::UNIMPLEMENTED) |
26 }); |
40 }); |
|
41 |
27 let (subcommand_name, subcommand_matches) = matches.subcommand(); |
42 let (subcommand_name, subcommand_matches) = matches.subcommand(); |
28 let run = subcommand_run_fn(subcommand_name) |
43 let run = subcommand_run_fn(subcommand_name) |
29 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired"); |
44 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired"); |
30 let args = subcommand_matches |
45 let args = subcommand_matches |
31 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired"); |
46 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired"); |
32 |
47 |
|
48 // Global arguments can be in either based on e.g. `hg -R ./foo log` v.s. |
|
49 // `hg log -R ./foo` |
|
50 let global_arg = |
|
51 |name| args.value_of_os(name).or_else(|| matches.value_of_os(name)); |
|
52 |
|
53 let repo_path = global_arg("repository").map(Path::new); |
33 let result = (|| -> Result<(), CommandError> { |
54 let result = (|| -> Result<(), CommandError> { |
34 let config = hg::config::Config::load()?; |
55 let config = hg::config::Config::load()?; |
35 run(&ui, &config, args) |
56 run(&ui, &config, repo_path, args) |
36 })(); |
57 })(); |
37 |
58 |
38 let exit_code = match result { |
59 let exit_code = match result { |
39 Ok(_) => exitcode::OK, |
60 Ok(_) => exitcode::OK, |
40 |
61 |
64 } |
85 } |
65 |
86 |
66 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { |
87 fn add_subcommand_args<'a, 'b>(app: App<'a, 'b>) -> App<'a, 'b> { |
67 app |
88 app |
68 $( |
89 $( |
69 .subcommand(commands::$command::args()) |
90 .subcommand(add_global_args(commands::$command::args())) |
70 )+ |
91 )+ |
71 } |
92 } |
72 |
93 |
73 fn subcommand_run_fn(name: &str) -> Option<fn( |
94 fn subcommand_run_fn(name: &str) -> Option<fn( |
74 &ui::Ui, |
95 &ui::Ui, |
75 &hg::config::Config, |
96 &hg::config::Config, |
|
97 Option<&Path>, |
76 &ArgMatches, |
98 &ArgMatches, |
77 ) -> Result<(), CommandError>> { |
99 ) -> Result<(), CommandError>> { |
78 match name { |
100 match name { |
79 $( |
101 $( |
80 stringify!($command) => Some(commands::$command::run), |
102 stringify!($command) => Some(commands::$command::run), |