use std::path::Path;
fn quadlet_platform_advisory(os: &str) -> Option<String> {
(os != "linux").then(|| {
"quadlet units require systemd (Linux); generated files will not run on this host"
.to_string()
})
}
pub(crate) fn write_quadlet(
file: &podup::compose::types::ComposeFile,
project: &str,
output: Option<&Path>,
) -> podup::Result<()> {
let result = podup::quadlet::generate(file, project);
if let Some(dup) = result.duplicate_filename() {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!(
"quadlet: two resources map to the same unit file {dup:?}; \
rename one so their names do not collide after sanitization"
),
)
.into());
}
if let Some(advisory) = quadlet_platform_advisory(std::env::consts::OS) {
eprintln!("podup: warning: {advisory}");
}
for warning in &result.warnings {
eprintln!("podup: warning: {warning}");
}
match output {
Some(dir) => {
std::fs::create_dir_all(dir)?;
for unit in &result.units {
if Path::new(&unit.filename).file_name()
!= Some(std::ffi::OsStr::new(&unit.filename))
{
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidInput,
format!("refusing unsafe quadlet unit file name: {}", unit.filename),
)
.into());
}
let path = dir.join(&unit.filename);
std::fs::write(&path, &unit.contents)?;
println!("wrote {}", path.display());
}
}
None => {
for unit in &result.units {
println!("# {}", unit.filename);
print!("{}", unit.contents);
println!();
}
}
}
Ok(())
}
#[cfg(test)]
mod tests {
use super::quadlet_platform_advisory;
#[test]
fn quadlet_advisory_only_on_non_linux() {
assert_eq!(quadlet_platform_advisory("linux"), None);
for os in ["macos", "windows", "freebsd"] {
let msg = quadlet_platform_advisory(os).expect("non-linux host warns");
assert!(msg.contains("systemd"), "advisory names the requirement");
}
}
}