use crate::compose::types::{BuildConfig, Service};
use super::{safe_unit_stem, sorted_label_pairs, QuadletUnit, Section};
pub(crate) fn build_unit_filename(name: &str) -> String {
format!("{}.build", safe_unit_stem(name))
}
pub(crate) fn emits_build_unit(service: &Service) -> bool {
match &service.build {
None => false,
Some(BuildConfig::Context(_)) => true,
Some(BuildConfig::Config {
dockerfile_inline, ..
}) => dockerfile_inline.is_none(),
}
}
pub(crate) fn build_unit(
name: &str,
project: &str,
service: &Service,
warnings: &mut Vec<String>,
) -> Option<QuadletUnit> {
let build = service.build.as_ref()?;
let mut section = Section::new("Build");
let image_tag = service
.image
.clone()
.unwrap_or_else(|| format!("{project}-{name}"));
section.add("ImageTag", image_tag);
match build {
BuildConfig::Context(context) => {
section.add("SetWorkingDirectory", context.clone());
}
BuildConfig::Config {
context,
dockerfile,
dockerfile_inline,
args,
target,
labels,
network,
..
} => {
if dockerfile_inline.is_some() {
warnings.push(format!(
"{name}: build.dockerfile_inline has no Quadlet `.build` equivalent; \
no .build unit emitted — build the image first and set `image`"
));
return None;
}
section.add(
"SetWorkingDirectory",
context.clone().unwrap_or_else(|| ".".to_string()),
);
if let Some(df) = dockerfile {
section.add("File", df.clone());
}
if let Some(t) = target {
section.add("Target", t.clone());
}
if let Some(net) = network {
section.add("Network", net.clone());
}
let mut build_args: Vec<(String, Option<String>)> = args.to_map().into_iter().collect();
build_args.sort_by(|a, b| a.0.cmp(&b.0));
for (key, val) in build_args {
match val {
Some(v) => section.add("BuildArg", format!("{key}={v}")),
None => section.add("BuildArg", key),
}
}
for (key, val) in sorted_label_pairs(labels.to_map()) {
section.add("Label", format!("{key}={val}"));
}
}
}
section.add("Label", format!("podup.project={project}"));
Some(QuadletUnit {
filename: build_unit_filename(name),
contents: section.render(),
})
}