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
//! CI error types.

use miette::Diagnostic;

use super::pipeline::{CompileError, PipelineError};
use super::runtime::RuntimeError;
use quire_core::fennel::FennelError;
use quire_core::secret;

/// Errors produced by CI operations.
#[derive(Debug, thiserror::Error, Diagnostic)]
pub enum Error {
    #[error("io error: {0}")]
    Io(#[from] std::io::Error),

    #[error(transparent)]
    #[diagnostic(transparent)]
    Fennel(#[from] Box<FennelError>),

    #[error(transparent)]
    #[diagnostic(transparent)]
    Pipeline(Box<PipelineError>),

    #[error("run already dispatched")]
    AlreadyDispatched,

    #[error("run already resolved")]
    AlreadyResolved,

    #[error(transparent)]
    Lua(Box<mlua::Error>),

    #[error("workspace materialization failed: {source}")]
    WorkspaceMaterializationFailed {
        #[source]
        source: std::io::Error,
    },

    #[error("git error: {0}")]
    Git(String),

    #[error(transparent)]
    Yaml(#[from] serde_yaml_ng::Error),

    #[error(transparent)]
    Utf8(#[from] std::string::FromUtf8Error),

    #[error(transparent)]
    Sql(#[from] rusqlite::Error),

    #[error(transparent)]
    Secret(#[from] secret::Error),

    #[error("command spawn failed: {program} in {}: {source}", cwd.display())]
    CommandSpawnFailed {
        program: String,
        cwd: std::path::PathBuf,
        #[source]
        source: std::io::Error,
    },

    #[error("quire-ci exited with status {exit:?}")]
    ProcessFailed { exit: Option<i32> },

    #[error("failed to parse quire-ci event stream at {}: {source}", path.display())]
    EventStreamParse {
        path: std::path::PathBuf,
        #[source]
        source: serde_json::Error,
    },
}

pub type Result<T> = std::result::Result<T, Error>;

impl From<PipelineError> for Error {
    fn from(err: PipelineError) -> Self {
        Error::Pipeline(Box::new(err))
    }
}

impl From<CompileError> for Error {
    fn from(err: CompileError) -> Self {
        match err {
            CompileError::Fennel(e) => Error::Fennel(e),
            CompileError::Pipeline(e) => Error::Pipeline(e),
        }
    }
}

impl From<RuntimeError> for Error {
    fn from(err: RuntimeError) -> Self {
        match err {
            RuntimeError::Secret(e) => Error::Secret(e),
            RuntimeError::Lua(e) => Error::Lua(e),
            RuntimeError::CommandSpawnFailed {
                program,
                cwd,
                source,
            } => Error::CommandSpawnFailed {
                program,
                cwd,
                source,
            },
            RuntimeError::Git(s) => Error::Git(s),
            RuntimeError::LogWriteFailed { path, source } => Error::CommandSpawnFailed {
                program: "write-cri-log".to_string(),
                cwd: path,
                source,
            },
        }
    }
}

impl From<FennelError> for Error {
    fn from(err: FennelError) -> Self {
        Error::Fennel(Box::new(err))
    }
}

impl From<mlua::Error> for Error {
    fn from(err: mlua::Error) -> Self {
        Error::Lua(Box::new(err))
    }
}