diff --git a/lib/src/cli.rs b/lib/src/cli.rs index 28bc4087f..eaf724153 100644 --- a/lib/src/cli.rs +++ b/lib/src/cli.rs @@ -315,8 +315,11 @@ async fn upgrade(opts: UpgradeOpts) -> Result<()> { crate::deploy::stage(sysroot, &osname, &fetched, &spec).await?; changed = true; if let Some(prev) = booted_image.as_ref() { - let diff = ostree_container::ManifestDiff::new(&prev.manifest, &fetched.manifest); - diff.print(); + if let Some(fetched_manifest) = fetched.get_manifest(repo)? { + let diff = + ostree_container::ManifestDiff::new(&prev.manifest, &fetched_manifest); + diff.print(); + } } } } diff --git a/lib/src/deploy.rs b/lib/src/deploy.rs index fd6fa3f47..2ff8bebd5 100644 --- a/lib/src/deploy.rs +++ b/lib/src/deploy.rs @@ -6,7 +6,6 @@ use anyhow::{Context, Result}; use fn_error_context::context; use ostree::{gio, glib}; -use ostree_container::store::LayeredImageState; use ostree_container::OstreeImageReference; use ostree_ext::container as ostree_container; use ostree_ext::container::store::PrepareResult; @@ -28,6 +27,13 @@ pub(crate) struct RequiredHostSpec<'a> { pub(crate) image: &'a ImageReference, } +/// State of a locally fetched image +pub(crate) struct ImageState { + pub(crate) manifest_digest: String, + pub(crate) version: Option, + pub(crate) ostree_commit: String, +} + impl<'a> RequiredHostSpec<'a> { /// Given a (borrowed) host specification, "unwrap" its internal /// options, giving a spec that is required to have a base container image. @@ -40,6 +46,29 @@ impl<'a> RequiredHostSpec<'a> { } } +impl From for ImageState { + fn from(value: ostree_container::store::LayeredImageState) -> Self { + let version = value.version().map(|v| v.to_owned()); + let ostree_commit = value.get_commit().to_owned(); + Self { + manifest_digest: value.manifest_digest, + version, + ostree_commit, + } + } +} + +impl ImageState { + /// Fetch the manifest corresponding to this image. May not be available in all backends. + pub(crate) fn get_manifest( + &self, + repo: &ostree::Repo, + ) -> Result> { + ostree_container::store::query_image_commit(repo, &self.ostree_commit) + .map(|v| Some(v.manifest)) + } +} + /// Wrapper for pulling a container image, wiring up status output. pub(crate) async fn new_importer( repo: &ostree::Repo, @@ -57,14 +86,14 @@ pub(crate) async fn pull( sysroot: &SysrootLock, imgref: &ImageReference, quiet: bool, -) -> Result> { +) -> Result> { let repo = &sysroot.repo(); let imgref = &OstreeImageReference::from(imgref.clone()); let mut imp = new_importer(repo, imgref).await?; let prep = match imp.prepare().await? { PrepareResult::AlreadyPresent(c) => { println!("No changes in {} => {}", imgref, c.manifest_digest); - return Ok(c); + return Ok(Box::new((*c).into())); } PrepareResult::Ready(p) => p, }; @@ -89,7 +118,7 @@ pub(crate) async fn pull( { eprintln!("{msg}") } - Ok(import) + Ok(Box::new((*import).into())) } pub(crate) async fn cleanup(sysroot: &SysrootLock) -> Result<()> { @@ -143,16 +172,15 @@ async fn deploy( sysroot: &SysrootLock, merge_deployment: Option<&Deployment>, stateroot: &str, - image: &LayeredImageState, + image: &ImageState, origin: &glib::KeyFile, ) -> Result<()> { let stateroot = Some(stateroot); // Copy to move into thread - let base_commit = image.get_commit().to_owned(); let cancellable = gio::Cancellable::NONE; let _new_deployment = sysroot.stage_tree_with_options( stateroot, - &base_commit, + image.ostree_commit.as_str(), Some(origin), merge_deployment, &Default::default(), @@ -166,7 +194,7 @@ async fn deploy( pub(crate) async fn stage( sysroot: &SysrootLock, stateroot: &str, - image: &LayeredImageState, + image: &ImageState, spec: &RequiredHostSpec<'_>, ) -> Result<()> { let merge_deployment = sysroot.merge_deployment(Some(stateroot)); @@ -187,11 +215,7 @@ pub(crate) async fn stage( .await?; crate::deploy::cleanup(sysroot).await?; println!("Queued for next boot: {imgref}"); - if let Some(version) = image - .configuration - .as_ref() - .and_then(ostree_container::version_for_config) - { + if let Some(version) = image.version.as_deref() { println!(" Version: {version}"); } println!(" Digest: {}", image.manifest_digest);