1use owo_colors::OwoColorize;
2use proplate_tui::logger::{self, AsError};
3
4#[derive(Debug, Clone)]
5pub enum TemplateErrorKind {
6 NotFound { is_remote: bool },
7 Invalid,
8 NoConfig,
9}
10
11#[derive(Debug, Clone)]
12pub enum CliErrorKind {
13 Prompt,
14}
15
16#[derive(Debug, Clone)]
17pub enum ProplateErrorKind {
18 Cli(CliErrorKind),
19 Template {
20 kind: TemplateErrorKind,
21 location: String,
22 },
23 Fs {
24 concerned_paths: Vec<String>,
25 operation: String,
26 },
27 Git {
28 cmd: String,
29 raw_stderr: String,
30 },
31}
32
33impl ToString for ProplateErrorKind {
34 fn to_string(&self) -> String {
35 let str = match self {
36 ProplateErrorKind::Cli(_) => "Cli",
37 ProplateErrorKind::Template { .. } => "Template",
38 ProplateErrorKind::Fs { .. } => "Fs",
39 ProplateErrorKind::Git { .. } => "Git",
40 };
41 str.into()
42 }
43}
44
45#[derive(Debug)]
46pub struct ProplateError {
47 kind: ProplateErrorKind,
48 cause: Option<String>,
49 ctx: Option<String>,
50}
51
52pub type ProplateResult<T> = Result<T, ProplateError>;
53
54impl ProplateError {
55 pub fn create(kind: ProplateErrorKind) -> ProplateError {
56 Self {
57 kind,
58 cause: None,
59 ctx: None,
60 }
61 }
62
63 pub fn with_ctx(mut self, ctx: &str) -> Self {
64 self.ctx = Some(ctx.into());
65 self
66 }
67
68 pub fn with_cause(mut self, cause: &str) -> Self {
69 self.cause = Some(cause.into());
70 self
71 }
72
73 pub fn has_ctx(&self) -> bool {
74 self.ctx.is_some()
75 }
76
77 pub fn has_cause(&self) -> bool {
78 self.cause.is_some()
79 }
80}
81
82impl AsError for ProplateError {
83 fn print_err(&self) -> String {
84 let contextual = match self.kind.clone() {
85 ProplateErrorKind::Template { kind, location } => match kind {
86 TemplateErrorKind::NotFound { is_remote } => {
87 let location_spec = match is_remote {
88 true => "remote",
89 false => "",
90 };
91 format!("{} template '{}' cannot be found", location_spec, location)
92 .trim()
93 .into()
94 }
95 TemplateErrorKind::Invalid => {
96 format!("template at '{}' config (meta.json) is not valid", location)
97 }
98
99 TemplateErrorKind::NoConfig => {
100 format!("template at '{}' has no config file", location)
101 }
102 },
103
104 ProplateErrorKind::Cli(kind) => match kind {
105 CliErrorKind::Prompt => format!("a problem occured when prompting the user"),
106 },
107
108 ProplateErrorKind::Fs {
109 concerned_paths,
110 operation,
111 } => format!(
112 "op '{}' cannot be done\n\nConcerned paths are:\n\n{}",
113 operation,
114 concerned_paths
115 .iter()
116 .map(|p| format!("- {}", p))
117 .collect::<Vec<_>>()
118 .join("\n")
119 ),
120
121 ProplateErrorKind::Git { cmd, raw_stderr } => {
122 format!("command '{}' failed with git err:\n\n{}", cmd, raw_stderr)
123 }
124 };
125
126 let kind = format!("Error: `{}`", self.kind.to_string());
127 let ctx = match self.ctx.clone() {
128 Some(_ctx) => format!("\n\nCtx: {}", &_ctx.bold()),
129 _ => "".into(),
130 };
131 let cause = match self.cause.clone() {
132 Some(_cause) => format!("\n\nCause:\n{}", &_cause).red().to_string(),
133 _ => "".into(),
134 };
135
136 logger::error(&format!("\n{kind}\n{contextual}{ctx}{cause}"))
137 }
138}