From 01743c3c75179ce855aa1a8435856a853732aa15 Mon Sep 17 00:00:00 2001 From: Nikkuss Date: Sat, 15 Nov 2025 07:51:32 +0000 Subject: [PATCH] cleanup --- src/download_display.rs | 2 +- src/download_pb.rs | 139 ---------------------- src/handlers/download.rs | 18 +-- src/handlers/substitute_status.rs | 23 ++-- src/main.rs | 165 +------------------------- src/state_manager.rs | 189 ------------------------------ 6 files changed, 24 insertions(+), 512 deletions(-) delete mode 100644 src/download_pb.rs delete mode 100644 src/state_manager.rs diff --git a/src/download_display.rs b/src/download_display.rs index 5525a64..65924e6 100644 --- a/src/download_display.rs +++ b/src/download_display.rs @@ -1,6 +1,6 @@ pub const DOWNLOAD_STYLE: owo_colors::Style = owo_colors::Style::new().blue().bold(); pub const EXTRACT_STYLE: owo_colors::Style = owo_colors::Style::new().green().bold(); -use std::{borrow::Cow, fmt::Display, rc::Rc}; +use std::{borrow::Cow, fmt::Display}; use indicatif::HumanBytes; use owo_colors::Style; diff --git a/src/download_pb.rs b/src/download_pb.rs deleted file mode 100644 index ea52f47..0000000 --- a/src/download_pb.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::{cell::RefCell, rc::Rc, sync::LazyLock, time::Instant}; - -use console::style; -use indicatif::{HumanBytes, MultiProgress, ProgressBar}; - -use crate::{ - estimator::Estimator, - multibar::{BarSegment, MultiBar}, - pad_string, -}; - -static DOWNLOAD_CHAR: LazyLock = LazyLock::new(|| style("#").blue().bold().to_string()); -static DONE_CHAR: LazyLock = LazyLock::new(|| style("#").green().bold().to_string()); - -const INFO_WIDTH: usize = 12; - -#[derive(Debug, Clone)] -pub struct DownloadBar { - pub download_estimator: Rc>, - pub extract_estimator: Rc>, - pub bar: ProgressBar, - pub name: String, - pub download_expected: Rc>, - pub download_done: Rc>, - pub extract_expected: Rc>, - pub extract_done: Rc>, - pub started_at: Instant, -} - -impl DownloadBar { - pub fn new(bar: ProgressBar, name: String, width: u16) -> Self { - bar.set_style(indicatif::ProgressStyle::with_template("{msg}").unwrap()); - let new_self = Self { - name, - bar, - download_estimator: Rc::new(RefCell::new(Estimator::new(Instant::now()))), - extract_estimator: Rc::new(RefCell::new(Estimator::new(Instant::now()))), - download_expected: Rc::new(RefCell::new(0)), - download_done: Rc::new(RefCell::new(0)), - extract_expected: Rc::new(RefCell::new(0)), - extract_done: Rc::new(RefCell::new(0)), - started_at: Instant::now(), - }; - new_self.update(width); - new_self - } - - pub fn update(&self, width: u16) { - let download_done = (*self.download_done.borrow()); - let download_expected = (*self.download_expected.borrow()); - let extract_done = *self.extract_done.borrow(); - let extract_expected = *self.extract_expected.borrow(); - - self.download_estimator - .borrow_mut() - .record(download_done, Instant::now()); - self.extract_estimator - .borrow_mut() - .record(extract_done, Instant::now()); - - let name = pad_string(&self.name, (width / 4) as usize); - let status = format!("Download {} |", style(name).magenta().bold()); - let status_len = (width / 4) as usize + 10; - - if download_expected == 0 || extract_expected == 0 { - let text = pad_string("Pending...", width as usize / 3); - self.bar.set_message(format!("{status}")); - return; - } - - let total_expected = download_expected + extract_expected; - let total_done = download_done + extract_done; - - let dl_percent = ((download_done as f64 / download_expected as f64) * 100.0) as u64; - let ex_percent = ((extract_done as f64 / extract_expected as f64) * 100.0) as u64; - - let download_per_sec = HumanBytes( - self.download_estimator - .borrow() - .steps_per_second(Instant::now()) as u64, - ) - .to_string(); - let download_done_human = HumanBytes(download_done).to_string(); - let download_done_human = style(pad_string(&download_done_human, INFO_WIDTH)) - .blue() - .bold() - .to_string(); - let extract_done_human = HumanBytes(extract_done).to_string(); - let extract_done_human = style(pad_string(&extract_done_human, INFO_WIDTH)) - .green() - .bold() - .to_string(); - let download_per_sec = style(pad_string(&format!("{download_per_sec}/s"), INFO_WIDTH)) - .blue() - .bold() - .to_string(); - - let display = format!("{download_per_sec} | {download_done_human} | {extract_done_human} "); - let display_length = (INFO_WIDTH * 3) + 9; - - // + 6 to account for final format - let total_length = status_len + display_length + 4; - - let min = dl_percent.min(ex_percent); - let dl = dl_percent.saturating_sub(min); - let bar = MultiBar([ - BarSegment::Dynamic(&DONE_CHAR, min), - BarSegment::Dynamic(&DOWNLOAD_CHAR, dl), - BarSegment::Dynamic(" ", 100 - min - dl), - ]) - .scale((width - total_length as u16) as u64); - - let msg = match width { - 0..50 => { - format!( - "{}: {}/{}", - self.name, - total_done, - if total_expected == 0 { - "-".to_string() - } else { - total_expected.to_string() - } - ) - } - _ => { - format!("{status} {display} [{bar}]",) - } - }; - self.bar.set_message(msg); - self.bar.tick(); - } -} - -fn str_len(s: &str) -> usize { - s.chars() - .filter(|x| x.is_alphanumeric() || x.is_whitespace()) - .count() -} diff --git a/src/handlers/download.rs b/src/handlers/download.rs index b2c55b6..be4964c 100644 --- a/src/handlers/download.rs +++ b/src/handlers/download.rs @@ -1,21 +1,18 @@ -use std::{borrow::Cow, sync::LazyLock, time::Instant}; +use std::{borrow::Cow, time::Instant}; use indicatif::{HumanBytes, ProgressBar}; -use owo_colors::{OwoColorize, Style}; +use owo_colors::Style; use crate::{ + DONE_CHAR, DOWNLOAD_CHAR, action::{Action, BuildStepId, ResultFields, StartFields}, download_display::{DOWNLOAD_STYLE, EXTRACT_STYLE, StyledString, style_bar}, estimator::Estimator, - handlers::{Handler, fetch::FetchHandler}, + handlers::Handler, multibar::{BarSegment, MultiBar}, - nix_path, pad_string, + nix_path, }; -static DOWNLOAD_CHAR: LazyLock = LazyLock::new(|| "-".blue().bold().to_string()); -static DONE_CHAR: LazyLock = LazyLock::new(|| "#".green().bold().to_string()); -const INFO_WIDTH: usize = 13; - pub struct SubstituteHandler; impl Handler for SubstituteHandler { @@ -109,12 +106,9 @@ impl DownloadHandler { }; let name = nix_path::extract_package_name_string(&self.path) .unwrap_or_else(|| "unknown".to_string()); - let name = pad_string(&name, (width / 4) as usize); - let status = format!("Download {} |", name.purple().bold()); - let status_len = (width / 4) as usize + 10; if self.download_expected == 0 || self.extract_expected == 0 { - bar.set_message(format!("{status}")); + bar.set_message(format!("Downloading {name}")); bar.tick(); return; } diff --git a/src/handlers/substitute_status.rs b/src/handlers/substitute_status.rs index 4d0b62f..3c1d8db 100644 --- a/src/handlers/substitute_status.rs +++ b/src/handlers/substitute_status.rs @@ -1,21 +1,17 @@ -use std::{borrow::Cow, collections::HashMap, sync::LazyLock, time::Instant}; +use std::{borrow::Cow, collections::HashMap, time::Instant}; use indicatif::{HumanBytes, ProgressBar}; -use owo_colors::{OwoColorize, Style}; +use owo_colors::Style; use crate::{ + DONE_CHAR, DOWNLOAD_CHAR, INPROGRESS_CHAR, action::{Action, ActionType, BuildStepId, ResultFields, StartFields}, download_display::{DOWNLOAD_STYLE, EXTRACT_STYLE, StyledString, style_bar}, estimator::Estimator, - handlers::{Handler, fetch::FetchHandler}, + handlers::Handler, multibar::{BarSegment, MultiBar}, - nix_path, pad_string, }; -static DOWNLOAD_CHAR: LazyLock = LazyLock::new(|| "-".blue().bold().to_string()); -static DONE_CHAR: LazyLock = LazyLock::new(|| "#".green().bold().to_string()); -static INPROGRESS_CHAR: LazyLock = LazyLock::new(|| "-".purple().bold().to_string()); - pub struct CopyPathsHandler; impl Handler for CopyPathsHandler { @@ -30,7 +26,6 @@ impl Handler for CopyPathsHandler { id, .. } => { - state.println(format!("CopyPaths start"))?; let progress = state.add_pb(ProgressBar::new(1)); progress.set_style(indicatif::ProgressStyle::with_template("{msg}").unwrap()); @@ -103,11 +98,15 @@ impl SubstitutionStatusHandler { } let dl_percent = ((self.get_done() as f64 / self.max_transfer as f64) * 100.0) as u64; let ex_percent = ((self.get_unpacked() as f64 / self.max_copy as f64) * 100.0) as u64; - let expected = (((self.get_running() + self.get_running_copy()) as f64 - / (self.max_transfer + self.max_copy) as f64) - * 100.0) as u64; + + let dl_expected_percent = + ((self.get_running() as f64 / self.max_transfer as f64) * 100.0) as u64; + let ex_expected_percent = + ((self.get_running_copy() as f64 / self.max_copy as f64) * 100.0) as u64; + let min = dl_percent.min(ex_percent); let dl = dl_percent.saturating_sub(min); + let expected = dl_expected_percent.max(ex_expected_percent); let exp = expected.saturating_sub(min + dl); let mbar = MultiBar([ BarSegment::Dynamic(&DONE_CHAR, min), diff --git a/src/main.rs b/src/main.rs index a4528f4..043efdb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,20 +1,24 @@ +use std::sync::LazyLock; use std::thread::sleep; use std::time::Duration; use console::Term; +use owo_colors::OwoColorize; use crate::state::State; pub mod action; pub mod action_raw; pub mod download_display; -pub mod download_pb; pub mod estimator; pub mod handlers; pub mod multibar; pub mod nix_path; pub mod state; -pub mod state_manager; + +pub static DOWNLOAD_CHAR: LazyLock = LazyLock::new(|| "-".blue().bold().to_string()); +pub static DONE_CHAR: LazyLock = LazyLock::new(|| "=".green().bold().to_string()); +pub static INPROGRESS_CHAR: LazyLock = LazyLock::new(|| "-".purple().bold().to_string()); pub fn pad_string(s: &str, width: usize) -> String { if s.len() >= width { @@ -32,168 +36,11 @@ fn main() -> Result<(), color_eyre::Report> { let lines = std::fs::read_to_string("build.log")?; let mut state = State::new(Term::stderr().size().1); - // let lines = lines.lines().take(0).collect::>().join("\n"); - // let term = Term::stdout(); - // let mut state = State { - // multi_progress: MultiProgress::new(), - // manager: StateManager::new(), - // separator: None, - // width: term.size().1, - // current_width: term.size().1, - // term, - // }; - for line in lines.lines() { let line = line.strip_prefix("@nix ").unwrap_or(line); sleep(Duration::from_millis(1)); let action = action::Action::parse(line)?; state.handle(&action)?; - // match action { - // action::Action::Msg { level, msg } => { - // state.println(format!("MSG (level {level}): {msg}"))?; - // } - // action::Action::Start { - // start_type, - // id, - // level: _, - // parent, - // text: _, - // } => { - // // state.progress.println(format!("START {start_type:?}")); - // if let Some(parent) = state.manager.get(*parent) { - // let mut child = parent.clone(); - // child.merge(&mut state, start_type); - // child.tick(&mut state); - // state.manager.insert_parent(*id, child); - // }; - // // 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.progress.println(format!( - // // "START QueryPathInfo (id: {}, parent: {}): path={}", - // // id, parent, path - // // ))?; - // // } - // // 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 } => { - // state.manager.remove(*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!( - // // "Completed: {}", - // // build_state.path.as_deref().unwrap_or("unknown") - // // ))?; - // // } - // } - // action::Action::Result { id, fields } => match fields { - // action::ResultFields::FetchStatus(status) => { - // state.println(format!( - // "RESULT FetchStatus (id: {}): status={}", - // id, status - // ))?; - // } - // action::ResultFields::Progress { - // done, - // expected, - // running, - // failed, - // } => { - // if expected == 0 { - // continue; - // }; - // if let Some(mut child) = state.manager.take(*id) { - // child.progress(&mut state, done, expected); - // state.manager.insert_parent(*id, child); - // } - // // 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") - // // )), - // // ); - // // pb.set_position(percentage); - // // build_state.progress_bar = Some(pb); - // // } - // // }; - // // } else { - // // // state.progress.println(format!( - // // // "RESULT Progress (id: {}): done={}, expected={}, running={}, failed={}", - // // // id, done, expected, running, failed - // // // ))?; - // // }; - // } - // _ => {} - // }, - // } } Ok(()) diff --git a/src/state_manager.rs b/src/state_manager.rs deleted file mode 100644 index 25340e4..0000000 --- a/src/state_manager.rs +++ /dev/null @@ -1,189 +0,0 @@ -use console::{Term, style}; -use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle}; -use std::{borrow::Cow, collections::HashMap, io, time::Instant}; - -use crate::{action::StartFields, download_pb::DownloadBar, nix_path}; - -pub struct State<'a> { - pub multi_progress: MultiProgress, - pub manager: StateManager<'a>, - pub separator: Option, - pub term: Term, - pub width: u16, - pub current_width: u16, -} - -impl<'a> State<'a> { - pub fn add_pb(&mut self, pb: ProgressBar) -> ProgressBar { - let separator = self.separator.get_or_insert_with(|| { - let separator = ProgressBar::new_spinner() - .with_style( - ProgressStyle::default_spinner() - .template(&style("··{wide_msg:<}").dim().to_string()) - .expect("invalid template"), - ) - .with_message("·".repeat(512)) - .with_finish(ProgressFinish::AndClear); - - let separator = self.multi_progress.insert(0, separator); - separator.set_length(0); - separator - }); - - self.multi_progress.insert_after(separator, pb) - // self.progress.add(pb) - } - pub fn add_pb_before(&mut self, before: &ProgressBar, pb: ProgressBar) -> ProgressBar { - self.multi_progress.insert_before(before, pb) - } - pub fn add_pb_after(&mut self, after: &ProgressBar, pb: ProgressBar) -> ProgressBar { - self.multi_progress.insert_after(after, pb) - } - pub fn println>(&self, msg: I) -> io::Result<()> { - self.multi_progress.println(msg) - } -} - -#[derive(Debug, Clone)] -pub enum BuildEnumState<'a> { - Init, - Unknown, - Realise, - Builds, - CopyPaths, - Substitute { - source: Cow<'a, str>, - target: Cow<'a, str>, - }, - SubstituteCopy { - path: Cow<'a, str>, - bar: DownloadBar, - }, - SubstituteFetch { - path: Cow<'a, str>, - bar: DownloadBar, - }, - Query { - path: Cow<'a, str>, - source: Cow<'a, str>, - }, - QueryFetch { - target: Cow<'a, str>, - }, -} -#[derive(Debug, Clone)] -pub struct BuildState<'a> { - pub path: Option, - pub progress_bar: Option, - pub state: BuildEnumState<'a>, -} -impl<'a> BuildState<'a> { - pub fn new() -> Self { - Self { - path: None, - progress_bar: None, - state: BuildEnumState::Init, - } - } -} - -impl<'a> BuildState<'a> { - pub fn merge(&mut self, state: &mut State, start_type: StartFields<'a>) { - let state = match (&self.state, start_type.clone()) { - (BuildEnumState::Init, StartFields::QueryPathInfo { path, source }) => { - BuildEnumState::Query { path, source } - } - (BuildEnumState::Query { path, source }, StartFields::FileTransfer { target }) => { - BuildEnumState::QueryFetch { target } - } - (BuildEnumState::Init, StartFields::Realise) => BuildEnumState::Realise, - (BuildEnumState::Init, StartFields::Builds) => BuildEnumState::Builds, - (BuildEnumState::Init, StartFields::CopyPaths) => BuildEnumState::CopyPaths, - (BuildEnumState::Init, StartFields::Substitute { source, target }) => { - BuildEnumState::Substitute { source, target } - } - (BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => { - let name = - nix_path::extract_package_name_string(&path).unwrap_or("unknown".to_string()); - let bar = state.add_pb(ProgressBar::new(100)); - let bar = DownloadBar::new(bar, name, state.width); - BuildEnumState::SubstituteCopy { path, bar } - } - (BuildEnumState::SubstituteCopy { path, bar }, StartFields::FileTransfer { .. }) => { - BuildEnumState::SubstituteFetch { - path: path.clone(), - bar: bar.clone(), - } - } - (_, StartFields::Unknown) => BuildEnumState::Unknown, - _ => unimplemented!( - "Unsupported state transition from {:?} with {:?}", - self.state, - start_type - ), - }; - self.state = state; - } - pub fn tick(&mut self, state: &mut State<'a>) { - match &self.state { - BuildEnumState::QueryFetch { target } => { - let pb = state.add_pb(ProgressBar::new_spinner()); - pb.set_message(format!("Fetching info for {}", target)); - pb.enable_steady_tick(std::time::Duration::from_millis(100)); - self.progress_bar = Some(pb); - } - _ => {} - } - } - pub fn progress(&mut self, state: &mut State<'a>, done: u64, expected: u64) { - match &self.state { - BuildEnumState::SubstituteFetch { bar, .. } => { - bar.download_expected.replace(expected); - bar.download_done.replace(done); - bar.update(state.width); - } - BuildEnumState::SubstituteCopy { path, bar } => { - bar.extract_expected.replace(expected); - bar.extract_done.replace(done); - bar.update(state.width); - } - _ => {} - } - } -} - -pub struct StateManager<'a> { - states: HashMap>, -} - -impl<'a> StateManager<'a> { - pub fn new() -> Self { - let mut states = HashMap::new(); - states.insert(0, BuildState::new()); - Self { states } - } - pub fn get(&self, id: u64) -> Option<&BuildState<'a>> { - self.states.get(&id) - } - pub fn get_mut(&mut self, id: u64) -> Option<&mut BuildState<'a>> { - self.states.get_mut(&id) - } - pub fn insert_parent(&mut self, id: u64, state: BuildState<'a>) { - self.states.insert(id, state); - } - pub fn get_or_insert(&mut self, id: u64) -> &mut BuildState<'a> { - self.states.entry(id).or_insert_with(BuildState::new) - } - pub fn take(&mut self, id: u64) -> Option> { - self.states.remove(&id) - } - pub fn remove(&mut self, id: u64) { - if let Some(state) = self.states.get(&id) { - if let Some(pb) = &state.progress_bar { - pb.finish_and_clear(); - self.states.remove(&id); - } - } - self.states.remove(&id); - } -}