Skip to main content

cfgd_core/config/
platform.rs

1use std::collections::HashMap;
2
3use super::source::ConfigSourceProvides;
4
5// --- Platform Detection ---
6
7/// Detected platform information for matching source `platform-profiles`.
8#[derive(Debug, Clone)]
9pub struct PlatformInfo {
10    pub os: String,
11    pub distro: Option<String>,
12    pub distro_version: Option<String>,
13}
14
15/// Detect the current platform OS, distro, and version.
16pub fn detect_platform() -> PlatformInfo {
17    let os = match std::env::consts::OS {
18        "macos" => "macos".to_string(),
19        other => other.to_string(),
20    };
21    let (distro, version) = if os == "linux" {
22        parse_os_release_file()
23    } else {
24        (None, None)
25    };
26    PlatformInfo {
27        os,
28        distro,
29        distro_version: version,
30    }
31}
32
33/// Match platform info against a source's `platform-profiles` map.
34/// Tries exact distro match first, then OS-level match.
35pub fn match_platform_profile(
36    platform: &PlatformInfo,
37    platform_profiles: &HashMap<String, String>,
38) -> Option<String> {
39    // Try exact distro match first (e.g., "debian", "ubuntu", "fedora")
40    if let Some(ref distro) = platform.distro
41        && let Some(path) = platform_profiles.get(distro)
42    {
43        return Some(path.clone());
44    }
45    // Fall back to OS-level match (e.g., "macos", "linux")
46    if let Some(path) = platform_profiles.get(&platform.os) {
47        return Some(path.clone());
48    }
49    None
50}
51
52fn parse_os_release_file() -> (Option<String>, Option<String>) {
53    let fields = crate::platform::parse_os_release_content(
54        &std::fs::read_to_string("/etc/os-release").unwrap_or_default(),
55    );
56    (
57        fields.get("ID").map(|v| v.to_lowercase()),
58        fields.get("VERSION_ID").cloned(),
59    )
60}
61
62/// Get the list of profile names from a ConfigSource manifest.
63/// Prefers `profile_details` if populated, falls back to `profiles`.
64pub fn source_profile_names(provides: &ConfigSourceProvides) -> Vec<String> {
65    if !provides.profile_details.is_empty() {
66        provides
67            .profile_details
68            .iter()
69            .map(|p| p.name.clone())
70            .collect()
71    } else {
72        provides.profiles.clone()
73    }
74}