Nix flake configuration manager
at main 87 lines 2.5 kB view raw
1use std::process::Command; 2 3#[derive(Debug, Clone, PartialEq, Eq)] 4pub enum ConfigKind { 5 NixOS, 6 HomeManager, 7 Colmena, 8} 9 10impl ConfigKind { 11 pub fn label(&self) -> &'static str { 12 match self { 13 ConfigKind::NixOS => "NixOS", 14 ConfigKind::HomeManager => "Home Manager", 15 ConfigKind::Colmena => "Colmena", 16 } 17 } 18} 19 20#[derive(Debug, Clone)] 21pub struct ConfigEntry { 22 pub name: String, 23 pub kind: ConfigKind, 24} 25 26/// Discover all NixOS, Home Manager, and Colmena configurations in the flake. 27pub fn discover(flake_path: &str) -> Vec<ConfigEntry> { 28 let mut entries = Vec::new(); 29 entries.extend(discover_attr(flake_path, "nixosConfigurations", ConfigKind::NixOS)); 30 entries.extend(discover_attr(flake_path, "homeConfigurations", ConfigKind::HomeManager)); 31 entries.extend(discover_colmena(flake_path)); 32 entries 33} 34 35fn nix_attr_names(flake_path: &str, attr: &str) -> Vec<String> { 36 let flake_ref = format!("{}#{}", flake_path, attr); 37 let output = Command::new("nix") 38 .args([ 39 "eval", 40 "--json", 41 &flake_ref, 42 "--apply", 43 "builtins.attrNames", 44 ]) 45 .output(); 46 47 match output { 48 Ok(out) if out.status.success() => { 49 let json = String::from_utf8_lossy(&out.stdout); 50 serde_json::from_str::<Vec<String>>(&json).unwrap_or_default() 51 } 52 _ => vec![], 53 } 54} 55 56fn discover_attr(flake_path: &str, attr: &str, kind: ConfigKind) -> Vec<ConfigEntry> { 57 nix_attr_names(flake_path, attr) 58 .into_iter() 59 .map(|name| ConfigEntry { name, kind: kind.clone() }) 60 .collect() 61} 62 63fn discover_colmena(flake_path: &str) -> Vec<ConfigEntry> { 64 // Colmena uses `colmena` attribute; `meta` is config, not a host 65 let flake_ref = format!("{}#colmena", flake_path); 66 let output = Command::new("nix") 67 .args([ 68 "eval", 69 "--json", 70 &flake_ref, 71 "--apply", 72 r#"x: builtins.attrNames (builtins.removeAttrs x ["meta"])"#, 73 ]) 74 .output(); 75 76 match output { 77 Ok(out) if out.status.success() => { 78 let json = String::from_utf8_lossy(&out.stdout); 79 serde_json::from_str::<Vec<String>>(&json) 80 .unwrap_or_default() 81 .into_iter() 82 .map(|name| ConfigEntry { name, kind: ConfigKind::Colmena }) 83 .collect() 84 } 85 _ => vec![], 86 } 87}