Show More
@@ -0,0 +1,40 b'' | |||||
|
1 | use crate::commands::Command; | |||
|
2 | use crate::error::{CommandError, CommandErrorKind}; | |||
|
3 | use crate::ui::Ui; | |||
|
4 | use hg::operations::FindRoot; | |||
|
5 | ||||
|
6 | pub const HELP_TEXT: &str = " | |||
|
7 | Print the current repo requirements. | |||
|
8 | "; | |||
|
9 | ||||
|
10 | pub struct DebugRequirementsCommand {} | |||
|
11 | ||||
|
12 | impl DebugRequirementsCommand { | |||
|
13 | pub fn new() -> Self { | |||
|
14 | DebugRequirementsCommand {} | |||
|
15 | } | |||
|
16 | } | |||
|
17 | ||||
|
18 | impl Command for DebugRequirementsCommand { | |||
|
19 | fn run(&self, ui: &Ui) -> Result<(), CommandError> { | |||
|
20 | let root = FindRoot::new().run()?; | |||
|
21 | let requires = root.join(".hg").join("requires"); | |||
|
22 | let requirements = match std::fs::read(requires) { | |||
|
23 | Ok(bytes) => bytes, | |||
|
24 | ||||
|
25 | // Treat a missing file the same as an empty file. | |||
|
26 | // From `mercurial/localrepo.py`: | |||
|
27 | // > requires file contains a newline-delimited list of | |||
|
28 | // > features/capabilities the opener (us) must have in order to use | |||
|
29 | // > the repository. This file was introduced in Mercurial 0.9.2, | |||
|
30 | // > which means very old repositories may not have one. We assume | |||
|
31 | // > a missing file translates to no requirements. | |||
|
32 | Err(error) if error.kind() == std::io::ErrorKind::NotFound => Vec::new(), | |||
|
33 | ||||
|
34 | Err(error) => Err(CommandErrorKind::FileError(error))?, | |||
|
35 | }; | |||
|
36 | ||||
|
37 | ui.write_stdout(&requirements)?; | |||
|
38 | Ok(()) | |||
|
39 | } | |||
|
40 | } |
@@ -1,13 +1,14 b'' | |||||
1 | pub mod cat; |
|
1 | pub mod cat; | |
2 | pub mod debugdata; |
|
2 | pub mod debugdata; | |
|
3 | pub mod debugrequirements; | |||
3 | pub mod files; |
|
4 | pub mod files; | |
4 | pub mod root; |
|
5 | pub mod root; | |
5 | use crate::error::CommandError; |
|
6 | use crate::error::CommandError; | |
6 | use crate::ui::Ui; |
|
7 | use crate::ui::Ui; | |
7 |
|
8 | |||
8 | /// The common trait for rhg commands |
|
9 | /// The common trait for rhg commands | |
9 | /// |
|
10 | /// | |
10 | /// Normalize the interface of the commands provided by rhg |
|
11 | /// Normalize the interface of the commands provided by rhg | |
11 | pub trait Command { |
|
12 | pub trait Command { | |
12 | fn run(&self, ui: &Ui) -> Result<(), CommandError>; |
|
13 | fn run(&self, ui: &Ui) -> Result<(), CommandError>; | |
13 | } |
|
14 | } |
@@ -1,113 +1,117 b'' | |||||
1 | use crate::exitcode; |
|
1 | use crate::exitcode; | |
2 | use crate::ui::UiError; |
|
2 | use crate::ui::UiError; | |
3 | use hg::operations::{FindRootError, FindRootErrorKind}; |
|
3 | use hg::operations::{FindRootError, FindRootErrorKind}; | |
4 | use hg::utils::files::get_bytes_from_path; |
|
4 | use hg::utils::files::get_bytes_from_path; | |
5 | use std::convert::From; |
|
5 | use std::convert::From; | |
6 | use std::path::PathBuf; |
|
6 | use std::path::PathBuf; | |
7 |
|
7 | |||
8 | /// The kind of command error |
|
8 | /// The kind of command error | |
9 | #[derive(Debug)] |
|
9 | #[derive(Debug)] | |
10 | pub enum CommandErrorKind { |
|
10 | pub enum CommandErrorKind { | |
11 | /// The root of the repository cannot be found |
|
11 | /// The root of the repository cannot be found | |
12 | RootNotFound(PathBuf), |
|
12 | RootNotFound(PathBuf), | |
13 | /// The current directory cannot be found |
|
13 | /// The current directory cannot be found | |
14 | CurrentDirNotFound(std::io::Error), |
|
14 | CurrentDirNotFound(std::io::Error), | |
|
15 | /// Error while reading or writing a file | |||
|
16 | // TODO: add the file name/path? | |||
|
17 | FileError(std::io::Error), | |||
15 | /// The standard output stream cannot be written to |
|
18 | /// The standard output stream cannot be written to | |
16 | StdoutError, |
|
19 | StdoutError, | |
17 | /// The standard error stream cannot be written to |
|
20 | /// The standard error stream cannot be written to | |
18 | StderrError, |
|
21 | StderrError, | |
19 | /// The command aborted |
|
22 | /// The command aborted | |
20 | Abort(Option<Vec<u8>>), |
|
23 | Abort(Option<Vec<u8>>), | |
21 | /// A mercurial capability as not been implemented. |
|
24 | /// A mercurial capability as not been implemented. | |
22 | Unimplemented, |
|
25 | Unimplemented, | |
23 | } |
|
26 | } | |
24 |
|
27 | |||
25 | impl CommandErrorKind { |
|
28 | impl CommandErrorKind { | |
26 | pub fn get_exit_code(&self) -> exitcode::ExitCode { |
|
29 | pub fn get_exit_code(&self) -> exitcode::ExitCode { | |
27 | match self { |
|
30 | match self { | |
28 | CommandErrorKind::RootNotFound(_) => exitcode::ABORT, |
|
31 | CommandErrorKind::RootNotFound(_) => exitcode::ABORT, | |
29 | CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT, |
|
32 | CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT, | |
|
33 | CommandErrorKind::FileError(_) => exitcode::ABORT, | |||
30 | CommandErrorKind::StdoutError => exitcode::ABORT, |
|
34 | CommandErrorKind::StdoutError => exitcode::ABORT, | |
31 | CommandErrorKind::StderrError => exitcode::ABORT, |
|
35 | CommandErrorKind::StderrError => exitcode::ABORT, | |
32 | CommandErrorKind::Abort(_) => exitcode::ABORT, |
|
36 | CommandErrorKind::Abort(_) => exitcode::ABORT, | |
33 | CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, |
|
37 | CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND, | |
34 | } |
|
38 | } | |
35 | } |
|
39 | } | |
36 |
|
40 | |||
37 | /// Return the message corresponding to the error kind if any |
|
41 | /// Return the message corresponding to the error kind if any | |
38 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { |
|
42 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { | |
39 | match self { |
|
43 | match self { | |
40 | // TODO use formating macro |
|
44 | // TODO use formating macro | |
41 | CommandErrorKind::RootNotFound(path) => { |
|
45 | CommandErrorKind::RootNotFound(path) => { | |
42 | let bytes = get_bytes_from_path(path); |
|
46 | let bytes = get_bytes_from_path(path); | |
43 | Some( |
|
47 | Some( | |
44 | [ |
|
48 | [ | |
45 | b"abort: no repository found in '", |
|
49 | b"abort: no repository found in '", | |
46 | bytes.as_slice(), |
|
50 | bytes.as_slice(), | |
47 | b"' (.hg not found)!\n", |
|
51 | b"' (.hg not found)!\n", | |
48 | ] |
|
52 | ] | |
49 | .concat(), |
|
53 | .concat(), | |
50 | ) |
|
54 | ) | |
51 | } |
|
55 | } | |
52 | // TODO use formating macro |
|
56 | // TODO use formating macro | |
53 | CommandErrorKind::CurrentDirNotFound(e) => Some( |
|
57 | CommandErrorKind::CurrentDirNotFound(e) => Some( | |
54 | [ |
|
58 | [ | |
55 | b"abort: error getting current working directory: ", |
|
59 | b"abort: error getting current working directory: ", | |
56 | e.to_string().as_bytes(), |
|
60 | e.to_string().as_bytes(), | |
57 | b"\n", |
|
61 | b"\n", | |
58 | ] |
|
62 | ] | |
59 | .concat(), |
|
63 | .concat(), | |
60 | ), |
|
64 | ), | |
61 | CommandErrorKind::Abort(message) => message.to_owned(), |
|
65 | CommandErrorKind::Abort(message) => message.to_owned(), | |
62 | _ => None, |
|
66 | _ => None, | |
63 | } |
|
67 | } | |
64 | } |
|
68 | } | |
65 | } |
|
69 | } | |
66 |
|
70 | |||
67 | /// The error type for the Command trait |
|
71 | /// The error type for the Command trait | |
68 | #[derive(Debug)] |
|
72 | #[derive(Debug)] | |
69 | pub struct CommandError { |
|
73 | pub struct CommandError { | |
70 | pub kind: CommandErrorKind, |
|
74 | pub kind: CommandErrorKind, | |
71 | } |
|
75 | } | |
72 |
|
76 | |||
73 | impl CommandError { |
|
77 | impl CommandError { | |
74 | /// Exist the process with the corresponding exit code. |
|
78 | /// Exist the process with the corresponding exit code. | |
75 | pub fn exit(&self) { |
|
79 | pub fn exit(&self) { | |
76 | std::process::exit(self.kind.get_exit_code()) |
|
80 | std::process::exit(self.kind.get_exit_code()) | |
77 | } |
|
81 | } | |
78 |
|
82 | |||
79 | /// Return the message corresponding to the command error if any |
|
83 | /// Return the message corresponding to the command error if any | |
80 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { |
|
84 | pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> { | |
81 | self.kind.get_error_message_bytes() |
|
85 | self.kind.get_error_message_bytes() | |
82 | } |
|
86 | } | |
83 | } |
|
87 | } | |
84 |
|
88 | |||
85 | impl From<CommandErrorKind> for CommandError { |
|
89 | impl From<CommandErrorKind> for CommandError { | |
86 | fn from(kind: CommandErrorKind) -> Self { |
|
90 | fn from(kind: CommandErrorKind) -> Self { | |
87 | CommandError { kind } |
|
91 | CommandError { kind } | |
88 | } |
|
92 | } | |
89 | } |
|
93 | } | |
90 |
|
94 | |||
91 | impl From<UiError> for CommandError { |
|
95 | impl From<UiError> for CommandError { | |
92 | fn from(error: UiError) -> Self { |
|
96 | fn from(error: UiError) -> Self { | |
93 | CommandError { |
|
97 | CommandError { | |
94 | kind: match error { |
|
98 | kind: match error { | |
95 | UiError::StdoutError(_) => CommandErrorKind::StdoutError, |
|
99 | UiError::StdoutError(_) => CommandErrorKind::StdoutError, | |
96 | UiError::StderrError(_) => CommandErrorKind::StderrError, |
|
100 | UiError::StderrError(_) => CommandErrorKind::StderrError, | |
97 | }, |
|
101 | }, | |
98 | } |
|
102 | } | |
99 | } |
|
103 | } | |
100 | } |
|
104 | } | |
101 |
|
105 | |||
102 | impl From<FindRootError> for CommandError { |
|
106 | impl From<FindRootError> for CommandError { | |
103 | fn from(err: FindRootError) -> Self { |
|
107 | fn from(err: FindRootError) -> Self { | |
104 | match err.kind { |
|
108 | match err.kind { | |
105 | FindRootErrorKind::RootNotFound(path) => CommandError { |
|
109 | FindRootErrorKind::RootNotFound(path) => CommandError { | |
106 | kind: CommandErrorKind::RootNotFound(path), |
|
110 | kind: CommandErrorKind::RootNotFound(path), | |
107 | }, |
|
111 | }, | |
108 | FindRootErrorKind::GetCurrentDirError(e) => CommandError { |
|
112 | FindRootErrorKind::GetCurrentDirError(e) => CommandError { | |
109 | kind: CommandErrorKind::CurrentDirNotFound(e), |
|
113 | kind: CommandErrorKind::CurrentDirNotFound(e), | |
110 | }, |
|
114 | }, | |
111 | } |
|
115 | } | |
112 | } |
|
116 | } | |
113 | } |
|
117 | } |
@@ -1,177 +1,185 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 hg::operations::DebugDataKind; |
|
8 | use hg::operations::DebugDataKind; | |
9 | use std::convert::TryFrom; |
|
9 | use std::convert::TryFrom; | |
10 |
|
10 | |||
11 | mod commands; |
|
11 | mod commands; | |
12 | mod error; |
|
12 | mod error; | |
13 | mod exitcode; |
|
13 | mod exitcode; | |
14 | mod ui; |
|
14 | mod ui; | |
15 | use commands::Command; |
|
15 | use commands::Command; | |
16 | use error::CommandError; |
|
16 | use error::CommandError; | |
17 |
|
17 | |||
18 | fn main() { |
|
18 | fn main() { | |
19 | env_logger::init(); |
|
19 | env_logger::init(); | |
20 | let app = App::new("rhg") |
|
20 | let app = App::new("rhg") | |
21 | .setting(AppSettings::AllowInvalidUtf8) |
|
21 | .setting(AppSettings::AllowInvalidUtf8) | |
22 | .setting(AppSettings::SubcommandRequired) |
|
22 | .setting(AppSettings::SubcommandRequired) | |
23 | .setting(AppSettings::VersionlessSubcommands) |
|
23 | .setting(AppSettings::VersionlessSubcommands) | |
24 | .version("0.0.1") |
|
24 | .version("0.0.1") | |
25 | .subcommand( |
|
25 | .subcommand( | |
26 | SubCommand::with_name("root").about(commands::root::HELP_TEXT), |
|
26 | SubCommand::with_name("root").about(commands::root::HELP_TEXT), | |
27 | ) |
|
27 | ) | |
28 | .subcommand( |
|
28 | .subcommand( | |
29 | SubCommand::with_name("files") |
|
29 | SubCommand::with_name("files") | |
30 | .arg( |
|
30 | .arg( | |
31 | Arg::with_name("rev") |
|
31 | Arg::with_name("rev") | |
32 | .help("search the repository as it is in REV") |
|
32 | .help("search the repository as it is in REV") | |
33 | .short("-r") |
|
33 | .short("-r") | |
34 | .long("--revision") |
|
34 | .long("--revision") | |
35 | .value_name("REV") |
|
35 | .value_name("REV") | |
36 | .takes_value(true), |
|
36 | .takes_value(true), | |
37 | ) |
|
37 | ) | |
38 | .about(commands::files::HELP_TEXT), |
|
38 | .about(commands::files::HELP_TEXT), | |
39 | ) |
|
39 | ) | |
40 | .subcommand( |
|
40 | .subcommand( | |
41 | SubCommand::with_name("cat") |
|
41 | SubCommand::with_name("cat") | |
42 | .arg( |
|
42 | .arg( | |
43 | Arg::with_name("rev") |
|
43 | Arg::with_name("rev") | |
44 | .help("search the repository as it is in REV") |
|
44 | .help("search the repository as it is in REV") | |
45 | .short("-r") |
|
45 | .short("-r") | |
46 | .long("--revision") |
|
46 | .long("--revision") | |
47 | .value_name("REV") |
|
47 | .value_name("REV") | |
48 | .takes_value(true), |
|
48 | .takes_value(true), | |
49 | ) |
|
49 | ) | |
50 | .arg( |
|
50 | .arg( | |
51 | clap::Arg::with_name("files") |
|
51 | clap::Arg::with_name("files") | |
52 | .required(true) |
|
52 | .required(true) | |
53 | .multiple(true) |
|
53 | .multiple(true) | |
54 | .empty_values(false) |
|
54 | .empty_values(false) | |
55 | .value_name("FILE") |
|
55 | .value_name("FILE") | |
56 | .help("Activity to start: activity@category"), |
|
56 | .help("Activity to start: activity@category"), | |
57 | ) |
|
57 | ) | |
58 | .about(commands::cat::HELP_TEXT), |
|
58 | .about(commands::cat::HELP_TEXT), | |
59 | ) |
|
59 | ) | |
60 | .subcommand( |
|
60 | .subcommand( | |
61 | SubCommand::with_name("debugdata") |
|
61 | SubCommand::with_name("debugdata") | |
62 | .about(commands::debugdata::HELP_TEXT) |
|
62 | .about(commands::debugdata::HELP_TEXT) | |
63 | .arg( |
|
63 | .arg( | |
64 | Arg::with_name("changelog") |
|
64 | Arg::with_name("changelog") | |
65 | .help("open changelog") |
|
65 | .help("open changelog") | |
66 | .short("-c") |
|
66 | .short("-c") | |
67 | .long("--changelog"), |
|
67 | .long("--changelog"), | |
68 | ) |
|
68 | ) | |
69 | .arg( |
|
69 | .arg( | |
70 | Arg::with_name("manifest") |
|
70 | Arg::with_name("manifest") | |
71 | .help("open manifest") |
|
71 | .help("open manifest") | |
72 | .short("-m") |
|
72 | .short("-m") | |
73 | .long("--manifest"), |
|
73 | .long("--manifest"), | |
74 | ) |
|
74 | ) | |
75 | .group( |
|
75 | .group( | |
76 | ArgGroup::with_name("") |
|
76 | ArgGroup::with_name("") | |
77 | .args(&["changelog", "manifest"]) |
|
77 | .args(&["changelog", "manifest"]) | |
78 | .required(true), |
|
78 | .required(true), | |
79 | ) |
|
79 | ) | |
80 | .arg( |
|
80 | .arg( | |
81 | Arg::with_name("rev") |
|
81 | Arg::with_name("rev") | |
82 | .help("revision") |
|
82 | .help("revision") | |
83 | .required(true) |
|
83 | .required(true) | |
84 | .value_name("REV"), |
|
84 | .value_name("REV"), | |
85 | ), |
|
85 | ), | |
|
86 | ) | |||
|
87 | .subcommand( | |||
|
88 | SubCommand::with_name("debugrequirements") | |||
|
89 | .about(commands::debugrequirements::HELP_TEXT), | |||
86 | ); |
|
90 | ); | |
87 |
|
91 | |||
88 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { |
|
92 | let matches = app.clone().get_matches_safe().unwrap_or_else(|err| { | |
89 | let _ = ui::Ui::new().writeln_stderr_str(&err.message); |
|
93 | let _ = ui::Ui::new().writeln_stderr_str(&err.message); | |
90 | std::process::exit(exitcode::UNIMPLEMENTED_COMMAND) |
|
94 | std::process::exit(exitcode::UNIMPLEMENTED_COMMAND) | |
91 | }); |
|
95 | }); | |
92 |
|
96 | |||
93 | let ui = ui::Ui::new(); |
|
97 | let ui = ui::Ui::new(); | |
94 |
|
98 | |||
95 | let command_result = match_subcommand(matches, &ui); |
|
99 | let command_result = match_subcommand(matches, &ui); | |
96 |
|
100 | |||
97 | match command_result { |
|
101 | match command_result { | |
98 | Ok(_) => std::process::exit(exitcode::OK), |
|
102 | Ok(_) => std::process::exit(exitcode::OK), | |
99 | Err(e) => { |
|
103 | Err(e) => { | |
100 | let message = e.get_error_message_bytes(); |
|
104 | let message = e.get_error_message_bytes(); | |
101 | if let Some(msg) = message { |
|
105 | if let Some(msg) = message { | |
102 | match ui.write_stderr(&msg) { |
|
106 | match ui.write_stderr(&msg) { | |
103 | Ok(_) => (), |
|
107 | Ok(_) => (), | |
104 | Err(_) => std::process::exit(exitcode::ABORT), |
|
108 | Err(_) => std::process::exit(exitcode::ABORT), | |
105 | }; |
|
109 | }; | |
106 | }; |
|
110 | }; | |
107 | e.exit() |
|
111 | e.exit() | |
108 | } |
|
112 | } | |
109 | } |
|
113 | } | |
110 | } |
|
114 | } | |
111 |
|
115 | |||
112 | fn match_subcommand( |
|
116 | fn match_subcommand( | |
113 | matches: ArgMatches, |
|
117 | matches: ArgMatches, | |
114 | ui: &ui::Ui, |
|
118 | ui: &ui::Ui, | |
115 | ) -> Result<(), CommandError> { |
|
119 | ) -> Result<(), CommandError> { | |
116 | match matches.subcommand() { |
|
120 | match matches.subcommand() { | |
117 | ("root", _) => commands::root::RootCommand::new().run(&ui), |
|
121 | ("root", _) => commands::root::RootCommand::new().run(&ui), | |
118 | ("files", Some(matches)) => { |
|
122 | ("files", Some(matches)) => { | |
119 | commands::files::FilesCommand::try_from(matches)?.run(&ui) |
|
123 | commands::files::FilesCommand::try_from(matches)?.run(&ui) | |
120 | } |
|
124 | } | |
121 | ("cat", Some(matches)) => { |
|
125 | ("cat", Some(matches)) => { | |
122 | commands::cat::CatCommand::try_from(matches)?.run(&ui) |
|
126 | commands::cat::CatCommand::try_from(matches)?.run(&ui) | |
123 | } |
|
127 | } | |
124 | ("debugdata", Some(matches)) => { |
|
128 | ("debugdata", Some(matches)) => { | |
125 | commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) |
|
129 | commands::debugdata::DebugDataCommand::try_from(matches)?.run(&ui) | |
126 | } |
|
130 | } | |
|
131 | ("debugrequirements", _) => { | |||
|
132 | commands::debugrequirements::DebugRequirementsCommand::new() | |||
|
133 | .run(&ui) | |||
|
134 | } | |||
127 | _ => unreachable!(), // Because of AppSettings::SubcommandRequired, |
|
135 | _ => unreachable!(), // Because of AppSettings::SubcommandRequired, | |
128 | } |
|
136 | } | |
129 | } |
|
137 | } | |
130 |
|
138 | |||
131 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { |
|
139 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::files::FilesCommand<'a> { | |
132 | type Error = CommandError; |
|
140 | type Error = CommandError; | |
133 |
|
141 | |||
134 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
142 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | |
135 | let rev = args.value_of("rev"); |
|
143 | let rev = args.value_of("rev"); | |
136 | Ok(commands::files::FilesCommand::new(rev)) |
|
144 | Ok(commands::files::FilesCommand::new(rev)) | |
137 | } |
|
145 | } | |
138 | } |
|
146 | } | |
139 |
|
147 | |||
140 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { |
|
148 | impl<'a> TryFrom<&'a ArgMatches<'_>> for commands::cat::CatCommand<'a> { | |
141 | type Error = CommandError; |
|
149 | type Error = CommandError; | |
142 |
|
150 | |||
143 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
151 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | |
144 | let rev = args.value_of("rev"); |
|
152 | let rev = args.value_of("rev"); | |
145 | let files = match args.values_of("files") { |
|
153 | let files = match args.values_of("files") { | |
146 | Some(files) => files.collect(), |
|
154 | Some(files) => files.collect(), | |
147 | None => vec![], |
|
155 | None => vec![], | |
148 | }; |
|
156 | }; | |
149 | Ok(commands::cat::CatCommand::new(rev, files)) |
|
157 | Ok(commands::cat::CatCommand::new(rev, files)) | |
150 | } |
|
158 | } | |
151 | } |
|
159 | } | |
152 |
|
160 | |||
153 | impl<'a> TryFrom<&'a ArgMatches<'_>> |
|
161 | impl<'a> TryFrom<&'a ArgMatches<'_>> | |
154 | for commands::debugdata::DebugDataCommand<'a> |
|
162 | for commands::debugdata::DebugDataCommand<'a> | |
155 | { |
|
163 | { | |
156 | type Error = CommandError; |
|
164 | type Error = CommandError; | |
157 |
|
165 | |||
158 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { |
|
166 | fn try_from(args: &'a ArgMatches) -> Result<Self, Self::Error> { | |
159 | let rev = args |
|
167 | let rev = args | |
160 | .value_of("rev") |
|
168 | .value_of("rev") | |
161 | .expect("rev should be a required argument"); |
|
169 | .expect("rev should be a required argument"); | |
162 | let kind = match ( |
|
170 | let kind = match ( | |
163 | args.is_present("changelog"), |
|
171 | args.is_present("changelog"), | |
164 | args.is_present("manifest"), |
|
172 | args.is_present("manifest"), | |
165 | ) { |
|
173 | ) { | |
166 | (true, false) => DebugDataKind::Changelog, |
|
174 | (true, false) => DebugDataKind::Changelog, | |
167 | (false, true) => DebugDataKind::Manifest, |
|
175 | (false, true) => DebugDataKind::Manifest, | |
168 | (true, true) => { |
|
176 | (true, true) => { | |
169 | unreachable!("Should not happen since options are exclusive") |
|
177 | unreachable!("Should not happen since options are exclusive") | |
170 | } |
|
178 | } | |
171 | (false, false) => { |
|
179 | (false, false) => { | |
172 | unreachable!("Should not happen since options are required") |
|
180 | unreachable!("Should not happen since options are required") | |
173 | } |
|
181 | } | |
174 | }; |
|
182 | }; | |
175 | Ok(commands::debugdata::DebugDataCommand::new(rev, kind)) |
|
183 | Ok(commands::debugdata::DebugDataCommand::new(rev, kind)) | |
176 | } |
|
184 | } | |
177 | } |
|
185 | } |
@@ -1,117 +1,126 b'' | |||||
1 | #require rust |
|
1 | #require rust | |
2 |
|
2 | |||
3 | Define an rhg function that will only run if rhg exists |
|
3 | Define an rhg function that will only run if rhg exists | |
4 | $ rhg() { |
|
4 | $ rhg() { | |
5 | > if [ -f "$RUNTESTDIR/../rust/target/debug/rhg" ]; then |
|
5 | > if [ -f "$RUNTESTDIR/../rust/target/debug/rhg" ]; then | |
6 | > "$RUNTESTDIR/../rust/target/debug/rhg" "$@" |
|
6 | > "$RUNTESTDIR/../rust/target/debug/rhg" "$@" | |
7 | > else |
|
7 | > else | |
8 | > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg." |
|
8 | > echo "skipped: Cannot find rhg. Try to run cargo build in rust/rhg." | |
9 | > exit 80 |
|
9 | > exit 80 | |
10 | > fi |
|
10 | > fi | |
11 | > } |
|
11 | > } | |
12 |
|
12 | |||
13 | Unimplemented command |
|
13 | Unimplemented command | |
14 | $ rhg unimplemented-command |
|
14 | $ rhg unimplemented-command | |
15 | error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context |
|
15 | error: Found argument 'unimplemented-command' which wasn't expected, or isn't valid in this context | |
16 |
|
16 | |||
17 | USAGE: |
|
17 | USAGE: | |
18 | rhg <SUBCOMMAND> |
|
18 | rhg <SUBCOMMAND> | |
19 |
|
19 | |||
20 | For more information try --help |
|
20 | For more information try --help | |
21 | [252] |
|
21 | [252] | |
22 |
|
22 | |||
23 | Finding root |
|
23 | Finding root | |
24 | $ rhg root |
|
24 | $ rhg root | |
25 | abort: no repository found in '$TESTTMP' (.hg not found)! |
|
25 | abort: no repository found in '$TESTTMP' (.hg not found)! | |
26 | [255] |
|
26 | [255] | |
27 |
|
27 | |||
28 | $ hg init repository |
|
28 | $ hg init repository | |
29 | $ cd repository |
|
29 | $ cd repository | |
30 | $ rhg root |
|
30 | $ rhg root | |
31 | $TESTTMP/repository |
|
31 | $TESTTMP/repository | |
32 |
|
32 | |||
33 | Unwritable file descriptor |
|
33 | Unwritable file descriptor | |
34 | $ rhg root > /dev/full |
|
34 | $ rhg root > /dev/full | |
35 | abort: No space left on device (os error 28) |
|
35 | abort: No space left on device (os error 28) | |
36 | [255] |
|
36 | [255] | |
37 |
|
37 | |||
38 | Deleted repository |
|
38 | Deleted repository | |
39 | $ rm -rf `pwd` |
|
39 | $ rm -rf `pwd` | |
40 | $ rhg root |
|
40 | $ rhg root | |
41 | abort: error getting current working directory: $ENOENT$ |
|
41 | abort: error getting current working directory: $ENOENT$ | |
42 | [255] |
|
42 | [255] | |
43 |
|
43 | |||
44 | Listing tracked files |
|
44 | Listing tracked files | |
45 | $ cd $TESTTMP |
|
45 | $ cd $TESTTMP | |
46 | $ hg init repository |
|
46 | $ hg init repository | |
47 | $ cd repository |
|
47 | $ cd repository | |
48 | $ for i in 1 2 3; do |
|
48 | $ for i in 1 2 3; do | |
49 | > echo $i >> file$i |
|
49 | > echo $i >> file$i | |
50 | > hg add file$i |
|
50 | > hg add file$i | |
51 | > done |
|
51 | > done | |
52 | > hg commit -m "commit $i" -q |
|
52 | > hg commit -m "commit $i" -q | |
53 |
|
53 | |||
54 | Listing tracked files from root |
|
54 | Listing tracked files from root | |
55 | $ rhg files |
|
55 | $ rhg files | |
56 | file1 |
|
56 | file1 | |
57 | file2 |
|
57 | file2 | |
58 | file3 |
|
58 | file3 | |
59 |
|
59 | |||
60 | Listing tracked files from subdirectory |
|
60 | Listing tracked files from subdirectory | |
61 | $ mkdir -p path/to/directory |
|
61 | $ mkdir -p path/to/directory | |
62 | $ cd path/to/directory |
|
62 | $ cd path/to/directory | |
63 | $ rhg files |
|
63 | $ rhg files | |
64 | ../../../file1 |
|
64 | ../../../file1 | |
65 | ../../../file2 |
|
65 | ../../../file2 | |
66 | ../../../file3 |
|
66 | ../../../file3 | |
67 |
|
67 | |||
68 | Listing tracked files through broken pipe |
|
68 | Listing tracked files through broken pipe | |
69 | $ rhg files | head -n 1 |
|
69 | $ rhg files | head -n 1 | |
70 | ../../../file1 |
|
70 | ../../../file1 | |
71 |
|
71 | |||
72 | Debuging data in inline index |
|
72 | Debuging data in inline index | |
73 | $ cd $TESTTMP |
|
73 | $ cd $TESTTMP | |
74 | $ rm -rf repository |
|
74 | $ rm -rf repository | |
75 | $ hg init repository |
|
75 | $ hg init repository | |
76 | $ cd repository |
|
76 | $ cd repository | |
77 | $ for i in 1 2 3; do |
|
77 | $ for i in 1 2 3; do | |
78 | > echo $i >> file$i |
|
78 | > echo $i >> file$i | |
79 | > hg add file$i |
|
79 | > hg add file$i | |
80 | > hg commit -m "commit $i" -q |
|
80 | > hg commit -m "commit $i" -q | |
81 | > done |
|
81 | > done | |
82 | $ rhg debugdata -c 2 |
|
82 | $ rhg debugdata -c 2 | |
83 | e36fa63d37a576b27a69057598351db6ee5746bd |
|
83 | e36fa63d37a576b27a69057598351db6ee5746bd | |
84 | test |
|
84 | test | |
85 | 0 0 |
|
85 | 0 0 | |
86 | file3 |
|
86 | file3 | |
87 |
|
87 | |||
88 | commit 3 (no-eol) |
|
88 | commit 3 (no-eol) | |
89 | $ rhg debugdata -m 2 |
|
89 | $ rhg debugdata -m 2 | |
90 | file1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) |
|
90 | file1\x00b8e02f6433738021a065f94175c7cd23db5f05be (esc) | |
91 | file2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc) |
|
91 | file2\x005d9299349fc01ddd25d0070d149b124d8f10411e (esc) | |
92 | file3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc) |
|
92 | file3\x002661d26c649684b482d10f91960cc3db683c38b4 (esc) | |
93 |
|
93 | |||
94 | Debuging with full node id |
|
94 | Debuging with full node id | |
95 | $ rhg debugdata -c `hg log -r 0 -T '{node}'` |
|
95 | $ rhg debugdata -c `hg log -r 0 -T '{node}'` | |
96 | c8e64718e1ca0312eeee0f59d37f8dc612793856 |
|
96 | c8e64718e1ca0312eeee0f59d37f8dc612793856 | |
97 | test |
|
97 | test | |
98 | 0 0 |
|
98 | 0 0 | |
99 | file1 |
|
99 | file1 | |
100 |
|
100 | |||
101 | commit 1 (no-eol) |
|
101 | commit 1 (no-eol) | |
102 |
|
102 | |||
103 | Cat files |
|
103 | Cat files | |
104 | $ cd $TESTTMP |
|
104 | $ cd $TESTTMP | |
105 | $ rm -rf repository |
|
105 | $ rm -rf repository | |
106 | $ hg init repository |
|
106 | $ hg init repository | |
107 | $ cd repository |
|
107 | $ cd repository | |
108 | $ echo "original content" > original |
|
108 | $ echo "original content" > original | |
109 | $ hg add original |
|
109 | $ hg add original | |
110 | $ hg commit -m "add original" original |
|
110 | $ hg commit -m "add original" original | |
111 | $ rhg cat -r 0 original |
|
111 | $ rhg cat -r 0 original | |
112 | original content |
|
112 | original content | |
113 | Cat copied file should not display copy metadata |
|
113 | Cat copied file should not display copy metadata | |
114 | $ hg copy original copy_of_original |
|
114 | $ hg copy original copy_of_original | |
115 | $ hg commit -m "add copy of original" |
|
115 | $ hg commit -m "add copy of original" | |
116 | $ rhg cat -r 1 copy_of_original |
|
116 | $ rhg cat -r 1 copy_of_original | |
117 | original content |
|
117 | original content | |
|
118 | ||||
|
119 | Requirements | |||
|
120 | $ rhg debugrequirements | |||
|
121 | dotencode | |||
|
122 | fncache | |||
|
123 | generaldelta | |||
|
124 | revlogv1 | |||
|
125 | sparserevlog | |||
|
126 | store |
General Comments 0
You need to be logged in to leave comments.
Login now