wtg_cli/
lib.rs

1use std::{env, ffi::OsString};
2
3use clap::Parser;
4
5use std::sync::Arc;
6
7use crate::backend::resolve_backend_with_notices;
8use crate::cli::Cli;
9use crate::error::{WtgError, WtgResult};
10use crate::resolution::resolve;
11
12pub mod backend;
13pub mod cli;
14pub mod constants;
15pub mod error;
16pub mod git;
17pub mod github;
18pub mod help;
19pub mod notice;
20pub mod output;
21pub mod parse_input;
22pub mod remote;
23pub mod resolution;
24pub mod semver;
25
26/// Run the CLI using the process arguments.
27pub fn run() -> WtgResult<()> {
28    run_with_args(env::args())
29}
30
31/// Run the CLI using a custom iterator of arguments.
32pub fn run_with_args<I, T>(args: I) -> WtgResult<()>
33where
34    I: IntoIterator<Item = T>,
35    T: Into<OsString> + Clone,
36{
37    let cli = match Cli::try_parse_from(args) {
38        Ok(cli) => cli,
39        Err(err) => {
40            // If the error is DisplayHelp, show our custom help
41            if err.kind() == clap::error::ErrorKind::DisplayHelp {
42                help::display_help();
43                return Ok(());
44            }
45            // Otherwise, propagate the error
46            return Err(WtgError::Cli {
47                message: err.to_string(),
48                code: err.exit_code(),
49            });
50        }
51    };
52    run_with_cli(cli)
53}
54
55fn run_with_cli(cli: Cli) -> WtgResult<()> {
56    // If no input provided, show custom help
57    if cli.input.is_none() {
58        help::display_help();
59        return Ok(());
60    }
61
62    let runtime = tokio::runtime::Builder::new_current_thread()
63        .enable_all()
64        .build()?;
65
66    runtime.block_on(run_async(cli))
67}
68
69async fn run_async(cli: Cli) -> WtgResult<()> {
70    // Parse the input to determine if it's a remote repo or local
71    let parsed_input = cli.parse_input()?;
72
73    // Create notice callback - all notices (capability warnings and operational info)
74    // are delivered via callback and printed by output::print_notice
75    let notice_cb = Arc::new(output::print_notice);
76
77    // Create the backend based on available resources
78    let backend = resolve_backend_with_notices(&parsed_input, cli.fetch, notice_cb)?;
79
80    // Resolve the query using the backend
81    let query = backend.disambiguate_query(parsed_input.query()).await?;
82    let result = resolve(backend.as_ref(), &query).await?;
83
84    // Display the result
85    output::display(result)?;
86
87    Ok(())
88}