1use std::fmt;
2use std::path::PathBuf;
3
4use colored::*;
5use failure::{Backtrace, Context, Fail};
6use semver::{Version, VersionReq};
7
8#[macro_export]
9macro_rules! bail {
10 ($err:expr) => {
11 return Err($err.into());
12 };
13}
14
15pub type Result<T> = std::result::Result<T, Error>;
16
17#[derive(Debug)]
18pub struct Error {
19 inner: Context<BuildErrorKind>,
20}
21
22#[derive(Debug, PartialEq, Fail, Clone)]
23pub enum BuildErrorKind {
24 CommandNotFound {
25 command: String,
26 hint: String,
27 },
28
29 CommandFailed {
30 command: String,
31 code: i32,
32 stderr: String,
33 },
34 CommandVersionNotFulfilled {
35 command: String,
36 current: Version,
37 required: VersionReq,
38 hint: String,
39 },
40
41 InvalidCratePath(PathBuf),
42 BuildFailed(Vec<String>),
43 InvalidCrateType(String),
44 MissingCrateType,
45 InternalError(String),
46 OtherError,
47}
48
49impl Fail for Error {
50 fn name(&self) -> Option<&str> {
51 self.inner.name()
52 }
53
54 fn cause(&self) -> Option<&Fail> {
55 self.inner.cause()
56 }
57
58 fn backtrace(&self) -> Option<&Backtrace> {
59 self.inner.backtrace()
60 }
61}
62
63impl fmt::Display for Error {
64 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
65 fmt::Display::fmt(&self.inner, formatter)
66 }
67}
68
69impl Error {
70 pub fn kind(&self) -> BuildErrorKind {
71 self.inner.get_context().clone()
72 }
73}
74
75impl From<BuildErrorKind> for Error {
76 fn from(kind: BuildErrorKind) -> Error {
77 Error {
78 inner: Context::new(kind),
79 }
80 }
81}
82
83impl From<Context<BuildErrorKind>> for Error {
84 fn from(inner: Context<BuildErrorKind>) -> Error {
85 Error { inner }
86 }
87}
88
89impl From<Context<String>> for Error {
90 fn from(inner: Context<String>) -> Error {
91 Error {
92 inner: inner.map(BuildErrorKind::InternalError),
93 }
94 }
95}
96
97impl<'a> From<Context<&'a str>> for Error {
98 fn from(inner: Context<&'a str>) -> Error {
99 Self::from(inner.map(String::from))
100 }
101}
102
103impl fmt::Display for BuildErrorKind {
104 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
105 use BuildErrorKind::*;
106
107 match self {
108 CommandNotFound { command, hint } => write!(
109 formatter,
110 "Command not found in PATH: '{}'. {}.",
111 command.bold(),
112 hint.underline()
113 ),
114
115 CommandFailed {
116 command,
117 code,
118 stderr,
119 } => write!(
120 formatter,
121 "Command failed: '{}' with code '{}' and output:\n{}",
122 command.bold(),
123 code,
124 stderr.trim(),
125 ),
126
127 CommandVersionNotFulfilled {
128 command,
129 current,
130 required,
131 hint,
132 } => write!(
133 formatter,
134 "Command version is not fulfilled: '{}' is currently '{}' but '{}' is required. {}.",
135 command.bold(),
136 current.to_string().underline(),
137 required.to_string().underline(),
138 hint.underline(),
139 ),
140
141 InvalidCratePath(path) => write!(
142 formatter,
143 "{}: {}",
144 "Invalid device crate path".bold(),
145 path.display()
146 ),
147
148 BuildFailed(lines) => write!(
149 formatter,
150 "{}\n{}",
151 "Unable to build a PTX crate!".bold(),
152 lines.join("\n")
153 ),
154
155 InvalidCrateType(crate_type) => write!(
156 formatter,
157 "{}: the crate cannot be build as '{}'",
158 "Impossible CrateType".bold(),
159 crate_type
160 ),
161
162 MissingCrateType => write!(
163 formatter,
164 "{}: it's mandatory for mixed-type crates",
165 "Missing CrateType".bold()
166 ),
167
168 InternalError(message) => write!(formatter, "{}: {}", "Internal error".bold(), message),
169 OtherError => write!(formatter, "Other error"),
170 }
171 }
172}