Compare commits

...

74 Commits
v0.2.0 ... main

Author SHA1 Message Date
Colin Walters 5ffd1e7aa5
Merge pull request #42 from containers/add-all-docs
Enable missing_docs lint, add missing docs
2025-07-01 12:27:08 -04:00
Colin Walters 262d9e0c6c Enable missing_docs lint, add missing docs
This is a general best practice.

Signed-off-by: Colin Walters <walters@verbum.org>
2025-07-01 07:47:07 -04:00
Colin Walters fb45756064
Merge pull request #29 from tofay/generic
Support custom image compression
2025-07-01 07:43:35 -04:00
Tom Fay fe0bd15f4f semver bump due to public type removal
Signed-off-by: Tom Fay <tom@teamfay.co.uk>
2025-07-01 07:25:15 +01:00
Tom Fay 96ecbea8c4 support custom compression
Signed-off-by: Tom Fay <tom@teamfay.co.uk>
2025-06-29 21:01:43 +01:00
Colin Walters 21b2e82baf
Merge pull request #41 from containers/release
Bump oci-spec and our semver
2025-06-17 09:29:42 -04:00
Colin Walters 4e5eb1c2bd Bump oci-spec and our semver
Just keeping up with dependencies.

Signed-off-by: Colin Walters <walters@verbum.org>
2025-06-17 09:18:55 -04:00
Colin Walters bb3111429a
Merge pull request #40 from champtar/canon-json
Switch to canon-json
2025-06-17 08:53:45 -04:00
Etienne Champetier 13a99d1519 Bump lints toolchain version / fix clippy warnings
Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
2025-06-17 08:42:42 -04:00
Etienne Champetier 0bbfb9487a Switch to canon-json
canon-json provides a serde_json Formatter to serialize
as RFC 8785 canonical JSON.
It's a drop in replacement for olpc-cjson.

Signed-off-by: Etienne Champetier <e.champetier@ateme.com>
2025-06-17 08:31:52 -04:00
Colin Walters 62ff21759e
Merge pull request #37 from containers/push-history
Add a push_layer_with_history
2025-06-15 01:48:49 -04:00
Colin Walters 59083d3566 Add a push_layer_with_history
This allows convenient control over all parts of the history,
including the timestamp.

Replaces https://github.com/containers/ocidir-rs/pull/36
Related to bootc-dev/bootc#1339

Signed-off-by: Colin Walters <walters@verbum.org>
2025-06-02 09:11:25 -04:00
Allison Karlitskaya db8d90cd39
Merge pull request #35 from containers/example-import
examples: Add example that injects arbitrary tar as OCI
2025-05-05 21:47:58 +02:00
Colin Walters 1b4e2642d0 examples: Add example that injects arbitrary tar as OCI
I wanted to test out how container runtimes behaved with
a tarball that had a filled in user/group name. For convenience
of testing arbitrary tarballs in container images, add this
example which takes an externally generated tar and just wraps
it with OCI metadata.

Signed-off-by: Colin Walters <walters@verbum.org>
2025-05-05 12:10:21 -04:00
Colin Walters 2be18fd388
Merge pull request #33 from containers/renovate/all
fix(deps): update rust crate thiserror to v2
2024-12-05 19:26:00 -05:00
Platform Engineering Bot 6331a9c3d5 fix(deps): update rust crate thiserror to v2
Signed-off-by: Platform Engineering Bot <platform-engineering@redhat.com>
2024-11-11 00:09:17 +00:00
Colin Walters 977bb48c4c
Merge pull request #32 from ariel-miculas/minor-comment-fix
Minor fix in the error description comment
2024-10-14 09:14:33 -04:00
Ariel Miculas-Trif 2c826b31d7 Minor fix in the error description comment
Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-10-14 10:52:13 +03:00
Colin Walters a943d18a54
Merge pull request #31 from ariel-miculas/fix-empty-config
new_empty_manifest: create a valid manifest with an empty config desc…
2024-10-13 09:14:46 -04:00
Ariel Miculas-Trif e88564eedd new_empty_manifest: create a valid manifest with an empty config descriptor
The empty descriptor is described in the image spec [1].
`new_empty_manifest` writes an empty config descriptor in the blobs
directory, which results in a valid image layout specification. This is
validated using the fsck function in the `test_new_empty_manifest` test.

Fixes #27

