1use clap::{Parser, Subcommand};
2use tracing::error;
3
4use crate::{
5 error::CapturedError,
6 experimental::{query::command::QueryCommand, tasks::TaskCommand},
7 invocation_context::{context, init_context},
8 sourcemaps::{hermes::HermesSubcommand, plain::SourcemapCommand},
9};
10
11#[derive(Parser)]
12#[command(version, about, long_about = None)]
13pub struct Cli {
14 #[arg(long)]
16 host: Option<String>,
17
18 #[arg(long, default_value = "false")]
20 no_fail: bool,
21 #[arg(long, default_value = "false")]
22 skip_ssl_verification: bool,
23
24 #[command(subcommand)]
25 command: Commands,
26}
27
28#[derive(Subcommand)]
29pub enum Commands {
30 Login,
33
34 Exp {
36 #[command(subcommand)]
37 cmd: ExpCommand,
38 },
39
40 #[command(about = "Upload a directory of bundled chunks to PostHog")]
41 Sourcemap {
42 #[command(subcommand)]
43 cmd: SourcemapCommand,
44 },
45}
46
47#[derive(Subcommand)]
48pub enum ExpCommand {
49 Task {
51 #[command(subcommand)]
52 cmd: TaskCommand,
53 #[arg(long, default_value = "false")]
57 skip_ssl_verification: bool,
58 },
59
60 Query {
62 #[command(subcommand)]
63 cmd: QueryCommand,
64 },
65
66 #[command(about = "Upload hermes sourcemaps to PostHog")]
67 Hermes {
68 #[command(subcommand)]
69 cmd: HermesSubcommand,
70 },
71}
72
73impl Cli {
74 pub fn run() -> Result<(), CapturedError> {
75 let command = Cli::parse();
76 let no_fail = command.no_fail;
77
78 match command.run_impl() {
79 Ok(_) => Ok(()),
80 Err(e) => {
81 let msg = match &e.exception_id {
82 Some(id) => format!("Oops! {} (ID: {})", e.inner, id),
83 None => format!("Oops! {:?}", e.inner),
84 };
85 error!(msg);
86 if no_fail {
87 Ok(())
88 } else {
89 Err(e)
90 }
91 }
92 }
93 }
94
95 fn run_impl(self) -> Result<(), CapturedError> {
96 if !matches!(self.command, Commands::Login) {
97 init_context(self.host.clone(), self.skip_ssl_verification)?;
98 }
99
100 match self.command {
101 Commands::Login => {
102 crate::login::login()?;
104 }
105 Commands::Sourcemap { cmd } => match cmd {
106 SourcemapCommand::Inject(input_args) => {
107 crate::sourcemaps::plain::inject::inject(&input_args)?;
108 }
109 SourcemapCommand::Upload(upload_args) => {
110 crate::sourcemaps::plain::upload::upload(&upload_args)?;
111 }
112 SourcemapCommand::Process(args) => {
113 let (inject, upload) = args.into();
114 crate::sourcemaps::plain::inject::inject(&inject)?;
115 crate::sourcemaps::plain::upload::upload(&upload)?;
116 }
117 },
118 Commands::Exp { cmd } => match cmd {
119 ExpCommand::Task {
120 cmd,
121 skip_ssl_verification: _,
122 } => {
123 cmd.run()?;
124 }
125 ExpCommand::Query { cmd } => {
126 crate::experimental::query::command::query_command(&cmd)?
127 }
128 ExpCommand::Hermes { cmd } => match cmd {
129 HermesSubcommand::Inject(args) => {
130 crate::sourcemaps::hermes::inject::inject(&args)?;
131 }
132 HermesSubcommand::Upload(args) => {
133 crate::sourcemaps::hermes::upload::upload(&args)?;
134 }
135 HermesSubcommand::Clone(args) => {
136 crate::sourcemaps::hermes::clone::clone(&args)?;
137 }
138 },
139 },
140 }
141
142 context().finish();
143
144 Ok(())
145 }
146}