nreplops_tool/
hosts_files.rs1use std::{
17 collections::HashMap,
18 env, fs,
19 io::{self, Read},
20 path::{Path, PathBuf},
21};
22
23use serde::Deserialize;
24use serde_with::{serde_as, DisplayFromStr};
25
26use crate::{
27 conn_expr::ConnectionExpr,
28 error::Error,
29 host_options::{HostKey, HostOptions, HostOptionsTable},
30};
31
32pub fn load_default_hosts_files() -> Result<HostOptionsTable, Error> {
33 let mut hosts = HostOptionsTable::default();
34 let ps = matching_config_files("nreplops-hosts.toml")
35 .map_err(Error::FailedToLoadDefaultHostConfig)?;
36 for p in ps.into_iter().rev() {
37 let mut f =
38 fs::File::open(p).map_err(Error::FailedToLoadDefaultHostConfig)?;
39 let mut s = String::new();
40 let _ = f
41 .read_to_string(&mut s)
42 .map_err(Error::FailedToLoadDefaultHostConfig)?;
43 let new_hosts: Hosts = toml::from_str(&s).unwrap();
44 hosts.extend(new_hosts.into_iter().map(|(k, v)| (k, v.into())));
45 }
46 Ok(hosts)
47}
48
49pub type Hosts = HashMap<HostKey, HostOptionsDe>;
50
51#[serde_as]
52#[derive(Debug, Deserialize)]
53pub struct HostOptionsDe {
54 name: Option<String>,
55 #[serde_as(as = "DisplayFromStr")]
56 connection: ConnectionExpr,
57 confirm: Option<bool>,
58}
59
60#[allow(clippy::from_over_into)]
63impl Into<HostOptions> for HostOptionsDe {
64 fn into(self) -> HostOptions {
65 HostOptions {
66 name: self.name,
67 conn_expr: self.connection,
68 ask_confirmation: self.confirm,
69 }
70 }
71}
72
73fn matching_config_files<P>(file_name: P) -> Result<Vec<PathBuf>, io::Error>
74where
75 P: AsRef<Path>,
76{
77 let mut found = Vec::new();
78
79 let mut current = PathBuf::from(".").canonicalize()?;
80 loop {
81 let mut p = current.clone();
82 p.push(file_name.as_ref());
83 if p.is_file() {
84 found.push(p);
85 }
86 if !current.pop() {
87 break;
88 }
89 }
90
91 if let Some(dir) = env::var_os("HOME") {
92 let mut p = PathBuf::from(dir);
93 if p.is_absolute() {
94 p.push("Library");
95 p.push("Application Support");
96 p.push("nreplops");
97 p.push(file_name.as_ref());
98 if p.is_file() {
99 found.push(p);
100 }
101 }
102 }
103
104 if let Some(dir) = env::var_os("XDG_CONFIG_HOME") {
105 let mut p = PathBuf::from(dir);
106 if p.is_absolute() {
107 p.push("nreplops");
108 p.push(file_name.as_ref());
109 if p.is_file() {
110 found.push(p);
111 }
112 }
113 }
114
115 if let Some(dir) = env::var_os("HOME") {
116 let mut p = PathBuf::from(dir);
117 if p.is_absolute() {
118 p.push(".nreplops");
119 p.push(file_name.as_ref());
120 if p.is_file() {
121 found.push(p);
122 }
123 }
124 }
125
126 Ok(found)
127}