[1] https://github.com/opencontainers/image-spec/blob/main/manifest.md#guidance-for-an-empty-descriptor

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-10-13 10:53:59 +03:00
Colin Walters 6817b48b34
Merge pull request #28 from ariel-miculas/add-helper-functions
Add find_manifest_descriptor_with_tag
2024-10-12 08:13:10 -04:00
Ariel Miculas-Trif 7f58190bc4 Modify read_index to return an ImageIndex instead of an Option<ImageIndex>
The index.json file MUST exist according to the OCI Image Layout Spec
[1], thus read_index should return the ImageIndex directly, there's no
need to wrap it into an Option.

[1] https://github.com/opencontainers/image-spec/blob/main/image-layout.md

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-10-12 02:46:56 +03:00
Ariel Miculas-Trif 8f3d8111dc Add find_manifest_descriptor_with_tag
Refactor find_manifest_with_tag to use this new function.

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-10-12 02:46:56 +03:00
Ariel Miculas-Trif 111ed71e34
Merge pull request #30 from tofay/zstd-no-tar
allow users to get ZstdLayerWriter directly
2024-10-04 19:19:52 +03:00
Tom Fay c3a9e5ca96
test/lint with --all-features
Signed-off-by: Tom Fay <tomfay@microsoft.com>
2024-10-04 16:59:55 +01:00
Tom Fay bdc4fbf4b5
allow users to get zstdlayerwriter directly
Signed-off-by: Tom Fay <tomfay@microsoft.com>
2024-10-01 15:22:28 +01:00
Ariel Miculas-Trif fbfffd2828
Merge pull request #25 from containers/update-for-semver
lib: Drop deprecated `write_json_blob` global
2024-09-30 21:00:14 +03:00
Ariel Miculas-Trif 0738d7ee85
Merge pull request #26 from containers/add-accessors
Make fields non-public with readonly accessors
2024-09-30 20:59:51 +03:00
Colin Walters e9680ac84e lib: Drop deprecated `write_json_blob` global
Since we're bumping semver.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-30 13:30:15 -04:00
Colin Walters 961c9df8b3 BlobWriter: Make fields non-public
No reason for these to be `pub`.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-30 13:26:34 -04:00
Colin Walters bce79bd42e blob: Make fields non-public with readonly accessors
This is a generally good best practice.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-30 13:26:34 -04:00
Colin Walters 3892030c1f dir: Make fields non-public with readonly accessors
This is a generally good best practice.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-30 13:26:34 -04:00
Colin Walters a5f5bfe857
Merge pull request #24 from tofay/zstd
add support for zstd layers
2024-09-30 19:20:02 +02:00
Colin Walters 97ffb16e82
Merge pull request #22 from ariel-miculas/support-symlinks-for-blob
Add support for symlinks in blobs/sha256 path
2024-09-30 19:08:28 +02:00
Ariel Miculas-Trif 0a88546abd Make the open and open_with_external_blobs more consistent
They now both take owned values of type cap_std::Dir for both parameters
instead of references to cap_std::Dir. The reason for owned values
instead of references is avoiding the undesired effects of sharing the
same underlying file handle [1].

[1] https://doc.rust-lang.org/nightly/std/fs/struct.File.html#method.try_clone

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-09-26 21:33:37 +03:00
Ariel Miculas-Trif 175cace3a5 Add support for external blobs
This feature is especially useful when we want to share blobs across OCI
repositories. See the `--dest-shared-blob-dir` option in skopeo [1] as
well as the LXC OCI template [2] (specifically OCI_USE_CACHE).

Usually this is done via symlinking oci/blobs or oci/blobs/sha256, but
ocidir-rs doesn't follow symlinks which lead outside the oci directory
(this is by design). This commit doesn't change the capability model, it
only addresses the blob sharing use case by adding a new
open_with_external_blobs function which takes the blobs directory as a
separate cap_std::Dir. The library won't allow any accesses outside the
blobs directory, but instead of reading the blobs directory from the OCI
directory, it will directly read the user supplied blobs directory.

closes #21

[1] https://github.com/containers/skopeo/blob/main/docs/skopeo-copy.1.md
[2] https://github.com/lxc/lxc/blob/main/templates/lxc-oci.in

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-09-26 21:04:08 +03:00
Tom Fay ff301f7c1f
use sha256writer in gziplayerwriter
Signed-off-by: Tom Fay <tomfay@microsoft.com>
2024-09-26 07:32:18 +01:00
Colin Walters 9cf943496b
Merge pull request #23 from tofay/layer-media-type
allow non-gzip layers
2024-09-25 18:55:50 +02:00
Tom Fay e38436699d
add support for zstd layers behind `zstd` feature
- zstd multi-threaded compression supported behind `zstdmt` feature

