74 lines
2.3 KiB
Rust
74 lines
2.3 KiB
Rust
use crate::nix::parse::flatten_set;
|
|
use anyhow::{anyhow, Result};
|
|
use std::collections::HashSet;
|
|
|
|
pub struct StackComposeInfo {
|
|
pub project: String,
|
|
pub services: Vec<String>,
|
|
}
|
|
|
|
const PROJECT_KEY: &str = "project\0name";
|
|
const SERVICES_PREFIX: &str = "services\0";
|
|
|
|
pub fn parse_arion_compose(file: &str) -> Result<StackComposeInfo> {
|
|
let ast = rnix::Root::parse(file).ok()?;
|
|
let expr = ast.expr().ok_or_else(|| anyhow!("invalid nix root"))?;
|
|
let flattened = flatten_set(expr)?;
|
|
|
|
if !flattened.contains_key(PROJECT_KEY) {
|
|
return Err(anyhow!("missing required key 'project.name'"));
|
|
}
|
|
let project = flattened[PROJECT_KEY].clone().trim_matches('"').to_string();
|
|
|
|
let services = flattened
|
|
.iter()
|
|
.filter_map(|(key, _)| {
|
|
key.strip_prefix(SERVICES_PREFIX)
|
|
.and_then(|key| key.split_once('\0'))
|
|
.map(|k| k.0.to_string())
|
|
})
|
|
.collect::<HashSet<_>>()
|
|
.into_iter()
|
|
.collect();
|
|
|
|
Ok(StackComposeInfo { project, services })
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn test_parse_compose() {
|
|
let source = r#"{
|
|
project.name = "traefik";
|
|
services.router = {
|
|
service.image = "traefik:v3.0";
|
|
service.restart = "always";
|
|
service.volumes = [
|
|
"${toString ./.}/traefik.toml:/traefik.toml"
|
|
"${toString ./.}/acme.json:/acme.json"
|
|
"${toString ./.}/rules.d:/rules.d"
|
|
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
|
];
|
|
service.ports = [
|
|
"80:80"
|
|
];
|
|
service.labels = {
|
|
"traefik.enable" = "true";
|
|
"traefik.http.routers.traefik_dashboard.rule" = "Host(`traefik.uchunext.local`)";
|
|
"traefik.http.routers.traefik_dashboard.service" = "api@internal";
|
|
"traefik.http.routers.traefik_dashboard.entrypoints" = "web";
|
|
"traefik.http.services.dashboard.loadbalancer.server.port" = "8080";
|
|
};
|
|
service.networks = ["web"];
|
|
};
|
|
networks.web.external = true;
|
|
}"#;
|
|
let info = parse_arion_compose(source).unwrap();
|
|
|
|
assert_eq!(info.project, "traefik");
|
|
assert_eq!(info.services[0], "router");
|
|
}
|
|
}
|