Skip to main content

turtle_build/
error.rs

1use crate::{
2    build_graph::BuildGraphError,
3    compile::CompileError,
4    infrastructure::{CommandError, ConsoleError, DatabaseError, FileError},
5    ir::Build,
6    module_dependency::ModuleDependencyError,
7    parse::ParseError,
8};
9use alloc::sync::Arc;
10use core::{
11    error::Error,
12    fmt::{self, Display, Formatter},
13};
14use tokio::{io, sync::AcquireError, task::JoinError};
15
16/// A build error.
17#[derive(Clone, Debug, Eq, PartialEq)]
18pub enum BuildError {
19    /// A semaphore acquisition error.
20    Acquire(String),
21    /// A build failure.
22    Build,
23    /// A build graph error.
24    BuildGraph(BuildGraphError),
25    /// A command error.
26    Command(CommandError),
27    /// A compile error.
28    Compile(CompileError),
29    /// A console error.
30    Console(ConsoleError),
31    /// A database error.
32    Database(DatabaseError),
33    /// A default output not found.
34    DefaultOutputNotFound(Arc<str>),
35    /// A dynamic dependency not found.
36    DynamicDependencyNotFound(Arc<Build>),
37    /// A file error.
38    File(FileError),
39    /// A file not found.
40    FileNotFound(String),
41    /// An input not built.
42    InputNotBuilt(String),
43    /// An input not found.
44    InputNotFound(String),
45    /// An I/O error.
46    Io(String),
47    /// A task join error.
48    Join(String),
49    /// A module dependency error.
50    ModuleDependency(ModuleDependencyError),
51    /// An output not found.
52    OutputNotFound(String),
53    /// A parse error.
54    Parse(ParseError),
55}
56
57impl Error for BuildError {}
58
59impl Display for BuildError {
60    fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
61        match self {
62            Self::Acquire(message) | Self::Io(message) | Self::Join(message) => {
63                write!(formatter, "{message}")
64            }
65            Self::Build => write!(formatter, "build failed"),
66            Self::Command(error) => write!(formatter, "{error}"),
67            Self::Compile(error) => write!(formatter, "{error}"),
68            Self::Console(error) => write!(formatter, "{error}"),
69            Self::Database(error) => write!(formatter, "{error}"),
70            Self::DefaultOutputNotFound(output) => {
71                write!(formatter, "default output \"{output}\" not found")
72            }
73            Self::DynamicDependencyNotFound(build) => {
74                write!(
75                    formatter,
76                    "outputs {} not found in dynamic dependency file {}",
77                    build.outputs().join(", "),
78                    build.dynamic_module().unwrap()
79                )
80            }
81            Self::File(error) => write!(formatter, "{error}"),
82            Self::FileNotFound(path) => write!(formatter, "file \"{path}\" not found"),
83            Self::InputNotBuilt(input) => {
84                write!(formatter, "input \"{input}\" not built yet")
85            }
86            Self::InputNotFound(input) => {
87                write!(formatter, "input \"{input}\" not found")
88            }
89            Self::ModuleDependency(error) => {
90                write!(formatter, "{error}")
91            }
92            Self::OutputNotFound(output) => {
93                write!(formatter, "output \"{output}\" not found")
94            }
95            Self::Parse(error) => write!(formatter, "{error}"),
96            Self::BuildGraph(error) => write!(formatter, "{error}"),
97        }
98    }
99}
100
101impl From<AcquireError> for BuildError {
102    fn from(error: AcquireError) -> Self {
103        Self::Acquire(error.to_string())
104    }
105}
106
107impl From<CommandError> for BuildError {
108    fn from(error: CommandError) -> Self {
109        Self::Command(error)
110    }
111}
112
113impl From<CompileError> for BuildError {
114    fn from(error: CompileError) -> Self {
115        Self::Compile(error)
116    }
117}
118
119impl From<ConsoleError> for BuildError {
120    fn from(error: ConsoleError) -> Self {
121        Self::Console(error)
122    }
123}
124
125impl From<DatabaseError> for BuildError {
126    fn from(error: DatabaseError) -> Self {
127        Self::Database(error)
128    }
129}
130
131impl From<FileError> for BuildError {
132    fn from(error: FileError) -> Self {
133        Self::File(error)
134    }
135}
136
137impl From<io::Error> for BuildError {
138    fn from(error: io::Error) -> Self {
139        Self::Io(error.to_string())
140    }
141}
142
143impl From<JoinError> for BuildError {
144    fn from(error: JoinError) -> Self {
145        Self::Join(error.to_string())
146    }
147}
148
149impl From<ModuleDependencyError> for BuildError {
150    fn from(error: ModuleDependencyError) -> Self {
151        Self::ModuleDependency(error)
152    }
153}
154
155impl From<ParseError> for BuildError {
156    fn from(error: ParseError) -> Self {
157        Self::Parse(error)
158    }
159}
160
161impl From<BuildGraphError> for BuildError {
162    fn from(error: BuildGraphError) -> Self {
163        Self::BuildGraph(error)
164    }
165}
166
167#[cfg(test)]
168mod tests {
169    use super::*;
170
171    #[test]
172    fn display_acquire() {
173        assert_eq!(
174            BuildError::Acquire("semaphore closed".into()).to_string(),
175            "semaphore closed"
176        );
177    }
178
179    #[test]
180    fn display_io() {
181        assert_eq!(
182            BuildError::Io("permission denied".into()).to_string(),
183            "permission denied"
184        );
185    }
186
187    #[test]
188    fn display_join() {
189        assert_eq!(
190            BuildError::Join("task cancelled".into()).to_string(),
191            "task cancelled"
192        );
193    }
194}