Signed-off-by: Tom Fay <tomfay@microsoft.com>
2024-09-25 15:51:00 +01:00
Tom Fay d8636aefac
allow non-gzip layers
Signed-off-by: Tom Fay <tomfay@microsoft.com>
2024-09-25 15:01:43 +01:00
John Eckersberg a41c6bcde9
Merge pull request #20 from containers/release
Move main lib docs into README.md && release
2024-09-20 16:03:12 -04:00
Colin Walters 6c0813923d Release 0.3.1
Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-20 15:03:12 -04:00
Colin Walters f13e9f85d7 README.md: Add docs.rs shield
Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-20 15:03:12 -04:00
Colin Walters f7a0a44825 Move main lib docs into README.md
So our repository landing page has more useful information.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-20 15:03:12 -04:00
Ariel Miculas 86e1c25b19
Merge pull request #19 from containers/unit-test-verified-followup
Add a unit test covering failure for write_verified_as()
2024-09-19 20:58:55 +02:00
Colin Walters 1ba15a82a1 Add a unit test covering failure for write_verified_as()
Followup to the previous commit that added a success path for this.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-19 13:22:46 -04:00
Colin Walters 2b7128f503
Merge pull request #18 from ariel-miculas/fix-complete-verified-as
Fix the behavior of complete_verified_as function
2024-09-18 16:50:54 -04:00
Ariel Miculas-Trif 2920ac3041 Fix the behavior of complete_verified_as function
`complete_verified_as` finishes writing the blob, verifying its digest
and size against the expected descriptor, and then writing the contents
to a file with a completely different sha256 digest. The reason is that
both `complete_verified_as` and `complete` call self.hash.finish(), but
this function can only be called once, because after the first call it
transitions into the Finalized state [1]. The second time it gets called
it realizes it's in the Finalized state and then it calls self.init,
resetting the hasher. This is a bad API design.

Fix this by only calling self.hash.finish() once and then passing the
result to a new internal function `complete_as`, which does the same
thing as `complete` but avoids calling self.hash.finish() again.

Add a test to ensure `complete_verified_as` behaves as expected.

[1] https://docs.rs/openssl/0.10.66/src/openssl/hash.rs.html#295-297

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-09-18 23:24:21 +03:00
Colin Walters aa0e9c1c81
Merge pull request #17 from ariel-miculas/fix_doctest
Fix doctest and run doctests in github CI
2024-09-15 15:09:59 -04:00
Ariel Miculas-Trif 9df6a22a35 Fix doctest and run doctests in github CI
`cargo test --all-features` does not run doc-tests. See
https://github.com/rust-lang/cargo/issues/6669

Signed-off-by: Ariel Miculas-Trif <amiculas@cisco.com>
2024-09-15 21:54:15 +03:00
Colin Walters 658a0de0fd
Merge pull request #16 from containers/use-thiserror
Port to thiserror, drop `get_manifest()` API
2024-09-13 11:16:04 -04:00
Colin Walters 855b3be9e6 Port to thiserror, drop `get_manifest()` API
It was requested that we use `thiserror` as we're a library.

I dropped the `read_manifest` API as I don't think people
should use it in general and it would have required its
own dedicated error type.

Closes: https://github.com/containers/ocidir-rs/issues/15
Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-13 10:27:13 -04:00
John Eckersberg 074a8029bf
Merge pull request #14 from containers/bump-oci-spec
lib: Update to oci-spec 0.7
2024-09-13 10:04:58 -04:00
Colin Walters 4860c7b449 lib: Update to oci-spec 0.7
There are a few semver breaks there, but I helped drive
them because they clean up the codebase here.

Most notably:

- We have hardened upstream "verify descriptor is sha256:" logic
- size is now properly u64

