use std::path::PathBuf;
use thiserror::Error;
pub type Result<T> = std::result::Result<T, Error>;
#[derive(Error, Debug)]
pub enum Error {
#[error("Failed to connect to BuildKit at {endpoint}: {source}")]
Connection {
endpoint: String,
#[source]
source: tonic::transport::Error,
},
#[error("Invalid BuildKit endpoint URL: {0}")]
InvalidEndpoint(String),
#[error("gRPC communication failed: {0}")]
Grpc(Box<tonic::Status>),
#[error("Session error: {0}")]
Session(String),
#[error("Session has not been started")]
SessionNotStarted,
#[error("File system error: {0}")]
Io(#[from] std::io::Error),
#[error("Path does not exist: {0}")]
PathNotFound(PathBuf),
#[error("Path is not a directory: {0}")]
NotADirectory(PathBuf),
#[error("Path {path} is outside root directory")]
PathOutsideRoot { path: String },
#[error("Failed to resolve absolute path for {path}: {source}")]
PathResolution {
path: PathBuf,
#[source]
source: std::io::Error,
},
#[error("Build execution failed: {0}")]
Build(String),
#[error("Invalid build configuration: {0}")]
InvalidConfig(String),
#[error("Invalid platform format: {0}")]
InvalidPlatform(String),
#[error("Progress monitoring failed: {0}")]
Progress(String),
#[error("Protocol error: {0}")]
Protocol(String),
#[error("HTTP/2 handshake failed: {source}")]
Http2Handshake {
#[source]
source: h2::Error,
},
#[error("HTTP/2 stream error: {source}")]
Http2Stream {
#[source]
source: h2::Error,
},
#[error("Failed to send {message_type}: {reason}")]
SendFailed {
message_type: String,
reason: String,
},
#[error("Failed to decode {message_type}: {source}")]
Decode {
message_type: String,
#[source]
source: prost::DecodeError,
},
#[error("Failed to encode {message_type}: {source}")]
Encode {
message_type: String,
#[source]
source: prost::EncodeError,
},
#[error("Secrets error: {0}")]
Secrets(String),
#[error("Secret not found: {0}")]
SecretNotFound(String),
#[error("Secrets service is not configured")]
SecretsNotConfigured,
#[error("{0}")]
Other(String),
}
impl Error {
pub fn session(msg: impl Into<String>) -> Self {
Error::Session(msg.into())
}
pub fn build(msg: impl Into<String>) -> Self {
Error::Build(msg.into())
}
pub fn protocol(msg: impl Into<String>) -> Self {
Error::Protocol(msg.into())
}
pub fn progress(msg: impl Into<String>) -> Self {
Error::Progress(msg.into())
}
pub fn secrets(msg: impl Into<String>) -> Self {
Error::Secrets(msg.into())
}
pub fn send_failed(message_type: impl Into<String>, reason: impl Into<String>) -> Self {
Error::SendFailed {
message_type: message_type.into(),
reason: reason.into(),
}
}
pub fn decode(message_type: impl Into<String>, source: prost::DecodeError) -> Self {
Error::Decode {
message_type: message_type.into(),
source,
}
}
pub fn encode(message_type: impl Into<String>, source: prost::EncodeError) -> Self {
Error::Encode {
message_type: message_type.into(),
source,
}
}
pub fn other(msg: impl Into<String>) -> Self {
Error::Other(msg.into())
}
}
impl From<prost::EncodeError> for Error {
fn from(e: prost::EncodeError) -> Self {
Error::Encode {
message_type: "unknown".to_string(),
source: e,
}
}
}
impl From<prost::DecodeError> for Error {
fn from(e: prost::DecodeError) -> Self {
Error::Decode {
message_type: "unknown".to_string(),
source: e,
}
}
}
impl From<tonic::Status> for Error {
fn from(status: tonic::Status) -> Self {
Error::Grpc(Box::new(status))
}
}