-
-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Traits to abstract oci-dir and oci-archive formats (#117)
Split from #108 - This PR introduces `ImageLayout` and `ImageLayoutBuilder` - `ImageLayout` abstracts a storage which satisfies [OCI Image layout](https://github.com/opencontainers/image-spec/blob/v1.1.0/image-layout.md), i.e. `index.json`, `blobs/`, and `oci-layout` file - In addition, `ImageLayout` assumes single layout contains single manifest. - Refactoring of `ocipkg::image::Builder` is done in this PR, and refactoring of `ocipkg::image::Archive` will be next PR.
- Loading branch information
Showing
10 changed files
with
375 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,79 @@ | ||
use crate::{image::ImageLayoutBuilder, ImageName}; | ||
use anyhow::Result; | ||
use oci_spec::image::{ | ||
Descriptor, DescriptorBuilder, ImageManifest, ImageManifestBuilder, MediaType, | ||
}; | ||
use std::collections::HashMap; | ||
|
||
/// Create a new OCI Artifact over [ImageLayoutBuilder] | ||
/// | ||
/// This creates a generic OCI Artifact, not the ocipkg artifact defined as `application/vnd.ocipkg.v1.artifact`. | ||
/// It is the task of the [crate::image::Builder]. | ||
pub struct ArtifactBuilder<Base: ImageLayoutBuilder> { | ||
name: ImageName, | ||
manifest: ImageManifest, | ||
layout: Base, | ||
} | ||
|
||
impl<Base: ImageLayoutBuilder> ArtifactBuilder<Base> { | ||
/// Create a new OCI Artifact with its media type | ||
pub fn new(mut layout: Base, artifact_type: MediaType, name: ImageName) -> Result<Self> { | ||
let empty_config = layout.add_empty_json()?; | ||
let manifest = ImageManifestBuilder::default() | ||
.schema_version(2_u32) | ||
.artifact_type(artifact_type) | ||
.config(empty_config) | ||
.layers(Vec::new()) | ||
.build()?; | ||
Ok(Self { | ||
layout, | ||
manifest, | ||
name, | ||
}) | ||
} | ||
|
||
/// Add `config` of the OCI Artifact | ||
/// | ||
/// Image manifest of artifact can store any type of configuration blob. | ||
pub fn add_config( | ||
&mut self, | ||
config_type: MediaType, | ||
config_blob: &[u8], | ||
annotations: HashMap<String, String>, | ||
) -> Result<Descriptor> { | ||
let (digest, size) = self.layout.add_blob(config_blob)?; | ||
let config = DescriptorBuilder::default() | ||
.media_type(config_type) | ||
.annotations(annotations) | ||
.digest(digest.to_string()) | ||
.size(size) | ||
.build()?; | ||
self.manifest.set_config(config.clone()); | ||
Ok(config) | ||
} | ||
|
||
/// Append a `layer` to the OCI Artifact | ||
/// | ||
/// Image manifest of artifact can store any type of layer blob. | ||
pub fn add_layer( | ||
&mut self, | ||
layer_type: MediaType, | ||
layer_blob: &[u8], | ||
annotations: HashMap<String, String>, | ||
) -> Result<Descriptor> { | ||
let (digest, size) = self.layout.add_blob(layer_blob)?; | ||
let layer = DescriptorBuilder::default() | ||
.media_type(layer_type) | ||
.digest(digest.to_string()) | ||
.size(size) | ||
.annotations(annotations) | ||
.build()?; | ||
self.manifest.layers_mut().push(layer.clone()); | ||
Ok(layer) | ||
} | ||
|
||
/// Build the OCI Artifact | ||
pub fn build(self) -> Result<Base::ImageLayout> { | ||
self.layout.build(self.manifest, self.name) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
use crate::{Digest, ImageName}; | ||
use anyhow::{Context, Result}; | ||
use oci_spec::image::{Descriptor, DescriptorBuilder, ImageIndex, ImageManifest, MediaType}; | ||
|
||
/// Handler of [OCI Image Layout] containing single manifest. | ||
/// | ||
/// Though the [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 ImageLayout { | ||
/// Get `index.json` | ||
fn get_index(&mut self) -> Result<ImageIndex>; | ||
/// Get blob content. | ||
fn get_blob(&mut self, digest: &Digest) -> Result<Vec<u8>>; | ||
|
||
/// Get manifest stored in the image layout. | ||
/// | ||
/// Note that this trait assumes a single manifest in a single layout. | ||
/// If `index.json` contains `org.opencontainers.image.ref.name` annotation, it is returned as [ImageName]. | ||
fn get_manifest(&mut self) -> Result<(Option<ImageName>, ImageManifest)> { | ||
let index = self.get_index()?; | ||
let desc = index.manifests().first().context("Missing manifest")?; | ||
let name = if let Some(name) = desc | ||
.annotations() | ||
.as_ref() | ||
.and_then(|annotations| annotations.get("org.opencontainers.image.ref.name")) | ||
{ | ||
// Invalid image name raises an error, while missing name is just ignored. | ||
Some(ImageName::parse(name)?) | ||
} else { | ||
None | ||
}; | ||
let digest = Digest::from_descriptor(desc)?; | ||
let manifest = serde_json::from_slice(self.get_blob(&digest)?.as_slice())?; | ||
Ok((name, manifest)) | ||
} | ||
} | ||
|
||
/// Create new image layout. | ||
/// | ||
/// Creating [ImageManifest] is out of scope of this trait. | ||
pub trait ImageLayoutBuilder { | ||
/// Handler of generated image. | ||
type ImageLayout: ImageLayout; | ||
/// Add a blob to the image layout. | ||
fn add_blob(&mut self, data: &[u8]) -> Result<(Digest, i64)>; | ||
/// Finish building image layout. | ||
fn build(self, manifest: ImageManifest, name: ImageName) -> Result<Self::ImageLayout>; | ||
|
||
/// A placeholder for `application/vnd.oci.empty.v1+json` | ||
fn add_empty_json(&mut self) -> Result<Descriptor> { | ||
let (digest, size) = self.add_blob(b"{}")?; | ||
Ok(DescriptorBuilder::default() | ||
.media_type(MediaType::EmptyJSON) | ||
.size(size) | ||
.digest(digest.to_string()) | ||
.build()?) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,19 @@ | ||
//! Read and Write images based on [OCI image specification](https://github.com/opencontainers/image-spec) | ||
//! Read and Write ocipkg artifacts defined as `application/vnd.ocipkg.v1.artifact` | ||
//! | ||
//! See the crate level documentation for more information. | ||
|
||
pub mod annotations; | ||
|
||
mod artifact; | ||
mod config; | ||
mod layout; | ||
mod oci_archive; | ||
mod read; | ||
mod write; | ||
|
||
pub use artifact::*; | ||
pub use config::*; | ||
pub use layout::*; | ||
pub use oci_archive::*; | ||
pub use read::*; | ||
pub use write::*; |
Oops, something went wrong.