1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use clap::Parser;
use clap_verbosity_flag::{InfoLevel, Verbosity};

mod compose_tests;

/// This macro simplifies the generation of CLI subcommand invocation structures by combining the
/// creation of the command enum and implementation of the dispatch function into one simple list.
#[macro_export]
macro_rules! cli_commands {
    // Peel off the list of module identifiers one-by-one
    ( :: $( $list:ident, )* :: mod $mod:ident, $( $rest:tt )* ) => {
        mod $mod;
        $crate::cli_commands! { :: $( $list, )* $mod, :: $( $rest )* }
    };
    ( :: $( $list:ident, )* :: $mod:ident, $( $rest:tt )* ) => {
        $crate::cli_commands! { :: $( $list, )* $mod, :: $( $rest )* }
    };
    // All the identifiers are parsed out, build up the enum and impl blocks
    ( :: $( $mod:ident, )* :: ) => {
        paste::paste! {
            #[derive(clap::Subcommand, Debug)]
            enum Commands {
                $( [<$mod:camel>]($mod::Cli), )*
            }

            impl Cli {
                pub fn exec(self) -> anyhow::Result<()> {
                    match self.command {
                        $( Commands::[<$mod:camel>](cli) => cli.exec(), )*
                    }
                }
            }
        }
    };
    // Start the above patterns
    ( $( $rest:tt )+ ) => { $crate::cli_commands! { :: :: $( $rest )+ } };
}

#[macro_export]
macro_rules! cli_subcommands {
    ( $doc:literal $( $rest:tt )* ) => {
        #[derive(clap::Args, Debug)]
        #[doc = $doc]
        #[command()]
        pub(super) struct Cli {
            #[command(subcommand)]
            command: Commands,
        }

        $crate::cli_commands! { $( $rest )* }
    }
}

/// Vector's unified dev tool
#[derive(Parser, Debug)]
#[command(
    version,
    bin_name = "vdev",
    infer_subcommands = true,
    disable_help_subcommand = true,
    after_help = r#"Environment variables:
  $CONTAINER_TOOL  Set the tool used to run containers (Defaults to autodetect)
                   Valid values are either "docker" or "podman".
"#
)]
pub struct Cli {
    #[clap(flatten)]
    pub verbose: Verbosity<InfoLevel>,

    #[command(subcommand)]
    command: Commands,
}

cli_commands! {
    mod build,
    mod check,
    mod complete,
    mod config,
    mod crate_versions,
    mod e2e,
    mod exec,
    mod features,
    mod fmt,
    mod info,
    mod integration,
    mod meta,
    mod package,
    mod release,
    mod run,
    mod status,
    mod test,
    mod test_vrl,
    mod version,
}

/// This macro creates a wrapper for an existing script.
#[macro_export]
macro_rules! script_wrapper {
    ( $mod:ident = $doc:literal => $script:literal ) => {
        paste::paste! {
            mod $mod {
                #[doc = $doc]
                #[derive(clap::Args, Debug)]
                #[command()]
                pub(super) struct Cli {
                    args: Vec<String>,
                }

                impl Cli {
                    pub(super) fn exec(self) -> anyhow::Result<()> {
                        $crate::app::exec(concat!("scripts/", $script), self.args, true)
                    }
                }
            }
        }
    };
}