@@ -13,7 +13,8 @@ use fn_error_context::context;
13
13
use ostree:: { gio, glib} ;
14
14
use ostree_container:: OstreeImageReference ;
15
15
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 ;
17
18
use ostree_ext:: ostree;
18
19
use ostree_ext:: ostree:: Deployment ;
19
20
use ostree_ext:: sysroot:: SysrootLock ;
@@ -112,34 +113,76 @@ pub(crate) fn check_bootc_label(config: &ostree_ext::oci_spec::image::ImageConfi
112
113
}
113
114
}
114
115
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
+
115
136
/// Write container fetch progress to standard output.
116
137
async fn handle_layer_progress_print (
117
138
mut layers : tokio:: sync:: mpsc:: Receiver < ostree_container:: store:: ImportProgress > ,
118
139
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 ,
121
141
) {
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}" )
127
154
. unwrap ( ) ,
128
155
) ;
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
+ ) ;
129
166
loop {
130
167
tokio:: select! {
131
168
// Always handle layer changes first.
132
169
biased;
133
170
layer = layers. recv( ) => {
134
171
if let Some ( l) = layer {
172
+ let layer = descriptor_of_progress( & l) ;
173
+ let layer_size = u64 :: try_from( layer. size( ) ) . unwrap( ) ;
135
174
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}" ) ) ;
137
181
} 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) ;
140
185
}
141
- pb. set_prefix( format!( "[{}/{}]" , * n_layers_fetched, total_layers) ) ;
142
- pb. set_message( ostree_ext:: cli:: layer_progress_format( & l) ) ;
143
186
} else {
144
187
// If the receiver is disconnected, then we're done
145
188
break
@@ -152,23 +195,35 @@ async fn handle_layer_progress_print(
152
195
}
153
196
let bytes = layer_bytes. borrow( ) ;
154
197
if let Some ( bytes) = & * bytes {
155
- pb. set_length( bytes. total) ;
156
- pb. set_position( bytes. fetched) ;
198
+ byte_bar. set_position( bytes. fetched) ;
157
199
}
158
200
}
159
-
160
201
}
161
202
}
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
+ ) ;
162
218
}
163
219
164
220
/// Wrapper for pulling a container image, wiring up status output.
165
221
#[ context( "Pulling" ) ]
166
222
pub ( crate ) async fn pull (
167
- sysroot : & SysrootLock ,
223
+ repo : & ostree :: Repo ,
168
224
imgref : & ImageReference ,
169
225
quiet : bool ,
170
226
) -> Result < Box < ImageState > > {
171
- let repo = & sysroot. repo ( ) ;
172
227
let ostree_imgref = & OstreeImageReference :: from ( imgref. clone ( ) ) ;
173
228
let mut imp = new_importer ( repo, ostree_imgref) . await ?;
174
229
let prep = match imp. prepare ( ) . await ? {
@@ -183,19 +238,14 @@ pub(crate) async fn pull(
183
238
ostree_ext:: cli:: print_deprecated_warning ( warning) . await ;
184
239
}
185
240
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 ( ) ;
186
243
let printer = ( !quiet) . then ( || {
187
244
let layer_progress = imp. request_progress ( ) ;
188
245
let layer_byte_progress = imp. request_layer_progress ( ) ;
189
- let total_layers = prep. layers_to_fetch ( ) . count ( ) ;
190
- let mut n_fetched = 0usize ;
191
246
tokio:: task:: spawn ( async move {
192
- handle_layer_progress_print (
193
- layer_progress,
194
- layer_byte_progress,
195
- total_layers,
196
- & mut n_fetched,
197
- )
198
- . await
247
+ handle_layer_progress_print ( layer_progress, layer_byte_progress, n_layers_to_fetch)
248
+ . await
199
249
} )
200
250
} ) ;
201
251
let import = imp. import ( prep) . await ;
0 commit comments