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::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
22 #[command(subcommand)]
23 command: Commands,
24}
25
26#[derive(Subcommand)]
27pub enum Commands {
28 Login,
31
32 Exp {
34 #[command(subcommand)]
35 cmd: ExpCommand,
36 },
37
38 #[command(about = "Upload a directory of bundled chunks to PostHog")]
39 Sourcemap {
40 #[command(subcommand)]
41 cmd: SourcemapCommand,
42 },
43}
44
45#[derive(Subcommand)]
46pub enum ExpCommand {
47 Task {
49 #[command(subcommand)]
50 cmd: TaskCommand,
51 #[arg(long, default_value = "false")]
55 skip_ssl_verification: bool,
56 },
57
58 Query {
60 #[command(subcommand)]
61 cmd: QueryCommand,
62 },
63}
64
65impl Cli {
66 pub fn run() -> Result<(), CapturedError> {
67 let command = Cli::parse();
68 let no_fail = command.no_fail;
69
70 match command.run_impl() {
71 Ok(_) => Ok(()),
72 Err(e) => {
73 let msg = match &e.exception_id {
74 Some(id) => format!("Oops! {} (ID: {})", e.inner, id),
75 None => format!("Oops! {:?}", e.inner),
76 };
77 error!(msg);
78 if no_fail {
79 Ok(())
80 } else {
81 Err(e)
82 }
83 }
84 }
85 }
86
87 fn run_impl(self) -> Result<(), CapturedError> {
88 match self.command {
89 Commands::Login => {
90 crate::login::login()?;
92 }
93 Commands::Sourcemap { cmd } => match cmd {
94 SourcemapCommand::Inject(input_args) => {
95 init_context(self.host.clone(), false)?;
96 crate::sourcemaps::inject::inject(&input_args)?;
97 }
98 SourcemapCommand::Upload(upload_args) => {
99 init_context(self.host.clone(), upload_args.skip_ssl_verification)?;
100 crate::sourcemaps::upload::upload_cmd(upload_args.clone())?;
101 }
102 SourcemapCommand::Process(args) => {
103 init_context(self.host.clone(), args.skip_ssl_verification)?;
104 let (inject, upload) = args.into();
105 crate::sourcemaps::inject::inject(&inject)?;
106 crate::sourcemaps::upload::upload_cmd(upload)?;
107 }
108 },
109 Commands::Exp { cmd } => match cmd {
110 ExpCommand::Task {
111 cmd,
112 skip_ssl_verification,
113 } => {
114 init_context(self.host.clone(), skip_ssl_verification)?;
115 cmd.run()?;
116 }
117 ExpCommand::Query { cmd } => {
118 init_context(self.host.clone(), false)?;
119 crate::experimental::query::command::query_command(&cmd)?
120 }
121 },
122 }
123
124 context().finish();
125
126 Ok(())
127 }
128}