wash_cli/common/
get_cmd.rs1use anyhow::Result;
2use crossterm::{
3 cursor, execute,
4 terminal::{Clear, ClearType},
5};
6use std::{collections::HashMap, io::Write, time::Duration};
7use tokio::time::sleep;
8use wash_lib::cli::claims::get_claims;
9use wash_lib::cli::get::{
10 get_host_inventories, get_hosts, GetCommand, GetHostInventoriesCommand, GetLinksCommand,
11};
12use wash_lib::cli::link::{LinkCommand, LinkQueryCommand};
13use wash_lib::cli::{CommandOutput, OutputKind};
14
15use crate::appearance::spinner::Spinner;
16use crate::cmd::link::invoke as invoke_link_cmd;
17use crate::ctl::{
18 get_claims_output, get_host_inventories_output, get_hosts_output, host_inventories_table,
19};
20
21pub async fn handle_command(command: GetCommand, output_kind: OutputKind) -> Result<CommandOutput> {
22 let out: CommandOutput = match command {
23 GetCommand::Links(GetLinksCommand { opts }) => {
24 invoke_link_cmd(LinkCommand::Query(LinkQueryCommand { opts }), output_kind).await?
25 }
26 GetCommand::Claims(cmd) => {
27 let sp: Spinner = Spinner::new(&output_kind)?;
28 sp.update_spinner_message("Retrieving claims ... ".to_string());
29 let claims = get_claims(cmd).await?;
30 get_claims_output(claims)
31 }
32 GetCommand::Hosts(cmd) => {
33 let sp: Spinner = Spinner::new(&output_kind)?;
34 sp.update_spinner_message(" Retrieving Hosts ...".to_string());
35 let hosts = get_hosts(cmd).await?;
36 get_hosts_output(hosts)
37 }
38 GetCommand::HostInventories(cmd) => {
39 let sp: Spinner = Spinner::new(&output_kind)?;
40 if let Some(id) = cmd.host_id.as_ref() {
41 sp.update_spinner_message(format!(" Retrieving inventory for host {} ...", id));
42 } else {
43 sp.update_spinner_message(" Retrieving hosts for inventory query ...".to_string());
44 }
45 get_inventory_handler(cmd, sp).await?
46 }
47 };
48
49 Ok(out)
50}
51
52async fn get_inventory_handler(
53 cmd: GetHostInventoriesCommand,
54 sp: Spinner,
55) -> Result<CommandOutput> {
56 if cmd.watch.is_some() {
57 watch_inventory(cmd, sp).await?;
58 Ok(CommandOutput::new(
59 "Completed Watching Inventory".to_string(),
60 HashMap::new(),
61 ))
62 } else {
63 let invs = get_host_inventories(cmd).await?;
64 Ok(get_host_inventories_output(invs))
65 }
66}
67
68async fn watch_inventory(cmd: GetHostInventoriesCommand, sp: Spinner) -> Result<()> {
69 let mut stdout = std::io::stdout();
70 let invs = get_host_inventories(cmd.clone()).await?;
71 sp.finish_and_clear();
72 execute!(stdout, Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0))
73 .map_err(|e| anyhow::anyhow!("Failed to clear terminal: {}", e))?;
74 let output = host_inventories_table(invs);
75 stdout
76 .write_all(output.as_bytes())
77 .map_err(|e| anyhow::anyhow!("Failed to write inventory to stdout: {}", e))?;
78
79 let mut ctrlc = std::pin::pin!(tokio::signal::ctrl_c());
80 let watch_interval = cmd.watch.unwrap_or(Duration::from_millis(5000));
81
82 loop {
83 let invs = tokio::select! {
84 res = get_host_inventories(cmd.clone()) => res?,
85 res = &mut ctrlc => {
86 res?;
87 execute!(stdout, Clear(ClearType::Purge),Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0), cursor::Show)
88 .map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
89 stdout.flush()
90 .map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
91 return Ok(());
92 }
93 };
94
95 execute!(stdout, Clear(ClearType::Purge), cursor::MoveTo(0, 0))
96 .map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
97
98 let output = host_inventories_table(invs);
99 stdout
100 .write_all(output.as_bytes())
101 .map_err(|e| anyhow::anyhow!("Failed to write inventory to stdout: {}", e))?;
102
103 stdout
104 .flush()
105 .map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
106
107 execute!(
108 stdout,
109 Clear(ClearType::CurrentLine),
110 Clear(ClearType::FromCursorDown),
111 )
112 .map_err(|e| anyhow::anyhow!("Failed to clear terminal: {}", e))?;
113
114 tokio::select! {
115 _ = sleep(watch_interval) => continue,
116 res = &mut ctrlc => {
117 res?;
118 execute!(stdout, Clear(ClearType::Purge),Clear(ClearType::FromCursorUp), cursor::MoveTo(0, 0), cursor::Show)
119 .map_err(|e| anyhow::anyhow!("Failed to execute terminal commands: {}", e))?;
120 stdout.flush()
121 .map_err(|e| anyhow::anyhow!("Failed to flush stdout: {}", e))?;
122 return Ok(());
123 }
124 }
125 }
126}