cargo_e/
e_cli.rs

1use clap::Parser;
2
3#[derive(Parser, Debug)]
4#[command(author,version, about = "cargo-e is for Example.", long_about = None)]
5#[command(disable_version_flag = true)]
6pub struct Cli {
7    /// Run all examples for a given number of seconds.
8    ///
9    /// If provided with a value (e.g. `--run-all 10`), each target will run for 10 seconds.
10    /// If provided without a value (i.e. just `--run-all`), it means run forever.
11    /// If not provided at all, then the default wait time is used.
12    #[arg(
13        long,
14        num_args = 0..=1,
15        default_value_t = RunAll::NotSpecified,
16        default_missing_value ="",
17        value_parser,
18        help = "Run all optionally specifying run time (in seconds) per target. \
19                If the flag is present without a value, run forever."
20    )]
21    pub run_all: RunAll,
22
23    #[arg(long, help = "Build and run in release mode.")]
24    pub release: bool,
25    #[arg(long, help = "Suppress cargo output when running the sample.")]
26    pub quiet: bool,
27    // /// Comma-separated list of package names.
28    // #[clap(long, value_delimiter = ',', help = "Optional list of package names to run examples for. If omitted, defaults to ALL_PACKAGES.")]
29    // pub specified_packages: Vec<String>,
30    /// Pre-build examples before running.
31    #[clap(
32        long,
33        help = "If enabled, pre-build the examples before executing them."
34    )]
35    pub pre_build: bool,
36
37    /// Print version and feature flags in JSON format.
38    #[arg(
39        long,
40        short = 'v',
41        help = "Print version and feature flags in JSON format."
42    )]
43    pub version: bool,
44
45    #[arg(
46        long,
47        short = 't',
48        help = "Launch the text-based user interface (TUI)."
49    )]
50    pub tui: bool,
51
52    #[arg(long, short = 'w', help = "Operate on the entire workspace.")]
53    pub workspace: bool,
54
55    /// Print the exit code of the process when run.
56    #[arg(
57        long = "pX",
58        default_value_t = false,
59        value_parser = clap::value_parser!(bool),
60        help = "Print the exit code of the process when run. (default: false)"
61    )]
62    pub print_exit_code: bool,
63
64    /// Print the program name before execution.
65    #[arg(
66        long = "pN",
67        default_value_t = false,
68        value_parser = clap::value_parser!(bool),
69        help = "Print the program name before execution. (default: false)"
70    )]
71    pub print_program_name: bool,
72
73    /// Print the program name before execution.
74    #[arg(
75        long = "pI",
76        default_value_t = true,
77        value_parser = clap::value_parser!(bool),
78        help = "Print the user instruction. (default: true)"
79    )]
80    pub print_instruction: bool,
81
82    #[arg(
83        long,
84        short = 'p',
85        default_value_t = true,
86        help = "Enable or disable paging (default: enabled)."
87    )]
88    pub paging: bool,
89
90    #[arg(
91        long,
92        short = 'r',
93        default_value_t = false,
94        help = "Relative numbers (default: enabled)."
95    )]
96    pub relative_numbers: bool,
97
98    #[arg(
99        long = "wait",
100        short = 'W',
101        default_value_t = 5,
102        help = "Set wait time in seconds (default: 5)."
103    )]
104    pub wait: u64,
105
106    #[arg(help = "Specify an explicit example to run.")]
107    pub explicit_example: Option<String>,
108
109    #[arg(last = true, help = "Additional arguments passed to the command.")]
110    pub extra: Vec<String>,
111}
112
113/// Print the version and the JSON array of feature flags.
114pub fn print_version_and_features() {
115    // Print the version string.
116    let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
117
118    // Build a list of feature flags. Enabled features are printed normally,
119    // while disabled features are prefixed with an exclamation mark.
120    let mut features = Vec::new();
121
122    if cfg!(feature = "tui") {
123        features.push("tui");
124    } else {
125        features.push("!tui");
126    }
127    if cfg!(feature = "concurrent") {
128        features.push("concurrent");
129    } else {
130        features.push("!concurrent");
131    }
132    if cfg!(target_os = "windows") {
133        features.push("windows");
134    } else {
135        features.push("!windows");
136    }
137    if cfg!(feature = "equivalent") {
138        features.push("equivalent");
139    } else {
140        features.push("!equivalent");
141    }
142
143    let json_features = format!(
144        "[{}]",
145        features
146            .iter()
147            .map(|f| format!("\"{}\"", f))
148            .collect::<Vec<String>>()
149            .join(", ")
150    );
151    println!("cargo-e {}", version);
152    println!("{}", json_features);
153    std::process::exit(0);
154}
155
156/// Returns a vector of feature flag strings.  
157/// Enabled features are listed as-is while disabled ones are prefixed with "!".
158pub fn get_feature_flags() -> Vec<&'static str> {
159    let mut flags = Vec::new();
160    if cfg!(feature = "tui") {
161        flags.push("tui");
162    } else {
163        flags.push("!tui");
164    }
165    if cfg!(feature = "concurrent") {
166        flags.push("concurrent");
167    } else {
168        flags.push("!concurrent");
169    }
170    if cfg!(target_os = "windows") {
171        flags.push("windows");
172    } else {
173        flags.push("!windows");
174    }
175    if cfg!(feature = "equivalent") {
176        flags.push("equivalent");
177    } else {
178        flags.push("!equivalent");
179    }
180    flags
181}
182
183use std::str::FromStr;
184
185/// Represents the state of the `--run-all` flag.
186#[derive(Debug, Clone, PartialEq)]
187pub enum RunAll {
188    /// The flag was not specified.
189    NotSpecified,
190    /// The flag was specified without a value—indicating “run forever.”
191    Forever,
192    /// The flag was specified with a timeout value.
193    Timeout(u64),
194}
195
196impl Default for RunAll {
197    fn default() -> Self {
198        RunAll::NotSpecified
199    }
200}
201
202impl FromStr for RunAll {
203    type Err = String;
204    fn from_str(s: &str) -> Result<Self, Self::Err> {
205        // An empty string means the flag was provided without a value → run forever.
206        if s.is_empty() {
207            Ok(RunAll::Forever)
208        } else if s.eq_ignore_ascii_case("not_specified") {
209            Ok(RunAll::NotSpecified)
210        } else {
211            // Otherwise, try parsing a u64 value.
212            s.parse::<u64>()
213                .map(RunAll::Timeout)
214                .map_err(|e| e.to_string())
215        }
216    }
217}
218
219impl std::fmt::Display for RunAll {
220    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
221        match self {
222            RunAll::NotSpecified => write!(f, "not_specified"),
223            RunAll::Forever => write!(f, "forever"),
224            RunAll::Timeout(secs) => write!(f, "{}", secs),
225        }
226    }
227}