meow meow
This commit is contained in:
4
src/lib.rs
Normal file
4
src/lib.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod action;
|
||||
pub mod action_raw;
|
||||
pub mod nix_path;
|
||||
pub mod state_manager;
|
||||
190
src/main.rs
190
src/main.rs
@@ -1,35 +1,29 @@
|
||||
use std::{collections::HashMap, thread::sleep, time::Duration};
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
||||
|
||||
use crate::action::StartFields;
|
||||
use crate::state_manager::{BuildEnumState, BuildState, StateManager};
|
||||
|
||||
pub mod action;
|
||||
pub mod action_raw;
|
||||
|
||||
enum BuildEnumState {
|
||||
Query,
|
||||
Downloading,
|
||||
}
|
||||
struct BuildState {
|
||||
path: Option<String>,
|
||||
progress_bar: ProgressBar,
|
||||
state: BuildEnumState,
|
||||
}
|
||||
pub mod nix_path;
|
||||
pub mod state_manager;
|
||||
|
||||
struct State {
|
||||
progress: MultiProgress,
|
||||
bars: HashMap<u64, BuildState>,
|
||||
manager: StateManager,
|
||||
}
|
||||
|
||||
fn main() -> Result<(), color_eyre::Report> {
|
||||
color_eyre::install().unwrap();
|
||||
let lines = std::fs::read_to_string("log2")?;
|
||||
let lines = std::fs::read_to_string("build.log")?;
|
||||
// let lines = lines.lines().take(1000).collect::<Vec<_>>().join("\n");
|
||||
|
||||
let mut state = State {
|
||||
progress: MultiProgress::new(),
|
||||
bars: HashMap::new(),
|
||||
manager: StateManager::new(),
|
||||
};
|
||||
|
||||
// let progress = MultiProgress::new();
|
||||
@@ -58,7 +52,7 @@ fn main() -> Result<(), color_eyre::Report> {
|
||||
for line in lines.lines() {
|
||||
lines_pb.inc(1);
|
||||
let line = line.strip_prefix("@nix ").unwrap_or(line);
|
||||
sleep(Duration::from_millis(50));
|
||||
sleep(Duration::from_millis(10));
|
||||
let action = action::Action::parse(line)?;
|
||||
match action {
|
||||
action::Action::Msg { level, msg } => {
|
||||
@@ -69,81 +63,123 @@ fn main() -> Result<(), color_eyre::Report> {
|
||||
action::Action::Start {
|
||||
start_type,
|
||||
id,
|
||||
level,
|
||||
level: _,
|
||||
parent,
|
||||
text,
|
||||
} => match start_type {
|
||||
StartFields::QueryPathInfo { path, source } => {
|
||||
state.bars.insert(
|
||||
*id,
|
||||
BuildState {
|
||||
path: Some(path.to_string()),
|
||||
progress_bar: state.progress.add(ProgressBar::new(100)),
|
||||
state: BuildEnumState::Query,
|
||||
},
|
||||
);
|
||||
text: _,
|
||||
} => {
|
||||
state.progress.println(format!("START {start_type:?}"));
|
||||
match start_type {
|
||||
StartFields::Substitute { source, target } => {
|
||||
state
|
||||
.manager
|
||||
.insert_parent(*id, BuildState::new(Some(source.to_string()), None));
|
||||
|
||||
let build_state = state.manager.get_mut(*id).unwrap();
|
||||
build_state.state = BuildEnumState::Substituting;
|
||||
}
|
||||
StartFields::CopyPath {
|
||||
path,
|
||||
origin,
|
||||
destination,
|
||||
} => {
|
||||
state.manager.add_child(*id, *parent);
|
||||
}
|
||||
// StartFields::QueryPathInfo { path, source: _ } => {
|
||||
// state
|
||||
// .manager
|
||||
// .insert_parent(*id, BuildState::new(Some(path.to_string()), None));
|
||||
// }
|
||||
StartFields::FileTransfer { target } => {
|
||||
// state.progress.println(format!(
|
||||
// "START FileTransfer (id: {}, parent: {}): target={}",
|
||||
// id, parent, target
|
||||
// ))?;
|
||||
if let Some(parent) = state.manager.get(*parent) {
|
||||
state
|
||||
.manager
|
||||
.insert_parent(*id, BuildState::new(parent.path.clone(), None));
|
||||
let build_state = state.manager.get_mut(*id).unwrap();
|
||||
build_state.state = BuildEnumState::Downloading;
|
||||
};
|
||||
|
||||
// state.manager.add_child(*id, *parent);
|
||||
// Add child ID mapping to parent
|
||||
}
|
||||
_ => {}
|
||||
};
|
||||
}
|
||||
action::Action::Stop { id } => {
|
||||
// Stop will only return Some when the last reference is stopped
|
||||
if let Some(build_state) = state.manager.stop(*id) {
|
||||
if let Some(pb) = &build_state.progress_bar {
|
||||
pb.finish_and_clear();
|
||||
state.progress.remove(pb);
|
||||
}
|
||||
state.progress.println(format!(
|
||||
"START FileTransfer (id: {}, parent: {}): target={}",
|
||||
id, parent, target
|
||||
"Completed: {}",
|
||||
build_state.path.as_deref().unwrap_or("unknown")
|
||||
))?;
|
||||
if let Some(bar) = state.bars.get_mut(&parent) {
|
||||
bar.state = BuildEnumState::Downloading;
|
||||
bar.progress_bar.set_style(
|
||||
}
|
||||
}
|
||||
action::Action::Result { id, fields } => match fields {
|
||||
action::ResultFields::Progress {
|
||||
done,
|
||||
expected,
|
||||
running,
|
||||
failed,
|
||||
} => {
|
||||
// sleep(Duration::from_millis(1));
|
||||
if let Some(build_state) = state.manager.get_mut(*id)
|
||||
&& expected > 0
|
||||
{
|
||||
let percentage = if expected == 0 {
|
||||
0
|
||||
} else {
|
||||
(done * 100 / expected) as u64
|
||||
};
|
||||
match &build_state.progress_bar {
|
||||
Some(pb) => {
|
||||
if percentage > pb.position() {
|
||||
pb.set_position(percentage);
|
||||
};
|
||||
}
|
||||
None => {
|
||||
state.progress.println(format!(
|
||||
"Creating progress bar for id {} (done: {}, expected: {})",
|
||||
id, done, expected
|
||||
))?;
|
||||
let n = match build_state.state {
|
||||
BuildEnumState::Downloading => "Downloading",
|
||||
BuildEnumState::Substituting => "Substituting",
|
||||
_ => "Processing",
|
||||
};
|
||||
let name =
|
||||
nix_path::extract_full_name(build_state.path.as_ref().unwrap());
|
||||
let pb = state.progress.add(
|
||||
ProgressBar::new(100)
|
||||
.with_style(
|
||||
ProgressStyle::default_bar()
|
||||
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
||||
.unwrap(),
|
||||
)
|
||||
.with_message(format!(
|
||||
"{n} {}",
|
||||
name.as_deref().unwrap_or("unknown")
|
||||
)),
|
||||
);
|
||||
bar.progress_bar.set_message(format!(
|
||||
"Downloading {}",
|
||||
bar.path.as_deref().unwrap_or("unknown")
|
||||
));
|
||||
pb.set_position(percentage);
|
||||
build_state.progress_bar = Some(pb);
|
||||
}
|
||||
// let bar = progress.add(ProgressBar::new(100));
|
||||
// bar // bar.set_message(format!("meow {id} "));
|
||||
// map.insert(id, bar);
|
||||
};
|
||||
} else {
|
||||
state.progress.println(format!(
|
||||
"RESULT Progress (id: {}): done={}, expected={}, running={}, failed={}",
|
||||
id, done, expected, running, failed
|
||||
))?;
|
||||
};
|
||||
}
|
||||
_ => {}
|
||||
},
|
||||
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:#?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
38
src/nix_path.rs
Normal file
38
src/nix_path.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
const NIX_STORE_PREFIX: &str = "/nix/store/";
|
||||
const NIX_HASH_LENGTH: usize = 32;
|
||||
pub fn extract_package_name(path: &str) -> Option<String> {
|
||||
let without_prefix = path.strip_prefix(NIX_STORE_PREFIX)?;
|
||||
|
||||
if without_prefix.len() <= NIX_HASH_LENGTH + 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let after_hash = &without_prefix[NIX_HASH_LENGTH + 1..];
|
||||
let parts: Vec<&str> = after_hash.split('-').collect();
|
||||
|
||||
if parts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
let name_parts: Vec<&str> = parts
|
||||
.iter()
|
||||
.take_while(|part| !part.chars().next().map_or(false, |c| c.is_ascii_digit()))
|
||||
.copied()
|
||||
.collect();
|
||||
|
||||
if name_parts.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(name_parts.join("-"))
|
||||
}
|
||||
|
||||
pub fn extract_full_name(path: &str) -> Option<&str> {
|
||||
let without_prefix = path.strip_prefix(NIX_STORE_PREFIX)?;
|
||||
|
||||
if without_prefix.len() <= NIX_HASH_LENGTH + 1 {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(&without_prefix[NIX_HASH_LENGTH + 1..])
|
||||
}
|
||||
107
src/state_manager.rs
Normal file
107
src/state_manager.rs
Normal file
@@ -0,0 +1,107 @@
|
||||
use indicatif::ProgressBar;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BuildEnumState {
|
||||
Query,
|
||||
Downloading,
|
||||
Substituting,
|
||||
}
|
||||
|
||||
pub struct BuildState {
|
||||
pub path: Option<String>,
|
||||
pub progress_bar: Option<ProgressBar>,
|
||||
pub state: BuildEnumState,
|
||||
ref_count: usize,
|
||||
}
|
||||
|
||||
impl BuildState {
|
||||
pub fn new(path: Option<String>, progress_bar: Option<ProgressBar>) -> Self {
|
||||
Self {
|
||||
path,
|
||||
progress_bar,
|
||||
state: BuildEnumState::Query,
|
||||
ref_count: 1,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct StateManager {
|
||||
states: HashMap<u64, BuildState>,
|
||||
id_to_canonical: HashMap<u64, u64>,
|
||||
}
|
||||
|
||||
impl StateManager {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
states: HashMap::new(),
|
||||
id_to_canonical: HashMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn insert_parent(&mut self, id: u64, state: BuildState) {
|
||||
self.id_to_canonical.insert(id, id); // parent maps to itself
|
||||
self.states.insert(id, state);
|
||||
}
|
||||
|
||||
pub fn add_child(&mut self, child_id: u64, parent_id: u64) {
|
||||
if let Some(&canonical_id) = self.id_to_canonical.get(&parent_id) {
|
||||
self.id_to_canonical.insert(child_id, canonical_id);
|
||||
|
||||
if let Some(state) = self.states.get_mut(&canonical_id) {
|
||||
state.ref_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, id: u64) -> Option<&BuildState> {
|
||||
self.id_to_canonical
|
||||
.get(&id)
|
||||
.and_then(|canonical_id| self.states.get(canonical_id))
|
||||
}
|
||||
|
||||
pub fn get_mut(&mut self, id: u64) -> Option<&mut BuildState> {
|
||||
self.id_to_canonical
|
||||
.get(&id)
|
||||
.copied()
|
||||
.and_then(|canonical_id| self.states.get_mut(&canonical_id))
|
||||
}
|
||||
|
||||
pub fn stop(&mut self, id: u64) -> Option<BuildState> {
|
||||
let canonical_id = self.id_to_canonical.get(&id).copied()?;
|
||||
|
||||
self.id_to_canonical.remove(&id);
|
||||
|
||||
if let Some(state) = self.states.get_mut(&canonical_id) {
|
||||
state.ref_count -= 1;
|
||||
|
||||
if state.ref_count == 0 {
|
||||
return self.states.remove(&canonical_id);
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn get_canonical_id(&self, id: u64) -> Option<u64> {
|
||||
self.id_to_canonical.get(&id).copied()
|
||||
}
|
||||
|
||||
pub fn contains(&self, id: u64) -> bool {
|
||||
self.id_to_canonical.contains_key(&id)
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.states.len()
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.states.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for StateManager {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user