wtg_cli/
lib.rs

1use clap::Parser;
2
3pub mod cli;
4pub mod constants;
5pub mod error;
6pub mod git;
7pub mod github;
8pub mod help;
9pub mod identifier;
10pub mod output;
11pub mod remote;
12pub mod repo_manager;
13
14use cli::Cli;
15use error::{Result, WtgError};
16use repo_manager::RepoManager;
17
18/// Run the CLI using the process arguments.
19pub fn run() -> Result<()> {
20    run_with_args(std::env::args())
21}
22
23/// Run the CLI using a custom iterator of arguments.
24pub fn run_with_args<I, T>(args: I) -> Result<()>
25where
26    I: IntoIterator<Item = T>,
27    T: Into<std::ffi::OsString> + Clone,
28{
29    let cli = match Cli::try_parse_from(args) {
30        Ok(cli) => cli,
31        Err(err) => {
32            // If the error is DisplayHelp, show our custom help
33            if err.kind() == clap::error::ErrorKind::DisplayHelp {
34                help::display_help();
35                return Ok(());
36            }
37            // Otherwise, propagate the error
38            return Err(WtgError::Cli {
39                message: err.to_string(),
40                code: err.exit_code(),
41            });
42        }
43    };
44    run_with_cli(cli)
45}
46
47fn run_with_cli(cli: Cli) -> Result<()> {
48    // If no input provided, show custom help
49    if cli.input.is_none() {
50        help::display_help();
51        return Ok(());
52    }
53
54    let runtime = tokio::runtime::Builder::new_current_thread()
55        .enable_all()
56        .build()?;
57
58    runtime.block_on(run_async(cli))
59}
60
61async fn run_async(cli: Cli) -> Result<()> {
62    // Parse the input to determine if it's a remote repo or local
63    let parsed_input = cli.parse_input().ok_or_else(|| WtgError::Cli {
64        message: "Invalid input".to_string(),
65        code: 1,
66    })?;
67
68    // Create the appropriate repo manager
69    let repo_manager = if let Some(owner) = &parsed_input.owner {
70        let repo = parsed_input.repo.as_ref().ok_or_else(|| WtgError::Cli {
71            message: "Invalid repository".to_string(),
72            code: 1,
73        })?;
74        RepoManager::remote(owner.clone(), repo.clone())?
75    } else {
76        RepoManager::local()?
77    };
78
79    // Get the git repo instance
80    let git_repo = repo_manager.git_repo()?;
81
82    // Determine the remote info - either from the remote repo manager or from the local repo
83    let remote_info = repo_manager
84        .remote_info()
85        .map_or_else(|| git_repo.github_remote(), Some);
86
87    // Print snarky messages if no GitHub remote (only for local repos)
88    if !repo_manager.is_remote() {
89        remote::check_remote_and_snark(remote_info.clone(), git_repo.path());
90    }
91
92    // Detect what type of input we have
93    let result = Box::pin(identifier::identify(&parsed_input.query, git_repo)).await?;
94
95    // Display the result
96    output::display(result)?;
97
98    Ok(())
99}