influxdb3_plugin_cli/config.rs
1//! Top-level embeddable CLI config.
2
3use clap::Parser;
4
5/// `<version>, revision <sha>` fragment fed to clap's `version` attribute.
6///
7/// `build.rs` writes the SHA value (a 40-char lowercase hex string, or
8/// the literal `unknown`) to `$OUT_DIR/version_fragment.rs`; we splice
9/// it onto `CARGO_PKG_VERSION` with the `, revision ` separator. clap
10/// prepends the binary `name` when rendering `--version`, producing:
11///
12/// ```text
13/// influxdb3-plugin <version>, revision <sha>
14/// ```
15const VERSION_STRING: &str = concat!(
16 env!("CARGO_PKG_VERSION"),
17 ", revision ",
18 include!(concat!(env!("OUT_DIR"), "/version_fragment.rs")),
19);
20
21/// Top-level embeddable CLI config for the `influxdb3-plugin` binary.
22///
23/// Parsed from argv via clap and dispatched through [`PluginConfig::run`].
24/// An embedding host can mount this as a variant of its own top-level
25/// command enum and invoke `run()` from its existing tokio runtime.
26#[derive(Debug, Parser)]
27#[command(
28 name = "influxdb3-plugin",
29 version = VERSION_STRING,
30 about = "Author-side tooling for InfluxDB 3 plugins.",
31 long_about = None,
32)]
33pub struct PluginConfig {
34 #[command(subcommand)]
35 command: Command,
36}
37
38#[derive(Debug, clap::Subcommand)]
39enum Command {
40 /// Scaffold a new plugin or index from a built-in template.
41 #[command(subcommand)]
42 New(crate::commands::new::NewCommand),
43 /// Search plugins in a local registry index.
44 Search(crate::commands::index::SearchArgs),
45 /// Inspect one plugin in a local registry index.
46 Info(crate::commands::index::InfoArgs),
47 /// Validate a plugin directory.
48 Validate(crate::commands::validate::Args),
49 /// Validate, archive, hash, and emit a derived index entry.
50 Package(crate::commands::package::Args),
51 /// Toggle the `yanked` flag on an existing index entry.
52 Yank(crate::commands::yank::Args),
53}
54
55impl PluginConfig {
56 /// Runs the parsed subcommand.
57 ///
58 /// `async` even though the current implementation is internally sync, so
59 /// an embedding host can `.await` this without a runtime switch. Errors
60 /// are returned via `Result`; this surface must not call
61 /// `std::process::exit`.
62 ///
63 /// # Examples
64 ///
65 /// Standalone binary entry — `main.rs` does the equivalent of:
66 ///
67 /// ```rust,no_run
68 /// # async fn _doc() -> anyhow::Result<()> {
69 /// use clap::Parser;
70 /// use influxdb3_plugin_cli::PluginConfig;
71 ///
72 /// let config = PluginConfig::parse();
73 /// config.run().await?;
74 /// # Ok(())
75 /// # }
76 /// ```
77 ///
78 /// Embedding host — invoke from the host's existing tokio runtime; no
79 /// nested runtime is needed:
80 ///
81 /// ```rust,no_run
82 /// # fn _doc(host_argv: Vec<String>) -> anyhow::Result<()> {
83 /// use clap::Parser;
84 /// use influxdb3_plugin_cli::PluginConfig;
85 ///
86 /// let config = PluginConfig::try_parse_from(host_argv)?;
87 /// let runtime = tokio::runtime::Builder::new_current_thread()
88 /// .enable_all()
89 /// .build()?;
90 /// runtime.block_on(config.run())?;
91 /// # Ok(())
92 /// # }
93 /// ```
94 pub async fn run(self) -> anyhow::Result<()> {
95 match self.command {
96 Command::New(sub) => sub.run(),
97 Command::Search(args) => args.run(),
98 Command::Info(args) => args.run(),
99 Command::Validate(args) => args.run(),
100 Command::Package(args) => args.run(),
101 Command::Yank(args) => args.run(),
102 }
103 }
104}