1 extern crate log; |
1 extern crate log; |
2 use crate::error::CommandError; |
2 use crate::error::CommandError; |
3 use crate::ui::{local_to_utf8, Ui}; |
3 use crate::ui::{local_to_utf8, Ui}; |
4 use clap::App; |
4 use clap::{command, Arg, ArgMatches}; |
5 use clap::AppSettings; |
|
6 use clap::Arg; |
|
7 use clap::ArgMatches; |
|
8 use format_bytes::{format_bytes, join}; |
5 use format_bytes::{format_bytes, join}; |
9 use hg::config::{Config, ConfigSource, PlainInfo}; |
6 use hg::config::{Config, ConfigSource, PlainInfo}; |
10 use hg::repo::{Repo, RepoError}; |
7 use hg::repo::{Repo, RepoError}; |
11 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes}; |
8 use hg::utils::files::{get_bytes_from_os_str, get_path_from_bytes}; |
12 use hg::utils::SliceExt; |
9 use hg::utils::SliceExt; |
33 repo: Result<&Repo, &NoRepoInCwdError>, |
30 repo: Result<&Repo, &NoRepoInCwdError>, |
34 config: &Config, |
31 config: &Config, |
35 ) -> Result<(), CommandError> { |
32 ) -> Result<(), CommandError> { |
36 check_unsupported(config, repo)?; |
33 check_unsupported(config, repo)?; |
37 |
34 |
38 let app = App::new("rhg") |
35 let app = command!() |
39 .global_setting(AppSettings::AllowInvalidUtf8) |
36 .subcommand_required(true) |
40 .global_setting(AppSettings::DisableVersion) |
|
41 .setting(AppSettings::SubcommandRequired) |
|
42 .setting(AppSettings::VersionlessSubcommands) |
|
43 .arg( |
37 .arg( |
44 Arg::with_name("repository") |
38 Arg::new("repository") |
45 .help("repository root directory") |
39 .help("repository root directory") |
46 .short("-R") |
40 .short('R') |
47 .long("--repository") |
|
48 .value_name("REPO") |
41 .value_name("REPO") |
49 .takes_value(true) |
|
50 // Both ok: `hg -R ./foo log` or `hg log -R ./foo` |
42 // Both ok: `hg -R ./foo log` or `hg log -R ./foo` |
51 .global(true), |
43 .global(true), |
52 ) |
44 ) |
53 .arg( |
45 .arg( |
54 Arg::with_name("config") |
46 Arg::new("config") |
55 .help("set/override config option (use 'section.name=value')") |
47 .help("set/override config option (use 'section.name=value')") |
56 .long("--config") |
|
57 .value_name("CONFIG") |
48 .value_name("CONFIG") |
58 .takes_value(true) |
|
59 .global(true) |
49 .global(true) |
|
50 .long("config") |
60 // Ok: `--config section.key1=val --config section.key2=val2` |
51 // Ok: `--config section.key1=val --config section.key2=val2` |
61 .multiple(true) |
|
62 // Not ok: `--config section.key1=val section.key2=val2` |
52 // Not ok: `--config section.key1=val section.key2=val2` |
63 .number_of_values(1), |
53 .action(clap::ArgAction::Append), |
64 ) |
54 ) |
65 .arg( |
55 .arg( |
66 Arg::with_name("cwd") |
56 Arg::new("cwd") |
67 .help("change working directory") |
57 .help("change working directory") |
68 .long("--cwd") |
|
69 .value_name("DIR") |
58 .value_name("DIR") |
70 .takes_value(true) |
59 .long("cwd") |
71 .global(true), |
60 .global(true), |
72 ) |
61 ) |
73 .arg( |
62 .arg( |
74 Arg::with_name("color") |
63 Arg::new("color") |
75 .help("when to colorize (boolean, always, auto, never, or debug)") |
64 .help("when to colorize (boolean, always, auto, never, or debug)") |
76 .long("--color") |
|
77 .value_name("TYPE") |
65 .value_name("TYPE") |
78 .takes_value(true) |
66 .long("color") |
79 .global(true), |
67 .global(true), |
80 ) |
68 ) |
81 .version("0.0.1"); |
69 .version("0.0.1"); |
82 let app = add_subcommand_args(app); |
70 let app = add_subcommand_args(app); |
83 |
71 |
84 let matches = app.clone().get_matches_from_safe(argv.iter())?; |
72 let matches = app.clone().try_get_matches_from(argv.iter())?; |
85 |
73 |
86 let (subcommand_name, subcommand_matches) = matches.subcommand(); |
74 let (subcommand_name, subcommand_args) = |
|
75 matches.subcommand().expect("subcommand required"); |
87 |
76 |
88 // Mercurial allows users to define "defaults" for commands, fallback |
77 // Mercurial allows users to define "defaults" for commands, fallback |
89 // if a default is detected for the current command |
78 // if a default is detected for the current command |
90 let defaults = config.get_str(b"defaults", subcommand_name.as_bytes()); |
79 let defaults = config.get_str(b"defaults", subcommand_name.as_bytes()); |
91 if defaults?.is_some() { |
80 if defaults?.is_some() { |
102 let msg = format!("{}-{} hook defined", prefix, subcommand_name); |
91 let msg = format!("{}-{} hook defined", prefix, subcommand_name); |
103 return Err(CommandError::unsupported(msg)); |
92 return Err(CommandError::unsupported(msg)); |
104 } |
93 } |
105 } |
94 } |
106 let run = subcommand_run_fn(subcommand_name) |
95 let run = subcommand_run_fn(subcommand_name) |
107 .expect("unknown subcommand name from clap despite AppSettings::SubcommandRequired"); |
96 .expect("unknown subcommand name from clap despite Command::subcommand_required"); |
108 let subcommand_args = subcommand_matches |
|
109 .expect("no subcommand arguments from clap despite AppSettings::SubcommandRequired"); |
|
110 |
97 |
111 let invocation = CliInvocation { |
98 let invocation = CliInvocation { |
112 ui, |
99 ui, |
113 subcommand_args, |
100 subcommand_args, |
114 config, |
101 config, |
567 status |
554 status |
568 } |
555 } |
569 |
556 |
570 pub struct CliInvocation<'a> { |
557 pub struct CliInvocation<'a> { |
571 ui: &'a Ui, |
558 ui: &'a Ui, |
572 subcommand_args: &'a ArgMatches<'a>, |
559 subcommand_args: &'a ArgMatches, |
573 config: &'a Config, |
560 config: &'a Config, |
574 /// References inside `Result` is a bit peculiar but allow |
561 /// References inside `Result` is a bit peculiar but allow |
575 /// `invocation.repo?` to work out with `&CliInvocation` since this |
562 /// `invocation.repo?` to work out with `&CliInvocation` since this |
576 /// `Result` type is `Copy`. |
563 /// `Result` type is `Copy`. |
577 repo: Result<&'a Repo, &'a NoRepoInCwdError>, |
564 repo: Result<&'a Repo, &'a NoRepoInCwdError>, |