1use crate::{deps::parse_deps, parse_image_config, Image, ImageConfig};
2use kdl::{KdlDocument, KdlError};
3use toposort::Toposort;
4
5use thiserror::Error;
6
7pub type BuildOrder = Vec<Vec<String>>;
8
9#[derive(Error, Debug)]
10pub enum IkkiConfigError {
11 #[error("Invalid Ikki configuration: {0}")]
12 InvalidConfiguration(String),
13 #[error("Configuration deserialization failed: {0}")]
14 Knuffel(#[from] knuffel::Error),
15}
16
17#[derive(Debug)]
18pub struct IkkiConfig {
19 image_config: ImageConfig,
20 build_order: Vec<Vec<String>>,
21}
22
23impl IkkiConfig {
24 pub fn images(&self) -> &Vec<Image> {
25 &self.image_config.images.images
26 }
27
28 pub fn find_image(&self, name: &str) -> Option<&Image> {
29 self.image_config
30 .images
31 .images
32 .iter()
33 .find(|img| img.name == name)
34 }
35
36 pub fn build_order(&self) -> BuildOrder {
37 self.build_order.clone()
38 }
39}
40
41pub fn parse(filename: &str, input: &str) -> Result<IkkiConfig, IkkiConfigError> {
42 let doc: KdlDocument = input
43 .parse()
44 .map_err(|e: KdlError| IkkiConfigError::InvalidConfiguration(e.to_string()))?;
45
46 let images = doc
47 .get("images")
48 .ok_or(IkkiConfigError::InvalidConfiguration(
49 "missing `images` configuration".to_string(),
50 ))?;
51
52 let dependencies = doc.get("dependencies");
53 let image_config = parse_image_config(filename, &images.to_string())?;
54 let build_order = dependencies
55 .map(|deps| {
56 let dag = parse_deps(deps);
57 dag.toposort().unwrap_or_default()
58 })
59 .unwrap_or_else(|| {
60 let image_names = image_config.image_names();
61 vec![image_names]
62 });
63
64 Ok(IkkiConfig {
65 image_config,
66 build_order,
67 })
68}