OCI image-build + path-extract — killing the last podman build/cp twin
Additive extension of the OCI backend (backend-oci) so a build-in-a-container job (Skidbladnir pack.rs: podman build a Containerfile → image, then podman create + podman cp <container>:/out <host> to capture artifacts) routes through draupnir's one OCI engine instead of a Command::new("podman") shell twin. Companion to oci-bind-mounts.md (which killed the podman -v twin for msi.rs).
What was added (additive — BootSpec and every existing call site UNCHANGED)
Two ContainerBoot methods (feature backend-oci; honest Error::Unsupported without it, Error::Backend when the socket is unreachable — never a fake):
| method | maps the podman twin | over bollard |
build_image(context_dir, containerfile, tag) -> tag |
podman build -f <containerfile> -t <tag> <context> |
tar the context (context_tar) → body_full → Docker::build_image (stream; an error_detail fails the call) |
extract_path(image, container_path, host_dest) |
podman create <image> + podman cp <c>:<path> <host> + rm |
create_container (un-started) → download_from_container (tar stream) → unpack into host_dest → force-remove_container (even on error) |
- tar rides the new
taroptional dep (inbackend-oci) — used to pack the build context and unpack the downloaded archive. Lean default pulls nothing. context_tar(dir)is a pure fn (daemon-free tested): every file under the context, nested included, lands at its relative path (archive root.).- The extracted tree is rooted at the basename of
container_path— the same layoutpodman cpyields, so the consumer's path handling is unchanged. - Zero-shell: every step is a bollard REST call, never a
podman/dockersubprocess.
Flow
Now routed (Skidbladnir side)
Skidbladnir/src/pack.rs's PodmanBuild::build_into now drops Command::new("podman") build/create/cp for ContainerBoot::build_image + extract_path behind the pack-oci feature (default-off, honest podman fallback kept), closing the last of the two pack/msi podman twins the dup-audit flagged. The Skidbladnir side flattens extract_path's basename-rooted (out/…) tar to the podman cp {cid}:/out/. contents-in-into layout so the manifest stays byte-identical across engines. Reuse-first: no second engine, no shell.
Tests
context_tar_packs_the_build_context (pure — temp context → tar → read back, asserts Containerfile + nested file present) · build_and_extract_are_unsupported_without_the_engine (lean build → honest Unsupported). backend-oci 37 pass, lean 34 pass.