etc.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-09-12 15:41:15 -04:00
John Eckersberg 189c1e989f
Merge pull request #12 from containers/more-fsck
Strengthen fsck
2024-08-28 09:42:00 -04:00
John Eckersberg 93e801225b
Merge pull request #13 from containers/fix-default-feature
build: Use `default-features` with a dash `-`
2024-08-28 09:21:33 -04:00
Colin Walters dc26082460 build: Use `default-features` with a dash `-`
Squashes a build warning.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-28 07:44:26 -04:00
Colin Walters 5da227fdd3 Strengthen fsck
In some other code I was hitting an unexpected size in a config
object; I'm not sure there's a bug here yet, but the obvious
thing to do is to strengthen our `fsck()` to walk descriptors,
not the blobs directly.

This way we validate:

- size of objects (cheap corruption detection too)
- Nothing is missing

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-28 07:43:42 -04:00
Colin Walters 0b193b9cae
Merge pull request #11 from containers/release
Release 0.2.1
2024-08-16 14:45:51 -04:00
Colin Walters 6786e5da06 Release 0.2.1
Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-16 13:42:06 -04:00
Colin Walters 118e37b4b1
Merge pull request #4 from containers/renovate/all
chore(deps): update actions/checkout action to v4
2024-08-16 13:40:31 -04:00
Joseph Marrero Corchado 860fe0ecb3
Merge pull request #9 from containers/misc
Misc
2024-08-16 13:37:12 -04:00
Colin Walters 272b022816 Add a method to write and verify against a descriptor
Useful when pulling.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters 25951930c5 Automatically set gzip media type on layer descriptor
This is a sane thing to default.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters e9626a95a0 Add a function to create a raw blob
This is needed for things that want to copy in external
data.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters bf577fed06 Add functions to query existence of manifests and blobs
This is useful for tooling that wants to check before e.g.
fetching.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters 672edeef6c lib: Add an API to write layers with timestamps
I didn't have an immediate use case, I was just reading
the code for unrelated reasons and noticed this.

But I'm sure we'd want this for reproducible builds.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters 0d3e398d90 lib: Create a const for sha256
Just a cleanup.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Colin Walters 2b75e2842b read_json_blob: Drop unnecessary constraints
Just noted this while scrolling by.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-03 15:55:12 -04:00
Platform Engineering Bot e36d09bc9e chore(deps): update actions/checkout action to v4
Signed-off-by: Platform Engineering Bot <platform-engineering@redhat.com>
2024-08-02 03:35:10 +00:00
Colin Walters dcc56d9666
Merge pull request #8 from containers/json-as-api
Move `write_json_blob` to be method
2024-08-01 10:54:38 -04:00
Colin Walters 3d55c4c77b Move `write_json_blob` to be method
No idea why this was a free function before. Add a method
which delegates to the free function, and deprecate the old
way.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-08-01 10:28:56 -04:00
Colin Walters ab12e90e49
Merge pull request #7 from containers/fsck
Add a `fsck` method
2024-07-25 14:05:16 -04:00
Colin Walters 5d35f3d3e4 Add a `fsck` method
Just on general principle, but also specifically as I was
looking at the `flush()` calls in the writer paths and was
uncertain why I added those. If we were somehow losing data,
this might help us find that.

Signed-off-by: Colin Walters <walters@verbum.org>
2024-07-23 15:21:27 -04:00
7 changed files with 957 additions and 269 deletions

View File

@ -18,7 +18,7 @@ concurrency:
env:
CARGO_TERM_COLOR: always
# Pinned toolchain for linting
ACTIONS_LINTS_TOOLCHAIN: 1.76.0
ACTIONS_LINTS_TOOLCHAIN: 1.86.0
jobs:
tests-stable:
@ -26,7 +26,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@v1
with:
@ -34,15 +34,18 @@ jobs:
- name: Cache build artifacts
uses: Swatinem/rust-cache@v2
- name: cargo build
run: cargo build --all-targets
run: cargo build --all-targets --all-features
- name: cargo test
run: cargo test --all-targets
run: cargo test --all-targets --all-features
# https://github.com/rust-lang/cargo/issues/6669
- name: cargo test --doc
run: cargo test --doc --all-features
linting:
name: Lints, pinned toolchain
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Install toolchain
uses: dtolnay/rust-toolchain@v1
with:
@ -53,4 +56,4 @@ jobs:
- name: cargo fmt (check)
run: cargo fmt -- --check -l
- name: cargo clippy (warnings)
run: cargo clippy --all-targets -- -D warnings
run: cargo clippy --all-targets --all-features -- -D warnings

View File

