Skip to main content

ctl_core/
run.rs

1//! Process exit wrapper.
2
3use std::process::ExitCode;
4
5use anyhow::Result;
6#[cfg(feature = "help")]
7use clap::CommandFactory;
8
9use crate::color::ColorMode;
10use crate::format::OutputFormat;
11
12/// Parse `C`, emit styled help if asked, then run `body`.
13#[cfg(feature = "help")]
14#[must_use]
15pub fn go<C: clap::Parser + CommandFactory>(
16    bin: &str,
17    body: impl FnOnce(C) -> Result<()>,
18) -> ExitCode {
19    main_with_help::<C>(bin, || {
20        let raw: Vec<std::ffi::OsString> = std::env::args_os().collect();
21        let words: Vec<String> = raw
22            .iter()
23            .skip(1)
24            .map(|arg| arg.to_string_lossy().into_owned())
25            .collect();
26        let warnings = crate::flags::chassis_warnings(words.iter().map(String::as_str));
27        crate::flags::emit_warnings(bin, &warnings);
28        let matches = crate::parser::apply_defaults(C::command()).get_matches_from(&raw);
29        let cli = C::from_arg_matches(&matches).unwrap_or_else(|err| err.exit());
30        body(cli)
31    })
32}
33
34/// Parse-free entry: print `{bin}: {error:#}` and return 1.
35#[must_use]
36pub fn main(bin: &str, body: impl FnOnce() -> Result<()>) -> ExitCode {
37    main_with(bin, OutputFormat::Pretty, ColorMode::Auto, body)
38}
39
40/// Same as [`main`] with an explicit format and color for the error path.
41#[must_use]
42pub fn main_with(
43    bin: &str,
44    format: OutputFormat,
45    color: ColorMode,
46    body: impl FnOnce() -> Result<()>,
47) -> ExitCode {
48    match body() {
49        Ok(()) => ExitCode::SUCCESS,
50        Err(error) => {
51            #[cfg(feature = "view")]
52            {
53                let _ = crate::view::View::new(format, color).emit_err(bin, &format!("{error:#}"));
54            }
55            #[cfg(not(feature = "view"))]
56            {
57                let _ = (format, color);
58                eprintln!("{bin}: {error:#}");
59            }
60            ExitCode::FAILURE
61        }
62    }
63}
64
65/// Emit styled help when `-h`/`--help` is present, then run `body`.
66#[cfg(feature = "help")]
67#[must_use]
68pub fn main_with_help<C: CommandFactory>(bin: &str, body: impl FnOnce() -> Result<()>) -> ExitCode {
69    match crate::help::try_emit::<C>() {
70        Ok(true) => return ExitCode::SUCCESS,
71        Ok(false) => {}
72        Err(_) => return ExitCode::FAILURE,
73    }
74    main(bin, body)
75}