1use clap::Subcommand;
2use miette::Result;
3use tracing::{debug, trace};
4
5pub use context::Context;
6pub mod context;
7
8#[macro_export]
20macro_rules! subcommands {
21 (
22 [$argtype:ty => $prep:expr]
23 $(
24 $(#[cfg($cfg:meta)])*
25 $(#[clap($clap:meta)])*
26 $modname:ident => $enumname:ident($argname:ident)
27 ),+
28 ) => {
29 $(
30 $(#[cfg($cfg)])*
31 pub mod $modname;
32 )*
33
34 #[derive(Debug, Clone, Subcommand)]
35 pub enum Action {
36 $(
37 $(#[cfg($cfg)])*
38 $(#[clap($clap)])*
39 $enumname($modname::$argname),
40 )*
41 }
42
43 pub async fn run(args: $argtype, ctx: Context) -> Result<()> {
44 let prep = $prep;
45 let (action, ctx) = prep(args, ctx)?;
46 match action {
47 $(
48 $(#[cfg($cfg)])*
49 Action::$enumname(args) => $modname::run(args, ctx).await,
50 )*
51 }
52 }
53 };
54}
55#[allow(unused_imports)]
56pub use subcommands;
57
58use crate::args::Args;
59
60subcommands! {
61 [Args => |args: Args, mut ctx: Context| -> Result<(Action, Context)> {
62 debug!(version=%env!("CARGO_PKG_VERSION"), "starting up");
63 trace!(action=?args.action, "action");
64 let action = args.action.clone();
65 ctx.provide(args);
66 Ok((action, ctx))
67 }]
68
69 #[cfg(feature = "tamanu-psql")]
70 audit_psql => AuditPsql(AuditPsqlArgs),
71 #[cfg(feature = "caddy")]
72 caddy => Caddy(CaddyArgs),
73 #[cfg(feature = "__canopy")]
74 canopy => Canopy(CanopyArgs),
75 #[cfg(feature = "completions")]
76 completions => Completions(CompletionsArgs),
77 #[cfg(feature = "crypto")]
78 crypto => Crypto(CryptoArgs),
79 #[clap(hide = true)]
80 #[clap(name = "_docs")]
81 docs => Docs(DocsArgs),
82 #[cfg(feature = "file")]
83 file => File(FileArgs),
84 #[cfg(feature = "__iti")]
85 iti => Iti(ItiArgs),
86 #[cfg(feature = "kopia")]
87 #[clap(alias = "k")]
88 kopia => Kopia(KopiaArgs),
89 #[cfg(feature = "rdp")]
90 rdp => Rdp(RdpArgs),
91 #[cfg(feature = "self-update")]
92 #[clap(alias = "self")]
93 self_update => SelfUpdate(SelfUpdateArgs),
94 #[cfg(feature = "ssh")]
95 ssh => Ssh(SshArgs),
96 #[cfg(feature = "__tamanu")]
97 #[clap(alias = "t")]
98 tamanu => Tamanu(TamanuArgs)
99}
100
101pub async fn run_with_update_check(args: Args) -> Result<()> {
102 let action = args.action.clone();
103
104 #[cfg(all(feature = "download", feature = "self-update"))]
105 if !matches!(action, Action::SelfUpdate(_))
106 && !crate::actions::self_update::is_package_manager_install()
107 && let Err(err) = crate::download::check_for_update().await
108 {
109 debug!("Failed to check for updates: {}", err);
110 }
111
112 run(args, Context::new()).await
113}