sbom_tools/watch/
config.rs1use super::WatchError;
4use crate::config::{EnrichmentConfig, OutputConfig};
5use std::path::PathBuf;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct WatchConfig {
11 pub watch_dirs: Vec<PathBuf>,
13 pub poll_interval: Duration,
15 pub enrich_interval: Duration,
17 pub debounce: Duration,
20 pub output: OutputConfig,
22 pub enrichment: EnrichmentConfig,
24 pub webhook_url: Option<String>,
26 pub exit_on_change: bool,
28 pub max_snapshots: usize,
30 pub quiet: bool,
32 pub dry_run: bool,
34}
35
36pub fn parse_duration(s: &str) -> Result<Duration, WatchError> {
48 let s = s.trim();
49 if s.is_empty() {
50 return Err(WatchError::InvalidInterval(s.to_string()));
51 }
52
53 let (num_str, unit) = if let Some(stripped) = s.strip_suffix("ms") {
54 (stripped, "ms")
55 } else if s.ends_with('s') || s.ends_with('m') || s.ends_with('h') || s.ends_with('d') {
56 (&s[..s.len() - 1], &s[s.len() - 1..])
57 } else {
58 return Err(WatchError::InvalidInterval(s.to_string()));
59 };
60
61 let value: u64 = num_str
62 .parse()
63 .map_err(|_| WatchError::InvalidInterval(s.to_string()))?;
64
65 match unit {
66 "ms" => Ok(Duration::from_millis(value)),
67 "s" => Ok(Duration::from_secs(value)),
68 "m" => Ok(Duration::from_secs(value * 60)),
69 "h" => Ok(Duration::from_secs(value * 3600)),
70 "d" => Ok(Duration::from_secs(value * 86400)),
71 _ => Err(WatchError::InvalidInterval(s.to_string())),
72 }
73}
74
75#[cfg(test)]
76mod tests {
77 use super::*;
78
79 #[test]
80 fn test_parse_duration_seconds() {
81 assert_eq!(parse_duration("30s").unwrap(), Duration::from_secs(30));
82 }
83
84 #[test]
85 fn test_parse_duration_minutes() {
86 assert_eq!(parse_duration("5m").unwrap(), Duration::from_secs(300));
87 }
88
89 #[test]
90 fn test_parse_duration_hours() {
91 assert_eq!(parse_duration("1h").unwrap(), Duration::from_secs(3600));
92 }
93
94 #[test]
95 fn test_parse_duration_days() {
96 assert_eq!(parse_duration("2d").unwrap(), Duration::from_secs(172_800));
97 }
98
99 #[test]
100 fn test_parse_duration_milliseconds() {
101 assert_eq!(parse_duration("500ms").unwrap(), Duration::from_millis(500));
102 }
103
104 #[test]
105 fn test_parse_duration_with_whitespace() {
106 assert_eq!(parse_duration(" 10s ").unwrap(), Duration::from_secs(10));
107 }
108
109 #[test]
110 fn test_parse_duration_invalid_unit() {
111 assert!(parse_duration("10x").is_err());
112 }
113
114 #[test]
115 fn test_parse_duration_invalid_number() {
116 assert!(parse_duration("abcs").is_err());
117 }
118
119 #[test]
120 fn test_parse_duration_empty() {
121 assert!(parse_duration("").is_err());
122 }
123
124 #[test]
125 fn test_parse_duration_no_unit() {
126 assert!(parse_duration("100").is_err());
127 }
128}