From a131591e2f0d1e38b093ee09f201d84ecfe0924d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Ravier?= Date: Wed, 17 Apr 2024 01:20:14 +0200 Subject: [PATCH] container: Support JSON out for ManifestDiff This will let higher level tools (Plasma Discover for example) more easily read the output of `bootc update --check --json`. --- lib/src/cli.rs | 19 +++++++++++++++---- lib/src/container/mod.rs | 39 +++++++++++++++++++++++++++++---------- 2 files changed, 44 insertions(+), 14 deletions(-) diff --git a/lib/src/cli.rs b/lib/src/cli.rs index af78d3dd..d89a58ea 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -10,7 +10,7 @@ use camino::{Utf8Path, Utf8PathBuf}; use cap_std::fs::Dir; use cap_std_ext::cap_std; use cap_std_ext::prelude::CapStdExtDirExt; -use clap::{Parser, Subcommand}; +use clap::{Parser, Subcommand, builder::ArgPredicate}; use fn_error_context::context; use io_lifetimes::AsFd; use ostree::{gio, glib}; @@ -178,6 +178,10 @@ pub(crate) enum ContainerOpts { /// Image reference, e.g. ostree-remote-image:someremote:registry:quay.io/exampleos/exampleos:latest #[clap(value_parser = parse_imgref)] imgref_new: OstreeImageReference, + + /// Use JSON as output format. + #[clap(long)] + json: bool, }, } @@ -234,6 +238,10 @@ pub(crate) enum ContainerImageOpts { /// the new manifest. #[clap(long)] check: Option, + + /// Use JSON as output format. Only applies to the --check option. + #[clap(long, requires_if(ArgPredicate::IsPresent, "check"))] + json: bool, }, /// Output metadata about an already stored container image. @@ -717,6 +725,7 @@ async fn container_store( proxyopts: ContainerProxyOpts, quiet: bool, check: Option, + json: bool ) -> Result<()> { let mut imp = ImageImporter::new(repo, imgref, proxyopts.into()).await?; let prep = match imp.prepare().await? { @@ -739,7 +748,7 @@ async fn container_store( } if let Some(previous_state) = prep.previous_state.as_ref() { let diff = ManifestDiff::new(&previous_state.manifest, &prep.manifest); - diff.print(); + diff.print(json); } print_layer_status(&prep); let printer = (!quiet).then(|| { @@ -965,9 +974,10 @@ async fn run_from_opt(opt: Opt) -> Result<()> { proxyopts, quiet, check, + json, } => { let repo = parse_repo(&repo)?; - container_store(&repo, &imgref, proxyopts, quiet, check).await + container_store(&repo, &imgref, proxyopts, quiet, check, json).await } ContainerImageOpts::History { repo, imgref } => { let repo = parse_repo(&repo)?; @@ -1177,12 +1187,13 @@ async fn run_from_opt(opt: Opt) -> Result<()> { ContainerOpts::Compare { imgref_old, imgref_new, + json, } => { let (manifest_old, _) = crate::container::fetch_manifest(&imgref_old).await?; let (manifest_new, _) = crate::container::fetch_manifest(&imgref_new).await?; let manifest_diff = crate::container::ManifestDiff::new(&manifest_old, &manifest_new); - manifest_diff.print(); + manifest_diff.print(json); Ok(()) } }, diff --git a/lib/src/container/mod.rs b/lib/src/container/mod.rs index f34f085c..7e0405a0 100644 --- a/lib/src/container/mod.rs +++ b/lib/src/container/mod.rs @@ -28,6 +28,7 @@ use anyhow::anyhow; use containers_image_proxy::oci_spec; use ostree::glib; +use serde_json::json; use std::borrow::Cow; use std::collections::HashMap; @@ -376,16 +377,34 @@ impl<'a> ManifestDiff<'a> { impl<'a> ManifestDiff<'a> { /// Prints the total, removed and added content between two OCI images - pub fn print(&self) { - let print_total = self.total; - let print_total_size = glib::format_size(self.total_size); - let print_n_removed = self.n_removed; - let print_removed_size = glib::format_size(self.removed_size); - let print_n_added = self.n_added; - let print_added_size = glib::format_size(self.added_size); - println!("Total new layers: {print_total:<4} Size: {print_total_size}"); - println!("Removed layers: {print_n_removed:<4} Size: {print_removed_size}"); - println!("Added layers: {print_n_added:<4} Size: {print_added_size}"); + pub fn print(&self, json: bool) { + if json { + let out = json!({ + "total": { + "count": self.total, + "size": self.total_size + }, + "removed": { + "count": self.n_removed, + "size": self.removed_size + }, + "added": { + "count": self.n_added, + "size": self.added_size + } + }); + println!("{}", out.to_string()); + } else { + let print_total = self.total; + let print_total_size = glib::format_size(self.total_size); + let print_n_removed = self.n_removed; + let print_removed_size = glib::format_size(self.removed_size); + let print_n_added = self.n_added; + let print_added_size = glib::format_size(self.added_size); + println!("Total new layers: {print_total:<4} Size: {print_total_size}"); + println!("Removed layers: {print_n_removed:<4} Size: {print_removed_size}"); + println!("Added layers: {print_n_added:<4} Size: {print_added_size}"); + } } }