From 4bb826190cdadde3e24edcb7117cf7e176208e51 Mon Sep 17 00:00:00 2001 From: Luke Yang Date: Mon, 10 Jul 2023 13:21:33 -0400 Subject: [PATCH] Add previous container state manifest This commit is a prerequisite to issue #4176 in the rpm-ostree repo, implementing the `rpm-ostree upgrade --check` feature for ostree native containers. A previous_state `LayeredImageState` object is added to the `PreparedImport` object, used to store the previous container state when importing a container image. A `export_as_string()` function is added to the `ManifestDiff` object to allow rpm-ostree to print the manifest diff on the client side. The code is exactly the same as the existing `print()` function for `ManifestDiff`, except it returns a string instead of printing out the diff in the terminal. --- lib/src/cli.rs | 6 +++++- lib/src/container/mod.rs | 17 +++++++++++++++++ lib/src/container/store.rs | 12 +++++++----- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/lib/src/cli.rs b/lib/src/cli.rs index acbc973a..eb2f8120 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -16,7 +16,7 @@ use tokio::sync::mpsc::Receiver; use crate::commit::container_commit; use crate::container::store::{ImportProgress, LayerProgress, PreparedImport}; -use crate::container::{self as ostree_container}; +use crate::container::{self as ostree_container, ManifestDiff}; use crate::container::{Config, ImageReference, OstreeImageReference}; use ostree_container::store::{ImageImporter, PrepareResult}; @@ -613,6 +613,10 @@ async fn container_store( if let Some(warning) = prep.deprecated_warning() { print_deprecated_warning(warning).await; } + if let Some(previous_state) = prep.previous_state.as_ref() { + let diff = ManifestDiff::new(&previous_state.manifest, &prep.manifest); + diff.print(); + } print_layer_status(&prep); let printer = (!quiet).then(|| { let layer_progress = imp.request_progress(); diff --git a/lib/src/container/mod.rs b/lib/src/container/mod.rs index 239d7529..dc80ad5b 100644 --- a/lib/src/container/mod.rs +++ b/lib/src/container/mod.rs @@ -324,6 +324,23 @@ impl<'a> ManifestDiff<'a> { println!("Removed layers: {n_removed:<4} Size: {removed_size_str}"); println!("Added layers: {n_added:<4} Size: {added_size_str}"); } + + /// Exports the total, removed and added content between two OCI images as a string + pub fn export_as_string(&self) -> String { + fn layersum<'a, I: Iterator>(layers: I) -> u64 { + layers.map(|layer| layer.size() as u64).sum() + } + let new_total = self.to.layers().len(); + let new_total_size = glib::format_size(layersum(self.to.layers().iter())); + let n_removed = self.removed.len(); + let n_added = self.added.len(); + let removed_size = layersum(self.removed.iter().copied()); + let removed_size_str = glib::format_size(removed_size); + let added_size = layersum(self.added.iter().copied()); + let added_size_str = glib::format_size(added_size); + let result = format!("Total new layers: {new_total:<4} Size: {new_total_size}\nRemoved layers: {n_removed:<4} Size: {removed_size_str}\nAdded layers: {n_added:<4} Size: {added_size_str}"); + return result + } } /// Apply default configuration for container image pulls to an existing configuration. diff --git a/lib/src/container/store.rs b/lib/src/container/store.rs index 3b72c29a..4279417c 100644 --- a/lib/src/container/store.rs +++ b/lib/src/container/store.rs @@ -191,6 +191,8 @@ pub struct PreparedImport { pub manifest: oci_image::ImageManifest, /// The deserialized configuration. pub config: oci_image::ImageConfiguration, + /// The previous manifest + pub previous_state: Option>, /// The previously stored manifest digest. pub previous_manifest_digest: Option, /// The previously stored image ID. @@ -532,7 +534,7 @@ impl ImageImporter { // Query for previous stored state - let (previous_manifest_digest, previous_imageid) = + let (previous_state, previous_imageid) = if let Some(previous_state) = try_query_image_ref(&self.repo, &self.imgref.imgref)? { // If the manifest digests match, we're done. if previous_state.manifest_digest == manifest_digest { @@ -543,10 +545,8 @@ impl ImageImporter { if previous_imageid == new_imageid { return Ok(PrepareResult::AlreadyPresent(previous_state)); } - ( - Some(previous_state.manifest_digest), - Some(previous_imageid.to_string()), - ) + let previous_imageid = previous_imageid.to_string(); + (Some(previous_state), Some(previous_imageid)) } else { (None, None) }; @@ -567,10 +567,12 @@ impl ImageImporter { .map(query) .collect::>>()?; + let previous_manifest_digest = previous_state.as_ref().map(|s| s.manifest_digest.clone()); let imp = PreparedImport { manifest, manifest_digest, config, + previous_state, previous_manifest_digest, previous_imageid, ostree_layers: component_layers,