1use crate::schema::validate::is_ip6;
11use crate::util::{print_values_as_table, to_string, Label, SemanticVersion};
12use human_units::FormatSize;
13use sysinfo::{Networks, System};
14use which::which;
15
16pub trait TableFormatPrint {
18 fn init() -> Self;
20 fn print(self);
22}
23#[derive(Debug, Clone)]
25pub struct InstalledSoftwareData {
26 pub version: Option<String>,
28 pub path: Option<String>,
30}
31pub struct MemoryInformation {
33 pub total: String,
35 pub available: String,
37 pub used: String,
39 pub swap: String,
41}
42#[derive(Debug, Clone)]
44pub struct Network {
45 pub ip_address: Vec<String>,
47 pub mac_address: String,
49 pub mtu: String,
51}
52#[derive(Debug, Clone)]
54pub struct NetworkInformation {
55 pub networks: Vec<Network>,
57}
58#[derive(Debug, Clone)]
61pub struct Processor {
62 pub frequency: u64,
64 pub brand: String,
66 pub vendor: String,
68}
69pub struct SystemInformation {
71 pub name: String,
73 pub kernel_version: String,
75 pub os_version: String,
77 pub host_name: String,
79 pub cpu_arch: String,
81 pub cpu_count: String,
83}
84pub struct SystemSoftwareInformation {
86 pub acorn: InstalledSoftwareData,
92 pub git: InstalledSoftwareData,
98 pub node: InstalledSoftwareData,
104 pub npm: InstalledSoftwareData,
112 pub npx: InstalledSoftwareData,
120 pub pandoc: InstalledSoftwareData,
126 pub vale: InstalledSoftwareData,
132}
133impl InstalledSoftwareData {
134 fn from_command(name: &str) -> InstalledSoftwareData {
135 InstalledSoftwareData {
136 version: match SemanticVersion::from_command(name) {
137 | Some(version) => Some(version.to_string()),
138 | None => None,
139 },
140 path: match which(name) {
141 | Ok(path) => Some(path.display().to_string()),
142 | Err(_) => None,
143 },
144 }
145 }
146 fn as_row(&self, title: &str) -> Vec<String> {
147 to_string(vec![
148 title,
149 &self.clone().is_installed(),
150 &self.clone().version.unwrap_or_else(|| "---".to_string()),
151 &self.clone().path.unwrap_or_else(|| "---".to_string()),
152 ])
153 }
154 fn is_installed(&self) -> String {
155 if self.version.is_some() {
156 Label::CHECKMARK.to_string()
157 } else {
158 Label::CAUTION.to_string()
159 }
160 }
161}
162impl TableFormatPrint for MemoryInformation {
163 fn init() -> MemoryInformation {
164 let mut sys = System::new_all();
165 sys.refresh_all();
166 MemoryInformation {
167 total: sys.total_memory().format_size().to_string(),
168 available: sys.available_memory().format_size().to_string(),
169 used: sys.used_memory().format_size().to_string(),
170 swap: format!("{} of {}", sys.used_swap().format_size(), sys.total_swap().format_size()),
171 }
172 }
173 fn print(self) {
174 let MemoryInformation {
175 total,
176 available,
177 used,
178 swap,
179 } = self;
180 let headers = vec!["Attribute", "Value"];
181 let rows = vec![
182 to_string(vec!["Total", &total]),
183 to_string(vec!["Available", &available]),
184 to_string(vec!["Used", &used]),
185 to_string(vec!["Swap", &swap]),
186 ];
187 print_values_as_table("Memory", headers, rows);
188 }
189}
190impl TableFormatPrint for NetworkInformation {
191 fn init() -> NetworkInformation {
192 let networks = Networks::new_with_refreshed_list()
193 .into_iter()
194 .map(|(_, network)| Network {
195 ip_address: parse_network_addresses(network),
196 mac_address: network.mac_address().to_string(),
197 mtu: network.mtu().to_string(),
198 })
199 .collect();
200 NetworkInformation { networks }
201 }
202 fn print(self) {
203 let headers = vec!["Network", "MAC Address", "MTU"];
204 let rows = self
205 .networks
206 .iter()
207 .filter_map(|network| {
208 if network.ip_address.is_empty() {
209 None
210 } else {
211 let ip = network.ip_address.join("\n");
212 let mac = network.clone().mac_address;
213 let mtu = network.clone().mtu;
214 Some(vec![ip, mac, mtu])
215 }
216 })
217 .collect::<Vec<_>>();
218 print_values_as_table("Network", headers, rows);
219 }
220}
221impl TableFormatPrint for SystemInformation {
222 fn init() -> SystemInformation {
223 let mut sys = System::new_all();
224 sys.refresh_all();
225 SystemInformation {
226 name: System::name().unwrap(),
227 kernel_version: System::kernel_version().unwrap(),
228 os_version: System::os_version().unwrap(),
229 host_name: System::host_name().unwrap(),
230 cpu_arch: System::cpu_arch(),
231 cpu_count: sys.cpus().len().to_string(),
232 }
233 }
234 fn print(self) {
235 let SystemInformation {
236 name,
237 kernel_version,
238 os_version,
239 host_name,
240 cpu_arch,
241 cpu_count,
242 } = self;
243 let headers = vec!["Attribute", "Value"];
244 let rows = vec![
245 to_string(vec!["Name", &name]),
246 to_string(vec!["Kernel Version", &kernel_version]),
247 to_string(vec!["OS Version", &os_version]),
248 to_string(vec!["Host Name", &host_name]),
249 to_string(vec!["CPU Architecture", &cpu_arch]),
250 to_string(vec!["CPU Count", &cpu_count]),
251 ];
252 print_values_as_table("System", headers, rows);
253 }
254}
255impl TableFormatPrint for SystemSoftwareInformation {
256 fn init() -> SystemSoftwareInformation {
257 SystemSoftwareInformation {
258 acorn: InstalledSoftwareData::from_command("acorn"),
259 git: InstalledSoftwareData::from_command("git"),
260 node: InstalledSoftwareData::from_command("node"),
261 npm: InstalledSoftwareData::from_command("npm"),
262 npx: InstalledSoftwareData::from_command("npx"),
263 pandoc: InstalledSoftwareData::from_command("pandoc"),
264 vale: InstalledSoftwareData::from_command("vale"),
265 }
266 }
267 fn print(self) {
268 let SystemSoftwareInformation {
269 acorn,
270 git,
271 node,
272 npm,
273 npx,
274 pandoc,
275 vale,
276 } = self;
277 let headers = vec!["Name", "Installed", "Version", "Location"];
278 let rows = vec![
279 acorn.as_row("Acorn"),
280 git.as_row("Git"),
281 node.as_row("Node.js"),
282 npm.as_row("npm"),
283 npx.as_row("npx"),
284 pandoc.as_row("Pandoc"),
285 vale.as_row("Vale"),
286 ];
287 print_values_as_table("Software", headers, rows);
288 }
289}
290fn parse_network_addresses(data: &sysinfo::NetworkData) -> Vec<String> {
291 data.ip_networks()
292 .iter()
293 .map(|ip| ip.addr.to_string())
294 .filter(|x| is_ip6(x).is_err())
295 .collect::<Vec<String>>()
296}