use crate::config::{Config, HostConfig, OverviewSection};
use crate::remote::{DEFAULT_REMOTE_COMMAND, RemoteTarget};
pub const LOCAL_NAME: &str = "local";
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum HostKind {
Local,
Remote(RemoteTarget),
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct HostSpec {
pub name: String,
pub kind: HostKind,
pub sections: Vec<OverviewSection>,
}
impl HostSpec {
pub fn is_local(&self) -> bool {
self.kind == HostKind::Local
}
}
pub fn host_specs(
config: &Config,
extra_destinations: &[String],
remote_command: Option<&str>,
) -> Vec<HostSpec> {
let default_sections = config.overview.sections.clone();
let mut specs = vec![HostSpec {
name: LOCAL_NAME.to_owned(),
kind: HostKind::Local,
sections: default_sections.clone(),
}];
let mut hosts: Vec<HostConfig> = config.hosts.clone();
for destination in extra_destinations {
let known = hosts
.iter()
.any(|h| h.name == *destination || h.destination() == destination);
if !known {
let mut host = HostConfig::from_destination(destination);
host.command = remote_command.map(str::to_owned);
hosts.push(host);
}
}
for host in hosts {
let command = host.command.as_deref().unwrap_or(DEFAULT_REMOTE_COMMAND);
let mut target = RemoteTarget::ssh(host.destination(), command);
target.name = host.name.clone();
specs.push(HostSpec {
sections: host
.sections
.clone()
.unwrap_or_else(|| default_sections.clone()),
name: host.name,
kind: HostKind::Remote(target),
});
}
specs
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn local_first_then_config_then_new_command_line_hosts() {
let mut config = Config::default();
config.hosts.push(HostConfig {
name: "nas".to_owned(),
ssh: Some("admin@nas.local".to_owned()),
command: Some("/opt/rigtop --agent".to_owned()),
sections: Some(vec![OverviewSection::Storage]),
});
let extra = vec!["admin@nas.local".to_owned(), "zefat".to_owned()];
let specs = host_specs(&config, &extra, Some("~/bin/rigtop --agent"));
let names: Vec<&str> = specs.iter().map(|s| s.name.as_str()).collect();
assert_eq!(names, vec!["local", "nas", "zefat"]);
assert!(specs[0].is_local());
assert_eq!(specs[1].sections, vec![OverviewSection::Storage]);
assert_eq!(specs[2].sections, OverviewSection::ALL.to_vec());
match (&specs[1].kind, &specs[2].kind) {
(HostKind::Remote(nas), HostKind::Remote(zefat)) => {
assert_eq!(nas.name, "nas");
assert!(nas.args.ends_with(&[
"admin@nas.local".to_owned(),
"/opt/rigtop --agent".to_owned()
]));
assert!(
zefat
.args
.ends_with(&["zefat".to_owned(), "~/bin/rigtop --agent".to_owned()])
);
}
other => panic!("unexpected {other:?}"),
}
}
}