isothrum_compiler/
project.rs1use crate::{Kind, Topology};
6
7#[derive(Debug, Clone, PartialEq, Eq)]
10pub struct ProjectFile {
11 pub path: String,
13 pub contents: String,
15}
16
17pub(crate) fn firmware_path(machine: &str) -> String {
19 format!("images/{machine}.bin")
20}
21
22pub(crate) fn config_path(machine: &str) -> String {
24 format!("configs/{machine}.cfg")
25}
26
27pub(crate) fn config_files(topo: &Topology) -> Vec<ProjectFile> {
29 topo.nodes
30 .iter()
31 .filter_map(|(name, n)| match &n.kind {
32 Kind::Container {
33 appliance: Some(_),
34 config: Some(c),
35 ..
36 } if !c.trim().is_empty() => Some(ProjectFile {
37 path: config_path(name),
38 contents: if c.ends_with('\n') { c.clone() } else { format!("{c}\n") },
39 }),
40 _ => None,
41 })
42 .collect()
43}
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48
49 #[test]
50 fn a_blank_configuration_is_no_file_and_a_last_line_break_is_added_once() {
51 let topo: Topology = serde_json::from_str(
52 r#"{"name": "x", "nodes": {
53 "r1": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": " \n"}}},
54 "r2": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": "hostname r2"}}},
55 "r3": {"kind": {"container": {"image": "i", "appliance": "cisco-iol", "config": "hostname r3\n"}}},
56 "pc": {"kind": {"container": {"image": "alpine:3.20"}}}}}"#,
57 )
58 .unwrap();
59 let files: Vec<(String, String)> = config_files(&topo).into_iter().map(|f| (f.path, f.contents)).collect();
60 assert_eq!(
61 files,
62 [
63 ("configs/r2.cfg".to_owned(), "hostname r2\n".to_owned()),
64 ("configs/r3.cfg".to_owned(), "hostname r3\n".to_owned())
65 ]
66 );
67 }
68
69 #[test]
70 fn a_machines_files_are_named_after_it() {
71 assert_eq!(config_path("r1"), "configs/r1.cfg");
72 assert_eq!(firmware_path("r1"), "images/r1.bin");
73 }
74}