Skip to content

Commit d8b5df2

Browse files
committed
pull: Improved progress output
indicatif has nice support for multiple bars. Instead of hand-rolling a `[nn/NN]` for the overall layer count, change things so that we have: ``` Fetching layers [bar...] 8/65 ostree chunk sha256:29fc11ff03e4b3 [bar] (0 B/s) ``` Signed-off-by: Colin Walters <[email protected]>
1 parent 6c81a40 commit d8b5df2

File tree

1 file changed

+76
-25
lines changed

1 file changed

+76
-25
lines changed

lib/src/deploy.rs

Lines changed: 76 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ use fn_error_context::context;
1313
use ostree::{gio, glib};
1414
use ostree_container::OstreeImageReference;
1515
use ostree_ext::container as ostree_container;
16-
use ostree_ext::container::store::PrepareResult;
16+
use ostree_ext::container::store::{ImportProgress, PrepareResult};
17+
use ostree_ext::oci_spec::image::Descriptor;
1718
use ostree_ext::ostree;
1819
use ostree_ext::ostree::Deployment;
1920
use ostree_ext::sysroot::SysrootLock;
@@ -112,34 +113,76 @@ pub(crate) fn check_bootc_label(config: &ostree_ext::oci_spec::image::ImageConfi
112113
}
113114
}
114115

116+
fn descriptor_of_progress(p: &ImportProgress) -> &Descriptor {
117+
match p {
118+
ImportProgress::OstreeChunkStarted(l) => l,
119+
ImportProgress::OstreeChunkCompleted(l) => l,
120+
ImportProgress::DerivedLayerStarted(l) => l,
121+
ImportProgress::DerivedLayerCompleted(l) => l,
122+
}
123+
}
124+
125+
fn prefix_of_progress(p: &ImportProgress) -> &'static str {
126+
match p {
127+
ImportProgress::OstreeChunkStarted(_) | ImportProgress::OstreeChunkCompleted(_) => {
128+
"ostree chunk"
129+
}
130+
ImportProgress::DerivedLayerStarted(_) | ImportProgress::DerivedLayerCompleted(_) => {
131+
"layer"
132+
}
133+
}
134+
}
135+
115136
/// Write container fetch progress to standard output.
116137
async fn handle_layer_progress_print(
117138
mut layers: tokio::sync::mpsc::Receiver<ostree_container::store::ImportProgress>,
118139
mut layer_bytes: tokio::sync::watch::Receiver<Option<ostree_container::store::LayerProgress>>,
119-
total_layers: usize,
120-
n_layers_fetched: &mut usize,
140+
n_layers_to_fetch: usize,
121141
) {
122-
let style = indicatif::ProgressStyle::default_bar();
123-
let pb = indicatif::ProgressBar::new(100);
124-
pb.set_style(
125-
style
126-
.template("{prefix} {bytes} [{bar:20}] ({eta}) {msg}")
142+
let start = std::time::Instant::now();
143+
let mut total_read = 0u64;
144+
let bar = indicatif::MultiProgress::new();
145+
let layers_bar = bar.add(indicatif::ProgressBar::new(
146+
n_layers_to_fetch.try_into().unwrap(),
147+
));
148+
let byte_bar = bar.add(indicatif::ProgressBar::new(0));
149+
// let byte_bar = indicatif::ProgressBar::new(0);
150+
// byte_bar.set_draw_target(indicatif::ProgressDrawTarget::hidden());
151+
layers_bar.set_style(
152+
indicatif::ProgressStyle::default_bar()
153+
.template("{prefix} {bar} {pos}/{len} {wide_msg}")
127154
.unwrap(),
128155
);
156+
layers_bar.set_prefix("Fetching layers");
157+
layers_bar.set_message("");
158+
byte_bar.set_prefix("Fetching");
159+
byte_bar.set_style(
160+
indicatif::ProgressStyle::default_bar()
161+
.template(
162+
" └ {prefix} {bar} {binary_bytes}/{binary_total_bytes} ({binary_bytes_per_sec}) {wide_msg}",
163+
)
164+
.unwrap()
165+
);
129166
loop {
130167
tokio::select! {
131168
// Always handle layer changes first.
132169
biased;
133170
layer = layers.recv() => {
134171
if let Some(l) = layer {
172+
let layer = descriptor_of_progress(&l);
173+
let layer_size = u64::try_from(layer.size()).unwrap();
135174
if l.is_starting() {
136-
pb.set_position(0);
175+
byte_bar.reset_elapsed();
176+
byte_bar.reset_eta();
177+
byte_bar.set_length(layer_size);
178+
let layer_type = prefix_of_progress(&l);
179+
let short_digest = &layer.digest()[0..21];
180+
byte_bar.set_message(format!("{layer_type} {short_digest}"));
137181
} else {
138-
pb.finish();
139-
*n_layers_fetched += 1;
182+
byte_bar.set_position(layer_size);
183+
layers_bar.inc(1);
184+
total_read = total_read.saturating_add(layer_size);
140185
}
141-
pb.set_prefix(format!("[{}/{}]", *n_layers_fetched, total_layers));
142-
pb.set_message(ostree_ext::cli::layer_progress_format(&l));
143186
} else {
144187
// If the receiver is disconnected, then we're done
145188
break
@@ -152,13 +195,26 @@ async fn handle_layer_progress_print(
152195
}
153196
let bytes = layer_bytes.borrow();
154197
if let Some(bytes) = &*bytes {
155-
pb.set_length(bytes.total);
156-
pb.set_position(bytes.fetched);
198+
byte_bar.set_position(bytes.fetched);
157199
}
158200
}
159-
160201
}
161202
}
203+
byte_bar.finish_and_clear();
204+
layers_bar.finish_and_clear();
205+
if let Err(e) = bar.clear() {
206+
tracing::warn!("clearing bar: {e}");
207+
}
208+
let end = std::time::Instant::now();
209+
let elapsed = end.duration_since(start);
210+
let persec = total_read as f64 / elapsed.as_secs_f64();
211+
let persec = indicatif::HumanBytes(persec as u64);
212+
println!(
213+
"Fetched layers: {} in {} ({}/s)",
214+
indicatif::HumanBytes(total_read),
215+
indicatif::HumanDuration(elapsed),
216+
persec,
217+
);
162218
}
163219

164220
/// Wrapper for pulling a container image, wiring up status output.
@@ -182,19 +238,14 @@ pub(crate) async fn pull(
182238
ostree_ext::cli::print_deprecated_warning(warning).await;
183239
}
184240
ostree_ext::cli::print_layer_status(&prep);
241+
let layers_to_fetch = prep.layers_to_fetch().collect::<Result<Vec<_>>>()?;
242+
let n_layers_to_fetch = layers_to_fetch.len();
185243
let printer = (!quiet).then(|| {
186244
let layer_progress = imp.request_progress();
187245
let layer_byte_progress = imp.request_layer_progress();
188-
let total_layers = prep.layers_to_fetch().count();
189-
let mut n_fetched = 0usize;
190246
tokio::task::spawn(async move {
191-
handle_layer_progress_print(
192-
layer_progress,
193-
layer_byte_progress,
194-
total_layers,
195-
&mut n_fetched,
196-
)
197-
.await
247+
handle_layer_progress_print(layer_progress, layer_byte_progress, n_layers_to_fetch)
248+
.await
198249
})
199250
});
200251
let import = imp.import(prep).await;

0 commit comments

Comments
 (0)