Read about our upcoming Code of Conduct on this issue

This instance was upgraded to Heptapod 0.28.0 today

error.rs 4.21 KB
Newer Older
1
2
use crate::exitcode;
use crate::ui::UiError;
3
use hg::operations::{FindRootError, FindRootErrorKind};
4
use hg::requirements::RequirementsError;
5
use hg::utils::files::get_bytes_from_path;
6
use std::convert::From;
7
use std::path::PathBuf;
8
9

/// The kind of command error
10
#[derive(Debug)]
11
12
pub enum CommandErrorKind {
    /// The root of the repository cannot be found
13
    RootNotFound(PathBuf),
14
    /// The current directory cannot be found
15
    CurrentDirNotFound(std::io::Error),
16
17
    /// `.hg/requires`
    RequirementsError(RequirementsError),
18
19
20
21
    /// The standard output stream cannot be written to
    StdoutError,
    /// The standard error stream cannot be written to
    StderrError,
22
23
    /// The command aborted
    Abort(Option<Vec<u8>>),
24
25
    /// A mercurial capability as not been implemented.
    Unimplemented,
26
27
28
29
30
}

impl CommandErrorKind {
    pub fn get_exit_code(&self) -> exitcode::ExitCode {
        match self {
31
32
            CommandErrorKind::RootNotFound(_) => exitcode::ABORT,
            CommandErrorKind::CurrentDirNotFound(_) => exitcode::ABORT,
33
34
35
            CommandErrorKind::RequirementsError(
                RequirementsError::Unsupported { .. },
            ) => exitcode::UNIMPLEMENTED_COMMAND,
36
            CommandErrorKind::RequirementsError(_) => exitcode::ABORT,
37
38
            CommandErrorKind::StdoutError => exitcode::ABORT,
            CommandErrorKind::StderrError => exitcode::ABORT,
39
            CommandErrorKind::Abort(_) => exitcode::ABORT,
40
            CommandErrorKind::Unimplemented => exitcode::UNIMPLEMENTED_COMMAND,
41
42
        }
    }
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

    /// Return the message corresponding to the error kind if any
    pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
        match self {
            // TODO use formating macro
            CommandErrorKind::RootNotFound(path) => {
                let bytes = get_bytes_from_path(path);
                Some(
                    [
                        b"abort: no repository found in '",
                        bytes.as_slice(),
                        b"' (.hg not found)!\n",
                    ]
                    .concat(),
                )
            }
            // TODO use formating macro
            CommandErrorKind::CurrentDirNotFound(e) => Some(
                [
                    b"abort: error getting current working directory: ",
                    e.to_string().as_bytes(),
                    b"\n",
                ]
                .concat(),
            ),
68
69
70
71
72
            CommandErrorKind::RequirementsError(
                RequirementsError::Corrupted,
            ) => Some(
                "abort: .hg/requires is corrupted\n".as_bytes().to_owned(),
            ),
73
            CommandErrorKind::Abort(message) => message.to_owned(),
74
75
76
            _ => None,
        }
    }
77
78
}

79
/// The error type for the Command trait
80
#[derive(Debug)]
81
82
83
84
85
86
pub struct CommandError {
    pub kind: CommandErrorKind,
}

impl CommandError {
    /// Exist the process with the corresponding exit code.
Antoine Cezar's avatar
Antoine Cezar committed
87
    pub fn exit(&self) {
88
89
        std::process::exit(self.kind.get_exit_code())
    }
90
91
92
93
94

    /// Return the message corresponding to the command error if any
    pub fn get_error_message_bytes(&self) -> Option<Vec<u8>> {
        self.kind.get_error_message_bytes()
    }
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
}

impl From<CommandErrorKind> for CommandError {
    fn from(kind: CommandErrorKind) -> Self {
        CommandError { kind }
    }
}

impl From<UiError> for CommandError {
    fn from(error: UiError) -> Self {
        CommandError {
            kind: match error {
                UiError::StdoutError(_) => CommandErrorKind::StdoutError,
                UiError::StderrError(_) => CommandErrorKind::StderrError,
            },
        }
    }
}
113
114
115
116
117
118
119
120
121
122
123
124
125

impl From<FindRootError> for CommandError {
    fn from(err: FindRootError) -> Self {
        match err.kind {
            FindRootErrorKind::RootNotFound(path) => CommandError {
                kind: CommandErrorKind::RootNotFound(path),
            },
            FindRootErrorKind::GetCurrentDirError(e) => CommandError {
                kind: CommandErrorKind::CurrentDirNotFound(e),
            },
        }
    }
}
126
127
128
129
130
131
132
133

impl From<RequirementsError> for CommandError {
    fn from(err: RequirementsError) -> Self {
        CommandError {
            kind: CommandErrorKind::RequirementsError(err),
        }
    }
}