@ -1,23 +1,31 @@
[package]
name = "ocidir"
description = "A Rust library for reading and writing OCI (opencontainers) layout directories"
version = "0.2.0"
version = "0.5.0"
edition = "2021"
license = "MIT OR Apache-2.0"
repository = "https://github.com/containers/ocidir-rs"
keywords = ["oci", "opencontainers", "docker", "podman", "containers"]
[dependencies]
anyhow = "1.0"
camino = "1.0.4"
chrono = "0.4.19"
olpc-cjson = "0.1.1"
cap-std-ext = "4.0"
flate2 = { features = ["zlib"], default_features = false, version = "1.0.20" }
fn-error-context = "0.2.0"
flate2 = { features = ["zlib"], default-features = false, version = "1.0.20" }
hex = "0.4.3"
openssl = "0.10.33"
serde = { features = ["derive"], version = "1.0.125" }
serde_json = "1.0.64"
tar = "0.4.38"
oci-spec = "0.6.5"
thiserror = "2"
oci-spec = "0.8.0"
zstd = { version = "0.13.2", optional = true }
canon-json = "0.2.0"
[dev-dependencies]
anyhow = "1.0.89"
cap-tempfile = "3.3.0"
[features]
zstd = ["dep:zstd"]
zstdmt = ["zstd", "zstd/zstdmt"]

View File

