1use super::app::AppContext;
2use super::auto_commit::{reset_explicit_push, set_explicit_push};
3use super::commands::{Cli, Commands};
4use super::error::CliResult;
5use super::handle_cloudflare;
6use super::handle_dns;
7#[cfg(feature = "docker")]
8use super::handle_docker;
9use super::handle_domains;
10#[cfg(feature = "kubernetes")]
11use super::handle_kubernetes;
12#[cfg(feature = "linear")]
13use super::handle_linear;
14#[cfg(feature = "monitoring")]
15use super::handle_monitoring;
16#[cfg(feature = "nordvpn")]
17use super::handle_nordvpn;
18#[cfg(feature = "secrets")]
19use super::handle_secrets;
20use super::handle_workers;
21use super::{
22 handle_api, handle_cloudflared, handle_commit, handle_config, handle_curl, handle_cursor,
23 handle_diag, handle_done, handle_env, handle_fix_process_monitor_json, handle_flush,
24 handle_resource,
25 handle_generate, handle_github, handle_init, handle_install, handle_issues, handle_list,
26 handle_login, handle_logs, handle_logs_flag, handle_mcp, handle_monitor, handle_network,
27 handle_deploy, handle_nginx, handle_no_command, handle_oci, handle_ports, handle_publish, handle_push,
28 handle_redeploy,
29 handle_redeploy_v2, handle_resurrect, handle_runners, handle_service, handle_services,
30 handle_setup, handle_snapshot, handle_ssh, handle_start, handle_stop, handle_tail,
31 handle_todos, handle_update, handle_version, handle_whoami, handle_worktree_watch,
32 handle_audit,
33};
34use std::future::Future;
35use std::pin::Pin;
36
37type DispatchFuture<'a> = Pin<Box<dyn Future<Output = CliResult<()>> + 'a>>;
38
39pub fn dispatch(cli: Cli, ctx: &mut AppContext) -> DispatchFuture<'_> {
40 let debug = ctx.debug();
41 let Cli {
42 logs,
43 list,
44 port,
45 push,
46 command,
47 ..
48 } = cli;
49
50 reset_explicit_push();
51 if push {
52 set_explicit_push(true);
53 }
54
55 if logs {
56 return Box::pin(handle_logs_flag());
57 }
58
59 if list && command.is_none() {
60 return Box::pin(handle_list(debug));
61 }
62
63 match command {
64 Some(Commands::Ports(cmd)) => Box::pin(handle_ports(cmd, port, debug)),
65 Some(Commands::Commit(cmd)) => Box::pin(handle_commit(cmd)),
66 Some(Commands::Push) => Box::pin(handle_push()),
67 Some(Commands::Deploy(cmd)) => Box::pin(handle_deploy(cmd, debug)),
68 Some(Commands::Oci(cmd)) => Box::pin(handle_oci(cmd, debug)),
69 Some(Commands::Init) => Box::pin(handle_init(debug)),
70 Some(Commands::Setup) => Box::pin(handle_setup(debug)),
71 Some(Commands::Redeploy { service_name }) => Box::pin(handle_redeploy(service_name, debug)),
72 Some(Commands::RedeployV2(cmd)) => Box::pin(handle_redeploy_v2(cmd, debug)),
73 Some(Commands::Config(cmd)) => Box::pin(handle_config(cmd, debug)),
74 Some(Commands::Install {
75 list,
76 force,
77 package,
78 }) => Box::pin(handle_install(package, list, force, debug)),
79 Some(Commands::Logs(cmd)) => Box::pin(handle_logs(cmd, debug)),
80 Some(Commands::Ssh(cmd)) => Box::pin(handle_ssh(cmd, debug)),
81 Some(Commands::Cloudflared(cmd)) => Box::pin(handle_cloudflared(cmd, debug)),
82 Some(Commands::Cloudflare(cmd)) => Box::pin(handle_cloudflare(cmd, debug)),
83 Some(Commands::List) => Box::pin(handle_list(debug)),
84 Some(Commands::Curl(cmd)) => Box::pin(handle_curl(cmd, debug)),
85 Some(Commands::Services) => Box::pin(handle_services(debug)),
86 Some(Commands::Service {
87 command,
88 service_name,
89 }) => Box::pin(handle_service(command, service_name, debug)),
90 Some(Commands::Nginx(cmd)) => Box::pin(handle_nginx(cmd.command, debug)),
91 Some(Commands::Network(cmd)) => Box::pin(handle_network(cmd, debug)),
92 Some(Commands::Diag(cmd)) => Box::pin(handle_diag(cmd, debug)),
93 Some(Commands::Resource(cmd)) => Box::pin(handle_resource(cmd, debug)),
94 Some(Commands::Monitor(cmd)) => Box::pin(handle_monitor(cmd, debug)),
95 Some(Commands::Snapshot) => Box::pin(handle_snapshot(debug)),
96 Some(Commands::Resurrect) => Box::pin(handle_resurrect(debug)),
97 Some(Commands::Stop { target }) => Box::pin(handle_stop(target, debug)),
98 Some(Commands::Flush { target }) => Box::pin(handle_flush(target, debug)),
99 Some(Commands::Login(cmd)) => Box::pin(handle_login(cmd)),
100 Some(Commands::Whoami) => Box::pin(handle_whoami()),
101 Some(Commands::Update(cmd)) => Box::pin(handle_update(cmd)),
102 Some(Commands::Version(cmd)) => Box::pin(handle_version(cmd, debug)),
103 Some(Commands::Publish(cmd)) => Box::pin(handle_publish(cmd, debug)),
104 Some(Commands::Env { target }) => Box::pin(handle_env(target, debug)),
105 Some(Commands::Tail(cmd)) => Box::pin(handle_tail(cmd, debug)),
106 Some(Commands::Start { args }) => Box::pin(handle_start(args, debug)),
107 Some(Commands::Generate(cmd)) => Box::pin(handle_generate(cmd, debug)),
108 Some(Commands::Api(cmd)) => Box::pin(handle_api(cmd, debug)),
109 Some(Commands::Runners(cmd)) => Box::pin(handle_runners(cmd, debug)),
110 Some(Commands::Mcp(cmd)) => Box::pin(handle_mcp(cmd, debug)),
111 Some(Commands::WorktreeWatch(cmd)) => Box::pin(handle_worktree_watch(cmd, debug)),
112 #[cfg(feature = "docker")]
113 Some(Commands::Docker(cmd)) => Box::pin(handle_docker(cmd, debug)),
114 #[cfg(feature = "secrets")]
115 Some(Commands::Secrets(cmd)) => Box::pin(handle_secrets(cmd, debug)),
116 Some(Commands::Workers(cmd)) => Box::pin(handle_workers(cmd, debug)),
117 Some(Commands::Dns(cmd)) => Box::pin(handle_dns(cmd, debug)),
118 Some(Commands::Domains(cmd)) => Box::pin(handle_domains(cmd, debug)),
119 Some(Commands::Done(cmd)) => Box::pin(handle_done(cmd, debug)),
120 #[cfg(feature = "linear")]
121 Some(Commands::Linear(cmd)) => Box::pin(handle_linear(cmd, debug)),
122 Some(Commands::Github(cmd)) => Box::pin(handle_github(cmd, debug)),
123 Some(Commands::Issues(cmd)) => Box::pin(handle_issues(cmd, debug)),
124 Some(Commands::Todos(cmd)) => Box::pin(handle_todos(cmd, debug)),
125 Some(Commands::Audit(cmd)) => Box::pin(handle_audit(cmd, debug)),
126 Some(Commands::FixProcessMonitorJson(cmd)) => {
127 Box::pin(handle_fix_process_monitor_json(cmd, debug))
128 }
129 Some(Commands::Cursor(cmd)) => Box::pin(handle_cursor(cmd)),
130 #[cfg(feature = "kubernetes")]
131 Some(Commands::Kubernetes(cmd)) => Box::pin(handle_kubernetes(cmd, debug)),
132 #[cfg(feature = "nordvpn")]
133 Some(Commands::Nordvpn(cmd)) => Box::pin(handle_nordvpn(cmd, debug)),
134 #[cfg(feature = "monitoring")]
135 Some(Commands::Monitoring(cmd)) => Box::pin(handle_monitoring(cmd)),
136 None => {
137 Box::pin(handle_no_command(port, debug))
139 }
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use clap::Parser;
147
148 #[test]
149 fn dispatch_future_is_boxed_and_small() {
150 let cli = Cli::parse_from(["xbp", "login"]);
151 let mut ctx = AppContext::new(false);
152 let future = dispatch(cli, &mut ctx);
153 assert!(std::mem::size_of_val(&future) <= 2 * std::mem::size_of::<usize>());
154 }
155}