Show More
@@ -1,15 +1,5 b'' | |||||
1 | pub mod cat; |
|
1 | pub mod cat; | |
2 | pub mod debugdata; |
|
2 | pub mod debugdata; | |
3 | pub mod debugrequirements; |
|
3 | pub mod debugrequirements; | |
4 | pub mod files; |
|
4 | pub mod files; | |
5 | pub mod root; |
|
5 | pub mod root; | |
6 | use crate::error::CommandError; |
|
|||
7 | use crate::ui::Ui; |
|
|||
8 | use hg::config::Config; |
|
|||
9 |
|
||||
10 | /// The common trait for rhg commands |
|
|||
11 | /// |
|
|||
12 | /// Normalize the interface of the commands provided by rhg |
|
|||
13 | pub trait Command { |
|
|||
14 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError>; |
|
|||
15 | } |
|
@@ -1,58 +1,51 b'' | |||||
1 | use crate::commands::Command; |
|
|||
2 |
|
|
1 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
2 | use crate::ui::Ui; | |
|
3 | use clap::ArgMatches; | |||
4 | use hg::config::Config; |
|
4 | use hg::config::Config; | |
5 | use hg::operations::cat; |
|
5 | use hg::operations::cat; | |
6 | use hg::repo::Repo; |
|
6 | use hg::repo::Repo; | |
7 | use hg::utils::hg_path::HgPathBuf; |
|
7 | use hg::utils::hg_path::HgPathBuf; | |
8 | use micro_timer::timed; |
|
8 | use micro_timer::timed; | |
9 | use std::convert::TryFrom; |
|
9 | use std::convert::TryFrom; | |
10 |
|
10 | |||
11 | pub const HELP_TEXT: &str = " |
|
11 | pub const HELP_TEXT: &str = " | |
12 | Output the current or given revision of files |
|
12 | Output the current or given revision of files | |
13 | "; |
|
13 | "; | |
14 |
|
14 | |||
15 | pub struct CatCommand<'a> { |
|
15 | #[timed] | |
16 | rev: Option<&'a str>, |
|
16 | pub fn run( | |
17 | files: Vec<&'a str>, |
|
17 | ui: &Ui, | |
18 | } |
|
18 | config: &Config, | |
19 |
|
19 | args: &ArgMatches, | ||
20 | impl<'a> CatCommand<'a> { |
|
20 | ) -> Result<(), CommandError> { | |
21 | pub fn new(rev: Option<&'a str>, files: Vec<&'a str>) -> Self { |
|
21 | let rev = args.value_of("rev"); | |
22 | Self { rev, files } |
|
22 | let file_args = match args.values_of("files") { | |
23 | } |
|
23 | Some(files) => files.collect(), | |
|
24 | None => vec![], | |||
|
25 | }; | |||
24 |
|
26 | |||
25 | fn display(&self, ui: &Ui, data: &[u8]) -> Result<(), CommandError> { |
|
|||
26 | ui.write_stdout(data)?; |
|
|||
27 | Ok(()) |
|
|||
28 | } |
|
|||
29 | } |
|
|||
30 |
|
||||
31 | impl<'a> Command for CatCommand<'a> { |
|
|||
32 | #[timed] |
|
|||
33 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError> { |
|
|||
34 |
|
|
27 | let repo = Repo::find(config)?; | |
35 |
|
|
28 | let cwd = hg::utils::current_dir()?; | |
36 |
|
29 | |||
37 |
|
|
30 | let mut files = vec![]; | |
38 |
|
|
31 | for file in file_args.iter() { | |
39 |
|
|
32 | // TODO: actually normalize `..` path segments etc? | |
40 |
|
|
33 | let normalized = cwd.join(&file); | |
41 |
|
|
34 | let stripped = normalized | |
42 |
|
|
35 | .strip_prefix(&repo.working_directory_path()) | |
43 |
|
|
36 | // TODO: error message for path arguments outside of the repo | |
44 |
|
|
37 | .map_err(|_| CommandError::abort(""))?; | |
45 |
|
|
38 | let hg_file = HgPathBuf::try_from(stripped.to_path_buf()) | |
46 |
|
|
39 | .map_err(|e| CommandError::abort(e.to_string()))?; | |
47 |
|
|
40 | files.push(hg_file); | |
48 |
|
|
41 | } | |
49 |
|
42 | |||
50 |
|
|
43 | match rev { | |
51 |
|
|
44 | Some(rev) => { | |
52 |
|
|
45 | let data = cat(&repo, rev, &files).map_err(|e| (e, rev))?; | |
53 | self.display(ui, &data) |
|
46 | ui.write_stdout(&data)?; | |
|
47 | Ok(()) | |||
54 |
|
|
48 | } | |
55 |
|
|
49 | None => Err(CommandError::Unimplemented.into()), | |
56 |
|
|
50 | } | |
57 | } |
|
51 | } | |
58 | } |
|
@@ -1,37 +1,42 b'' | |||||
1 | use crate::commands::Command; |
|
|||
2 |
|
|
1 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
2 | use crate::ui::Ui; | |
|
3 | use clap::ArgMatches; | |||
4 | use hg::config::Config; |
|
4 | use hg::config::Config; | |
5 | use hg::operations::{debug_data, DebugDataKind}; |
|
5 | use hg::operations::{debug_data, DebugDataKind}; | |
6 | use hg::repo::Repo; |
|
6 | use hg::repo::Repo; | |
7 | use micro_timer::timed; |
|
7 | use micro_timer::timed; | |
8 |
|
8 | |||
9 | pub const HELP_TEXT: &str = " |
|
9 | pub const HELP_TEXT: &str = " | |
10 | Dump the contents of a data file revision |
|
10 | Dump the contents of a data file revision | |
11 | "; |
|
11 | "; | |
12 |
|
12 | |||
13 | pub struct DebugDataCommand<'a> { |
|
13 | #[timed] | |
14 | rev: &'a str, |
|
14 | pub fn run( | |
15 | kind: DebugDataKind, |
|
15 | ui: &Ui, | |
16 | } |
|
16 | config: &Config, | |
17 |
|
17 | args: &ArgMatches, | ||
18 | impl<'a> DebugDataCommand<'a> { |
|
18 | ) -> Result<(), CommandError> { | |
19 | pub fn new(rev: &'a str, kind: DebugDataKind) -> Self { |
|
19 | let rev = args | |
20 | DebugDataCommand { rev, kind } |
|
20 | .value_of("rev") | |
|
21 | .expect("rev should be a required argument"); | |||
|
22 | let kind = | |||
|
23 | match (args.is_present("changelog"), args.is_present("manifest")) { | |||
|
24 | (true, false) => DebugDataKind::Changelog, | |||
|
25 | (false, true) => DebugDataKind::Manifest, | |||
|
26 | (true, true) => { | |||
|
27 | unreachable!("Should not happen since options are exclusive") | |||
21 | } |
|
28 | } | |
|
29 | (false, false) => { | |||
|
30 | unreachable!("Should not happen since options are required") | |||
22 | } |
|
31 | } | |
|
32 | }; | |||
23 |
|
33 | |||
24 | impl<'a> Command for DebugDataCommand<'a> { |
|
|||
25 | #[timed] |
|
|||
26 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError> { |
|
|||
27 |
|
|
34 | let repo = Repo::find(config)?; | |
28 |
|
|
35 | let data = debug_data(&repo, rev, kind).map_err(|e| (e, rev))?; | |
29 | .map_err(|e| (e, self.rev))?; |
|
|||
30 |
|
36 | |||
31 |
|
|
37 | let mut stdout = ui.stdout_buffer(); | |
32 |
|
|
38 | stdout.write_all(&data)?; | |
33 |
|
|
39 | stdout.flush()?; | |
34 |
|
40 | |||
35 |
|
|
41 | Ok(()) | |
36 | } |
|
42 | } | |
37 | } |
|
@@ -1,32 +1,26 b'' | |||||
1 | use crate::commands::Command; |
|
|||
2 |
|
|
1 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
2 | use crate::ui::Ui; | |
|
3 | use clap::ArgMatches; | |||
4 | use hg::config::Config; |
|
4 | use hg::config::Config; | |
5 | use hg::repo::Repo; |
|
5 | use hg::repo::Repo; | |
6 |
|
6 | |||
7 | pub const HELP_TEXT: &str = " |
|
7 | pub const HELP_TEXT: &str = " | |
8 | Print the current repo requirements. |
|
8 | Print the current repo requirements. | |
9 | "; |
|
9 | "; | |
10 |
|
10 | |||
11 | pub struct DebugRequirementsCommand {} |
|
11 | pub fn run( | |
12 |
|
12 | ui: &Ui, | ||
13 | impl DebugRequirementsCommand { |
|
13 | config: &Config, | |
14 | pub fn new() -> Self { |
|
14 | _args: &ArgMatches, | |
15 | DebugRequirementsCommand {} |
|
15 | ) -> Result<(), CommandError> { | |
16 | } |
|
|||
17 | } |
|
|||
18 |
|
||||
19 | impl Command for DebugRequirementsCommand { |
|
|||
20 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError> { |
|
|||
21 |
|
|
16 | let repo = Repo::find(config)?; | |
22 |
|
|
17 | let mut output = String::new(); | |
23 |
|
|
18 | let mut requirements: Vec<_> = repo.requirements().iter().collect(); | |
24 |
|
|
19 | requirements.sort(); | |
25 |
|
|
20 | for req in requirements { | |
26 |
|
|
21 | output.push_str(req); | |
27 |
|
|
22 | output.push('\n'); | |
28 |
|
|
23 | } | |
29 |
|
|
24 | ui.write_stdout(output.as_bytes())?; | |
30 |
|
|
25 | Ok(()) | |
31 | } |
|
26 | } | |
32 | } |
|
@@ -1,62 +1,55 b'' | |||||
1 | use crate::commands::Command; |
|
|||
2 |
|
|
1 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
2 | use crate::ui::Ui; | |
|
3 | use clap::ArgMatches; | |||
4 | use hg::config::Config; |
|
4 | use hg::config::Config; | |
5 | use hg::operations::list_rev_tracked_files; |
|
5 | use hg::operations::list_rev_tracked_files; | |
6 | use hg::operations::Dirstate; |
|
6 | use hg::operations::Dirstate; | |
7 | use hg::repo::Repo; |
|
7 | use hg::repo::Repo; | |
8 | use hg::utils::files::{get_bytes_from_path, relativize_path}; |
|
8 | use hg::utils::files::{get_bytes_from_path, relativize_path}; | |
9 | use hg::utils::hg_path::{HgPath, HgPathBuf}; |
|
9 | use hg::utils::hg_path::{HgPath, HgPathBuf}; | |
10 |
|
10 | |||
11 | pub const HELP_TEXT: &str = " |
|
11 | pub const HELP_TEXT: &str = " | |
12 | List tracked files. |
|
12 | List tracked files. | |
13 |
|
13 | |||
14 | Returns 0 on success. |
|
14 | Returns 0 on success. | |
15 | "; |
|
15 | "; | |
16 |
|
16 | |||
17 | pub struct FilesCommand<'a> { |
|
17 | pub fn run( | |
18 | rev: Option<&'a str>, |
|
18 | ui: &Ui, | |
|
19 | config: &Config, | |||
|
20 | args: &ArgMatches, | |||
|
21 | ) -> Result<(), CommandError> { | |||
|
22 | let rev = args.value_of("rev"); | |||
|
23 | ||||
|
24 | let repo = Repo::find(config)?; | |||
|
25 | if let Some(rev) = rev { | |||
|
26 | let files = | |||
|
27 | list_rev_tracked_files(&repo, rev).map_err(|e| (e, rev))?; | |||
|
28 | display_files(ui, &repo, files.iter()) | |||
|
29 | } else { | |||
|
30 | let distate = Dirstate::new(&repo)?; | |||
|
31 | let files = distate.tracked_files()?; | |||
|
32 | display_files(ui, &repo, files) | |||
|
33 | } | |||
19 | } |
|
34 | } | |
20 |
|
35 | |||
21 | impl<'a> FilesCommand<'a> { |
|
36 | fn display_files<'a>( | |
22 | pub fn new(rev: Option<&'a str>) -> Self { |
|
|||
23 | FilesCommand { rev } |
|
|||
24 | } |
|
|||
25 |
|
||||
26 | fn display_files( |
|
|||
27 | &self, |
|
|||
28 |
|
|
37 | ui: &Ui, | |
29 |
|
|
38 | repo: &Repo, | |
30 |
|
|
39 | files: impl IntoIterator<Item = &'a HgPath>, | |
31 |
|
|
40 | ) -> Result<(), CommandError> { | |
32 |
|
|
41 | let cwd = hg::utils::current_dir()?; | |
33 |
|
|
42 | let rooted_cwd = cwd | |
34 |
|
|
43 | .strip_prefix(repo.working_directory_path()) | |
35 |
|
|
44 | .expect("cwd was already checked within the repository"); | |
36 |
|
|
45 | let rooted_cwd = HgPathBuf::from(get_bytes_from_path(rooted_cwd)); | |
37 |
|
46 | |||
38 |
|
|
47 | let mut stdout = ui.stdout_buffer(); | |
39 |
|
48 | |||
40 |
|
|
49 | for file in files { | |
41 |
|
|
50 | stdout.write_all(relativize_path(file, &rooted_cwd).as_ref())?; | |
42 |
|
|
51 | stdout.write_all(b"\n")?; | |
43 |
|
|
52 | } | |
44 |
|
|
53 | stdout.flush()?; | |
45 |
|
|
54 | Ok(()) | |
46 | } |
|
55 | } | |
47 | } |
|
|||
48 |
|
||||
49 | impl<'a> Command for FilesCommand<'a> { |
|
|||
50 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError> { |
|
|||
51 | let repo = Repo::find(config)?; |
|
|||
52 | if let Some(rev) = self.rev { |
|
|||
53 | let files = |
|
|||
54 | list_rev_tracked_files(&repo, rev).map_err(|e| (e, rev))?; |
|
|||
55 | self.display_files(ui, &repo, files.iter()) |
|
|||
56 | } else { |
|
|||
57 | let distate = Dirstate::new(&repo)?; |
|
|||
58 | let files = distate.tracked_files()?; |
|
|||
59 | self.display_files(ui, &repo, files) |
|
|||
60 | } |
|
|||
61 | } |
|
|||
62 | } |
|
@@ -1,30 +1,24 b'' | |||||
1 | use crate::commands::Command; |
|
|||
2 |
|
|
1 | use crate::error::CommandError; | |
3 | use crate::ui::Ui; |
|
2 | use crate::ui::Ui; | |
|
3 | use clap::ArgMatches; | |||
4 | use format_bytes::format_bytes; |
|
4 | use format_bytes::format_bytes; | |
5 | use hg::config::Config; |
|
5 | use hg::config::Config; | |
6 | use hg::repo::Repo; |
|
6 | use hg::repo::Repo; | |
7 | use hg::utils::files::get_bytes_from_path; |
|
7 | use hg::utils::files::get_bytes_from_path; | |
8 |
|
8 | |||
9 | pub const HELP_TEXT: &str = " |
|
9 | pub const HELP_TEXT: &str = " | |
10 | Print the root directory of the current repository. |
|
10 | Print the root directory of the current repository. | |
11 |
|
11 | |||
12 | Returns 0 on success. |
|
12 | Returns 0 on success. | |
13 | "; |
|
13 | "; | |
14 |
|
14 | |||
15 | pub struct RootCommand {} |
|
15 | pub fn run( | |
16 |
|
16 | ui: &Ui, | ||
17 | impl RootCommand { |
|
17 | config: &Config, | |
18 | pub fn new() -> Self { |
|
18 | _args: &ArgMatches, | |
19 | RootCommand {} |
|
19 | ) -> Result<(), CommandError> { | |
20 | } |
|
|||
21 | } |
|
|||
22 |
|
||||
23 | impl Command for RootCommand { |
|
|||
24 | fn run(&self, ui: &Ui, config: &Config) -> Result<(), CommandError> { |
|
|||
25 |
|
|
20 | let repo = Repo::find(config)?; | |
26 |
|
|
21 | let bytes = get_bytes_from_path(repo.working_directory_path()); | |
27 |
|
|
22 | ui.write_stdout(&format_bytes!(b"{}\n", bytes.as_slice()))?; | |
28 |
|
|
23 | Ok(()) | |
29 | } |
|
24 | } | |
30 | } |
|
@@ -1,194 +1,137 b'' | |||||
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::Arg; | |
5 | use clap::ArgGroup; |
|
5 | use clap::ArgGroup; | |
6 | use clap::ArgMatches; |
|
6 | use clap::ArgMatches; | |
7 | use clap::SubCommand; |
|
7 | use clap::SubCommand; | |
8 | use format_bytes::format_bytes; |
|
8 | use format_bytes::format_bytes; | |
9 | use hg::operations::DebugDataKind; |
|
|||
10 | use std::convert::TryFrom; |
|
|||
11 |
|
9 | |||
12 | mod commands; |
|
10 | mod commands; | |
13 | mod error; |
|
11 | mod error; | |
14 | mod exitcode; |
|
12 | mod exitcode; | |
15 | mod ui; |
|
13 | mod ui; | |
16 | use commands::Command; |
|
|||
17 | use error::CommandError; |
|
14 | use error::CommandError; | |
18 |
|
15 | |||
19 | fn main() { |
|
16 | fn main() { | |
20 | env_logger::init(); |
|
17 | env_logger::init(); | |
21 | let app = App::new("rhg") |
|
18 | let app = App::new("rhg") | |
22 | .setting(AppSettings::AllowInvalidUtf8) |
|
19 | .setting(AppSettings::AllowInvalidUtf8) | |
23 | .setting(AppSettings::SubcommandRequired) |
|
20 | .setting(AppSettings::SubcommandRequired) | |
24 | .setting(AppSettings::VersionlessSubcommands) |
|
21 | .setting(AppSettings::VersionlessSubcommands) | |
25 | .version("0.0.1") |
|
22 | .version("0.0.1") | |
26 | .subcommand( |
|
23 | .subcommand( | |
27 | SubCommand::with_name("root").about(commands::root::HELP_TEXT), |
|
24 | SubCommand::with_name("root").about(commands::root::HELP_TEXT), | |
28 | ) |
|
25 | ) | |
29 | .subcommand( |
|
26 | .subcommand( | |
30 | SubCommand::with_name("files") |
|
27 | SubCommand::with_name("files") | |
31 | .arg( |
|
28 | .arg( | |
32 | Arg::with_name("rev") |
|
29 | Arg::with_name("rev") | |
33 | .help("search the repository as it is in REV") |
|
30 | .help("search the repository as it is in REV") | |
34 | .short("-r") |
|
31 | .short("-r") | |
35 | .long("--revision") |
|
32 | .long("--revision") | |
36 | .value_name("REV") |
|
33 | .value_name("REV") | |
37 | .takes_value(true), |
|
34 | .takes_value(true), | |
38 | ) |
|
35 | ) | |
39 | .about(commands::files::HELP_TEXT), |
|
36 | .about(commands::files::HELP_TEXT), | |
40 | ) |
|
37 | ) | |
41 | .subcommand( |
|
38 | .subcommand( | |
42 | SubCommand::with_name("cat") |
|
39 | SubCommand::with_name("cat") | |
43 | .arg( |
|
40 | .arg( | |
44 | Arg::with_name("rev") |
|
41 | Arg::with_name("rev") | |
45 | .help("search the repository as it is in REV") |
|
42 | .help("search the repository as it is in REV") | |
46 | .short("-r") |
|
43 | .short("-r") | |
47 | .long("--revision") |
|
44 | .long("--revision") | |
48 | .value_name("REV") |
|
45 | .value_name("REV") | |
49 | .takes_value(true), |
|
46 | .takes_value(true), | |
50 | ) |
|
47 | ) | |
51 | .arg( |
|
48 | .arg( | |
52 | clap::Arg::with_name("files") |
|
49 | clap::Arg::with_name("files") | |
53 | .required(true) |
|
50 | .required(true) | |
54 | .multiple(true) |
|
51 | .multiple(true) | |
55 | .empty_values(false) |
|
52 | .empty_values(false) | |
56 | .value_name("FILE") |
|
53 | .value_name("FILE") | |
57 | .help("Activity to start: activity@category"), |
|
54 | .help("Activity to start: activity@category"), | |
58 | ) |
|
55 | ) | |
59 | .about(commands::cat::HELP_TEXT), |
|
56 | .about(commands::cat::HELP_TEXT), | |
60 | ) |
|
57 | ) | |
61 | .subcommand( |
|
58 | .subcommand( | |
62 | SubCommand::with_name("debugdata") |
|
59 | SubCommand::with_name("debugdata") | |
63 | .about(commands::debugdata::HELP_TEXT) |
|
60 | .about(commands::debugdata::HELP_TEXT) | |
64 | .arg( |
|
61 | .arg( | |
65 | Arg::with_name("changelog") |
|
62 | Arg::with_name("changelog") | |
66 | .help("open changelog") |
|
63 | .help("open changelog") | |
67 | .short("-c") |
|
64 | .short("-c") | |
68 | .long("--changelog"), |
|
65 | .long("--changelog"), | |
69 | ) |
|
66 | ) | |
70 | .arg( |
|
67 | .arg( | |
71 | Arg::with_name("manifest") |
|
68 | Arg::with_name("manifest") | |
72 | .help("open manifest") |
|
69 | .help("open manifest") | |
73 | .short("-m") |
|
70 | .short("-m") | |
74 | .long("--manifest"), |
|
71 | .long("--manifest"), | |
75 | ) |
|
72 | ) | |
76 | .group( |
|
73 | .group( | |
77 | ArgGroup::with_name("") |
|
74 | ArgGroup::with_name("") | |
78 | .args(&["changelog", "manifest"]) |
|
75 | .args(&["changelog", "manifest"]) | |
79 | .required(true), |
|
76 | .required(true), | |
80 | ) |
|
77 | ) | |
81 | .arg( |
|
78 | .arg( | |
82 | Arg::with_name("rev") |
|
79 | Arg::with_name("rev") | |
83 | .help("revision") |
|
80 | .help("revision") | |
84 | .required(true) |
|
81 | .required(true) | |
85 | .value_name("REV"), |
|
82 | .value_name("REV"), | |
86 | ), |
|
83 | ), | |
87 | ) |
|
84 | ) | |
88 | .subcommand( |
|
85 | .subcommand( | |
89 | SubCommand::with_name("debugrequirements") |
|
86 | SubCommand::with_name("debugrequirements") | |
90 | .about(commands::debugrequirements::HELP_TEXT), |
|
87 | .about(commands::debugrequirements::HELP_TEXT), | |
91 | ); |
|
88 | ); | |
92 |
|
89 | |||
93 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { |
|
90 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { | |
94 | let _ = ui::Ui::new().writeln_stderr_str(&err.message); |
|
91 | let _ = ui::Ui::new().writeln_stderr_str(&err.message); | |
95 | std::process::exit(exitcode::UNIMPLEMENTED) |
|
92 | std::process::exit(exitcode::UNIMPLEMENTED) | |
96 | }); |
|
93 | }); | |
97 |
|
94 | |||
98 | let ui = ui::Ui::new(); |
|
95 | let ui = ui::Ui::new(); | |
99 |
|
96 | |||
100 | let command_result = match_subcommand(matches, &ui); |
|
97 | let command_result = match_subcommand(matches, &ui); | |
101 |
|
98 | |||
102 | let exit_code = match command_result { |
|
99 | let exit_code = match command_result { | |
103 | Ok(_) => exitcode::OK, |
|
100 | Ok(_) => exitcode::OK, | |
104 |
|
101 | |||
105 | // Exit with a specific code and no error message to let a potential |
|
102 | // Exit with a specific code and no error message to let a potential | |
106 | // wrapper script fallback to Python-based Mercurial. |
|
103 | // wrapper script fallback to Python-based Mercurial. | |
107 | Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, |
|
104 | Err(CommandError::Unimplemented) => exitcode::UNIMPLEMENTED, | |
108 |
|
105 | |||
109 | Err(CommandError::Abort { message }) => { |
|
106 | Err(CommandError::Abort { message }) => { | |
110 | if !message.is_empty() { |
|
107 | if !message.is_empty() { | |
111 | // Ignore errors when writing to stderr, weβre already exiting |
|
108 | // Ignore errors when writing to stderr, weβre already exiting | |
112 | // with failure code so thereβs not much more we can do. |
|
109 | // with failure code so thereβs not much more we can do. | |
113 | let _ = |
|
110 | let _ = | |
114 | ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); |
|
111 | ui.write_stderr(&format_bytes!(b"abort: {}\n", message)); | |
115 | } |
|
112 | } | |
116 | exitcode::ABORT |
|
113 | exitcode::ABORT | |
117 | } |
|
114 | } | |
118 | }; |
|
115 | }; | |
119 | std::process::exit(exit_code) |
|
116 | std::process::exit(exit_code) | |
120 | } |
|
117 | } | |
121 |
|
118 | |||
122 | fn match_subcommand( |
|
119 | fn match_subcommand( | |
123 | matches: ArgMatches, |
|
120 | matches: ArgMatches, | |
124 | ui: &ui::Ui, |
|
121 | ui: &ui::Ui, | |
125 | ) -> Result<(), CommandError> { |
|
122 | ) -> Result<(), CommandError> { | |
126 | let config = hg::config::Config::load()?; |
|
123 | let config = hg::config::Config::load()?; | |
127 |
|
124 | |||
128 | match matches.subcommand() { |
|
125 | match matches.subcommand() { | |
129 |
("root", |
|
126 | ("root", Some(matches)) => commands::root::run(ui, &config, matches), | |
130 |
("files", Some(matches)) => |
|
127 | ("files", Some(matches)) => commands::files::run(ui, &config, matches), | |
131 | commands::files::FilesCommand::try_from(matches)?.run(&ui, &config) |
|
128 | ("cat", Some(matches)) => commands::cat::run(ui, &config, matches), | |
132 | } |
|
129 | ("debugdata", Some(matches)) => { | |
133 | ("cat", Some(matches)) => { |
|
130 | commands::debugdata::run(ui, &config, matches) | |
134 | commands::cat::CatCommand::try_from(matches)?.run(&ui, &config) |
|
|||
135 | } |
|
131 | } | |
136 |
("debug |
|
132 | ("debugrequirements", Some(matches)) => { | |
137 | commands::debugdata::DebugDataCommand::try_from(matches)? |
|
133 | commands::debugrequirements::run(ui, &config, matches) | |
138 | .run(&ui, &config) |
|
|||
139 | } |
|
|||
140 | ("debugrequirements", _) => { |
|
|||
141 | commands::debugrequirements::DebugRequirementsCommand::new() |
|
|||
142 | .run(&ui, &config) |
|
|||
143 | } |
|
134 | } | |
144 | _ => unreachable!(), // Because of AppSettings::SubcommandRequired, |
|
135 | _ => unreachable!(), // Because of AppSettings::SubcommandRequired, | |
145 | } |
|
136 | } | |
146 | } |
|
137 | } | |
147 |
|
||||
148 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { |
|
|||
149 | type Error = CommandError; |
|
|||
150 |
|
||||
151 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
|||
152 | let rev = args.value_of("rev"); |
|
|||
153 | Ok(commands::files::FilesCommand::new(rev)) |
|
|||
154 | } |
|
|||
155 | } |
|
|||
156 |
|
||||
157 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { |
|
|||
158 | type Error = CommandError; |
|
|||
159 |
|
||||
160 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
|||
161 | let rev = args.value_of("rev"); |
|
|||
162 | let files = match args.values_of("files") { |
|
|||
163 | Some(files) => files.collect(), |
|
|||
164 | None => vec![], |
|
|||
165 | }; |
|
|||
166 | Ok(commands::cat::CatCommand::new(rev, files)) |
|
|||
167 | } |
|
|||
168 | } |
|
|||
169 |
|
||||
170 | impl<'a> TryFrom<&'a ArgMatches<'_>> |
|
|||
171 | for commands::debugdata::DebugDataCommand<'a> |
|
|||
172 | { |
|
|||
173 | type Error = CommandError; |
|
|||
174 |
|
||||
175 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
|||
176 | let rev = args |
|
|||
177 | .value_of("rev") |
|
|||
178 | .expect("rev should be a required argument"); |
|
|||
179 | let kind = match ( |
|
|||
180 | args.is_present("changelog"), |
|
|||
181 | args.is_present("manifest"), |
|
|||
182 | ) { |
|
|||
183 | (true, false) => DebugDataKind::Changelog, |
|
|||
184 | (false, true) => DebugDataKind::Manifest, |
|
|||
185 | (true, true) => { |
|
|||
186 | unreachable!("Should not happen since options are exclusive") |
|
|||
187 | } |
|
|||
188 | (false, false) => { |
|
|||
189 | unreachable!("Should not happen since options are required") |
|
|||
190 | } |
|
|||
191 | }; |
|
|||
192 | Ok(commands::debugdata::DebugDataCommand::new(rev, kind)) |
|
|||
193 | } |
|
|||
194 | } |
|
General Comments 0
You need to be logged in to leave comments.
Login now