init
This commit is contained in:
151
src/action.rs
Normal file
151
src/action.rs
Normal file
@@ -0,0 +1,151 @@
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Display;
|
||||
use std::ops::Deref;
|
||||
|
||||
use color_eyre::eyre::Context;
|
||||
use serde::Deserialize;
|
||||
use serde_repr::Deserialize_repr;
|
||||
|
||||
use crate::action_raw::RawAction;
|
||||
|
||||
// ---
|
||||
// --- ActionType
|
||||
// ---
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize_repr)]
|
||||
#[repr(u8)]
|
||||
#[derive(Eq, PartialEq)]
|
||||
pub enum ActionType {
|
||||
Unknown = 0,
|
||||
CopyPath = 100,
|
||||
FileTransfer = 101,
|
||||
Realise = 102,
|
||||
CopyPaths = 103,
|
||||
Builds = 104,
|
||||
Build = 105,
|
||||
OptimiseStore = 106,
|
||||
VerifyPaths = 107,
|
||||
Substitute = 108,
|
||||
QueryPathInfo = 109,
|
||||
PostBuildHook = 110,
|
||||
BuildWaiting = 111,
|
||||
}
|
||||
|
||||
impl Default for ActionType {
|
||||
fn default() -> Self {
|
||||
Self::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
// --- BuildStepId
|
||||
// ---
|
||||
|
||||
#[derive(Copy, Clone, Debug, Default, Deserialize, Eq, PartialEq, Hash)]
|
||||
pub struct BuildStepId(u64);
|
||||
|
||||
impl Deref for BuildStepId {
|
||||
type Target = u64;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u64> for BuildStepId {
|
||||
fn from(value: u64) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<BuildStepId> for u64 {
|
||||
fn from(val: BuildStepId) -> Self {
|
||||
val.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for BuildStepId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
// ---
|
||||
// --- Action
|
||||
// ---
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum StartFields<'a> {
|
||||
Unknown,
|
||||
CopyPath {
|
||||
path: Cow<'a, str>,
|
||||
origin: Cow<'a, str>,
|
||||
destination: Cow<'a, str>,
|
||||
},
|
||||
FileTransfer {
|
||||
target: Cow<'a, str>,
|
||||
},
|
||||
Realise,
|
||||
CopyPaths,
|
||||
Builds,
|
||||
Build {
|
||||
target: Cow<'a, str>,
|
||||
source: Cow<'a, str>, // TODO: check
|
||||
val1: u64,
|
||||
val2: u64,
|
||||
},
|
||||
OptimiseStore,
|
||||
VerifyPaths,
|
||||
Substitute {
|
||||
source: Cow<'a, str>,
|
||||
target: Cow<'a, str>,
|
||||
},
|
||||
QueryPathInfo,
|
||||
PostBuildHook,
|
||||
BuildWaiting,
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum ResultFields<'a> {
|
||||
BuildLogLine(Cow<'a, str>),
|
||||
SetPhase(&'a str),
|
||||
Progress {
|
||||
done: u64,
|
||||
expected: u64,
|
||||
running: u64,
|
||||
failed: u64,
|
||||
},
|
||||
SetExpected {
|
||||
action: ActionType,
|
||||
expected: u64,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum Action<'a> {
|
||||
Msg {
|
||||
level: u8,
|
||||
msg: Cow<'a, str>,
|
||||
},
|
||||
Start {
|
||||
start_type: StartFields<'a>,
|
||||
id: BuildStepId,
|
||||
level: u8,
|
||||
parent: BuildStepId,
|
||||
text: Cow<'a, str>,
|
||||
},
|
||||
Result {
|
||||
id: BuildStepId,
|
||||
fields: ResultFields<'a>,
|
||||
},
|
||||
Stop {
|
||||
id: BuildStepId,
|
||||
},
|
||||
}
|
||||
|
||||
impl<'a> Action<'a> {
|
||||
pub fn parse(buf: &'a str) -> color_eyre::Result<Self> {
|
||||
let raw: RawAction = serde_json::from_str(buf).context("Could not parse raw JSON")?;
|
||||
raw.try_into().context("Could not convert raw action")
|
||||
}
|
||||
}
|
||||
174
src/action_raw.rs
Normal file
174
src/action_raw.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
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,
|
||||
}
|
||||
|
||||
#[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 => StartFields::QueryPathInfo,
|
||||
ActionType::PostBuildHook => StartFields::PostBuildHook,
|
||||
ActionType::BuildWaiting => StartFields::BuildWaiting,
|
||||
};
|
||||
|
||||
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 => todo!("FileLinked({raw_fields})"),
|
||||
101 => {
|
||||
let [line] = serde_json::from_str(raw_fields).context("invalid fields")?;
|
||||
ResultFields::BuildLogLine(line)
|
||||
}
|
||||
102 => todo!("UntrustedPath({raw_fields})"),
|
||||
103 => todo!("CorruptedPath({raw_fields})"),
|
||||
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 => todo!("PostBuildLogLine({raw_fields})"),
|
||||
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)
|
||||
}
|
||||
}
|
||||
115
src/main.rs
Normal file
115
src/main.rs
Normal file
@@ -0,0 +1,115 @@
|
||||
use std::{collections::HashMap, thread::sleep, time::Duration};
|
||||
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use crate::action::StartFields;
|
||||
|
||||
pub mod action;
|
||||
pub mod action_raw;
|
||||
fn main() -> Result<(), color_eyre::Report> {
|
||||
color_eyre::install().unwrap();
|
||||
let lines = std::fs::read_to_string("log2")?;
|
||||
// let lines = lines.lines().take(1000).collect::<Vec<_>>().join("\n");
|
||||
|
||||
let progress = MultiProgress::new();
|
||||
let lines_pb = progress.add(ProgressBar::new(lines.lines().count() as u64));
|
||||
// progress.println("Parsing build.log...")?;
|
||||
// let pb1 = progress.add(ProgressBar::new(lines.lines().count() as u64));
|
||||
// pb1.set_style(
|
||||
// ProgressStyle::default_spinner()
|
||||
// .template("[{elapsed_precise:>6}] {msg}")
|
||||
// .unwrap(),
|
||||
// );
|
||||
// pb1.set_message("Processing line2342s\n|\n|\n>");
|
||||
// let pb2 = progress.add(ProgressBar::new(lines.lines().count() as u64));
|
||||
// pb2.set_style(
|
||||
// ProgressStyle::default_spinner()
|
||||
// .template("[{elapsed_precise:>6}] {msg}")
|
||||
// .unwrap(),
|
||||
// );
|
||||
// pb2.set_message("Processing line2342s\n|\n|\n>");
|
||||
// sleep(Duration::from_secs(1));
|
||||
|
||||
let mut map = HashMap::new();
|
||||
|
||||
for line in lines.lines() {
|
||||
lines_pb.inc(1);
|
||||
let line = line.strip_prefix("@nix ").unwrap_or(line);
|
||||
// sleep(Duration::from_millis(5));
|
||||
let action = action::Action::parse(line)?;
|
||||
match action {
|
||||
action::Action::Msg { level, msg } => {
|
||||
progress.println(format!("MSG (level {level}): {msg}"))?;
|
||||
}
|
||||
action::Action::Start {
|
||||
start_type,
|
||||
id,
|
||||
level,
|
||||
parent,
|
||||
text,
|
||||
} => match start_type {
|
||||
StartFields::CopyPath {
|
||||
path,
|
||||
origin,
|
||||
destination,
|
||||
} => {
|
||||
progress.println(format!(
|
||||
"START (id: {}, level: {}, parent: {}): CopyPath - {} (from: {}, to: {})",
|
||||
id, level, parent, text, origin, destination
|
||||
))?;
|
||||
}
|
||||
StartFields::FileTransfer { target } => {
|
||||
let bar = progress.add(ProgressBar::new(100));
|
||||
bar.set_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
||||
.unwrap(),
|
||||
);
|
||||
bar.set_message(format!("meow {id} "));
|
||||
map.insert(id, bar);
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
action::Action::Stop { id } => {
|
||||
if let Some(bar) = map.get(&id) {
|
||||
bar.finish();
|
||||
// bar.finish_with_message(format!("Transfer stopped (id: {})", id));
|
||||
progress.remove(bar);
|
||||
map.remove(&id);
|
||||
}
|
||||
// progress.println(format!("STOP (id: {})", id))?;
|
||||
}
|
||||
action::Action::Result { id, fields } => {
|
||||
// progress.println(format!("RESULT (id: {}): {:?}", id, fields))?;
|
||||
match fields {
|
||||
action::ResultFields::Progress {
|
||||
done,
|
||||
expected,
|
||||
running,
|
||||
failed,
|
||||
} => {
|
||||
sleep(Duration::from_millis(1));
|
||||
if let Some(bar) = map.get(&id) {
|
||||
let percentage = if expected == 0 {
|
||||
0
|
||||
} else {
|
||||
(done * 100 / expected) as u64
|
||||
};
|
||||
bar.set_position(percentage);
|
||||
// if done >= expected {
|
||||
// bar.finish_with_message(format!("Completed transfer (id: {})", id));
|
||||
// map.remove(&id);
|
||||
// }
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("{action:#?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
Reference in New Issue
Block a user