use crate::{Kind, Topology};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ProjectFile {
pub path: String,
pub contents: String,
}
pub(crate) fn firmware_path(machine: &str) -> String {
format!("images/{machine}.bin")
}
pub(crate) fn config_path(machine: &str) -> String {
format!("configs/{machine}.cfg")
}
pub(crate) fn config_files(topo: &Topology) -> Vec<ProjectFile> {
topo.nodes
.iter()
.filter_map(|(name, n)| match &n.kind {
Kind::Container {
appliance: Some(_),
config: Some(c),
..
} if !c.trim().is_empty() => Some(ProjectFile {
path: config_path(name),
contents: if c.ends_with('\n') { c.clone() } else { format!("{c}\n") },
}),
_ => None,
})
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_blank_configuration_is_no_file_and_a_last_line_break_is_added_once() {
let topo: Topology = serde_json::from_str(
r#"{"name": "x", "nodes": {
"r1": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": " \n"}}},
"r2": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": "hostname r2"}}},
"r3": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": "hostname r3\n"}}},
"pc": {"kind": {"container": {"image": "alpine:3.20"}}}}}"#,
)
.unwrap();
let files: Vec<(String, String)> = config_files(&topo).into_iter().map(|f| (f.path, f.contents)).collect();
assert_eq!(
files,
[
("configs/r2.cfg".to_owned(), "hostname r2\n".to_owned()),
("configs/r3.cfg".to_owned(), "hostname r3\n".to_owned())
]
);
}
#[test]
fn a_machines_files_are_named_after_it() {
assert_eq!(config_path("r1"), "configs/r1.cfg");
assert_eq!(firmware_path("r1"), "images/r1.bin");
}
}