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