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    parse::ParseError,
7};
8use alloc::sync::Arc;
9use thiserror::Error;
10use tokio::{io, sync::AcquireError, task::JoinError};
11
12/// A build error.
13#[derive(Clone, Debug, Eq, Error, PartialEq)]
14pub enum BuildError {
15    /// A semaphore acquisition error.
16    #[error("{0}")]
17    Acquire(String),
18    /// A build failure.
19    #[error("build failed")]
20    Build,
21    /// A build graph error.
22    #[error(transparent)]
23    BuildGraph(#[from] BuildGraphError),
24    /// A circular module dependency.
25    #[error("build file dependency cycle detected")]
26    CircularModuleDependency,
27    /// A command error.
28    #[error(transparent)]
29    Command(#[from] CommandError),
30    /// A compile error.
31    #[error(transparent)]
32    Compile(#[from] CompileError),
33    /// A console error.
34    #[error(transparent)]
35    Console(#[from] ConsoleError),
36    /// A database error.
37    #[error(transparent)]
38    Database(#[from] DatabaseError),
39    /// A default output not found.
40    #[error("default output \"{0}\" not found")]
41    DefaultOutputNotFound(Arc<str>),
42    /// A dynamic dependency not found.
43    #[error(
44        "outputs {} not found in dynamic dependency file {}",
45        .0.outputs().join(", "),
46        .0.dynamic_module().unwrap()
47    )]
48    DynamicDependencyNotFound(Arc<Build>),
49    /// A file error.
50    #[error(transparent)]
51    File(#[from] FileError),
52    /// A file not found.
53    #[error("file \"{0}\" not found")]
54    FileNotFound(String),
55    /// An input not built.
56    #[error("input \"{0}\" not built yet")]
57    InputNotBuilt(String),
58    /// An input not found.
59    #[error("input \"{0}\" not found")]
60    InputNotFound(String),
61    /// An I/O error.
62    #[error("{0}")]
63    Io(String),
64    /// A task join error.
65    #[error("{0}")]
66    Join(String),
67    /// An output not found.
68    #[error("output \"{0}\" not found")]
69    OutputNotFound(String),
70    /// A parse error.
71    #[error(transparent)]
72    Parse(#[from] ParseError),
73}
74
75impl From<AcquireError> for BuildError {
76    fn from(error: AcquireError) -> Self {
77        Self::Acquire(error.to_string())
78    }
79}
80
81impl From<io::Error> for BuildError {
82    fn from(error: io::Error) -> Self {
83        Self::Io(error.to_string())
84    }
85}
86
87impl From<JoinError> for BuildError {
88    fn from(error: JoinError) -> Self {
89        Self::Join(error.to_string())
90    }
91}
92
93#[cfg(test)]
94mod tests {
95    use super::*;
96
97    #[test]
98    fn display_acquire() {
99        assert_eq!(
100            BuildError::Acquire("semaphore closed".into()).to_string(),
101            "semaphore closed"
102        );
103    }
104
105    #[test]
106    fn display_dynamic_dependency_not_found() {
107        assert_eq!(
108            BuildError::DynamicDependencyNotFound(
109                Build::new(
110                    vec!["foo".into(), "bar".into()],
111                    vec![],
112                    None,
113                    vec![],
114                    vec![],
115                    Some("baz".into())
116                )
117                .into()
118            )
119            .to_string(),
120            "outputs foo, bar not found in dynamic dependency file baz"
121        );
122    }
123
124    #[test]
125    fn display_io() {
126        assert_eq!(
127            BuildError::Io("permission denied".into()).to_string(),
128            "permission denied"
129        );
130    }
131
132    #[test]
133    fn display_join() {
134        assert_eq!(
135            BuildError::Join("task cancelled".into()).to_string(),
136            "task cancelled"
137        );
138    }
139}