work on download progress bars
This commit is contained in:
90
src/download_pb.rs
Normal file
90
src/download_pb.rs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
use std::{cell::RefCell, rc::Rc};
|
||||||
|
|
||||||
|
use indicatif::{MultiProgress, ProgressBar};
|
||||||
|
|
||||||
|
use crate::multibar::{BarSegment, MultiBar};
|
||||||
|
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct DownloadBar {
|
||||||
|
pub bar: ProgressBar,
|
||||||
|
pub name: String,
|
||||||
|
pub download_expected: Rc<RefCell<u64>>,
|
||||||
|
pub download_done: Rc<RefCell<u64>>,
|
||||||
|
pub extract_expected: Rc<RefCell<u64>>,
|
||||||
|
pub extract_done: Rc<RefCell<u64>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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_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)),
|
||||||
|
};
|
||||||
|
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();
|
||||||
|
|
||||||
|
let name = pad_string(&self.name, 20);
|
||||||
|
if download_expected == 0 || extract_expected == 0 {
|
||||||
|
self.bar.set_message(format!("Download {}", name));
|
||||||
|
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 msg = match width {
|
||||||
|
0..50 => {
|
||||||
|
format!(
|
||||||
|
"{}: {}/{}",
|
||||||
|
self.name,
|
||||||
|
total_done,
|
||||||
|
if total_expected == 0 {
|
||||||
|
"-".to_string()
|
||||||
|
} else {
|
||||||
|
total_expected.to_string()
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
let bar_dl = MultiBar([
|
||||||
|
BarSegment::Dynamic("=", download_done),
|
||||||
|
BarSegment::Dynamic(" ", download_expected.saturating_sub(download_done)),
|
||||||
|
])
|
||||||
|
.scale((width / 6) as u64);
|
||||||
|
let bar_ex = MultiBar([
|
||||||
|
BarSegment::Dynamic("=", extract_done),
|
||||||
|
BarSegment::Dynamic(" ", extract_expected.saturating_sub(extract_done)),
|
||||||
|
])
|
||||||
|
.scale((width / 6) as u64);
|
||||||
|
format!("Download {name} [{bar_dl}] {dl_percent:3}% [{bar_ex}] {ex_percent:3}%",)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.bar.set_message(msg);
|
||||||
|
self.bar.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pad_string(s: &str, width: usize) -> String {
|
||||||
|
if s.len() >= width {
|
||||||
|
s.to_string()
|
||||||
|
} else {
|
||||||
|
let mut padded = s.to_string();
|
||||||
|
padded.push_str(&" ".repeat(width - s.len()));
|
||||||
|
padded
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
pub mod action;
|
pub mod action;
|
||||||
pub mod action_raw;
|
pub mod action_raw;
|
||||||
|
pub mod download_pb;
|
||||||
|
pub mod multibar;
|
||||||
pub mod nix_path;
|
pub mod nix_path;
|
||||||
pub mod state_manager;
|
pub mod state_manager;
|
||||||
|
|||||||
34
src/main.rs
34
src/main.rs
@@ -17,6 +17,7 @@ static LAZY: LazyLock<i32> = LazyLock::new(|| {
|
|||||||
|
|
||||||
pub mod action;
|
pub mod action;
|
||||||
pub mod action_raw;
|
pub mod action_raw;
|
||||||
|
pub mod download_pb;
|
||||||
pub mod multibar;
|
pub mod multibar;
|
||||||
pub mod nix_path;
|
pub mod nix_path;
|
||||||
pub mod state_manager;
|
pub mod state_manager;
|
||||||
@@ -71,7 +72,7 @@ impl TermLike for TextTerm {
|
|||||||
|
|
||||||
fn main() -> Result<(), color_eyre::Report> {
|
fn main() -> Result<(), color_eyre::Report> {
|
||||||
color_eyre::install().unwrap();
|
color_eyre::install().unwrap();
|
||||||
println!("Lazy value: {}", *LAZY);
|
// println!("Lazy value: {}", *LAZY);
|
||||||
// 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)));
|
||||||
//
|
//
|
||||||
@@ -86,25 +87,27 @@ fn main() -> Result<(), color_eyre::Report> {
|
|||||||
// sleep(Duration::from_millis(50));
|
// sleep(Duration::from_millis(50));
|
||||||
// }
|
// }
|
||||||
// pb.finish_and_clear();
|
// pb.finish_and_clear();
|
||||||
let term = Term::stdout();
|
// let empty = style("-").blue().to_string();
|
||||||
let empty = style("-").blue().to_string();
|
// let bar = MultiBar([
|
||||||
let bar = MultiBar([
|
// BarSegment::Dynamic("=", 10),
|
||||||
BarSegment::Dynamic("=", 10),
|
// BarSegment::Static(">"),
|
||||||
BarSegment::Static(">"),
|
// BarSegment::Dynamic(empty.as_str(), 3),
|
||||||
BarSegment::Dynamic(empty.as_str(), 3),
|
// BarSegment::Dynamic(" ", 50),
|
||||||
BarSegment::Dynamic(" ", 50),
|
// ])
|
||||||
])
|
// .scale(u64::from(term.size().1 - 2));
|
||||||
.scale(u64::from(term.size().1 - 2));
|
// println!("[{}]", bar);
|
||||||
println!("[{}]", bar);
|
// return Ok(());
|
||||||
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 term = Term::stdout();
|
||||||
let mut state = State {
|
let mut state = State {
|
||||||
multi_progress: MultiProgress::new(),
|
multi_progress: MultiProgress::new(),
|
||||||
manager: StateManager::new(),
|
manager: StateManager::new(),
|
||||||
separator: None,
|
separator: None,
|
||||||
|
width: term.size().1,
|
||||||
|
current_width: term.size().1,
|
||||||
|
term,
|
||||||
};
|
};
|
||||||
|
|
||||||
// let progress = MultiProgress::new();
|
// let progress = MultiProgress::new();
|
||||||
@@ -224,8 +227,9 @@ fn main() -> Result<(), color_eyre::Report> {
|
|||||||
if expected == 0 {
|
if expected == 0 {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
if let Some(child) = state.manager.get_mut(*id) {
|
if let Some(mut child) = state.manager.take(*id) {
|
||||||
child.progress(done, expected);
|
child.progress(&mut state, done, expected);
|
||||||
|
state.manager.insert_parent(*id, child);
|
||||||
}
|
}
|
||||||
// sleep(Duration::from_millis(1));
|
// sleep(Duration::from_millis(1));
|
||||||
// if let Some(build_state) = state.manager.get_mut(*id)
|
// if let Some(build_state) = state.manager.get_mut(*id)
|
||||||
|
|||||||
@@ -1,13 +1,14 @@
|
|||||||
use console::style;
|
use console::{Term, style};
|
||||||
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
use indicatif::{MultiProgress, ProgressBar, ProgressFinish, ProgressStyle};
|
||||||
use std::{borrow::Cow, collections::HashMap, io};
|
use std::{borrow::Cow, collections::HashMap, io};
|
||||||
|
|
||||||
use crate::{action::StartFields, nix_path};
|
use crate::{action::StartFields, download_pb::DownloadBar, nix_path};
|
||||||
|
|
||||||
pub struct State<'a> {
|
pub struct State<'a> {
|
||||||
pub multi_progress: MultiProgress,
|
pub multi_progress: MultiProgress,
|
||||||
pub manager: StateManager<'a>,
|
pub manager: StateManager<'a>,
|
||||||
pub separator: Option<ProgressBar>,
|
pub separator: Option<ProgressBar>,
|
||||||
|
pub term: Term,
|
||||||
pub width: u16,
|
pub width: u16,
|
||||||
pub current_width: u16,
|
pub current_width: u16,
|
||||||
}
|
}
|
||||||
@@ -56,12 +57,11 @@ pub enum BuildEnumState<'a> {
|
|||||||
},
|
},
|
||||||
SubstituteCopy {
|
SubstituteCopy {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
bar: ProgressBar,
|
bar: DownloadBar,
|
||||||
},
|
},
|
||||||
SubstituteFetch {
|
SubstituteFetch {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
extract_bar: ProgressBar,
|
bar: DownloadBar,
|
||||||
download_bar: ProgressBar,
|
|
||||||
},
|
},
|
||||||
Query {
|
Query {
|
||||||
path: Cow<'a, str>,
|
path: Cow<'a, str>,
|
||||||
@@ -105,32 +105,13 @@ impl<'a> BuildState<'a> {
|
|||||||
(BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => {
|
(BuildEnumState::Substitute { .. }, StartFields::CopyPath { path, .. }) => {
|
||||||
let name = nix_path::extract_package_name(&path).unwrap_or("unknown".to_string());
|
let name = nix_path::extract_package_name(&path).unwrap_or("unknown".to_string());
|
||||||
let bar = state.add_pb(ProgressBar::new(100));
|
let bar = state.add_pb(ProgressBar::new(100));
|
||||||
bar.set_message(format!("Copying substitute for {}", name));
|
let bar = DownloadBar::new(bar, name, state.width);
|
||||||
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, bar }
|
||||||
}
|
}
|
||||||
(BuildEnumState::SubstituteCopy { path, bar }, 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(),
|
||||||
extract_bar: bar.clone(),
|
bar: bar.clone(),
|
||||||
download_bar,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(_, StartFields::Unknown) => BuildEnumState::Unknown,
|
(_, StartFields::Unknown) => BuildEnumState::Unknown,
|
||||||
@@ -153,19 +134,17 @@ impl<'a> BuildState<'a> {
|
|||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn progress(&mut self, done: u64, expected: u64) {
|
pub fn progress(&mut self, state: &mut State<'a>, done: u64, expected: u64) {
|
||||||
match &self.state {
|
match &self.state {
|
||||||
BuildEnumState::SubstituteFetch { download_bar, .. } => {
|
BuildEnumState::SubstituteFetch { bar, .. } => {
|
||||||
let percentage = (done * 100 / expected) as u64;
|
bar.download_expected.replace(expected);
|
||||||
if percentage > download_bar.position() {
|
bar.download_done.replace(done);
|
||||||
download_bar.set_position(percentage);
|
bar.update(state.width);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
BuildEnumState::SubstituteCopy { path, bar } => {
|
BuildEnumState::SubstituteCopy { path, bar } => {
|
||||||
let percentage = (done * 100 / expected) as u64;
|
bar.extract_expected.replace(expected);
|
||||||
if percentage > bar.position() {
|
bar.extract_done.replace(done);
|
||||||
bar.set_position(percentage);
|
bar.update(state.width);
|
||||||
};
|
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -194,6 +173,9 @@ impl<'a> StateManager<'a> {
|
|||||||
pub fn get_or_insert(&mut self, id: u64) -> &mut BuildState<'a> {
|
pub fn get_or_insert(&mut self, id: u64) -> &mut BuildState<'a> {
|
||||||
self.states.entry(id).or_insert_with(BuildState::new)
|
self.states.entry(id).or_insert_with(BuildState::new)
|
||||||
}
|
}
|
||||||
|
pub fn take(&mut self, id: u64) -> Option<BuildState<'a>> {
|
||||||
|
self.states.remove(&id)
|
||||||
|
}
|
||||||
pub fn remove(&mut self, id: u64) {
|
pub fn remove(&mut self, id: u64) {
|
||||||
if let Some(state) = self.states.get(&id) {
|
if let Some(state) = self.states.get(&id) {
|
||||||
if let Some(pb) = &state.progress_bar {
|
if let Some(pb) = &state.progress_bar {
|
||||||
|
|||||||
Reference in New Issue
Block a user