Skip to main content

isothrum_compiler/
compiled.rs

1//! [`compile`]: the drawing's spec, written and read back by Isoloom, with the project's own files.
2
3use isoloom_spec::Spec;
4
5use crate::document::{ProvisionDoc, SpecDoc};
6use crate::draft::Draft;
7use crate::{Error, ProjectFile, Result, Topology, cables, lans, machines, project, routers, starters, vlans};
8
9/// A compiled project: the `isoloom.yml` text, the spec Isoloom reads from it, and the project's own files
10/// where the spec points (the appliances' configurations, a starter for each provisioning step).
11#[derive(Debug, Clone, PartialEq)]
12pub struct Compiled {
13    yaml: String,
14    spec: Spec,
15    files: Vec<ProjectFile>,
16}
17
18impl Compiled {
19    /// The spec's text, ready to write to `isoloom.yml`.
20    #[must_use]
21    pub fn yaml(&self) -> &str {
22        &self.yaml
23    }
24
25    /// The spec as Isoloom reads it (with where each field is written, for its problems).
26    #[must_use]
27    pub fn spec(&self) -> &Spec {
28        &self.spec
29    }
30
31    /// The project's own files, next to `isoloom.yml` where its paths point: the appliances'
32    /// configurations, then a starter for each provisioning step (each path once, inside the
33    /// project).
34    #[must_use]
35    pub fn files(&self) -> &[ProjectFile] {
36        &self.files
37    }
38
39    /// The text, the spec and the project's own files.
40    #[must_use]
41    pub fn into_parts(self) -> (String, Spec, Vec<ProjectFile>) {
42        (self.yaml, self.spec, self.files)
43    }
44}
45
46/// Compiles a drawing into an Isoloom spec and the project's own files.
47///
48/// # Errors
49///
50/// [`Error`]: what the drawing can't say (a cable to an unknown node, a LAN that's full, two
51/// machines asking for one address...). [`Error::Unreadable`] would mean the compiler wrote
52/// something Isoloom's format doesn't hold: a bug.
53pub fn compile(topo: &Topology) -> Result<Compiled> {
54    cables::check_count(topo)?;
55    vlans::check_switch_names(topo)?;
56    let mut draft = Draft::default();
57    machines::add(topo, &mut draft)?;
58    lans::address(topo, &mut draft)?;
59    cables::allocate(topo, &mut draft)?;
60    routers::add_reach_rules(&mut draft);
61    routers::cisco_gateways(topo, &mut draft);
62    vlans::nest(topo, &mut draft);
63    let doc = SpecDoc {
64        version: 1,
65        name: topo.name.clone(),
66        networks: draft.networks,
67        reach: draft.reach,
68        machines: draft.machines,
69        provision: draft.controller.iter().map(ProvisionDoc::from).collect(),
70    };
71    let yaml = serde_yaml_ng::to_string(&doc).map_err(Error::Yaml)?;
72    let spec = isoloom_spec::syntax::parse(&yaml).map_err(Error::Unreadable)?;
73    let mut files = project::config_files(topo);
74    starters::add_starters(&mut files, &spec, &draft.controller);
75    Ok(Compiled { yaml, spec, files })
76}