### Open or Create OCI Directories Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Use OciDir::open for existing directories or OciDir::ensure to initialize a new OCI layout. Requires a cap-std directory handle. ```rust use ocidir::OciDir; use ocidir::cap_std::fs::Dir; // Open an existing OCI directory let dir = Dir::open_ambient_dir("/path/to/ocidir", ocidir::cap_std::ambient_authority())?; let oci_dir = OciDir::open(dir)?; // Create or open an OCI directory (creates oci-layout and blobs/sha256 if missing) let dir = Dir::open_ambient_dir("/path/to/new-ocidir", ocidir::cap_std::ambient_authority())?; let oci_dir = OciDir::ensure(dir)?; // Read the image index to see what manifests are available let index = oci_dir.read_index()?; println!("Manifests in directory: {}", index.manifests().len()); for desc in index.manifests() { println!(" {} ({})", desc.digest(), desc.media_type()); } ``` -------------------------------- ### Create Image Layers with Gzip Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Combine create_gzip_layer with the tar crate to package filesystem content into OCI layers. Use push_layer to update manifests and configurations. ```rust use ocidir::OciDir; use oci_spec::image::{ImageConfigurationBuilder, Platform}; use std::io::Write; let oci_dir = OciDir::ensure(dir)?; // Create a new empty manifest and config let mut manifest = oci_dir.new_empty_manifest()?.build()?; let mut config = ImageConfigurationBuilder::default().build()?; // Create a gzip-compressed tar layer let layer_writer = oci_dir.create_gzip_layer(None)?; // None = default compression let mut tar_builder = tar::Builder::new(layer_writer); tar_builder.follow_symlinks(false); // Add files to the layer tar_builder.append_dir_all("app", "/path/to/application")?; // Finalize the layer let layer = tar_builder.into_inner()?.complete()?; // Push the layer onto the manifest and config oci_dir.push_layer( &mut manifest, &mut config, layer, "Add application files", // History description None, // Optional annotations ); // Insert the manifest into the image index let descriptor = oci_dir.insert_manifest_and_config( manifest, config, Some("v1.0"), // Tag name Platform::default(), )?; println!("Image created: {}", descriptor.digest()); ``` -------------------------------- ### Create Zstd Compressed Layers Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Demonstrates creating layers with standard and multithreaded zstd compression. Requires the 'zstd' or 'zstdmt' features respectively. ```rust use ocidir::OciDir; use oci_spec::image::{ImageConfigurationBuilder, Platform}; let oci_dir = OciDir::ensure(dir)?; let mut manifest = oci_dir.new_empty_manifest()?.build()?; let mut config = ImageConfigurationBuilder::default().build()?; // Create a zstd-compressed layer (requires "zstd" feature) let layer_writer = oci_dir.create_layer_zstd(Some(3))?; // Compression level 3 let mut tar_builder = tar::Builder::new(layer_writer); tar_builder.append_dir_all(".", "/path/to/content")?; let layer = tar_builder.into_inner()?.complete()?; oci_dir.push_layer(&mut manifest, &mut config, layer, "Add content with zstd", None); // For large layers, use multithreaded compression (requires "zstdmt" feature) let layer_writer = oci_dir.create_layer_zstd_multithread(Some(3), 4)?; // 4 threads let mut tar_builder = tar::Builder::new(layer_writer); tar_builder.append_dir_all(".", "/path/to/large-content")?; let layer = tar_builder.into_inner()?.complete()?; oci_dir.push_layer(&mut manifest, &mut config, layer, "Add large content", None); let _desc = oci_dir.insert_manifest_and_config(manifest, config, None, Platform::default())?; ``` -------------------------------- ### Open Images for the Current Platform Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Resolves an image manifest for the native platform, handling manifest lists automatically. ```rust use ocidir::OciDir; let oci_dir = OciDir::open(dir)?; // Open the image for the current platform (auto-resolves manifest lists) let resolved = oci_dir.open_image_this_platform(None)?; println!("Manifest digest: {}", resolved.manifest_descriptor.digest()); println!("Layers: {}", resolved.manifest.layers().len()); // Check if it came from a manifest list if let Some((index, index_desc)) = &resolved.source_index { println!("Resolved from manifest list: {}", index_desc.digest()); println!("Available platforms: {}", index.manifests().len()); } // Open a specific tagged image for this platform let resolved = oci_dir.open_image_this_platform(Some("v2.0"))?; println!("Tagged image manifest: {}", resolved.manifest_descriptor.digest()); ``` -------------------------------- ### Create OCI Artifact Manifests with ocidir-rs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt The `insert_artifact_manifest` method creates OCI 1.1 artifact manifests, which include a `subject` field for attaching metadata like SBOMs or signatures to images. This process involves first creating or referencing a base image, then creating the artifact content (e.g., an SBOM blob), and finally constructing the artifact manifest that references the base image and its content. ```rust use ocidir::OciDir; use oci_spec::image::{MediaType, Platform}; use std::collections::HashMap; use std::io::Write; let oci_dir = OciDir::ensure(dir)?; // First, create or reference a base image let manifest = oci_dir.new_empty_manifest()?.build()?; let config = ocidir::oci_spec::image::ImageConfigurationBuilder::default().build()?; let subject_desc = oci_dir.insert_manifest_and_config( manifest, config, Some("myimage"), Platform::default(), )?; // Create SBOM content blob let sbom_content = br#"{"packages": [{"name": "myapp", "version": "1.0.0"}]}"#; let mut sbom_blob = oci_dir.create_blob()?; sbom_blob.write_all(sbom_content)?; let sbom_blob = sbom_blob.complete()?; let sbom_layer = sbom_blob.descriptor() .media_type(MediaType::Other("application/spdx+json".into())) .build()?; // Create the artifact manifest referencing the base image let artifact_type = MediaType::Other("application/vnd.example.sbom.v1".into()); let annotations: HashMap = [ ("org.example.format".into(), "spdx".into()), ("org.example.tool".into(), "sbom-generator".into()), ].into_iter().collect(); let artifact_desc = oci_dir.insert_artifact_manifest( subject_desc.clone(), // The image this artifact references artifact_type, vec![sbom_layer], // Content layers (or empty for metadata-only) Some(annotations), )?; println!("SBOM artifact: {}", artifact_desc.digest()); println!("Artifact type: {:?}", artifact_desc.artifact_type()); ``` -------------------------------- ### Import Pre-built Tarballs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Imports a tarball directly as an uncompressed layer blob without re-compression. ```rust use ocidir::OciDir; use oci_spec::image::{ImageConfigurationBuilder, MediaType, Platform, HistoryBuilder}; use std::fs::File; use std::io::{BufReader, Write}; use chrono::Utc; let oci_dir = OciDir::ensure(dir)?; // Open the pre-built tarball let tarball = File::open("/path/to/rootfs.tar")?; let mtime = tarball.metadata()?.modified()?; let mut reader = BufReader::new(tarball); // Create manifest and config let mut manifest = oci_dir.new_empty_manifest()?.build()?; let mut config = ImageConfigurationBuilder::default().build()?; // Write the tarball as a raw blob (uncompressed layer) let mut writer = oci_dir.create_blob()?; std::io::copy(&mut reader, &mut writer)?; let blob = writer.complete()?; // Build the layer descriptor let descriptor = blob.descriptor() .media_type(MediaType::ImageLayer) // Uncompressed tar .build()?; // Add to manifest's layers manifest.layers_mut().push(descriptor.clone()); // Update config's rootfs diff_ids let mut rootfs = config.rootfs().clone(); rootfs.diff_ids_mut().push(descriptor.digest().to_string()); config.set_rootfs(rootfs); // Add history entry let created = chrono::DateTime::::from(mtime); let history = HistoryBuilder::default() .created(created.to_rfc3339()) .created_by("Imported from rootfs.tar") .build()?; config.history_mut().get_or_insert_default().push(history); // Insert into the image index let _desc = oci_dir.insert_manifest_and_config( manifest, config, Some("imported"), Platform::default(), )?; ``` -------------------------------- ### Create Custom Compression Layers Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Implements the WriteComplete trait to define custom layer compression logic, such as no compression. ```rust use ocidir::{BlobWriter, OciDir, WriteComplete}; use oci_spec::image::{ImageConfigurationBuilder, MediaType, Platform}; use std::io::{self, Write}; // Define a no-compression wrapper struct NoCompression<'a>(BlobWriter<'a>); impl io::Write for NoCompression<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { self.0.write(buf) } fn flush(&mut self) -> io::Result<()> { self.0.flush() } } impl<'a> WriteComplete> for NoCompression<'a> { fn complete(self) -> io::Result> { Ok(self.0) } } // Use the custom layer writer let oci_dir = OciDir::ensure(dir)?; let mut manifest = oci_dir.new_empty_manifest()?.build()?; let mut config = ImageConfigurationBuilder::default().build()?; let layer_writer = oci_dir.create_custom_layer( |bw| Ok(NoCompression(bw)), MediaType::ImageLayer, // Uncompressed tar )?; let mut tar_builder = tar::Builder::new(layer_writer); tar_builder.append_dir_all(".", "/path/to/content")?; let layer = tar_builder.into_inner()?.complete()?; oci_dir.push_layer(&mut manifest, &mut config, layer, "Uncompressed layer", None); let _desc = oci_dir.insert_manifest_and_config(manifest, config, None, Platform::default())?; ``` -------------------------------- ### Create and Manage Blobs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Utilize BlobWriter to compute SHA-256 checksums during write operations. The complete() method finalizes the blob and moves it to the content-addressed storage. ```rust use ocidir::OciDir; use std::io::Write; let oci_dir = OciDir::ensure(dir)?; // Create a raw blob (any content) let mut blob_writer = oci_dir.create_blob()?; blob_writer.write_all(b"arbitrary blob content")?; let blob = blob_writer.complete()?; // Get the blob's SHA-256 digest and size println!("Blob digest: {}", blob.sha256()); println!("Blob size: {}", blob.size()); // Build a descriptor for use in manifests let descriptor = blob.descriptor() .media_type(oci_spec::image::MediaType::Other("application/octet-stream".into())) .build()?; ``` -------------------------------- ### Access an OCI directory Source: https://github.com/bootc-dev/ocidir-rs/blob/main/README.md Opens an existing OCI directory using cap-std and reads the index. ```rust # use ocidir::cap_std; # use anyhow::{anyhow, Result}; # fn main() -> anyhow::Result<()> { let d = cap_std::fs::Dir::open_ambient_dir("/path/to/ocidir", cap_std::ambient_authority())?; let d = ocidir::OciDir::open(d)?; println!("{:?}", d.read_index()?); # Ok(()) # } ``` -------------------------------- ### Find Referrers using OCI Referrers API with ocidir-rs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt The `find_referrers` method implements the OCI Referrers API locally, allowing you to discover all artifacts that reference a given image by its digest. You can optionally filter these referrers by their artifact type. ```rust use ocidir::OciDir; use oci_spec::image::MediaType; let oci_dir = OciDir::open(dir)?; // Find the base image let index = oci_dir.read_index()?; let image_desc = oci_dir.find_manifest_descriptor_with_tag("myimage")? .expect("image not found"); // Find ALL referrers (SBOMs, signatures, attestations, etc.) let all_referrers = oci_dir.find_referrers(image_desc.digest(), None)?; println!("Found {} referrer(s)", all_referrers.len()); for referrer in &all_referrers { println!(" Digest: {}", referrer.digest()); println!(" Artifact type: {:?}", referrer.artifact_type()); if let Some(annos) = referrer.annotations() { for (k, v) in annos { println!(" {}: {}", k, v); } } } // Filter referrers by artifact type let sbom_type = MediaType::Other("application/vnd.example.sbom.v1".into()); let sbom_referrers = oci_dir.find_referrers(image_desc.digest(), Some(&sbom_type))?; println!("SBOM referrers: {}", sbom_referrers.len()); let sig_type = MediaType::Other("application/vnd.cncf.notary.signature".into()); let signature_referrers = oci_dir.find_referrers(image_desc.digest(), Some(&sig_type))?; println!("Signature referrers: {}", signature_referrers.len()); ``` -------------------------------- ### Read Manifests and Blobs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Retrieves and deserializes OCI image components, including indices, manifests, and raw blob data. ```rust use ocidir::OciDir; use oci_spec::image::{ImageManifest, ImageConfiguration}; let oci_dir = OciDir::open(dir)?; // Read the image index let index = oci_dir.read_index()?; // Find a manifest by tag if let Some(manifest) = oci_dir.find_manifest_with_tag("latest")? { println!("Found manifest with {} layers", manifest.layers().len()); // Read the config blob let config: ImageConfiguration = oci_dir.read_json_blob(manifest.config())?; if let Some(history) = config.history() { for entry in history { println!("History: {:?}", entry.created_by()); } } } // Read a manifest by descriptor let manifest_desc = &index.manifests()[0]; let manifest: ImageManifest = oci_dir.read_json_blob(manifest_desc)?; // Read raw blob data let layer_desc = &manifest.layers()[0]; let mut blob_file = oci_dir.read_blob(layer_desc)?; // blob_file is a std::fs::File that can be read // Check if blobs exist let exists = oci_dir.has_blob(layer_desc)?; let manifest_exists = oci_dir.has_manifest(manifest_desc)?; ``` -------------------------------- ### Verify Image Integrity (fsck) Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Validates the OCI directory by checking digests and sizes of all manifests, configs, and layer blobs. ```rust use ocidir::OciDir; let oci_dir = OciDir::open(dir)?; // Verify all blobs in the directory match oci_dir.fsck() { Ok(validated_count) => { println!("Verified {} blobs successfully", validated_count); } Err(ocidir::Error::DigestMismatch { expected, found }) => { eprintln!("Corruption detected! Expected {} but found {}", expected, found); } Err(ocidir::Error::SizeMismatch { expected, found }) => { eprintln!("Size mismatch! Expected {} bytes but found {}", expected, found); } Err(e) => { eprintln!("Verification failed: {}", e); } } ``` -------------------------------- ### Write JSON Blobs with ocidir-rs Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Use `write_json_blob` to serialize any Serde-serializable type to a blob with canonical JSON formatting. This method returns a descriptor builder for the written content. Ensure you have the `OciDir` instance and the data to be serialized. ```rust use ocidir::OciDir; use oci_spec::image::{ImageConfigurationBuilder, MediaType}; let oci_dir = OciDir::ensure(dir)?; // Create an image configuration let config = ImageConfigurationBuilder::default() .os("linux") .architecture("amd64") .build()?; // Write it as a blob and get a descriptor let config_desc = oci_dir.write_config(config)?; println!("Config blob: {}", config_desc.digest()); // Write arbitrary JSON as a blob #[derive(serde::Serialize)] struct CustomMetadata { version: String, author: String, } let metadata = CustomMetadata { version: "1.0.0".into(), author: "example".into(), }; let desc_builder = oci_dir.write_json_blob( &metadata, MediaType::Other("application/vnd.example.metadata+json".into()), )?; let descriptor = desc_builder.build()?; ``` -------------------------------- ### Verify Blobs Against Expected Descriptors Source: https://context7.com/bootc-dev/ocidir-rs/llms.txt Validates that written content matches an expected descriptor using BlobWriter. ```rust use ocidir::OciDir; use oci_spec::image::{DescriptorBuilder, MediaType, Sha256Digest}; use std::io::Write; use std::str::FromStr; let oci_dir = OciDir::ensure(dir)?; // Expected descriptor from an external source (e.g., pulled manifest) let expected_descriptor = DescriptorBuilder::default() .media_type(MediaType::ImageLayerGzip) .size(1234u64) .digest(Sha256Digest::from_str( "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" )?) .build()?; // Write content and verify against the expected descriptor let mut writer = oci_dir.create_blob()?; writer.write_all(&external_blob_data)?; match writer.complete_verified_as(&expected_descriptor) { Ok(blob) => { println!("Blob verified and stored: {}", blob.sha256()); } Err(ocidir::Error::DigestMismatch { expected, found }) => { eprintln!("Digest mismatch: expected {} got {}", expected, found); } Err(ocidir::Error::SizeMismatch { expected, found }) => { eprintln!("Size mismatch: expected {} got {}", expected, found); } Err(e) => return Err(e.into()), } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.