Skip to main content

rtb_cli/
init.rs

1//! Initialisers — the `init` subcommand's plug-in point.
2
3use async_trait::async_trait;
4use linkme::distributed_slice;
5use rtb_app::app::App;
6
7/// A pluggable bootstrap step run by the `init` subcommand.
8///
9/// Initialisers typically prompt for configuration values, write a
10/// user config file, set up OS keychain entries, generate SSH keys,
11/// etc. The `init` command iterates every registered initialiser in
12/// registration order, skipping any that report `is_configured ==
13/// true` unless the user passes `--force`.
14#[async_trait]
15pub trait Initialiser: Send + Sync + 'static {
16    /// Short identifier shown in `init` output.
17    fn name(&self) -> &'static str;
18
19    /// Returns `true` if this initialiser's prerequisites are already
20    /// met — e.g. the relevant config key is present.
21    async fn is_configured(&self, app: &App) -> bool;
22
23    /// Perform the bootstrap. Typically interactive.
24    async fn configure(&self, app: &App) -> miette::Result<()>;
25}
26
27/// Link-time registry of initialiser factories.
28///
29/// ```no_run
30/// use rtb_app::app::App;
31/// use rtb_app::linkme::distributed_slice;
32/// use rtb_cli::init::{Initialiser, INITIALISERS};
33///
34/// struct MyInitialiser;
35///
36/// #[async_trait::async_trait]
37/// impl Initialiser for MyInitialiser {
38///     fn name(&self) -> &'static str {
39///         "my-initialiser"
40///     }
41///
42///     async fn is_configured(&self, _app: &App) -> bool {
43///         false
44///     }
45///
46///     async fn configure(&self, _app: &App) -> miette::Result<()> {
47///         Ok(())
48///     }
49/// }
50///
51/// #[distributed_slice(INITIALISERS)]
52/// fn register() -> Box<dyn Initialiser> { Box::new(MyInitialiser) }
53/// ```
54#[distributed_slice]
55pub static INITIALISERS: [fn() -> Box<dyn Initialiser>];