use ossctl_core::SCHEMA_VERSION;
use serde::Serialize;
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum ExitKind {
User = 1,
System = 2,
}
#[derive(Debug, Serialize)]
struct ErrorPayload<'a> {
schema_version: u32,
error: ErrorBody<'a>,
}
#[derive(Debug, Serialize)]
struct ErrorBody<'a> {
code: &'a str,
message: &'a str,
#[serde(skip_serializing_if = "Option::is_none")]
invalid_value: Option<&'a str>,
#[serde(skip_serializing_if = "Option::is_none")]
expected: Option<&'a serde_json::Value>,
#[serde(skip_serializing_if = "Option::is_none")]
problems: Option<&'a [String]>,
}
#[derive(Debug)]
pub struct CliError {
pub kind: ExitKind,
pub code: String,
pub message: String,
pub invalid_value: Option<String>,
pub expected: Option<Box<serde_json::Value>>,
pub problems: Option<Vec<String>>,
}
impl CliError {
pub fn user(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
kind: ExitKind::User,
code: code.into(),
message: message.into(),
invalid_value: None,
expected: None,
problems: None,
}
}
pub fn system(code: impl Into<String>, message: impl Into<String>) -> Self {
Self {
kind: ExitKind::System,
code: code.into(),
message: message.into(),
invalid_value: None,
expected: None,
problems: None,
}
}
pub fn with_invalid_value(mut self, value: impl Into<String>) -> Self {
self.invalid_value = Some(value.into());
self
}
pub fn with_expected(mut self, expected: serde_json::Value) -> Self {
self.expected = Some(Box::new(expected));
self
}
pub fn with_problems(mut self, problems: Vec<String>) -> Self {
self.problems = Some(problems);
self
}
pub fn emit(&self) {
let payload = ErrorPayload {
schema_version: SCHEMA_VERSION,
error: ErrorBody {
code: &self.code,
message: &self.message,
invalid_value: self.invalid_value.as_deref(),
expected: self.expected.as_deref(),
problems: self.problems.as_deref(),
},
};
match serde_json::to_string(&payload) {
Ok(s) => eprintln!("{s}"),
Err(_) => eprintln!(
"{{\"schema_version\":{SCHEMA_VERSION},\"error\":{{\"code\":\"internal_serialize\",\"message\":\"failed to serialize error envelope\"}}}}"
),
}
}
}