mod buildah;
#[cfg(target_os = "macos")]
mod sandbox;
pub use buildah::BuildahBackend;
#[cfg(target_os = "macos")]
pub use sandbox::SandboxBackend;
use std::path::Path;
use std::sync::Arc;
use crate::builder::{BuildOptions, BuiltImage, RegistryAuth};
use crate::dockerfile::Dockerfile;
use crate::error::{BuildError, Result};
use crate::tui::BuildEvent;
#[async_trait::async_trait]
pub trait BuildBackend: Send + Sync {
async fn build_image(
&self,
context: &Path,
dockerfile: &Dockerfile,
options: &BuildOptions,
event_tx: Option<std::sync::mpsc::Sender<BuildEvent>>,
) -> Result<BuiltImage>;
async fn push_image(&self, tag: &str, auth: Option<&RegistryAuth>) -> Result<()>;
async fn tag_image(&self, image: &str, new_tag: &str) -> Result<()>;
async fn manifest_create(&self, name: &str) -> Result<()>;
async fn manifest_add(&self, manifest: &str, image: &str) -> Result<()>;
async fn manifest_push(&self, name: &str, destination: &str) -> Result<()>;
async fn is_available(&self) -> bool;
fn name(&self) -> &'static str;
}
pub async fn detect_backend() -> Result<Arc<dyn BuildBackend>> {
if let Ok(forced) = std::env::var("ZLAYER_BACKEND") {
match forced.to_lowercase().as_str() {
"buildah" => {
let backend = BuildahBackend::new().await?;
return Ok(Arc::new(backend));
}
#[cfg(target_os = "macos")]
"sandbox" => {
let backend = SandboxBackend::default();
return Ok(Arc::new(backend));
}
other => {
return Err(BuildError::BuildahNotFound {
message: format!("Unknown ZLAYER_BACKEND value: {other}"),
});
}
}
}
#[cfg(target_os = "macos")]
{
if let Ok(backend) = BuildahBackend::try_new().await {
Ok(Arc::new(backend))
} else {
tracing::info!("Buildah not available on macOS, falling back to sandbox backend");
Ok(Arc::new(SandboxBackend::default()))
}
}
#[cfg(not(target_os = "macos"))]
{
let backend = BuildahBackend::new().await?;
Ok(Arc::new(backend))
}
}