use std::path::Path;
use std::sync::mpsc;
use crate::buildah::{BuildahExecutor, BuildahTransport};
use crate::builder::{BuildOptions, BuiltImage, RegistryAuth};
use crate::dockerfile::Dockerfile;
use crate::error::{BuildError, Result};
use crate::tui::BuildEvent;
use super::buildah::BuildahBackend;
use super::BuildBackend;
pub struct Wsl2BuildBackend {
inner: BuildahBackend,
distro: String,
}
impl Wsl2BuildBackend {
pub async fn new(distro: &str) -> Result<Self> {
if !zlayer_wsl::distro::distro_exists().await {
return Err(BuildError::NotSupported {
operation: format!(
"WSL2 distro '{distro}' not found — run `zlayer daemon install` to \
provision it before building Linux images on this host"
),
});
}
let probe = tokio::process::Command::new("wsl.exe")
.args(["-d", distro, "--", "buildah", "--version"])
.output()
.await
.map_err(|e| BuildError::BuildahNotFound {
message: format!("failed to invoke wsl.exe for distro '{distro}': {e}"),
})?;
if !probe.status.success() {
return Err(BuildError::BuildahNotFound {
message: format!(
"buildah is not available inside WSL2 distro '{distro}': {}",
String::from_utf8_lossy(&probe.stderr).trim()
),
});
}
let executor =
BuildahExecutor::with_path("buildah").with_transport(BuildahTransport::Wsl {
distro: distro.to_string(),
});
Ok(Self {
inner: BuildahBackend::with_executor(executor),
distro: distro.to_string(),
})
}
}
#[async_trait::async_trait]
impl BuildBackend for Wsl2BuildBackend {
async fn build_image(
&self,
context: &Path,
dockerfile: &Dockerfile,
options: &BuildOptions,
event_tx: Option<mpsc::Sender<BuildEvent>>,
) -> Result<BuiltImage> {
self.inner
.build_image(context, dockerfile, options, event_tx)
.await
}
async fn push_image(&self, tag: &str, auth: Option<&RegistryAuth>) -> Result<()> {
self.inner.push_image(tag, auth).await
}
async fn tag_image(&self, image: &str, new_tag: &str) -> Result<()> {
self.inner.tag_image(image, new_tag).await
}
async fn manifest_create(&self, name: &str) -> Result<()> {
self.inner.manifest_create(name).await
}
async fn manifest_add(&self, manifest: &str, image: &str) -> Result<()> {
self.inner.manifest_add(manifest, image).await
}
async fn manifest_push(
&self,
name: &str,
destination: &str,
auth: Option<&RegistryAuth>,
) -> Result<()> {
self.inner.manifest_push(name, destination, auth).await
}
async fn is_available(&self) -> bool {
if !zlayer_wsl::distro::distro_exists().await {
return false;
}
tokio::process::Command::new("wsl.exe")
.args(["-d", self.distro.as_str(), "--", "buildah", "--version"])
.output()
.await
.is_ok_and(|o| o.status.success())
}
fn name(&self) -> &'static str {
"wsl2-buildah"
}
}