1
1
use std:: borrow:: Cow ;
2
2
use std:: collections:: VecDeque ;
3
3
use std:: io:: IsTerminal ;
4
+ use std:: io:: Read ;
4
5
use std:: io:: Write ;
5
6
6
7
use anyhow:: { Context , Result } ;
@@ -325,10 +326,37 @@ pub(crate) async fn status(opts: super::cli::StatusOpts) -> Result<()> {
325
326
Ok ( ( ) )
326
327
}
327
328
329
+ #[ derive( Debug ) ]
330
+ enum Slot {
331
+ Staged ,
332
+ Booted ,
333
+ Rollback ,
334
+ }
335
+
336
+ impl std:: fmt:: Display for Slot {
337
+ fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
338
+ let s = match self {
339
+ Slot :: Staged => "staged" ,
340
+ Slot :: Booted => "booted" ,
341
+ Slot :: Rollback => "rollback" ,
342
+ } ;
343
+ f. write_str ( s)
344
+ }
345
+ }
346
+
347
+ /// Output a row title, prefixed by spaces
348
+ fn write_row_name ( mut out : impl Write , s : & str , prefix_len : usize ) -> Result < ( ) > {
349
+ let n = prefix_len. saturating_sub ( s. chars ( ) . count ( ) ) ;
350
+ let mut spaces = std:: io:: repeat ( b' ' ) . take ( n as u64 ) ;
351
+ std:: io:: copy ( & mut spaces, & mut out) ?;
352
+ write ! ( out, "{s}: " ) ?;
353
+ Ok ( ( ) )
354
+ }
355
+
328
356
/// Write the data for a container image based status.
329
357
fn human_render_imagestatus (
330
358
mut out : impl Write ,
331
- slot_name : & str ,
359
+ slot : Slot ,
332
360
image : & crate :: spec:: ImageStatus ,
333
361
) -> Result < ( ) > {
334
362
let transport = & image. image . transport ;
@@ -340,46 +368,70 @@ fn human_render_imagestatus(
340
368
// But for non-registry we include the transport
341
369
Cow :: Owned ( format ! ( "{transport}:{imagename}" ) )
342
370
} ;
343
- writeln ! ( out, "Current {slot_name} image: {imageref}" ) ?;
344
-
345
- let version = image
346
- . version
347
- . as_deref ( )
348
- . unwrap_or ( "No image version defined" ) ;
349
- let timestamp = image
350
- . timestamp
351
- . as_ref ( )
352
- . map ( |t| t. to_string ( ) )
353
- . unwrap_or_else ( || "No timestamp present" . to_owned ( ) ) ;
371
+ let prefix = match slot {
372
+ Slot :: Staged => " Staged image" . into ( ) ,
373
+ Slot :: Booted => format ! ( "{} Booted image" , crate :: glyph:: Glyph :: BlackCircle ) ,
374
+ Slot :: Rollback => " Rollback image" . into ( ) ,
375
+ } ;
376
+ let prefix_len = prefix. chars ( ) . count ( ) ;
377
+ writeln ! ( out, "{prefix}: {imageref}" ) ?;
378
+
379
+ write_row_name ( & mut out, "Digest" , prefix_len) ?;
354
380
let digest = & image. image_digest ;
381
+ writeln ! ( out, "{digest}" ) ?;
382
+
383
+ let timestamp = image. timestamp . as_ref ( ) ;
384
+ // If we have a version, combine with timestamp
385
+ if let Some ( version) = image. version . as_deref ( ) {
386
+ write_row_name ( & mut out, "Version" , prefix_len) ?;
387
+ if let Some ( timestamp) = timestamp {
388
+ writeln ! ( out, "{version} ({timestamp})" ) ?;
389
+ } else {
390
+ writeln ! ( out, "{version}" ) ?;
391
+ }
392
+ } else if let Some ( timestamp) = timestamp. as_deref ( ) {
393
+ // Otherwise just output timestamp
394
+ write_row_name ( & mut out, "Timestamp" , prefix_len) ?;
395
+ writeln ! ( out, "{timestamp}" ) ?;
396
+ }
355
397
356
- writeln ! ( out, " Image version: {version} ({timestamp})" ) ?;
357
- writeln ! ( out, " Image digest: {digest}" ) ?;
358
398
Ok ( ( ) )
359
399
}
360
400
361
- fn human_render_ostree ( mut out : impl Write , slot_name : & str , _ostree_commit : & str ) -> Result < ( ) > {
401
+ fn human_render_ostree ( mut out : impl Write , slot : Slot , ostree_commit : & str ) -> Result < ( ) > {
362
402
// TODO consider rendering more ostree stuff here like rpm-ostree status does
363
- writeln ! ( out, "Current {slot_name} state is native ostree" ) ?;
403
+ let prefix = match slot {
404
+ Slot :: Staged => " Staged ostree" . into ( ) ,
405
+ Slot :: Booted => format ! ( "{} Booted ostree" , crate :: glyph:: Glyph :: BlackCircle ) ,
406
+ Slot :: Rollback => " Rollback ostree" . into ( ) ,
407
+ } ;
408
+ let prefix_len = prefix. len ( ) ;
409
+ writeln ! ( out, "{prefix}" ) ?;
410
+ write_row_name ( & mut out, "Commit" , prefix_len) ?;
411
+ writeln ! ( out, "{ostree_commit}" ) ?;
364
412
Ok ( ( ) )
365
413
}
366
414
367
415
fn human_readable_output_booted ( mut out : impl Write , host : & Host ) -> Result < ( ) > {
416
+ let mut first = true ;
368
417
for ( slot_name, status) in [
369
- ( "staged" , & host. status . staged ) ,
370
- ( "booted" , & host. status . booted ) ,
371
- ( "rollback" , & host. status . rollback ) ,
418
+ ( Slot :: Staged , & host. status . staged ) ,
419
+ ( Slot :: Booted , & host. status . booted ) ,
420
+ ( Slot :: Rollback , & host. status . rollback ) ,
372
421
] {
373
422
if let Some ( host_status) = status {
423
+ if first {
424
+ first = false ;
425
+ } else {
426
+ writeln ! ( out) ?;
427
+ }
374
428
if let Some ( image) = & host_status. image {
375
429
human_render_imagestatus ( & mut out, slot_name, image) ?;
376
430
} else if let Some ( ostree) = host_status. ostree . as_ref ( ) {
377
431
human_render_ostree ( & mut out, slot_name, & ostree. checksum ) ?;
378
432
} else {
379
433
writeln ! ( out, "Current {slot_name} state is unknown" ) ?;
380
434
}
381
- } else {
382
- writeln ! ( out, "No {slot_name} image present" ) ?;
383
435
}
384
436
}
385
437
Ok ( ( ) )
@@ -413,14 +465,14 @@ mod tests {
413
465
let w = human_status_from_spec_fixture ( include_str ! ( "fixtures/spec-staged-booted.yaml" ) )
414
466
. expect ( "No spec found" ) ;
415
467
let expected = indoc:: indoc! { r"
416
- Current staged image: quay.io/example/someimage:latest
417
- Image version: nightly (2023-10-14 19:22:15 UTC)
418
- Image digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
419
- Current booted image: quay.io/example/someimage:latest
420
- Image version: nightly (2023-09-30 19:22:16 UTC)
421
- Image digest : sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
422
- No rollback image present
423
- " } ;
468
+ Staged image: quay.io/example/someimage:latest
469
+ Digest: sha256:16dc2b6256b4ff0d2ec18d2dbfb06d117904010c8cf9732cdb022818cf7a7566
470
+ Version: nightly (2023-10-14 19:22:15 UTC)
471
+
472
+ ● Booted image: quay.io/example/someimage:latest
473
+ Digest : sha256:736b359467c9437c1ac915acaae952aad854e07eb4a16a94999a48af08c83c34
474
+ Version: nightly (2023-09-30 19:22:16 UTC)
475
+ " } ;
424
476
similar_asserts:: assert_eq!( w, expected) ;
425
477
}
426
478
@@ -432,10 +484,12 @@ mod tests {
432
484
) )
433
485
. expect ( "No spec found" ) ;
434
486
let expected = indoc:: indoc! { r"
435
- Current staged state is native ostree
436
- Current booted state is native ostree
437
- No rollback image present
438
- " } ;
487
+ Staged ostree
488
+ Commit: 1c24260fdd1be20f72a4a97a75c582834ee3431fbb0fa8e4f482bb219d633a45
489
+
490
+ ● Booted ostree
491
+ Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
492
+ " } ;
439
493
similar_asserts:: assert_eq!( w, expected) ;
440
494
}
441
495
@@ -445,12 +499,13 @@ mod tests {
445
499
let w = human_status_from_spec_fixture ( include_str ! ( "fixtures/spec-ostree-to-bootc.yaml" ) )
446
500
. expect ( "No spec found" ) ;
447
501
let expected = indoc:: indoc! { r"
448
- Current staged image: quay.io/centos-bootc/centos-bootc:stream9
449
- Image version: stream9.20240807.0 (No timestamp present)
450
- Image digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
451
- Current booted state is native ostree
452
- No rollback image present
453
- " } ;
502
+ Staged image: quay.io/centos-bootc/centos-bootc:stream9
503
+ Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
504
+ Version: stream9.20240807.0
505
+
506
+ ● Booted ostree
507
+ Commit: f9fa3a553ceaaaf30cf85bfe7eed46a822f7b8fd7e14c1e3389cbc3f6d27f791
508
+ " } ;
454
509
similar_asserts:: assert_eq!( w, expected) ;
455
510
}
456
511
@@ -460,12 +515,10 @@ mod tests {
460
515
let w = human_status_from_spec_fixture ( include_str ! ( "fixtures/spec-only-booted.yaml" ) )
461
516
. expect ( "No spec found" ) ;
462
517
let expected = indoc:: indoc! { r"
463
- No staged image present
464
- Current booted image: quay.io/centos-bootc/centos-bootc:stream9
465
- Image version: stream9.20240807.0 (No timestamp present)
466
- Image digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
467
- No rollback image present
468
- " } ;
518
+ ● Booted image: quay.io/centos-bootc/centos-bootc:stream9
519
+ Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
520
+ Version: stream9.20240807.0
521
+ " } ;
469
522
similar_asserts:: assert_eq!( w, expected) ;
470
523
}
471
524
@@ -483,12 +536,10 @@ mod tests {
483
536
let w = human_status_from_spec_fixture ( include_str ! ( "fixtures/spec-via-local-oci.yaml" ) )
484
537
. unwrap ( ) ;
485
538
let expected = indoc:: indoc! { r"
486
- No staged image present
487
- Current booted image: oci:/var/mnt/osupdate
488
- Image version: stream9.20240807.0 (No timestamp present)
489
- Image digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
490
- No rollback image present
491
- " } ;
539
+ ● Booted image: oci:/var/mnt/osupdate
540
+ Digest: sha256:47e5ed613a970b6574bfa954ab25bb6e85656552899aa518b5961d9645102b38
541
+ Version: stream9.20240807.0
542
+ " } ;
492
543
similar_asserts:: assert_eq!( w, expected) ;
493
544
}
494
545
0 commit comments