use crate::format_string::FormatString;
use serde::Deserialize;
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct Action {
pub command: FormatString,
pub args: Option<Vec<FormatString>>,
pub cancelation: Option<CancelationMode>,
pub timeout: Option<FormatString>,
}
#[derive(Debug, Clone)]
pub enum CancelationMode {
Terminate,
NotifyThenTerminate {
notify_period_in_seconds: Option<FormatString>,
},
}
impl<'de> Deserialize<'de> for CancelationMode {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
use std::collections::HashMap;
let map = HashMap::<String, serde_json::Value>::deserialize(deserializer)?;
let mode = map
.get("mode")
.and_then(|v| v.as_str())
.ok_or_else(|| serde::de::Error::missing_field("mode"))?;
match mode {
"TERMINATE" => {
let extra: Vec<_> = map.keys().filter(|k| *k != "mode").collect();
if !extra.is_empty() {
return Err(serde::de::Error::custom(format!(
"unknown field `{}`, TERMINATE accepts no additional fields",
extra[0]
)));
}
Ok(CancelationMode::Terminate)
}
"NOTIFY_THEN_TERMINATE" => {
let extra: Vec<_> = map
.keys()
.filter(|k| *k != "mode" && *k != "notifyPeriodInSeconds")
.collect();
if !extra.is_empty() {
return Err(serde::de::Error::custom(format!(
"unknown field `{}`, expected `notifyPeriodInSeconds`",
extra[0]
)));
}
let notify = map
.get("notifyPeriodInSeconds")
.map(|v| FormatString::deserialize(v.clone()))
.transpose()
.map_err(serde::de::Error::custom)?;
Ok(CancelationMode::NotifyThenTerminate {
notify_period_in_seconds: notify,
})
}
other => Err(serde::de::Error::custom(format!(
"unknown variant `{other}`, expected `TERMINATE` or `NOTIFY_THEN_TERMINATE`"
))),
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct StepActions {
pub on_run: Action,
}
#[derive(Debug, Clone, Deserialize)]
#[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct EnvironmentActions {
pub on_enter: Option<Action>,
pub on_exit: Option<Action>,
}