diff --git a/ostree-ext/src/cli.rs b/ostree-ext/src/cli.rs index c70beeff..a069d17d 100644 --- a/ostree-ext/src/cli.rs +++ b/ostree-ext/src/cli.rs @@ -277,6 +277,17 @@ pub(crate) enum ContainerImageOpts { config: bool, }, + /// Remove metadata for a cached update. + ClearCachedUpdate { + /// Path to the repository + #[clap(long, value_parser)] + repo: Utf8PathBuf, + + /// Container image reference, e.g. registry:quay.io/exampleos/exampleos:latest + #[clap(value_parser = parse_base_imgref)] + imgref: ImageReference, + }, + /// Copy a pulled container image from one repo to another. Copy { /// Path to the source repository @@ -1132,6 +1143,11 @@ async fn run_from_opt(opt: Opt) -> Result<()> { stdout.flush()?; Ok(()) } + ContainerImageOpts::ClearCachedUpdate { repo, imgref } => { + let repo = parse_repo(&repo)?; + crate::container::store::clear_cached_update(&repo, &imgref)?; + Ok(()) + } ContainerImageOpts::Remove { repo, imgrefs, diff --git a/ostree-ext/src/container/store.rs b/ostree-ext/src/container/store.rs index 906dc508..c2a70e25 100644 --- a/ostree-ext/src/container/store.rs +++ b/ostree-ext/src/container/store.rs @@ -23,9 +23,10 @@ use futures_util::TryFutureExt; use oci_spec::image::{ self as oci_image, Arch, Descriptor, Digest, History, ImageConfiguration, ImageManifest, }; +use ostree::glib::FromVariant; use ostree::prelude::{Cast, FileEnumeratorExt, FileExt, ToVariant}; use ostree::{gio, glib}; -use std::collections::{BTreeSet, HashMap}; +use std::collections::{BTreeMap, BTreeSet, HashMap}; use std::iter::FromIterator; use tokio::sync::mpsc::{Receiver, Sender}; @@ -1196,6 +1197,37 @@ fn parse_cached_update(meta: &glib::VariantDict) -> Result Result<()> { + let cancellable = gio::Cancellable::NONE; + let ostree_ref = ref_for_image(imgref)?; + let rev = repo.require_rev(&ostree_ref)?; + let Some(commitmeta) = repo.read_commit_detached_metadata(&rev, cancellable)? else { + return Ok(()); + }; + + // SAFETY: We know this is an a{sv} + let mut commitmeta: BTreeMap = + BTreeMap::from_variant(&commitmeta).unwrap(); + let mut changed = false; + for key in [ + ImageImporter::CACHED_KEY_CONFIG, + ImageImporter::CACHED_KEY_MANIFEST, + ImageImporter::CACHED_KEY_MANIFEST_DIGEST, + ] { + if commitmeta.remove(key).is_some() { + changed = true; + } + } + if !changed { + return Ok(()); + } + let commitmeta = glib::Variant::from(commitmeta); + repo.write_commit_detached_metadata(&rev, Some(&commitmeta), cancellable)?; + Ok(()) +} + /// Query metadata for a pulled image via an OSTree commit digest. /// The digest must refer to a pulled container image's merge commit. pub fn query_image_commit(repo: &ostree::Repo, commit: &str) -> Result> {