96 lines · 2.5 KB · Rust
RawDownload
use std::collections::BTreeSet; pub fn parse_ssh_config_hosts(config: &str) -> BTreeSet<String> {    let mut hosts = BTreeSet::new();    let mut needs_another_line = false;    for line in config.lines() {        let line = line.trim_start();        if let Some(line) = line.strip_prefix("Host") {            match line.chars().next() {                Some('\\') => {                    needs_another_line = true;                }                Some('\n' | '\r') => {                    needs_another_line = false;                }                Some(c) if c.is_whitespace() => {                    parse_hosts_from(line, &mut hosts);                }                Some(_) | None => {                    needs_another_line = false;                }            };             if needs_another_line {                parse_hosts_from(line, &mut hosts);                needs_another_line = line.trim_end().ends_with('\\');            } else {                needs_another_line = false;            }        } else if needs_another_line {            needs_another_line = line.trim_end().ends_with('\\');            parse_hosts_from(line, &mut hosts);        } else {            needs_another_line = false;        }    }     hosts} fn parse_hosts_from(line: &str, hosts: &mut BTreeSet<String>) {    hosts.extend(        line.split_whitespace()            .filter(|field| !field.starts_with("!"))            .filter(|field| !field.contains("*"))            .filter(|field| !field.is_empty())            .map(|field| field.to_owned()),    );} #[cfg(test)]mod tests {    use super::*;     #[test]    fn test_thank_you_bjorn3() {        let hosts = "            Host *              AddKeysToAgent yes              UseKeychain yes              IdentityFile ~/.ssh/id_ed25519             Host whatever.*            User another             Host !not_this            User not_me             Host something        HostName whatever.tld         Host linux bsd host3          User bjorn         Host rpi          user rpi          hostname rpi.local         Host \               somehost \        anotherhost        Hostname 192.168.3.3";         let expected_hosts = BTreeSet::from_iter([            "something".to_owned(),            "linux".to_owned(),            "host3".to_owned(),            "bsd".to_owned(),            "rpi".to_owned(),            "somehost".to_owned(),            "anotherhost".to_owned(),        ]);         assert_eq!(expected_hosts, parse_ssh_config_hosts(hosts));    }}