1use crate::{
2 cli::{Cli, Command, ConfigCommand, ConnectionCommand},
3 commands, config, interactive,
4};
5use std::{io::IsTerminal, path::Path};
6
7pub fn run(cli: Cli) -> i32 {
8 match dispatch(cli) {
9 Ok(code) => code,
10 Err(error) => {
11 eprintln!("Error: {error}");
12 2
13 }
14 }
15}
16
17fn dispatch(cli: Cli) -> Result<i32, Box<dyn std::error::Error>> {
18 let Some(command) = cli.command.clone() else {
19 if cli.options.non_interactive {
20 return Err("non-interactive mode requires a subcommand".into());
21 }
22 return interactive::run(cli);
23 };
24 if matches!(
25 &command,
26 Command::Config {
27 command: ConfigCommand::Init
28 }
29 ) {
30 return commands::run_config_init(cli.options.format.into());
31 }
32 let options = command_options(&cli.options, &command);
33 let runtime = config::runtime::load(&options, Path::new("."))?;
34 let approval = config::runtime::approval_mode(&options)?;
35 let format = config::runtime::format_name(&options, &runtime.resolved);
36 let can_prompt = !options.non_interactive && std::io::stdin().is_terminal();
37 tokio::runtime::Builder::new_current_thread()
38 .enable_all()
39 .build()?
40 .block_on(commands::run(
41 command,
42 &runtime,
43 format,
44 approval,
45 can_prompt,
46 options.include_profiles.clone(),
47 ))
48}
49
50fn command_options(
51 options: &crate::cli::GlobalOptions,
52 command: &Command,
53) -> crate::cli::GlobalOptions {
54 let mut options = options.clone();
55 if options.profile.is_none() {
56 let profile = match command {
57 Command::Connection {
58 command:
59 ConnectionCommand::Test { profile_name }
60 | ConnectionCommand::Schema { profile_name, .. },
61 } => Some(profile_name.clone()),
62 _ => None,
63 };
64 options.profile = profile;
65 }
66 options
67}