1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
use std::{collections::HashSet, fmt};

use owo_colors::OwoColorize;

use crate::Command;

#[derive(Debug)]
pub enum RuntimeError {
    NonExistentCommand(Command),
    ProcessFailure(String, i32),
    RunScriptError(run_script::ScriptError),
    IoError(std::io::Error),
}

impl fmt::Display for RuntimeError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let m = match self {
            Self::NonExistentCommand(c) => {
                let command = match c {
                    Command::Local(n) => n.to_string(),
                    Command::External(ns, n) => format!("{n} from {ns}"),
                    Command::Internal(_) => panic!(),
                };

                format!("Unable to find the command {command}")
            }
            Self::ProcessFailure(p, ec) => {
                format!("Process `{p}` failed with error code {ec}")
            }
            Self::RunScriptError(e) => {
                format!("An issue regarding `run_script` occurred: {e}")
            }
            Self::IoError(e) => format!("{e}"),
        };
        writeln!(f, "{m}")
    }
}

impl From<std::io::Error> for RuntimeError {
    fn from(value: std::io::Error) -> Self {
        Self::IoError(value)
    }
}

impl From<run_script::ScriptError> for RuntimeError {
    fn from(value: run_script::ScriptError) -> Self {
        Self::RunScriptError(value)
    }
}

pub enum Notification {
    Start {
        build_goal: String,
    },
    TaskRun {
        task_name: String,
        dep_names: HashSet<String>,
    },
    DependencyRun {
        dep_name: String,
    },
    CommandRun {
        command: Command,
    },
    CommandDefinition {
        command: Command,
    },
    Completion,
    Fail {
        error: RuntimeError,
    },
}

impl Notification {
    pub fn print(&self) {
        eprintln!("{self}");
    }
}

impl fmt::Display for Notification {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let m = match self {
            Self::Start { build_goal } => {
                format!(
                    "{} Preparing to complete `{build_goal}`",
                    "    START    ".black().on_green()
                )
            }
            Self::TaskRun {
                task_name,
                dep_names,
            } => {
                format!(
                    "{} Running task `{task_name}` with dependencies `{dep_names:?}`",
                    "    TASK ↴   ".black().on_purple()
                )
            }
            Self::DependencyRun { dep_name } => {
                format!(
                    "{} Expanding dependency `{dep_name}` to task for execution",
                    " DEPDENDENCY ".black().on_yellow()
                )
            }
            Self::CommandRun { command } => {
                let ic = match command {
                    Command::Internal(ic) => ic,
                    _ => panic!(),
                };

                format!(
                    "{} Executing internal command: `{ic:?}`",
                    "   COMMAND   ".black().on_blue()
                )
            }
            Self::CommandDefinition { command } => {
                let c = match command {
                    Command::Local(l) => l.to_owned(),
                    Command::External(n, e) => format!("{n}.{e}"),
                    _ => panic!(),
                };

                format!(
                    "{} Expanding command definition `{c}`",
                    "   CMDDEF↴   ".black().on_bright_cyan()
                )
            }
            Self::Completion => {
                format!(
                    "{} All required tasks have been completed",
                    "    DONE ✓   ".black().on_green()
                )
            }
            Self::Fail { error } => {
                format!(
                    "{} An error occurred during runtime: {error:?}",
                    "    FAIL ✕   ".black().on_red()
                )
            }
        };

        write!(f, "{m}")
    }
}