diff --git a/Cargo.lock b/Cargo.lock index c496e3079..5d7423adc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -958,9 +958,9 @@ dependencies = [ [[package]] name = "containers-image-proxy" -version = "0.10.0" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a00f7ac9ad66c570e37fcbf7644d678dcfabb50a4d8e85136ceb2fa45335597c" +checksum = "75af58c668f3331f80098044f39832e4bde15e5a58b4c9fb4beb0afa78bc3466" dependencies = [ "cap-std-ext 5.1.2", "futures-util", diff --git a/crates/lib/src/bootc_composefs/status.rs b/crates/lib/src/bootc_composefs/status.rs index bd8b7a19c..59e818062 100644 --- a/crates/lib/src/bootc_composefs/status.rs +++ b/crates/lib/src/bootc_composefs/status.rs @@ -25,7 +25,7 @@ use crate::{ bls_config::{BLSConfig, BLSConfigType, parse_bls_config}, grub_menuconfig::{MenuEntry, parse_grub_menuentry_file}, }, - spec::{BootEntry, BootOrder, Host, HostSpec, ImageReference, ImageStatus}, + spec::{BootEntry, BootOrder, Host, HostSpec, ImageStatus}, store::Storage, utils::{EfiError, read_uefi_var}, }; @@ -493,7 +493,7 @@ fn boot_entry_from_composefs_deployment( let image = match origin.get::("origin", ORIGIN_CONTAINER) { Some(img_name_from_config) => { let ostree_img_ref = OstreeImageReference::from_str(&img_name_from_config)?; - let img_ref = ImageReference::from(ostree_img_ref); + let img_ref = crate::spec::ImageReference::from(ostree_img_ref); let img_conf = get_imginfo(storage, &verity)?; diff --git a/crates/ostree-ext/Cargo.toml b/crates/ostree-ext/Cargo.toml index 21fbab810..3029da9fd 100644 --- a/crates/ostree-ext/Cargo.toml +++ b/crates/ostree-ext/Cargo.toml @@ -39,7 +39,7 @@ xshell = { workspace = true, optional = true } # Crate-specific dependencies comfy-table = "7.1.1" -containers-image-proxy = "0.10.0" +containers-image-proxy = "0.10.1" flate2 = { features = ["zlib"], default-features = false, version = "1.0.20" } futures-util = "0.3.13" gvariant = "0.5.0" diff --git a/crates/ostree-ext/src/cli.rs b/crates/ostree-ext/src/cli.rs index b386c09b9..7c3f9995f 100644 --- a/crates/ostree-ext/src/cli.rs +++ b/crates/ostree-ext/src/cli.rs @@ -43,7 +43,7 @@ pub fn parse_imgref(s: &str) -> Result { /// Parse a base [`ImageReference`] from a CLI argument. pub fn parse_base_imgref(s: &str) -> Result { - ImageReference::try_from(s) + Ok(ImageReference::try_from(s)?) } /// Parse an [`ostree::Repo`] from a CLI argument. diff --git a/crates/ostree-ext/src/container/mod.rs b/crates/ostree-ext/src/container/mod.rs index 0fec7f757..3419bdf82 100644 --- a/crates/ostree-ext/src/container/mod.rs +++ b/crates/ostree-ext/src/container/mod.rs @@ -187,34 +187,10 @@ pub(crate) const COMPONENT_SEPARATOR: char = ','; type Result = anyhow::Result; /// A backend/transport for OCI/Docker images. -#[derive(Copy, Clone, Hash, Debug, PartialEq, Eq)] -pub enum Transport { - /// A remote Docker/OCI registry (`registry:` or `docker://`) - Registry, - /// A local OCI directory (`oci:`) - OciDir, - /// A local OCI archive tarball (`oci-archive:`) - OciArchive, - /// A local Docker archive tarball (`docker-archive:`) - DockerArchive, - /// Local container storage (`containers-storage:`) - ContainerStorage, - /// Local directory (`dir:`) - Dir, - /// Local Docker daemon (`docker-daemon:`) - DockerDaemon, -} +pub type Transport = containers_image_proxy::transport::Transport; /// Combination of a remote image reference and transport. -/// -/// For example, -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct ImageReference { - /// The storage and transport for the image - pub transport: Transport, - /// The image name (e.g. `quay.io/somerepo/someimage:latest`) - pub name: String, -} +pub type ImageReference = containers_image_proxy::ImageReference; /// Policy for signature verification. #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -240,77 +216,6 @@ pub struct OstreeImageReference { pub imgref: ImageReference, } -impl TryFrom<&str> for Transport { - type Error = anyhow::Error; - - fn try_from(value: &str) -> Result { - Ok(match value { - Self::REGISTRY_STR | "docker" => Self::Registry, - Self::OCI_STR => Self::OciDir, - Self::OCI_ARCHIVE_STR => Self::OciArchive, - Self::DOCKER_ARCHIVE_STR => Self::DockerArchive, - Self::CONTAINERS_STORAGE_STR => Self::ContainerStorage, - Self::LOCAL_DIRECTORY_STR => Self::Dir, - Self::DOCKER_DAEMON_STR => Self::DockerDaemon, - o => return Err(anyhow!("Unknown transport '{}'", o)), - }) - } -} - -impl Transport { - const OCI_STR: &'static str = "oci"; - const OCI_ARCHIVE_STR: &'static str = "oci-archive"; - const DOCKER_ARCHIVE_STR: &'static str = "docker-archive"; - const CONTAINERS_STORAGE_STR: &'static str = "containers-storage"; - const LOCAL_DIRECTORY_STR: &'static str = "dir"; - const REGISTRY_STR: &'static str = "registry"; - const DOCKER_DAEMON_STR: &'static str = "docker-daemon"; - - /// Retrieve an identifier that can then be re-parsed from [`Transport::try_from::<&str>`]. - pub fn serializable_name(&self) -> &'static str { - match self { - Transport::Registry => Self::REGISTRY_STR, - Transport::OciDir => Self::OCI_STR, - Transport::OciArchive => Self::OCI_ARCHIVE_STR, - Transport::DockerArchive => Self::DOCKER_ARCHIVE_STR, - Transport::ContainerStorage => Self::CONTAINERS_STORAGE_STR, - Transport::Dir => Self::LOCAL_DIRECTORY_STR, - Transport::DockerDaemon => Self::DOCKER_DAEMON_STR, - } - } -} - -impl TryFrom<&str> for ImageReference { - type Error = anyhow::Error; - - fn try_from(value: &str) -> Result { - let (transport_name, mut name) = value - .split_once(':') - .ok_or_else(|| anyhow!("Missing ':' in {}", value))?; - let transport: Transport = transport_name.try_into()?; - if name.is_empty() { - return Err(anyhow!("Invalid empty name in {}", value)); - } - if transport_name == "docker" { - name = name - .strip_prefix("//") - .ok_or_else(|| anyhow!("Missing // in docker:// in {}", value))?; - } - Ok(Self { - transport, - name: name.to_string(), - }) - } -} - -impl FromStr for ImageReference { - type Err = anyhow::Error; - - fn from_str(s: &str) -> Result { - Self::try_from(s) - } -} - impl TryFrom<&str> for SignatureSource { type Error = anyhow::Error; @@ -388,28 +293,6 @@ impl FromStr for OstreeImageReference { } } -impl std::fmt::Display for Transport { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let s = match self { - // TODO once skopeo supports this, canonicalize as registry: - Self::Registry => "docker://", - Self::OciArchive => "oci-archive:", - Self::DockerArchive => "docker-archive:", - Self::OciDir => "oci:", - Self::ContainerStorage => "containers-storage:", - Self::Dir => "dir:", - Self::DockerDaemon => "docker-daemon:", - }; - f.write_str(s) - } -} - -impl std::fmt::Display for ImageReference { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}{}", self.transport, self.name) - } -} - impl std::fmt::Display for SignatureSource { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { @@ -642,7 +525,7 @@ mod tests { Transport::DockerArchive, Transport::OciDir, ] { - assert_eq!(Transport::try_from(v.serializable_name()).unwrap(), v); + assert_eq!(Transport::try_from(v.to_string().as_ref()).unwrap(), v); } } diff --git a/crates/ostree-ext/src/container/store.rs b/crates/ostree-ext/src/container/store.rs index ea0665d40..8acf5831e 100644 --- a/crates/ostree-ext/src/container/store.rs +++ b/crates/ostree-ext/src/container/store.rs @@ -2096,8 +2096,9 @@ fn gc_image_layers_impl( let deployment_commits = list_container_deployment_manifests(repo, cancellable)?; let all_manifests = all_images .into_iter() - .map(|img| { - ImageReference::try_from(img.as_str()).and_then(|ir| manifest_for_image(repo, &ir)) + .map(|img| -> Result<_> { + let ir = ImageReference::try_from(img.as_str())?; + manifest_for_image(repo, &ir) }) .chain(deployment_commits.into_iter().map(Ok)) .collect::>>()?; diff --git a/crates/ostree-ext/src/repair.rs b/crates/ostree-ext/src/repair.rs index b46408cba..b481f0b42 100644 --- a/crates/ostree-ext/src/repair.rs +++ b/crates/ostree-ext/src/repair.rs @@ -183,7 +183,7 @@ pub fn analyze_for_repair(sysroot: &SysrootLock, verbose: bool) -> Result Result<_> { Ok(crate::container::ImageReference::try_from(img.as_str())?) }) .collect::>>()?; println!("Verifying ostree-container images: {}", all_images.len()); let mut likely_corrupted_container_image_merges = Vec::new(); diff --git a/crates/xtask/src/man.rs b/crates/xtask/src/man.rs index a1b080518..b41565c40 100644 --- a/crates/xtask/src/man.rs +++ b/crates/xtask/src/man.rs @@ -10,6 +10,8 @@ use serde::{Deserialize, Serialize}; use std::{fs, io::Write}; use xshell::{Shell, cmd}; +use crate::out_of_sync_error; + /// Represents a CLI option extracted from the JSON dump #[derive(Debug, Serialize, Deserialize)] pub struct CliOption { @@ -664,10 +666,7 @@ pub fn check_manpages(sh: &Shell) -> Result<()> { let filename = format!("bootc-{}.8.md", command_parts.join("-")); let filepath = Utf8Path::new("docs/src/man").join(&filename); if !filepath.exists() { - anyhow::bail!( - "{} is missing; run `cargo xtask update-generated` to create it", - filepath - ); + return out_of_sync_error(&format!("{filepath} is missing")); } } @@ -729,10 +728,7 @@ fn check_markdown_options( return Ok(()); }; if new_content != content { - anyhow::bail!( - "{} is out of date; run `cargo xtask update-generated` to update it", - markdown_path - ); + return out_of_sync_error(&format!("{markdown_path} is out of date")); } Ok(()) } @@ -750,10 +746,7 @@ fn check_markdown_subcommands( return Ok(()); }; if new_content != content { - anyhow::bail!( - "{} is out of date; run `cargo xtask update-generated` to update it", - markdown_path - ); + return out_of_sync_error(&format!("{markdown_path} is out of date")); } Ok(()) } diff --git a/crates/xtask/src/tmt.rs b/crates/xtask/src/tmt.rs index 0152285ef..795830343 100644 --- a/crates/xtask/src/tmt.rs +++ b/crates/xtask/src/tmt.rs @@ -34,7 +34,7 @@ const DISTRO_CENTOS_9: &str = "centos-9"; // Import the argument types from xtask.rs use crate::bcvk::BcvkInstallOpts; -use crate::{RunTmtArgs, SealState, TmtProvisionArgs}; +use crate::{RunTmtArgs, SealState, TmtProvisionArgs, out_of_sync_error}; /// Generate a random alphanumeric suffix for VM names fn generate_random_suffix() -> String { @@ -941,16 +941,10 @@ pub(crate) fn check_integration() -> Result<()> { .with_context(|| format!("Reading {}", integration_fmf_path))?; if tests_generated != tests_on_disk { - anyhow::bail!( - "{} is out of date; run `cargo xtask update-generated` to update it", - tests_fmf_path - ); + return out_of_sync_error(&format!("{tests_fmf_path} is out of date")); } if integration_generated != integration_on_disk { - anyhow::bail!( - "{} is out of date; run `cargo xtask update-generated` to update it", - integration_fmf_path - ); + return out_of_sync_error(&format!("{integration_fmf_path} is out of date")); } Ok(()) diff --git a/crates/xtask/src/xtask.rs b/crates/xtask/src/xtask.rs index 448a4fff4..79f4ffff6 100644 --- a/crates/xtask/src/xtask.rs +++ b/crates/xtask/src/xtask.rs @@ -40,6 +40,11 @@ const TAR_REPRODUCIBLE_OPTS: &[&str] = &[ "--pax-option=exthdr.name=%d/PaxHeaders/%f,delete=atime,delete=ctime", ]; +/// Helper function to write out out-of-sync error messages for manpages, tmt tests +fn out_of_sync_error(message: &str) -> Result<()> { + anyhow::bail!("{}; run `just update-generated` to update it", message) +} + /// Build tasks for bootc #[derive(Debug, Parser)] #[command(name = "xtask")] @@ -623,9 +628,7 @@ fn check_json_schemas(sh: &Shell) -> Result<()> { let on_disk = std::fs::read_to_string(target).with_context(|| format!("Reading {target}"))?; if generated != on_disk { - anyhow::bail!( - "{target} is out of date; run `cargo xtask update-generated` to update it" - ); + return out_of_sync_error(&format!("{target} is out of date")); } } Ok(())