1use std::path::PathBuf;
2
3fn parse_cli_args_from<I: IntoIterator<Item = String>>(
5 args: I,
6) -> (bool, u8, Option<bool>, Option<PathBuf>) {
7 let mut dry_run = false;
8 let mut verbosity: u8 = 0;
9 let mut config_path: Option<PathBuf> = None;
10 let mut toggle_wifi: Option<bool> = None;
11 let mut iter = args.into_iter();
12 while let Some(a) = iter.next() {
13 match a.as_str() {
14 "--dry-run" => dry_run = true,
15 s if s.starts_with("-v") && s.chars().skip(1).all(|c| c == 'v') => {
16 let count = s.chars().skip(1).count();
17 verbosity = std::cmp::min(3, count as u8);
19 }
20 "--verbose" => {
21 verbosity = std::cmp::max(verbosity, 1);
23 }
24 s if s.starts_with("--toggle-wifi") => {
25 if s == "--toggle-wifi" {
26 toggle_wifi = Some(true);
27 } else if let Some(eq) = s.find('=') {
28 let val = s[eq + 1..].to_ascii_lowercase();
29 toggle_wifi = Some(val == "true" || val == "1" || val == "yes");
30 }
31 }
32 s if s.starts_with("--config") => {
33 if s == "--config" {
34 if let Some(p) = iter.next() {
35 config_path = Some(PathBuf::from(p));
36 }
37 } else if let Some(eq) = s.find('=') {
38 let p = &s[eq + 1..];
39 if !p.is_empty() {
40 config_path = Some(PathBuf::from(p));
41 }
42 }
43 }
44 _ => {}
45 }
46 }
47 (dry_run, verbosity, toggle_wifi, config_path)
48}
49
50pub fn parse_cli_args() -> (bool, u8, Option<bool>, Option<PathBuf>) {
51 parse_cli_args_from(std::env::args())
52}
53
54#[cfg(test)]
55mod tests {
56 use crate::Config;
57
58 use super::*;
59
60 #[test]
61 fn test_parse_cli_args_from_flags() {
62 let tmp = std::env::temp_dir().join(format!(
63 "uconsole_cli_cfg_{}",
64 std::time::SystemTime::now()
65 .duration_since(std::time::UNIX_EPOCH)
66 .unwrap()
67 .as_millis()
68 ));
69 let _ = std::fs::create_dir_all(&tmp);
70 let cfg_path = tmp.join("cli_cfg");
71 std::fs::write(&cfg_path, "SAVING_CPU_FREQ=55,66\nHOLD_TRIGGER_SEC=1.4\n").unwrap();
72
73 let args = vec![
74 String::from("prog"),
75 String::from("--dry-run"),
76 String::from("--config"),
77 cfg_path.to_string_lossy().to_string(),
78 ];
79 let (dry_run, verbosity, _toggle_wifi, cli_config_path) = parse_cli_args_from(args);
80 assert!(dry_run);
81 assert_eq!(verbosity, 0);
82 assert_eq!(cli_config_path, Some(cfg_path.clone()));
83
84 let loaded = Config::load(cli_config_path.clone());
86 assert_eq!(loaded.saving_cpu_freq.unwrap(), "55,66");
87 assert_eq!(loaded.hold_trigger_sec.unwrap(), 1.4_f32);
88 }
90
91 #[test]
92 fn test_parse_cli_args_from_flags_eq_form() {
93 let tmp = std::env::temp_dir().join(format!(
94 "uconsole_cli_cfg_{}",
95 std::time::SystemTime::now()
96 .duration_since(std::time::UNIX_EPOCH)
97 .unwrap()
98 .as_millis()
99 ));
100 let _ = std::fs::create_dir_all(&tmp);
101 let cfg_path = tmp.join("cli_cfg2");
102 std::fs::write(&cfg_path, "SAVING_CPU_FREQ=22,33\nHOLD_TRIGGER_SEC=2.1\n").unwrap();
103
104 let args = vec![
105 String::from("prog"),
106 String::from("--dry-run"),
107 format!("--config={}", cfg_path.to_string_lossy()),
108 ];
109 let (dry_run, verbosity, _toggle_wifi, cli_config_path) = parse_cli_args_from(args);
110 assert!(dry_run);
111 assert_eq!(verbosity, 0);
112 assert_eq!(cli_config_path, Some(cfg_path.clone()));
113 let loaded = Config::load(cli_config_path.clone());
114 assert_eq!(loaded.saving_cpu_freq.unwrap(), "22,33");
115 assert_eq!(loaded.hold_trigger_sec.unwrap(), 2.1_f32);
116 }
117
118 #[test]
119 fn test_toggle_wifi_cli_precedence_over_config() {
120 use crate::Config;
121 let cfg = Config {
122 toggle_wifi: true,
123 ..Default::default()
124 };
125 let toggle_wifi_flag = Some(false);
126 let final_toggle_wifi = match toggle_wifi_flag {
127 Some(v) => v,
128 None => cfg.toggle_wifi,
129 };
130 assert!(!final_toggle_wifi);
131 }
132
133 #[test]
134 fn test_parse_cli_args_verbosity_v() {
135 let args = vec![String::from("prog"), String::from("-v")];
136 let (_dry_run, verbosity, _toggle_wifi, _cli_config_path) = parse_cli_args_from(args);
137 assert_eq!(verbosity, 1);
138 }
139
140 #[test]
141 fn test_parse_cli_args_verbosity_vv() {
142 let args = vec![String::from("prog"), String::from("-vv")];
143 let (_dry_run, verbosity, _toggle_wifi, _cli_config_path) = parse_cli_args_from(args);
144 assert_eq!(verbosity, 2);
145 }
146
147 #[test]
148 fn test_parse_cli_args_verbosity_vvv() {
149 let args = vec![String::from("prog"), String::from("-vvv")];
150 let (_dry_run, verbosity, _toggle_wifi, _cli_config_path) = parse_cli_args_from(args);
151 assert_eq!(verbosity, 3);
152 }
153}