Skip to main content

verifyos_cli/
config.rs

1use serde::Deserialize;
2use std::path::{Path, PathBuf};
3
4#[derive(Debug, Clone, Default, Deserialize, PartialEq, Eq)]
5pub struct FileConfig {
6    pub format: Option<String>,
7    pub baseline: Option<PathBuf>,
8    pub md_out: Option<PathBuf>,
9    pub profile: Option<String>,
10    pub fail_on: Option<String>,
11    pub timings: Option<String>,
12    pub include: Option<Vec<String>>,
13    pub exclude: Option<Vec<String>>,
14}
15
16#[derive(Debug, Clone, Default, PartialEq, Eq)]
17pub struct CliOverrides {
18    pub format: Option<String>,
19    pub baseline: Option<PathBuf>,
20    pub md_out: Option<PathBuf>,
21    pub profile: Option<String>,
22    pub fail_on: Option<String>,
23    pub timings: Option<String>,
24    pub include: Vec<String>,
25    pub exclude: Vec<String>,
26}
27
28#[derive(Debug, Clone, PartialEq, Eq)]
29pub struct RuntimeConfig {
30    pub format: String,
31    pub baseline: Option<PathBuf>,
32    pub md_out: Option<PathBuf>,
33    pub profile: String,
34    pub fail_on: String,
35    pub timings: String,
36    pub include: Vec<String>,
37    pub exclude: Vec<String>,
38}
39
40pub fn load_file_config(config_path: Option<&Path>) -> Result<FileConfig, miette::Report> {
41    let Some(path) = resolve_config_path(config_path) else {
42        return Ok(FileConfig::default());
43    };
44
45    let raw = std::fs::read_to_string(&path)
46        .map_err(|err| miette::miette!("Failed to read config file {}: {}", path.display(), err))?;
47    toml::from_str(&raw)
48        .map_err(|err| miette::miette!("Failed to parse config file {}: {}", path.display(), err))
49}
50
51pub fn resolve_runtime_config(file: FileConfig, cli: CliOverrides) -> RuntimeConfig {
52    RuntimeConfig {
53        format: cli
54            .format
55            .or(file.format)
56            .unwrap_or_else(|| "table".to_string()),
57        baseline: cli.baseline.or(file.baseline),
58        md_out: cli.md_out.or(file.md_out),
59        profile: cli
60            .profile
61            .or(file.profile)
62            .unwrap_or_else(|| "full".to_string()),
63        fail_on: cli
64            .fail_on
65            .or(file.fail_on)
66            .unwrap_or_else(|| "error".to_string()),
67        timings: cli
68            .timings
69            .or(file.timings)
70            .unwrap_or_else(|| "off".to_string()),
71        include: if cli.include.is_empty() {
72            file.include.unwrap_or_default()
73        } else {
74            cli.include
75        },
76        exclude: if cli.exclude.is_empty() {
77            file.exclude.unwrap_or_default()
78        } else {
79            cli.exclude
80        },
81    }
82}
83
84fn resolve_config_path(config_path: Option<&Path>) -> Option<PathBuf> {
85    if let Some(path) = config_path {
86        return Some(path.to_path_buf());
87    }
88
89    let default = PathBuf::from("verifyos.toml");
90    if default.exists() {
91        Some(default)
92    } else {
93        None
94    }
95}