From 3df48ac10afdf7f50d699b4ec716c28d625a7644 Mon Sep 17 00:00:00 2001 From: Toshiki Teramura Date: Fri, 10 May 2024 19:11:52 +0900 Subject: [PATCH] Allow creating oci-archive and oci-dir without image name (#132) In some cases, one want to create an oci-archive or oci-dir which never pushed to registry. --- ocipkg/src/image/layout.rs | 5 ++--- ocipkg/src/image/oci_archive.rs | 25 +++++++++++++++++++++---- ocipkg/src/image/oci_dir.rs | 24 ++++++++++++++++++++---- 3 files changed, 43 insertions(+), 11 deletions(-) diff --git a/ocipkg/src/image/layout.rs b/ocipkg/src/image/layout.rs index 6098da2..97fd985 100644 --- a/ocipkg/src/image/layout.rs +++ b/ocipkg/src/image/layout.rs @@ -6,16 +6,15 @@ use anyhow::{bail, Context, Result}; use oci_spec::image::{Descriptor, DescriptorBuilder, ImageIndex, ImageManifest, MediaType}; use std::path::Path; -/// Handler of [OCI Image Layout] with containing single manifest and its name. +/// Handler of [OCI Image Layout] with containing single manifest /// -/// - [OCI Image Layout] allows empty image name, i.e. no `org.opencontainers.image.ref.name` annotation, but this trait does not allow it. /// - [OCI Image Layout] allows containing multiple manifests in a single layout, /// this trait assumes a single manifest in a single layout. /// /// [OCI Image Layout]: https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md /// pub trait Image { - /// The name of this image. + /// The name of this image. This fails if the image does not have name. fn get_name(&mut self) -> Result; /// Get blob content. diff --git a/ocipkg/src/image/oci_archive.rs b/ocipkg/src/image/oci_archive.rs index ade7cc5..e9eb960 100644 --- a/ocipkg/src/image/oci_archive.rs +++ b/ocipkg/src/image/oci_archive.rs @@ -14,12 +14,25 @@ use std::{ /// Build an [OciArchive] pub struct OciArchiveBuilder { - image_name: ImageName, + image_name: Option, path: PathBuf, ar: tar::Builder, } impl OciArchiveBuilder { + pub fn new_unnamed(path: PathBuf) -> Result { + if path.exists() { + bail!("File already exists: {}", path.display()); + } + let f = fs::File::create(&path)?; + let ar = tar::Builder::new(f); + Ok(Self { + ar, + path, + image_name: None, + }) + } + pub fn new(path: PathBuf, image_name: ImageName) -> Result { if path.exists() { bail!("File already exists: {}", path.display()); @@ -29,7 +42,7 @@ impl OciArchiveBuilder { Ok(Self { ar, path, - image_name, + image_name: Some(image_name), }) } } @@ -51,8 +64,12 @@ impl ImageBuilder for OciArchiveBuilder { .media_type(MediaType::ImageManifest) .size(size) .digest(digest.to_string()) - .annotations(hashmap! { - "org.opencontainers.image.ref.name".to_string() => self.image_name.to_string() + .annotations(if let Some(name) = &self.image_name { + hashmap! { + "org.opencontainers.image.ref.name".to_string() => name.to_string() + } + } else { + hashmap! {} }) .build()?; let index = ImageIndexBuilder::default() diff --git a/ocipkg/src/image/oci_dir.rs b/ocipkg/src/image/oci_dir.rs index ff4737c..7bc8b4d 100644 --- a/ocipkg/src/image/oci_dir.rs +++ b/ocipkg/src/image/oci_dir.rs @@ -16,7 +16,7 @@ use super::get_name_from_index; /// Build an [OciDir] pub struct OciDirBuilder { - image_name: ImageName, + image_name: Option, oci_dir_root: PathBuf, is_finished: bool, } @@ -37,13 +37,25 @@ impl Drop for OciDirBuilder { } impl OciDirBuilder { + pub fn new_unnamed(oci_dir_root: PathBuf) -> Result { + if oci_dir_root.exists() { + bail!("oci-dir {} already exists", oci_dir_root.display()); + } + fs::create_dir_all(&oci_dir_root)?; + Ok(Self { + image_name: None, + oci_dir_root, + is_finished: false, + }) + } + pub fn new(oci_dir_root: PathBuf, image_name: ImageName) -> Result { if oci_dir_root.exists() { bail!("oci-dir {} already exists", oci_dir_root.display()); } fs::create_dir_all(&oci_dir_root)?; Ok(Self { - image_name, + image_name: Some(image_name), oci_dir_root, is_finished: false, }) @@ -68,8 +80,12 @@ impl ImageBuilder for OciDirBuilder { .media_type(MediaType::ImageManifest) .size(size) .digest(digest.to_string()) - .annotations(hashmap! { - "org.opencontainers.image.ref.name".to_string() => self.image_name.to_string(), + .annotations(if let Some(name) = &self.image_name { + hashmap! { + "org.opencontainers.image.ref.name".to_string() => name.to_string() + } + } else { + hashmap! {} }) .build()?; let index = ImageIndexBuilder::default()