work on multibar
This commit is contained in:
50
src/main.rs
50
src/main.rs
@@ -8,6 +8,7 @@ use crate::state_manager::{BuildEnumState, BuildState, State, StateManager};
|
|||||||
|
|
||||||
pub mod action;
|
pub mod action;
|
||||||
pub mod action_raw;
|
pub mod action_raw;
|
||||||
|
pub mod multibar;
|
||||||
pub mod nix_path;
|
pub mod nix_path;
|
||||||
pub mod state_manager;
|
pub mod state_manager;
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -62,35 +63,36 @@ impl TermLike for TextTerm {
|
|||||||
fn main() -> Result<(), color_eyre::Report> {
|
fn main() -> Result<(), color_eyre::Report> {
|
||||||
color_eyre::install().unwrap();
|
color_eyre::install().unwrap();
|
||||||
|
|
||||||
let pb = ProgressBar::new(100);
|
// let pb = ProgressBar::new(100);
|
||||||
pb.set_draw_target(indicatif::ProgressDrawTarget::term_like(Box::new(TextTerm)));
|
// pb.set_draw_target(indicatif::ProgressDrawTarget::term_like(Box::new(TextTerm)));
|
||||||
|
//
|
||||||
|
// pb.set_style(
|
||||||
|
// ProgressStyle::default_bar()
|
||||||
|
// .template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
||||||
|
// .unwrap(),
|
||||||
|
// );
|
||||||
|
// pb.set_message("Example Progress Bar");
|
||||||
|
// for i in 0..=5 {
|
||||||
|
// pb.set_position(i);
|
||||||
|
// sleep(Duration::from_millis(50));
|
||||||
|
// }
|
||||||
|
// pb.finish_and_clear();
|
||||||
|
|
||||||
pb.set_style(
|
// return Ok(());
|
||||||
ProgressStyle::default_bar()
|
|
||||||
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
|
||||||
.unwrap(),
|
|
||||||
);
|
|
||||||
pb.set_message("Example Progress Bar");
|
|
||||||
for i in 0..=5 {
|
|
||||||
pb.set_position(i);
|
|
||||||
sleep(Duration::from_millis(50));
|
|
||||||
}
|
|
||||||
pb.finish_and_clear();
|
|
||||||
|
|
||||||
return Ok(());
|
|
||||||
|
|
||||||
let lines = std::fs::read_to_string("build.log")?;
|
let lines = std::fs::read_to_string("build.log")?;
|
||||||
let lines = lines.lines().take(0).collect::<Vec<_>>().join("\n");
|
// let lines = lines.lines().take(0).collect::<Vec<_>>().join("\n");
|
||||||
|
|
||||||
let mut state = State {
|
let mut state = State {
|
||||||
progress: MultiProgress::new(),
|
multi_progress: MultiProgress::new(),
|
||||||
manager: StateManager::new(),
|
manager: StateManager::new(),
|
||||||
|
separator: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// let progress = MultiProgress::new();
|
// let progress = MultiProgress::new();
|
||||||
let lines_pb = state
|
// let lines_pb = state
|
||||||
.progress
|
// .multi_progress
|
||||||
.add(ProgressBar::new(lines.lines().count() as u64));
|
// .add(ProgressBar::new(lines.lines().count() as u64));
|
||||||
// progress.println("Parsing build.log...")?;
|
// progress.println("Parsing build.log...")?;
|
||||||
// let pb1 = progress.add(ProgressBar::new(lines.lines().count() as u64));
|
// let pb1 = progress.add(ProgressBar::new(lines.lines().count() as u64));
|
||||||
// pb1.set_style(
|
// pb1.set_style(
|
||||||
@@ -111,15 +113,13 @@ fn main() -> Result<(), color_eyre::Report> {
|
|||||||
// let mut map = HashMap::new();
|
// let mut map = HashMap::new();
|
||||||
|
|
||||||
for line in lines.lines() {
|
for line in lines.lines() {
|
||||||
lines_pb.inc(1);
|
// lines_pb.inc(1);
|
||||||
let line = line.strip_prefix("@nix ").unwrap_or(line);
|
let line = line.strip_prefix("@nix ").unwrap_or(line);
|
||||||
sleep(Duration::from_millis(1));
|
sleep(Duration::from_millis(1));
|
||||||
let action = action::Action::parse(line)?;
|
let action = action::Action::parse(line)?;
|
||||||
match action {
|
match action {
|
||||||
action::Action::Msg { level, msg } => {
|
action::Action::Msg { level, msg } => {
|
||||||
state
|
state.println(format!("MSG (level {level}): {msg}"))?;
|
||||||
.progress
|
|
||||||
.println(format!("MSG (level {level}): {msg}"))?;
|
|
||||||
}
|
}
|
||||||
action::Action::Start {
|
action::Action::Start {
|
||||||
start_type,
|
start_type,
|
||||||
@@ -192,7 +192,7 @@ fn main() -> Result<(), color_eyre::Report> {
|
|||||||
}
|
}
|
||||||
action::Action::Result { id, fields } => match fields {
|
action::Action::Result { id, fields } => match fields {
|
||||||
action::ResultFields::FetchStatus(status) => {
|
action::ResultFields::FetchStatus(status) => {
|
||||||
state.progress.println(format!(
|
state.println(format!(
|
||||||
"RESULT FetchStatus (id: {}): status={}",
|
"RESULT FetchStatus (id: {}): status={}",
|
||||||
id, status
|
id, status
|
||||||
))?;
|
))?;
|
||||||
|
|||||||
39
src/multibar.rs
Normal file
39
src/multibar.rs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct MultiBar<'s, const N: usize>(pub [(&'s str, u64); N]);
|
||||||
|
|
||||||
|
impl<const N: usize> MultiBar<'_, N> {
|
||||||
|
/// Total length of the bar
|
||||||
|
pub(crate) fn length(&self) -> u64 {
|
||||||
|
self.0.iter().map(|(_, len)| *len).sum()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Transforms the bar to be of target size
|
||||||
|
pub(crate) fn scale(&self, size: u64) -> Self {
|
||||||
|
let length = std::cmp::max(self.length(), 1);
|
||||||
|
let mut prev_prop = 0;
|
||||||
|
let mut curr_prop = 0;
|
||||||
|
|
||||||
|
let inner = self.0.map(|(c, len)| {
|
||||||
|
curr_prop += len;
|
||||||
|
let nb_chars = size * curr_prop / length - size * prev_prop / length;
|
||||||
|
prev_prop = curr_prop;
|
||||||
|
(c, nb_chars)
|
||||||
|
});
|
||||||
|
|
||||||
|
Self(inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const N: usize> fmt::Display for MultiBar<'_, N> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
for &(c, len) in &self.0 {
|
||||||
|
for _ in 0..len {
|
||||||
|
f.write_str(c)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,16 +1,43 @@
|
|||||||
use indicatif::{MultiProgress, ProgressBar, ProgressStyle};
|
use console::style;
|
||||||
use std::{borrow::Cow, collections::HashMap};
|
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
||||||
|
use std::{borrow::Cow, collections::HashMap, io};
|
||||||
|
|
||||||
use crate::{action::StartFields, nix_path};
|
use crate::{action::StartFields, nix_path};
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
pub progress: MultiProgress,
|
pub multi_progress: MultiProgress,
|
||||||
pub manager: StateManager<'a>,
|
pub manager: StateManager<'a>,
|
||||||
|
pub separator: Option<ProgressBar>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> State<'a> {
|
impl<'a> State<'a> {
|
||||||
pub fn add_pb(&mut self, pb: ProgressBar) -> ProgressBar {
|
pub fn add_pb(&mut self, pb: ProgressBar) -> ProgressBar {
|
||||||
self.progress.add(pb)
|
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<I: AsRef<str>>(&self, msg: I) -> io::Result<()> {
|
||||||
|
self.multi_progress.println(msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -27,10 +54,12 @@ pub enum BuildEnumState<'a> {
|
|||||||
},
|
},
|
||||||
SubstituteCopy {
|
SubstituteCopy {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
|
bar: ProgressBar,
|
||||||
},
|
},
|
||||||
SubstituteFetch {
|
SubstituteFetch {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
bar: ProgressBar,
|
extract_bar: ProgressBar,
|
||||||
|
download_bar: ProgressBar,
|
||||||
},
|
},
|
||||||
Query {
|
Query {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
@@ -74,12 +103,34 @@ impl<'a> BuildState<'a> {
|
|||||||
BuildEnumState::Substitute { source, target }
|
BuildEnumState::Substitute { source, target }
|
||||||
}
|
}
|
||||||
(BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => {
|
(BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => {
|
||||||
BuildEnumState::SubstituteCopy { path }
|
let name = nix_path::extract_package_name(&path).unwrap_or("unknown".to_string());
|
||||||
|
let bar = state.add_pb(ProgressBar::new(100));
|
||||||
|
bar.set_message(format!("Copying substitute for {}", name));
|
||||||
|
bar.set_style(
|
||||||
|
ProgressStyle::default_bar()
|
||||||
|
.template("{prefix}{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
||||||
|
.unwrap()
|
||||||
|
.progress_chars("=> "),
|
||||||
|
);
|
||||||
|
bar.tick();
|
||||||
|
BuildEnumState::SubstituteCopy { path, bar }
|
||||||
}
|
}
|
||||||
(BuildEnumState::SubstituteCopy { path }, StartFields::FileTransfer { .. }) => {
|
(BuildEnumState::SubstituteCopy { path, bar }, StartFields::FileTransfer { .. }) => {
|
||||||
|
let download_bar = state.add_pb_after(bar, ProgressBar::new(100));
|
||||||
|
let name = nix_path::extract_package_name(path).unwrap_or("unknown".to_string());
|
||||||
|
download_bar.set_message(format!("Fetching substitute for {}", name));
|
||||||
|
download_bar.set_style(
|
||||||
|
ProgressStyle::default_bar()
|
||||||
|
.template("{prefix}{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
||||||
|
.unwrap()
|
||||||
|
.progress_chars("=> "),
|
||||||
|
);
|
||||||
|
download_bar.set_prefix("=== ");
|
||||||
|
download_bar.tick();
|
||||||
BuildEnumState::SubstituteFetch {
|
BuildEnumState::SubstituteFetch {
|
||||||
path: path.clone(),
|
path: path.clone(),
|
||||||
bar: state.add_pb(ProgressBar::new(100)),
|
extract_bar: bar.clone(),
|
||||||
|
download_bar,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, StartFields::Unknown) => BuildEnumState::Unknown,
|
(_, StartFields::Unknown) => BuildEnumState::Unknown,
|
||||||
@@ -94,29 +145,23 @@ impl<'a> BuildState<'a> {
|
|||||||
pub fn tick(&mut self, state: &mut State<'a>) {
|
pub fn tick(&mut self, state: &mut State<'a>) {
|
||||||
match &self.state {
|
match &self.state {
|
||||||
BuildEnumState::QueryFetch { target } => {
|
BuildEnumState::QueryFetch { target } => {
|
||||||
let pb = state.progress.add(ProgressBar::new_spinner());
|
let pb = state.add_pb(ProgressBar::new_spinner());
|
||||||
pb.set_message(format!("Fetching info for {}", target));
|
pb.set_message(format!("Fetching info for {}", target));
|
||||||
pb.enable_steady_tick(std::time::Duration::from_millis(100));
|
pb.enable_steady_tick(std::time::Duration::from_millis(100));
|
||||||
self.progress_bar = Some(pb);
|
self.progress_bar = Some(pb);
|
||||||
}
|
}
|
||||||
BuildEnumState::SubstituteFetch { path, bar } => {
|
|
||||||
let name = nix_path::extract_package_name(path).unwrap_or("unknown".to_string());
|
|
||||||
bar.set_message(format!("Fetching substitute for {}", name));
|
|
||||||
bar.set_style(
|
|
||||||
ProgressStyle::default_bar()
|
|
||||||
.template("{msg} [{bar:40.cyan/blue}] {pos:>3}%")
|
|
||||||
.unwrap()
|
|
||||||
.progress_chars("=> "),
|
|
||||||
);
|
|
||||||
// bar.enable_steady_tick(std::time::Duration::from_millis(100));
|
|
||||||
// self.progress_bar = Some(bar.clone());
|
|
||||||
}
|
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn progress(&mut self, done: u64, expected: u64) {
|
pub fn progress(&mut self, done: u64, expected: u64) {
|
||||||
match &self.state {
|
match &self.state {
|
||||||
BuildEnumState::SubstituteFetch { bar, .. } => {
|
BuildEnumState::SubstituteFetch { download_bar, .. } => {
|
||||||
|
let percentage = (done * 100 / expected) as u64;
|
||||||
|
if percentage > download_bar.position() {
|
||||||
|
download_bar.set_position(percentage);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
BuildEnumState::SubstituteCopy { path, bar } => {
|
||||||
let percentage = (done * 100 / expected) as u64;
|
let percentage = (done * 100 / expected) as u64;
|
||||||
if percentage > bar.position() {
|
if percentage > bar.position() {
|
||||||
bar.set_position(percentage);
|
bar.set_position(percentage);
|
||||||
|
|||||||
Reference in New Issue
Block a user