1pub mod app;
2pub mod cli;
3pub mod client;
4pub mod command_result;
5pub mod commands;
6pub mod config;
7pub mod credentials;
8pub mod error;
9pub mod exit_code;
10pub mod input;
11pub mod output;
12pub mod redaction;
13mod update;
14
15use std::{
16 env,
17 ffi::OsString,
18 io::{self, Write},
19 process::ExitCode,
20};
21
22use clap::{CommandFactory, Parser, error::ErrorKind};
23
24use crate::{
25 app::App,
26 cli::Cli,
27 config::ServerSelection,
28 error::AppError,
29 output::{OutputFormat, render_error, write_success},
30};
31
32pub fn run() -> impl std::future::Future<Output = ExitCode> {
35 Box::pin(run_command())
39}
40
41async fn run_command() -> ExitCode {
42 let args: Vec<OsString> = env::args_os().collect();
43 let cli = match Cli::try_parse_from(&args) {
44 Ok(cli) => cli,
45 Err(error)
46 if matches!(
47 error.kind(),
48 ErrorKind::DisplayHelp | ErrorKind::DisplayVersion
49 ) =>
50 {
51 let code = error.exit_code();
52 let _ = error.print();
53 return ExitCode::from(code as u8);
54 }
55 Err(error) => {
56 let requested_output = OutputFormat::detect_from_args(&args);
57 let app_error = AppError::invalid_input(error.to_string());
58 eprintln!("{}", render_error(requested_output, &app_error));
59 return app_error.exit_code().into();
60 }
61 };
62
63 let output_format = cli.output;
64 if let Err(error) = cli.command.validate_output(output_format) {
65 eprintln!("{}", render_error(output_format, &error));
66 return error.exit_code().into();
67 }
68 let app = App::production_with_confirmation_interactivity(
69 ServerSelection::new(cli.server, cli.profile_name, cli.allow_insecure_http),
70 output_format != OutputFormat::Json,
71 );
72 match app.check_for_update(output_format, &cli.command).await {
73 Ok(outcome) => {
74 if let Err(error) = output::write_update_notice(&outcome, &mut io::stderr()) {
75 eprintln!("{}", render_error(output_format, &error));
76 return error.exit_code().into();
77 }
78 if outcome.should_exit() {
79 return ExitCode::SUCCESS;
80 }
81 }
82 Err(error) => {
83 eprintln!("{}", render_error(output_format, &error));
84 return error.exit_code().into();
85 }
86 }
87
88 match app.execute(cli.command).await {
89 Ok(success) => {
90 let mut stdout = io::stdout().lock();
91 let mut stderr = io::stderr().lock();
92 match write_success(output_format, success, &mut stdout, &mut stderr).await {
93 Ok(exit_code) => exit_code,
94 Err(error) => {
95 let _ = writeln!(stderr, "{}", render_error(output_format, &error));
96 error.exit_code().into()
97 }
98 }
99 }
100 Err(error) => {
101 eprintln!("{}", render_error(output_format, &error));
102 error.exit_code().into()
103 }
104 }
105}
106
107pub fn command() -> clap::Command {
109 Cli::command()
110}