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::release_filter::ReleaseFilter;
11use crate::resolution::resolve;
12
13pub mod backend;
14pub mod changelog;
15pub mod cli;
16pub mod constants;
17pub mod error;
18pub mod git;
19pub mod github;
20pub mod help;
21pub mod notice;
22pub mod output;
23pub mod parse_input;
24pub mod release_filter;
25pub mod remote;
26pub mod resolution;
27pub mod semver;
28
29pub fn run() -> WtgResult<()> {
31 run_with_args(env::args())
32}
33
34pub fn run_with_args<I, T>(args: I) -> WtgResult<()>
36where
37 I: IntoIterator<Item = T>,
38 T: Into<OsString> + Clone,
39{
40 let _ = env_logger::try_init();
43
44 let cli = match Cli::try_parse_from(args) {
45 Ok(cli) => cli,
46 Err(err) => {
47 if err.kind() == clap::error::ErrorKind::DisplayHelp {
49 help::display_help();
50 return Ok(());
51 }
52 return Err(WtgError::Cli {
54 message: err.to_string(),
55 code: err.exit_code(),
56 });
57 }
58 };
59 run_with_cli(cli)
60}
61
62fn run_with_cli(cli: Cli) -> WtgResult<()> {
63 if cli.input.is_none() {
65 help::display_help();
66 return Ok(());
67 }
68
69 let runtime = tokio::runtime::Builder::new_current_thread()
70 .enable_all()
71 .build()?;
72
73 runtime.block_on(run_async(cli))
74}
75
76async fn run_async(cli: Cli) -> WtgResult<()> {
77 let parsed_input = cli.parse_input()?;
79 log::debug!("Parsed input: {parsed_input:?}");
80
81 let notice_cb = Arc::new(output::print_notice);
84
85 log::debug!("Resolving backend (fetch={})", cli.fetch);
87 let backend = resolve_backend_with_notices(&parsed_input, cli.fetch, notice_cb)?;
88 log::debug!("Backend resolved");
89
90 let filter = if let Some(ref release) = cli.release {
92 ReleaseFilter::Specific(release.clone())
93 } else if cli.skip_prereleases {
94 ReleaseFilter::SkipPrereleases
95 } else {
96 ReleaseFilter::Unrestricted
97 };
98
99 log::debug!("Disambiguating query: {:?}", parsed_input.query());
101 let query = backend.disambiguate_query(parsed_input.query()).await?;
102 log::debug!("Disambiguated to: {query:?}");
103
104 log::debug!("Resolving query");
105 let result = resolve(backend.as_ref(), &query, &filter).await?;
106 log::debug!("Resolution complete");
107
108 output::display(result, &filter)?;
110
111 Ok(())
112}