@ -4,6 +4,36 @@
[crates-badge]: https://img.shields.io/crates/v/ocidir.svg
[crates-url]: https://crates.io/crates/ocidir
[![docs.rs](https://docs.rs/ocidir/badge.svg)](https://docs.rs/ocidir)
A low level Rust library for reading and writing
[OCI directories](https://github.com/opencontainers/image-spec/).
# Read and write to OCI image layout directories
This library contains medium and low-level APIs for working with
[OCI images], which are basically a directory with blobs and JSON files
for metadata.
## Dependency on cap-std
This library makes use of [cap-std] to operate in a capability-oriented
fashion. In practice, the code in this project is well tested and would
not traverse outside its own path root. However, using capabilities
is a generally good idea when operating in the container ecosystem,
in particular when actively processing tar streams.
## Examples
To access an existing OCI directory:
```rust,no_run
# 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(())
# }
```
[cap-std]: https://docs.rs/cap-std/
[OCI images]: https://github.com/opencontainers/image-spec

View File

@ -0,0 +1,61 @@
/// Example that shows how to use a custom compression and media type for image layers.
/// The example below does no compression.
use std::{env, io, path::PathBuf};
use oci_spec::image::Platform;
use ocidir::{cap_std::fs::Dir, BlobWriter, OciDir, WriteComplete};
struct NoCompression<'a>(BlobWriter<'a>);
impl io::Write for NoCompression<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.0.flush()
}
}
impl<'a> WriteComplete<BlobWriter<'a>> for NoCompression<'a> {
fn complete(self) -> io::Result<BlobWriter<'a>> {
Ok(self.0)
}
}
fn main() {
let dir = Dir::open_ambient_dir(env::temp_dir(), ocidir::cap_std::ambient_authority()).unwrap();
let oci_dir = OciDir::ensure(dir).unwrap();
let mut manifest = oci_dir.new_empty_manifest().unwrap().build().unwrap();
let mut config = ocidir::oci_spec::image::ImageConfigurationBuilder::default()
.build()
.unwrap();
// Add the src as a layer
let writer = oci_dir
.create_custom_layer(
|bw| Ok(NoCompression(bw)),
oci_spec::image::MediaType::ImageLayer,
)
.unwrap();
let mut builder = tar::Builder::new(writer);
builder.follow_symlinks(false);
builder
.append_dir_all(".", PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src"))
.unwrap();
let layer = builder.into_inner().unwrap().complete().unwrap();
oci_dir.push_layer(&mut manifest, &mut config, layer, "src", None);
println!(
"Created image with manifest: {}",
manifest.to_string_pretty().unwrap()
);
// Add the image manifest
let _descriptor = oci_dir
.insert_manifest_and_config(manifest.clone(), config, None, Platform::default())
.unwrap();
}

View File

@ -0,0 +1,80 @@
//! # Import a pre-generated tarball, wrapping with OCI metadata into an OCI directory.
//!
//! This little exmaple shows a bit of how to use the ocidir API. But it has a use case
//! for low-level testing of OCI runtimes by injecting arbitrary tarballs.
use std::io::BufReader;
use std::{fs::File, path::Path};
use anyhow::Context;
use cap_tempfile::cap_std;
use chrono::Utc;
use oci_spec::image::{MediaType, Platform};
use ocidir::OciDir;
fn import(oci_dir: &OciDir, name: &str, src: File) -> anyhow::Result<()> {
let mtime = src.metadata()?.modified()?;
let mut input_tar = BufReader::new(src);
let created = chrono::DateTime::<Utc>::from(mtime);
let mut manifest = oci_dir.new_empty_manifest().unwrap().build().unwrap();
let mut config = ocidir::oci_spec::image::ImageConfigurationBuilder::default()
.build()
.unwrap();
// Add the src as a layer
let mut writer = oci_dir.create_blob().unwrap();
std::io::copy(&mut input_tar, &mut writer)?;
let blob = writer.complete()?;
let descriptor = blob
.descriptor()
.media_type(MediaType::ImageLayer)
.build()
.unwrap();
let blob_digest = descriptor.digest().to_string();
manifest.layers_mut().push(descriptor);
let mut rootfs = config.rootfs().clone();
rootfs.diff_ids_mut().push(blob_digest);
config.set_rootfs(rootfs);
let h = oci_spec::image::HistoryBuilder::default()
.created(created.to_rfc3339_opts(chrono::SecondsFormat::Secs, true))
.created_by(name.to_string())
.build()
.unwrap();
config.history_mut().push(h);
println!(
"Created image with manifest: {}",
manifest.to_string_pretty().unwrap()
);
// Add the image manifest
let _descriptor = oci_dir
.insert_manifest_and_config(
manifest.clone(),
config,
Some("latest"),
Platform::default(),
)
.unwrap();
Ok(())
}
fn main() -> anyhow::Result<()> {
let args = std::env::args().collect::<Vec<_>>();
let ocidir = args[1].as_str();
let path = Path::new(args[2].as_str());
let Some(name) = path.file_stem().and_then(|v| v.to_str()) else {
anyhow::bail!("Invalid path: {path:?}");
};
let f = File::open(path).with_context(|| format!("Opening {path:?}"))?;
let dir = &cap_std::fs::Dir::open_ambient_dir(ocidir, cap_std::ambient_authority())
.with_context(|| format!("Opening {ocidir}"))?;
let oci_dir = OciDir::ensure(dir.try_clone()?)?;
import(&oci_dir, name, f)?;
Ok(())
}

55
examples/zstd.rs Normal file
View File

@ -0,0 +1,55 @@
#[cfg(feature = "zstdmt")]
fn main() {
use std::{env, path::PathBuf};
use cap_tempfile::TempDir;
use oci_spec::image::Platform;
use ocidir::OciDir;
let dir = TempDir::new(ocidir::cap_std::ambient_authority()).unwrap();
let oci_dir = OciDir::ensure(dir.try_clone().unwrap()).unwrap();
let mut manifest = oci_dir.new_empty_manifest().unwrap().build().unwrap();
let mut config = ocidir::oci_spec::image::ImageConfigurationBuilder::default()
.build()
.unwrap();
// Add the src as a layer
let writer = oci_dir.create_layer_zstd(Some(0)).unwrap();
let mut builder = tar::Builder::new(writer);
builder.follow_symlinks(false);
builder
.append_dir_all(".", PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("src"))
.unwrap();
let layer = builder.into_inner().unwrap().complete().unwrap();
oci_dir.push_layer(&mut manifest, &mut config, layer, "src", None);
// Add the examples as a layer, using multithreaded compression
let writer = oci_dir.create_layer_zstd_multithread(Some(0), 4).unwrap();
let mut builder = tar::Builder::new(writer);
builder.follow_symlinks(false);
builder
.append_dir_all(
".",
PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("examples"),
)
.unwrap();
let layer = builder.into_inner().unwrap().complete().unwrap();
oci_dir.push_layer(&mut manifest, &mut config, layer, "examples", None);
println!(
"Created image with manifest: {}",
manifest.to_string_pretty().unwrap()
);
// Add the image manifest
let _descriptor = oci_dir
.insert_manifest_and_config(manifest.clone(), config, None, Platform::default())
.unwrap();
}
#[cfg(not(feature = "zstdmt"))]
fn main() {
println!("Run this example with `cargo run --example zstd --features zstdmt`");
}

File diff suppressed because it is too large Load Diff