##// END OF EJS Templates
rhg: ask the error message from `CommandError`...
Antoine Cezar -
r45920:47997afa default
parent child Browse files
Show More
@@ -1,9 +1,9 b''
1 1 pub mod root;
2 2 use crate::error::CommandError;
3 3
4 4 /// The common trait for rhg commands
5 5 ///
6 6 /// Normalize the interface of the commands provided by rhg
7 pub trait Command {
7 pub trait Command<'a> {
8 8 fn run(&self) -> Result<(), CommandError>;
9 9 }
@@ -1,76 +1,42 b''
1 1 use crate::commands::Command;
2 2 use crate::error::{CommandError, CommandErrorKind};
3 3 use crate::ui::Ui;
4 use hg::operations::{FindRoot, FindRootError, FindRootErrorKind};
4 use hg::operations::{FindRoot, FindRootErrorKind};
5 5 use hg::utils::files::get_bytes_from_path;
6 use std::path::PathBuf;
7 6
8 7 pub const HELP_TEXT: &str = "
9 8 Print the root directory of the current repository.
10 9
11 10 Returns 0 on success.
12 11 ";
13 12
14 pub struct RootCommand {
15 ui: Ui,
13 pub struct RootCommand<'a> {
14 ui: &'a Ui,
15 }
16
17 impl<'a> RootCommand<'a> {
18 pub fn new(ui: &'a Ui) -> Self {
19 RootCommand { ui }
20 }
16 21 }
17 22
18 impl RootCommand {
19 pub fn new() -> Self {
20 RootCommand { ui: Ui::new() }
21 }
23 impl<'a> Command<'a> for RootCommand<'a> {
24 fn run(&self) -> Result<(), CommandError> {
25 let path_buf =
26 FindRoot::new().run().map_err(|err| match err.kind {
27 FindRootErrorKind::RootNotFound(path) => {
28 CommandErrorKind::RootNotFound(path)
29 }
30 FindRootErrorKind::GetCurrentDirError(e) => {
31 CommandErrorKind::CurrentDirNotFound(e)
32 }
33 })?;
22 34
23 fn display_found_path(
24 &self,
25 path_buf: PathBuf,
26 ) -> Result<(), CommandError> {
27 35 let bytes = get_bytes_from_path(path_buf);
28 36
29 37 // TODO use formating macro
30 38 self.ui.write_stdout(&[bytes.as_slice(), b"\n"].concat())?;
31 39
32 40 Ok(())
33 41 }
34
35 fn display_error(&self, error: FindRootError) -> Result<(), CommandError> {
36 match error.kind {
37 FindRootErrorKind::RootNotFound(path) => {
38 let bytes = get_bytes_from_path(path);
39
40 // TODO use formating macro
41 self.ui.write_stderr(
42 &[
43 b"abort: no repository found in '",
44 bytes.as_slice(),
45 b"' (.hg not found)!\n",
46 ]
47 .concat(),
48 )?;
49
50 Err(CommandErrorKind::RootNotFound.into())
51 }
52 FindRootErrorKind::GetCurrentDirError(e) => {
53 // TODO use formating macro
54 self.ui.write_stderr(
55 &[
56 b"abort: error getting current working directory: ",
57 e.to_string().as_bytes(),
58 b"\n",
59 ]
60 .concat(),
61 )?;
62
63 Err(CommandErrorKind::CurrentDirNotFound.into())
64 }
65 }
66 }
67 42 }
68
69 impl Command for RootCommand {
70 fn run(&self) -> Result<(), CommandError> {
71 match FindRoot::new().run() {
72 Ok(path_buf) => self.display_found_path(path_buf),
73 Err(e) => self.display_error(e),
74 }
75 }
76 }
@@ -1,57 +1,92 b''
1 1 use crate::exitcode;
2 2 use crate::ui::UiError;
3 use hg::utils::files::get_bytes_from_path;
3 4 use std::convert::From;
5 use std::path::PathBuf;
4 6
5 7 /// The kind of command error
6 #[derive(Debug, PartialEq)]
8 #[derive(Debug)]
7 9 pub enum CommandErrorKind {
8 10 /// The root of the repository cannot be found
9 RootNotFound,
11 RootNotFound(PathBuf),
10 12 /// The current directory cannot be found
11 CurrentDirNotFound,
13 CurrentDirNotFound(std::io::Error),
12 14 /// The standard output stream cannot be written to
13 15 StdoutError,
14 16 /// The standard error stream cannot be written to
15 17 StderrError,
16 18 }
17 19
18 20 impl CommandErrorKind {
19 21 pub fn get_exit_code(&self) -> exitcode::ExitCode {
20 22 match self {
21 CommandErrorKind::RootNotFound => exitcode::ABORT,
22 CommandErrorKind::CurrentDirNotFound => exitcode::ABORT,
23 CommandErrorKind::RootNotFound(_) => exitcode::ABORT,
24 CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT,
23 25 CommandErrorKind::StdoutError => exitcode::ABORT,
24 26 CommandErrorKind::StderrError => exitcode::ABORT,
25 27 }
26 28 }
29
30 /// Return the message corresponding to the error kind if any
31 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
32 match self {
33 // TODO use formating macro
34 CommandErrorKind::RootNotFound(path) => {
35 let bytes = get_bytes_from_path(path);
36 Some(
37 [
38 b"abort: no repository found in '",
39 bytes.as_slice(),
40 b"' (.hg not found)!\n",
41 ]
42 .concat(),
43 )
44 }
45 // TODO use formating macro
46 CommandErrorKind::CurrentDirNotFound(e) => Some(
47 [
48 b"abort: error getting current working directory: ",
49 e.to_string().as_bytes(),
50 b"\n",
51 ]
52 .concat(),
53 ),
54 _ => None,
55 }
56 }
27 57 }
28 58
29 59 /// The error type for the Command trait
30 #[derive(Debug, PartialEq)]
60 #[derive(Debug)]
31 61 pub struct CommandError {
32 62 pub kind: CommandErrorKind,
33 63 }
34 64
35 65 impl CommandError {
36 66 /// Exist the process with the corresponding exit code.
37 67 pub fn exit(&self) -> () {
38 68 std::process::exit(self.kind.get_exit_code())
39 69 }
70
71 /// Return the message corresponding to the command error if any
72 pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
73 self.kind.get_error_message_bytes()
74 }
40 75 }
41 76
42 77 impl From<CommandErrorKind> for CommandError {
43 78 fn from(kind: CommandErrorKind) -> Self {
44 79 CommandError { kind }
45 80 }
46 81 }
47 82
48 83 impl From<UiError> for CommandError {
49 84 fn from(error: UiError) -> Self {
50 85 CommandError {
51 86 kind: match error {
52 87 UiError::StdoutError(_) => CommandErrorKind::StdoutError,
53 88 UiError::StderrError(_) => CommandErrorKind::StderrError,
54 89 },
55 90 }
56 91 }
57 92 }
@@ -1,42 +1,53 b''
1 1 use clap::App;
2 2 use clap::AppSettings;
3 3 use clap::SubCommand;
4 4
5 5 mod commands;
6 6 mod error;
7 7 mod exitcode;
8 8 mod ui;
9 9 use commands::Command;
10 10
11 11 fn main() {
12 12 let mut app = App::new("rhg")
13 13 .setting(AppSettings::AllowInvalidUtf8)
14 14 .setting(AppSettings::SubcommandRequired)
15 15 .setting(AppSettings::VersionlessSubcommands)
16 16 .version("0.0.1")
17 17 .subcommand(
18 18 SubCommand::with_name("root").about(commands::root::HELP_TEXT),
19 19 );
20 20
21 21 let matches = app.clone().get_matches_safe().unwrap_or_else(|_| {
22 22 std::process::exit(exitcode::UNIMPLEMENTED_COMMAND)
23 23 });
24 24
25 let ui = ui::Ui::new();
26
25 27 let command_result = match matches.subcommand_name() {
26 28 Some(name) => match name {
27 "root" => commands::root::RootCommand::new().run(),
29 "root" => commands::root::RootCommand::new(&ui).run(),
28 30 _ => std::process::exit(exitcode::UNIMPLEMENTED_COMMAND),
29 31 },
30 32 _ => {
31 33 match app.print_help() {
32 34 Ok(_) => std::process::exit(exitcode::OK),
33 35 Err(_) => std::process::exit(exitcode::ABORT),
34 36 };
35 37 }
36 38 };
37 39
38 40 match command_result {
39 41 Ok(_) => std::process::exit(exitcode::OK),
40 Err(e) => e.exit(),
42 Err(e) => {
43 let message = e.get_error_message_bytes();
44 if let Some(msg) = message {
45 match ui.write_stderr(&msg) {
46 Ok(_) => (),
47 Err(_) => std::process::exit(exitcode::ABORT),
48 };
49 };
50 e.exit()
51 }
41 52 }
42 53 }
General Comments 0
You need to be logged in to leave comments. Login now