202 lines
7.6 KiB
Rust
202 lines
7.6 KiB
Rust
use std::borrow::Cow;
|
|
|
|
use color_eyre::eyre::{self, Context};
|
|
use serde::Deserialize;
|
|
use serde_json::value::RawValue;
|
|
use serde_repr::Deserialize_repr;
|
|
|
|
use crate::action::{Action, ActionType, BuildStepId, ResultFields, StartFields};
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
#[serde(rename_all = "lowercase")]
|
|
pub enum RawActionType {
|
|
Msg,
|
|
Start,
|
|
Result,
|
|
Stop,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize_repr)]
|
|
#[repr(u8)]
|
|
pub enum RawEnumType {
|
|
FileLinked = 100,
|
|
BuildLogLine = 101,
|
|
UntrustedPath = 102,
|
|
CorruptedPath = 103,
|
|
SetPhase = 104,
|
|
Progress = 105,
|
|
SetExpected = 106,
|
|
PostBuildLogLine = 107,
|
|
FetchStatus = 108,
|
|
}
|
|
|
|
#[derive(Debug, Deserialize)]
|
|
#[serde(tag = "action", rename_all = "lowercase")]
|
|
pub struct RawAction<'a> {
|
|
#[serde(rename = "action")]
|
|
pub action_type: RawActionType,
|
|
pub level: Option<u8>,
|
|
pub msg: Option<Cow<'a, str>>,
|
|
pub id: Option<BuildStepId>,
|
|
pub parent: Option<BuildStepId>,
|
|
pub text: Option<Cow<'a, str>>,
|
|
#[serde(borrow)]
|
|
pub fields: Option<&'a RawValue>,
|
|
#[serde(rename = "type")]
|
|
pub any_type: Option<u8>,
|
|
}
|
|
|
|
impl<'a> TryFrom<RawAction<'a>> for Action<'a> {
|
|
type Error = color_eyre::Report;
|
|
|
|
fn try_from(val: RawAction<'a>) -> Result<Self, Self::Error> {
|
|
let missing = |field: &'static str| eyre::eyre!("missing field `{field}`");
|
|
|
|
let action = match val.action_type {
|
|
RawActionType::Msg => Action::Msg {
|
|
level: val.level.ok_or_else(|| missing("level"))?,
|
|
msg: val.msg.ok_or_else(|| missing("msg"))?,
|
|
},
|
|
|
|
RawActionType::Start => {
|
|
let start_type: ActionType =
|
|
serde_json::from_value(val.any_type.ok_or_else(|| missing("type"))?.into())
|
|
.context("invalid type")?;
|
|
|
|
let start_type = match start_type {
|
|
ActionType::Unknown => StartFields::Unknown,
|
|
ActionType::CopyPath => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let (path, origin, destination) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
StartFields::CopyPath {
|
|
path,
|
|
origin,
|
|
destination,
|
|
}
|
|
}
|
|
ActionType::FileTransfer => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let [target] =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
StartFields::FileTransfer { target }
|
|
}
|
|
ActionType::Realise => StartFields::Realise,
|
|
ActionType::CopyPaths => StartFields::CopyPaths,
|
|
ActionType::Builds => StartFields::Builds,
|
|
ActionType::Build => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let (target, source, val1, val2) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
StartFields::Build {
|
|
target,
|
|
source,
|
|
val1,
|
|
val2,
|
|
}
|
|
}
|
|
ActionType::OptimiseStore => StartFields::OptimiseStore,
|
|
ActionType::VerifyPaths => StartFields::VerifyPaths,
|
|
ActionType::Substitute => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let (source, target) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
StartFields::Substitute { source, target }
|
|
}
|
|
ActionType::QueryPathInfo => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let (path, source) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
StartFields::QueryPathInfo { path, source }
|
|
}
|
|
ActionType::PostBuildHook => StartFields::PostBuildHook,
|
|
ActionType::BuildWaiting => StartFields::BuildWaiting,
|
|
ActionType::FetchTree => StartFields::FetchTree,
|
|
};
|
|
|
|
Action::Start {
|
|
start_type,
|
|
id: val.id.ok_or_else(|| missing("id"))?,
|
|
level: val.level.ok_or_else(|| missing("level"))?,
|
|
parent: val.parent.ok_or_else(|| missing("parent"))?,
|
|
text: val.text.ok_or_else(|| missing("text"))?,
|
|
}
|
|
}
|
|
|
|
RawActionType::Result => {
|
|
let raw_fields = val.fields.ok_or_else(|| missing("fields"))?.get();
|
|
|
|
let fields = match val.any_type.ok_or_else(|| missing("type"))? {
|
|
100 => {
|
|
let (val1, val2) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::FileLinked { val1, val2 }
|
|
}
|
|
101 => {
|
|
let [line] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::BuildLogLine(line)
|
|
}
|
|
102 => {
|
|
let [path] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::UntrustedPath(path)
|
|
}
|
|
103 => {
|
|
let [path] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::CorruptedPath(path)
|
|
}
|
|
104 => {
|
|
let [phase] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::SetPhase(phase)
|
|
}
|
|
105 => {
|
|
let (done, expected, running, failed) =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
|
|
ResultFields::Progress {
|
|
done,
|
|
expected,
|
|
running,
|
|
failed,
|
|
}
|
|
}
|
|
106 => {
|
|
let (action, expected) = serde_json::from_str(raw_fields).unwrap();
|
|
ResultFields::SetExpected { action, expected }
|
|
}
|
|
107 => {
|
|
let [line] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::PostBuildLogLine(line)
|
|
}
|
|
108 => {
|
|
let [status] =
|
|
serde_json::from_str(raw_fields).context("invalid fields")?;
|
|
ResultFields::FetchStatus(status)
|
|
}
|
|
v => eyre::bail!("Unknown result type `{v}`"),
|
|
};
|
|
|
|
Action::Result {
|
|
id: val.id.ok_or_else(|| missing("id"))?,
|
|
fields,
|
|
}
|
|
}
|
|
|
|
RawActionType::Stop => Action::Stop {
|
|
id: val.id.ok_or_else(|| missing("id"))?,
|
|
},
|
|
};
|
|
|
|
Ok(action)
|
|
}
|
|
}
|