use std::error::Error;
use std::fmt::{Display, Formatter, Result as FResult};
use std::path::PathBuf;
use brane_ast::DataType;
use specifications::container::LocalContainerInfoError;
use specifications::package::PackageKind;
#[derive(Debug)]
pub enum LetError {
JuiceFSLaunchError { command: String, err: std::io::Error },
JuiceFSError { command: String, code: i32, stdout: String, stderr: String },
RedirectorError { address: String, err: String },
ArgumentsBase64Error { err: base64::DecodeError },
ArgumentsUTF8Error { err: std::string::FromUtf8Error },
ArgumentsJSONError { err: serde_json::Error },
LocalContainerInfoError { path: PathBuf, err: LocalContainerInfoError },
PackageInfoError { err: anyhow::Error },
MissingFunctionsProperty { path: PathBuf },
UnknownFunction { function: String, package: String, kind: PackageKind },
MissingInputArgument { function: String, package: String, kind: PackageKind, name: String },
IncompatibleTypes { function: String, package: String, kind: PackageKind, name: String, expected: DataType, got: DataType },
WorkdirInitLaunchError { command: String, err: std::io::Error },
WorkdirInitError { command: String, code: i32, stdout: String, stderr: String },
EntrypointPathError { path: PathBuf, err: std::io::Error },
DuplicateArgument { name: String },
DuplicateArrayArgument { array: String, elem: usize, name: String },
DuplicateStructArgument { sname: String, field: String, name: String },
UnsupportedType { argument: String, elem_type: DataType },
UnsupportedNestedArray { elem: usize },
UnsupportedArrayElement { elem: usize, elem_type: String },
UnsupportedStructArray { name: String, field: String },
UnsupportedNestedStruct { name: String, field: String },
UnsupportedStructField { name: String, field: String, elem_type: String },
IllegalNestedURL { name: String, field: String },
PackageLaunchError { command: String, err: std::io::Error },
IllegalOasDocument { path: PathBuf, err: anyhow::Error },
PackageRunError { err: std::io::Error },
ClosedStdout,
ClosedStderr,
StdoutReadError { err: std::io::Error },
StderrReadError { err: std::io::Error },
DecodeError { stdout: String, err: serde_yaml::Error },
OasDecodeError { stdout: String, err: serde_json::Error },
UnsupportedMultipleOutputs { n: usize },
SerializeError { argument: String, data_type: DataType, err: serde_json::Error },
ArraySerializeError { argument: String, err: serde_json::Error },
ClassSerializeError { argument: String, class: String, err: serde_json::Error },
ResultJSONError { value: String, err: serde_json::Error },
}
impl Display for LetError {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
use LetError::*;
match self {
JuiceFSLaunchError { command, err } => write!(f, "Could not run JuiceFS command '{command}': {err}"),
JuiceFSError { command, code, stdout, stderr } => write!(
f,
"JuiceFS command '{}' returned exit code {}:\n\nstdout:\n{}\n{}\n{}\n\nstderr:\n{}\n{}\n{}\n\n",
command,
code,
(0..80).map(|_| '-').collect::<String>(),
stdout,
(0..80).map(|_| '-').collect::<String>(),
(0..80).map(|_| '-').collect::<String>(),
stderr,
(0..80).map(|_| '-').collect::<String>()
),
RedirectorError { address, err } => write!(f, "Could not start redirector to '{address}' in the background: {err}"),
ArgumentsBase64Error { err } => write!(f, "Could not decode input arguments as Base64: {err}"),
ArgumentsUTF8Error { err } => write!(f, "Could not decode input arguments as UTF-8: {err}"),
ArgumentsJSONError { err } => write!(f, "Could not parse input arguments as JSON: {err}"),
LocalContainerInfoError { path, err } => write!(f, "Could not load local container information file '{}': {}", path.display(), err),
PackageInfoError { err } => write!(f, "Could not parse package information file from Open-API document: {err}"),
MissingFunctionsProperty { path } => write!(f, "Missing property 'functions' in package information file '{}'", path.display()),
UnknownFunction { function, package, kind } => write!(f, "Unknown function '{}' in package '{}' ({})", function, package, kind.pretty()),
MissingInputArgument { function, package, kind, name } => {
write!(f, "Parameter '{}' not specified for function '{}' in package '{}' ({})", name, function, package, kind.pretty())
},
IncompatibleTypes { function, package, kind, name, expected, got } => write!(
f,
"Type check failed for parameter '{}' of function '{}' in package '{}' ({}): expected {}, got {}",
name,
function,
package,
kind.pretty(),
expected,
got
),
WorkdirInitLaunchError { command, err } => write!(f, "Could not run init.sh ('{command}'): {err}"),
WorkdirInitError { command, code, stdout, stderr } => write!(
f,
"init.sh ('{}') returned exit code {}:\n\nstdout:\n{}\n{}\n{}\n\nstderr:\n{}\n{}\n{}\n\n",
command,
code,
(0..80).map(|_| '-').collect::<String>(),
stdout,
(0..80).map(|_| '-').collect::<String>(),
(0..80).map(|_| '-').collect::<String>(),
stderr,
(0..80).map(|_| '-').collect::<String>()
),
EntrypointPathError { path, err } => write!(f, "Could not canonicalize path '{}': {}", path.display(), err),
DuplicateArgument { name } => write!(
f,
"Encountered duplicate function argument '{name}'; make sure your names don't conflict in case-insensitive scenarios either"
),
DuplicateArrayArgument { array, elem, name } => write!(
f,
"Element {elem} of array '{array}' has the same name as environment variable '{name}'; remember that arrays generate new arguments \
for each element"
),
DuplicateStructArgument { sname, field, name } => write!(
f,
"Field '{field}' of struct '{sname}' has the same name as environment variable '{name}'; remember that structs generate new \
arguments for each field"
),
UnsupportedType { argument, elem_type } => {
write!(f, "Argument '{argument}' has type '{elem_type}'; this type is not (yet) supported, please use other types")
},
UnsupportedNestedArray { elem } => {
write!(f, "Element {elem} of array is an array; nested arrays are not (yet) supported, please use flat arrays only")
},
UnsupportedArrayElement { elem, elem_type } => {
write!(f, "Element {elem} of array has type '{elem_type}'; this type is not (yet) supported in arrays, please use other types")
},
UnsupportedStructArray { name, field } => write!(
f,
"Field '{field}' of struct '{name}' is an array; nested arrays in structs are not (yet) supported, please pass arrays separately as \
flat arrays"
),
UnsupportedNestedStruct { name, field } => write!(
f,
"Field '{field}' of struct '{name}' is a non-File, non-Directory struct; nested structs are not (yet) supported, please pass \
structs separately"
),
UnsupportedStructField { name, field, elem_type } => write!(
f,
"Field '{field}' of struct '{name}' has type '{elem_type}'; this type is not (yet) supported in structs, please use other types"
),
IllegalNestedURL { name, field } => {
write!(f, "Field '{field}' of struct '{name}' is a Directory or a File struct, but misses the 'URL' field")
},
PackageLaunchError { command, err } => write!(f, "Could not run nested package call '{command}': {err}"),
IllegalOasDocument { path, err } => write!(f, "Could not parse OpenAPI specification '{}': {}", path.display(), err),
ClosedStdout => write!(f, "Could not open subprocess stdout"),
ClosedStderr => write!(f, "Could not open subprocess stdout"),
StdoutReadError { err } => write!(f, "Could not read from stdout: {err}"),
StderrReadError { err } => write!(f, "Could not read from stderr: {err}"),
PackageRunError { err } => write!(f, "Could not get package run status: {err}"),
DecodeError { stdout, err } => write!(
f,
"Could not parse package stdout: {}\n\nstdout:\n{}\n{}\n{}\n\n",
err,
(0..80).map(|_| '-').collect::<String>(),
stdout,
(0..80).map(|_| '-').collect::<String>()
),
OasDecodeError { stdout, err } => write!(
f,
"Could not parse package stdout: {}\n\nstdout:\n{}\n{}\n{}\n\n",
err,
(0..80).map(|_| '-').collect::<String>(),
stdout,
(0..80).map(|_| '-').collect::<String>()
),
UnsupportedMultipleOutputs { n } => write!(f, "Function return {n} outputs; this is not (yet) supported, please return only one"),
SerializeError { argument, data_type, err } => write!(f, "Failed to serialize argument '{argument}' ({data_type}) to JSON: {err}"),
ArraySerializeError { argument, err } => write!(f, "Failed to serialize Array in argument '{argument}' to JSON: {err}"),
ClassSerializeError { argument, class, err } => write!(f, "Failed to serialize Class '{class}' in argument '{argument}' to JSON: {err}"),
ResultJSONError { value, err } => write!(f, "Could not serialize value '{value}' to JSON: {err}"),
}
}
}
impl Error for LetError {}
#[derive(Debug)]
pub enum DecodeError {
InvalidYAML { err: yaml_rust::ScanError },
InvalidJSON { err: serde_json::Error },
NotAHash,
MissingOutputArgument { name: String },
OutputTypeMismatch { name: String, expected: String, got: String },
UnknownClassType { name: String, class_name: String },
MissingStructProperty { name: String, class_name: String, property_name: String },
}
impl Display for DecodeError {
fn fmt(&self, f: &mut Formatter<'_>) -> FResult {
match self {
DecodeError::InvalidYAML { err } => write!(f, "Invalid YAML: {err}"),
DecodeError::InvalidJSON { err } => write!(f, "Invalid JSON: {err}"),
DecodeError::NotAHash => write!(f, "Top-level YAML is not a valid hash"),
DecodeError::MissingOutputArgument { name } => write!(f, "Missing output argument '{name}' in function output"),
DecodeError::OutputTypeMismatch { name, expected, got } => {
write!(f, "Function output '{name}' has type '{got}', but expected type '{expected}'")
},
DecodeError::UnknownClassType { name, class_name } => {
write!(f, "Function output '{name}' has object type '{class_name}', but that object type is undefined")
},
DecodeError::MissingStructProperty { name, class_name, property_name } => {
write!(f, "Function output '{name}' has object type '{class_name}', but is missing property '{property_name}'")
},
}
}
}
impl Error for DecodeError {}