use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use tatara_lisp_derive::TataraDomain as DeriveTataraDomain;
use crate::derivation::Derivation;
use crate::module::Module;
use crate::overlay::Overlay;
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FlakeInput {
pub name: String,
pub url: String,
#[serde(default)]
pub locked_hash: Option<String>,
#[serde(default)]
pub follows: BTreeMap<String, String>,
}
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FlakeOutputs {
#[serde(default)]
pub packages: BTreeMap<String, Vec<Derivation>>,
#[serde(default)]
pub modules: Vec<Module>,
#[serde(default)]
pub overlays: Vec<Overlay>,
#[serde(default)]
pub apps: BTreeMap<String, Vec<App>>,
#[serde(default)]
pub checks: BTreeMap<String, Vec<Derivation>>,
}
#[derive(Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct App {
pub name: String,
pub program: String,
#[serde(default)]
pub description: Option<String>,
}
#[derive(DeriveTataraDomain, Clone, Debug, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
#[tatara(keyword = "defflake")]
pub struct Flake {
pub name: String,
#[serde(default)]
pub description: Option<String>,
#[serde(default)]
pub inputs: Vec<FlakeInput>,
#[serde(default)]
pub outputs: FlakeOutputs,
}
#[cfg(test)]
mod tests {
use super::*;
use tatara_lisp::{domain::TataraDomain, read};
#[test]
fn minimal_flake_compiles() {
let forms = read(
r#"(defflake
:name "my-system"
:description "tatara programmable convergence computer"
:inputs ((:name "nixpkgs" :url "github:NixOS/nixpkgs/25.11")))"#,
)
.unwrap();
let f = Flake::compile_from_sexp(&forms[0]).unwrap();
assert_eq!(f.name, "my-system");
assert_eq!(f.inputs.len(), 1);
assert_eq!(f.inputs[0].name, "nixpkgs");
}
}