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(
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(
26 long,
27 short = 'q',
28 help = "Suppress cargo output when running the sample."
29 )]
30 pub quiet: bool,
31 #[clap(
36 long,
37 help = "If enabled, pre-build the examples before executing them."
38 )]
39 pub pre_build: bool,
40
41 #[arg(
43 long = "filter",
44 short = 'f',
45 help = "Enable passthrough mode. No cargo output is filtered, and stdout is captured."
46 )]
47 pub filter: bool,
48 #[arg(
50 long,
51 short = 'v',
52 help = "Print version and feature flags in JSON format."
53 )]
54 pub version: bool,
55
56 #[arg(
57 long,
58 short = 't',
59 help = "Launch the text-based user interface (TUI)."
60 )]
61 pub tui: bool,
62
63 #[arg(long, short = 'w', help = "Operate on the entire workspace.")]
64 pub workspace: bool,
65
66 #[arg(
68 long = "pX",
69 default_value_t = false,
70 value_parser = clap::value_parser!(bool),
71 help = "Print the exit code of the process when run. (default: false)"
72 )]
73 pub print_exit_code: bool,
74
75 #[arg(
77 long = "pN",
78 default_value_t = false,
79 value_parser = clap::value_parser!(bool),
80 help = "Print the program name before execution. (default: false)"
81 )]
82 pub print_program_name: bool,
83
84 #[arg(
86 long = "pI",
87 default_value_t = true,
88 value_parser = clap::value_parser!(bool),
89 help = "Print the user instruction. (default: true)"
90 )]
91 pub print_instruction: bool,
92
93 #[arg(
94 long,
95 short = 'p',
96 default_value_t = true,
97 help = "Enable or disable paging (default: enabled)."
98 )]
99 pub paging: bool,
100
101 #[arg(
102 long,
103 short = 'r',
104 default_value_t = false,
105 help = "Relative numbers (default: enabled)."
106 )]
107 pub relative_numbers: bool,
108
109 #[arg(
110 long = "wait",
111 short = 'W',
112 default_value_t = 15,
113 help = "Set wait time in seconds (default: 15)."
114 )]
115 pub wait: u64,
116
117 #[arg(
119 long = "subcommand",
120 short = 's',
121 value_parser,
122 default_value = "run",
123 help = "Specify subcommands (e.g., `build|b`, `test|t`)."
124 )]
125 pub subcommand: String,
126
127 #[arg(help = "Specify an explicit target to run.")]
128 pub explicit_example: Option<String>,
129
130 #[arg(last = true, help = "Additional arguments passed to the command.")]
131 pub extra: Vec<String>,
132}
133
134pub fn print_version_and_features() {
136 let version = option_env!("CARGO_PKG_VERSION").unwrap_or("unknown");
138
139 let mut features = Vec::new();
142
143 if cfg!(feature = "tui") {
144 features.push("tui");
145 } else {
146 features.push("!tui");
147 }
148 if cfg!(feature = "concurrent") {
149 features.push("concurrent");
150 } else {
151 features.push("!concurrent");
152 }
153 if cfg!(target_os = "windows") {
154 features.push("windows");
155 } else {
156 features.push("!windows");
157 }
158 if cfg!(feature = "equivalent") {
159 features.push("equivalent");
160 } else {
161 features.push("!equivalent");
162 }
163
164 let json_features = format!(
165 "[{}]",
166 features
167 .iter()
168 .map(|f| format!("\"{}\"", f))
169 .collect::<Vec<String>>()
170 .join(", ")
171 );
172 println!("cargo-e {}", version);
173 println!("{}", json_features);
174 std::process::exit(0);
175}
176
177pub fn get_feature_flags() -> Vec<&'static str> {
180 let mut flags = Vec::new();
181 if cfg!(feature = "tui") {
182 flags.push("tui");
183 } else {
184 flags.push("!tui");
185 }
186 if cfg!(feature = "concurrent") {
187 flags.push("concurrent");
188 } else {
189 flags.push("!concurrent");
190 }
191 if cfg!(target_os = "windows") {
192 flags.push("windows");
193 } else {
194 flags.push("!windows");
195 }
196 if cfg!(feature = "equivalent") {
197 flags.push("equivalent");
198 } else {
199 flags.push("!equivalent");
200 }
201 flags
202}
203
204use std::str::FromStr;
205
206#[derive(Debug, Clone, PartialEq)]
208pub enum RunAll {
209 NotSpecified,
211 Forever,
213 Timeout(u64),
215}
216
217impl Default for RunAll {
218 fn default() -> Self {
219 RunAll::NotSpecified
220 }
221}
222
223impl FromStr for RunAll {
224 type Err = String;
225 fn from_str(s: &str) -> Result<Self, Self::Err> {
226 if s.is_empty() {
228 Ok(RunAll::Forever)
229 } else if s.eq_ignore_ascii_case("not_specified") {
230 Ok(RunAll::NotSpecified)
231 } else {
232 s.parse::<u64>()
234 .map(RunAll::Timeout)
235 .map_err(|e| e.to_string())
236 }
237 }
238}
239
240impl std::fmt::Display for RunAll {
241 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
242 match self {
243 RunAll::NotSpecified => write!(f, "not_specified"),
244 RunAll::Forever => write!(f, "forever"),
245 RunAll::Timeout(secs) => write!(f, "{}", secs),
246 }
247 }
248}