1use crate::config::{Config, HostConfig, OverviewSection};
5use crate::remote::{DEFAULT_REMOTE_COMMAND, RemoteTarget};
6
7pub const LOCAL_NAME: &str = "local";
9
10#[derive(Debug, Clone, PartialEq, Eq)]
12pub enum HostKind {
13 Local,
15 Remote(RemoteTarget),
17}
18
19#[derive(Debug, Clone, PartialEq, Eq)]
21pub struct HostSpec {
22 pub name: String,
24 pub kind: HostKind,
25 pub sections: Vec<OverviewSection>,
27}
28
29impl HostSpec {
30 pub fn is_local(&self) -> bool {
32 self.kind == HostKind::Local
33 }
34}
35
36pub fn host_specs(
40 config: &Config,
41 extra_destinations: &[String],
42 remote_command: Option<&str>,
43) -> Vec<HostSpec> {
44 let default_sections = config.overview.sections.clone();
45 let mut specs = vec![HostSpec {
46 name: LOCAL_NAME.to_owned(),
47 kind: HostKind::Local,
48 sections: default_sections.clone(),
49 }];
50 let mut hosts: Vec<HostConfig> = config.hosts.clone();
51 for destination in extra_destinations {
52 let known = hosts
53 .iter()
54 .any(|h| h.name == *destination || h.destination() == destination);
55 if !known {
56 let mut host = HostConfig::from_destination(destination);
57 host.command = remote_command.map(str::to_owned);
58 hosts.push(host);
59 }
60 }
61 for host in hosts {
62 let command = host.command.as_deref().unwrap_or(DEFAULT_REMOTE_COMMAND);
63 let mut target = RemoteTarget::ssh(host.destination(), command);
64 target.name = host.name.clone();
65 specs.push(HostSpec {
66 sections: host
67 .sections
68 .clone()
69 .unwrap_or_else(|| default_sections.clone()),
70 name: host.name,
71 kind: HostKind::Remote(target),
72 });
73 }
74 specs
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80
81 #[test]
82 fn local_first_then_config_then_new_command_line_hosts() {
83 let mut config = Config::default();
84 config.hosts.push(HostConfig {
85 name: "nas".to_owned(),
86 ssh: Some("admin@nas.local".to_owned()),
87 command: Some("/opt/rigtop --agent".to_owned()),
88 sections: Some(vec![OverviewSection::Storage]),
89 });
90 let extra = vec!["admin@nas.local".to_owned(), "zefat".to_owned()];
91 let specs = host_specs(&config, &extra, Some("~/bin/rigtop --agent"));
92 let names: Vec<&str> = specs.iter().map(|s| s.name.as_str()).collect();
93 assert_eq!(names, vec!["local", "nas", "zefat"]);
95 assert!(specs[0].is_local());
96 assert_eq!(specs[1].sections, vec![OverviewSection::Storage]);
97 assert_eq!(specs[2].sections, OverviewSection::ALL.to_vec());
98 match (&specs[1].kind, &specs[2].kind) {
99 (HostKind::Remote(nas), HostKind::Remote(zefat)) => {
100 assert_eq!(nas.name, "nas");
101 assert!(nas.args.ends_with(&[
102 "admin@nas.local".to_owned(),
103 "/opt/rigtop --agent".to_owned()
104 ]));
105 assert!(
107 zefat
108 .args
109 .ends_with(&["zefat".to_owned(), "~/bin/rigtop --agent".to_owned()])
110 );
111 }
112 other => panic!("unexpected {other:?}"),
113 }
114 }
115}