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