1use clap::Parser;
2
3#[derive(Parser, Debug, Clone)]
4#[command(author,version, about = "cargo-e is for Example.", long_about = None)]
5#[command(disable_version_flag = true)]
6pub struct Cli {
7 #[arg(
11 long,
12 value_name = "PATH",
13 help = "Path to read/write the stdout of the executed command."
14 )]
15 pub stdout: Option<std::path::PathBuf>,
16
17 #[arg(
19 long,
20 value_name = "PATH",
21 help = "Path to read/write the stderr of the executed command."
22 )]
23 pub stderr: Option<std::path::PathBuf>,
24 #[arg(
29 long,
30 num_args = 0..=1,
31 default_value_t = RunAll::NotSpecified,
32 default_missing_value ="",
33 value_parser,
34 help = "Run all optionally specifying run time (in seconds) per target. \
35 If the flag is present without a value, run forever."
36 )]
37 pub run_all: RunAll,
38
39 #[arg(long, help = "Create GIST run_report.md on exit.")]
40 pub gist: bool,
41 #[arg(long, help = "Build and run in release mode.")]
42 pub release: bool,
43 #[arg(
44 long,
45 short = 'q',
46 help = "Suppress cargo output when running the sample."
47 )]
48 pub quiet: bool,
49 #[clap(
54 long,
55 help = "If enabled, pre-build the examples before executing them."
56 )]
57 pub pre_build: bool,
58
59 #[arg(
61 long = "filter",
62 short = 'f',
63 help = "Enable passthrough mode. No cargo output is filtered, and stdout is captured."
64 )]
65 pub filter: bool,
66 #[arg(
68 long,
69 short = 'v',
70 help = "Print version and feature flags in JSON format."
71 )]
72 pub version: bool,
73
74 #[arg(
75 long,
76 short = 't',
77 help = "Launch the text-based user interface (TUI)."
78 )]
79 pub tui: bool,
80
81 #[arg(long, short = 'w', help = "Operate on the entire workspace.")]
82 pub workspace: bool,
83
84 #[arg(
86 long = "pX",
87 default_value_t = false,
88 value_parser = clap::value_parser!(bool),
89 help = "Print the exit code of the process when run. (default: false)"
90 )]
91 pub print_exit_code: bool,
92
93 #[arg(
95 long = "pN",
96 default_value_t = false,
97 value_parser = clap::value_parser!(bool),
98 help = "Print the program name before execution. (default: false)"
99 )]
100 pub print_program_name: bool,
101
102 #[arg(
104 long = "pI",
105 default_value_t = true,
106 value_parser = clap::value_parser!(bool),
107 help = "Print the user instruction. (default: true)"
108 )]
109 pub print_instruction: bool,
110
111 #[arg(
112 long,
113 short = 'p',
114 default_value_t = true,
115 help = "Enable or disable paging (default: enabled)."
116 )]
117 pub paging: bool,
118
119 #[arg(
120 long,
121 short = 'r',
122 default_value_t = false,
123 help = "Relative numbers (default: enabled)."
124 )]
125 pub relative_numbers: bool,
126
127 #[arg(
128 long = "wait",
129 short = 'W',
130 default_value_t = 15,
131 help = "Set wait time in seconds (default: 15)."
132 )]
133 pub wait: u64,
134
135 #[arg(
137 long = "subcommand",
138 short = 's',
139 value_parser,
140 default_value = "run",
141 help = "Specify subcommands (e.g., `build|b`, `test|t`)."
142 )]
143 pub subcommand: String,
144
145 #[arg(help = "Specify an explicit target to run.")]
146 pub explicit_example: Option<String>,
147
148 #[arg(
149 long = "run-at-a-time",
150 short = 'J',
151 default_value_t = 1,
152 value_parser = clap::value_parser!(usize),
153 help = "Number of targets to run at a time in --run-all mode (--run-at-a-time)"
154 )]
155 pub run_at_a_time: usize,
156
157 #[arg(last = true, help = "Additional arguments passed to the command.")]
158 pub extra: Vec<String>,
159}
160
161pub fn print_version_and_features() {
163 let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
165
166 let mut features = Vec::new();
169
170 if cfg!(feature = "tui") {
171 features.push("tui");
172 } else {
173 features.push("!tui");
174 }
175 if cfg!(feature = "concurrent") {
176 features.push("concurrent");
177 } else {
178 features.push("!concurrent");
179 }
180 if cfg!(target_os = "windows") {
181 features.push("windows");
182 } else {
183 features.push("!windows");
184 }
185 if cfg!(feature = "equivalent") {
186 features.push("equivalent");
187 } else {
188 features.push("!equivalent");
189 }
190
191 let json_features = format!(
192 "[{}]",
193 features
194 .iter()
195 .map(|f| format!("\"{}\"", f))
196 .collect::<Vec<String>>()
197 .join(", ")
198 );
199 println!("cargo-e {}", version);
200 println!("{}", json_features);
201 std::process::exit(0);
202}
203
204pub fn get_feature_flags() -> Vec<&'static str> {
207 let mut flags = Vec::new();
208 if cfg!(feature = "tui") {
209 flags.push("tui");
210 } else {
211 flags.push("!tui");
212 }
213 if cfg!(feature = "concurrent") {
214 flags.push("concurrent");
215 } else {
216 flags.push("!concurrent");
217 }
218 if cfg!(target_os = "windows") {
219 flags.push("windows");
220 } else {
221 flags.push("!windows");
222 }
223 if cfg!(feature = "equivalent") {
224 flags.push("equivalent");
225 } else {
226 flags.push("!equivalent");
227 }
228 flags
229}
230
231use std::str::FromStr;
232
233#[derive(Debug, Clone, PartialEq, Default)]
235pub enum RunAll {
236 #[default]
238 NotSpecified,
239 Forever,
241 Timeout(u64),
243}
244
245impl FromStr for RunAll {
246 type Err = String;
247 fn from_str(s: &str) -> Result<Self, Self::Err> {
248 if s.is_empty() {
250 Ok(RunAll::Forever)
251 } else if s.eq_ignore_ascii_case("not_specified") {
252 Ok(RunAll::NotSpecified)
253 } else {
254 s.parse::<u64>()
256 .map(RunAll::Timeout)
257 .map_err(|e| e.to_string())
258 }
259 }
260}
261
262impl std::fmt::Display for RunAll {
263 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
264 match self {
265 RunAll::NotSpecified => write!(f, "not_specified"),
266 RunAll::Forever => write!(f, "forever"),
267 RunAll::Timeout(secs) => write!(f, "{}", secs),
268 }
269 }
270}
271
272pub fn custom_cli(args: &mut Vec<String>) -> (Option<usize>, Vec<&String>) {
273 if args.len() > 1 && args[1].as_str() == "e" {
275 args.remove(1);
276 }
277 let mut run_at_a_time: Option<usize> = None;
278 let mut filtered_args = vec![];
280 for arg in &*args {
281 if let Some(num) = arg
282 .strip_prefix("--run-")
283 .and_then(|s| s.strip_suffix("-at-a-time"))
284 {
285 if let Ok(n) = num.parse() {
286 println!("run-at-a-time: {}", n);
287 run_at_a_time = Some(n);
288 }
289 continue;
291 }
292 filtered_args.push(arg);
293 }
294 (run_at_a_time, filtered_args)
295}