refraction-forger/crates/forge-engine/src/phase2/oci.rs
Till Wegmueller 48f8db1236
Initial implementation of refraction-forger
Standalone workspace with 4 crates for building optimized OS images
and publishing to OCI registries:

- spec-parser: KDL image spec parsing with include resolution and
  profile-based conditional filtering
- forge-oci: OCI image creation (tar layers, manifests, Image Layout)
  and registry push via oci-client
- forge-engine: Build pipeline with Phase 1 (rootfs assembly via native
  package managers with -R) and Phase 2 (QCOW2/OCI/artifact targets),
  plus dyn-compatible ToolRunner trait for external tool execution
- forger: CLI binary with build, validate, inspect, push, and targets
  commands

Ported KDL specs and overlay files from the vm-manager prototype.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 15:30:22 +01:00

52 lines
1.5 KiB
Rust

use std::path::Path;
use spec_parser::schema::Target;
use tracing::info;
use crate::error::ForgeError;
/// Build an OCI container image from the staged rootfs.
pub fn build_oci(
target: &Target,
staging_root: &Path,
output_dir: &Path,
) -> Result<(), ForgeError> {
info!("Building OCI container image");
// Create the tar.gz layer from staging
let layer =
forge_oci::tar_layer::create_layer(staging_root).map_err(|e| ForgeError::OciBuild(e.to_string()))?;
info!(
digest = %layer.digest,
size = layer.data.len(),
"Layer created"
);
// Build image options from target spec
let mut options = forge_oci::manifest::ImageOptions::default();
if let Some(ref ep) = target.entrypoint {
options.entrypoint = Some(vec![ep.command.clone()]);
}
if let Some(ref env) = target.environment {
options.env = env
.vars
.iter()
.map(|v| format!("{}={}", v.key, v.value))
.collect();
}
// Build manifest and config
let (config_json, manifest_json) = forge_oci::manifest::build_manifest(&[layer.clone()], &options)
.map_err(|e| ForgeError::OciBuild(e.to_string()))?;
// Write OCI Image Layout
let oci_output = output_dir.join(format!("{}-oci", target.name));
forge_oci::layout::write_oci_layout(&oci_output, &[layer], &config_json, &manifest_json)
.map_err(|e| ForgeError::OciBuild(e.to_string()))?;
info!(path = %oci_output.display(), "OCI Image Layout written");
Ok(())
}