]>
Commit | Line | Data |
---|---|---|
a7813a04 XL |
1 | //! Command-line interface of the rustbuild build system. |
2 | //! | |
3 | //! This module implements the command-line parsing of the build system which | |
4 | //! has various flags to configure how it's run. | |
5 | ||
49aad941 | 6 | use std::path::{Path, PathBuf}; |
7453a54e | 7 | |
49aad941 | 8 | use clap::{CommandFactory, Parser, ValueEnum}; |
c30ab7b3 | 9 | |
ed00b5ec FG |
10 | use crate::core::build_steps::setup::Profile; |
11 | use crate::core::builder::{Builder, Kind}; | |
12 | use crate::core::config::{target_selection_list, Config, TargetSelectionList}; | |
0731742a | 13 | use crate::{Build, DocTests}; |
3b2f2976 | 14 | |
49aad941 | 15 | #[derive(Copy, Clone, Default, Debug, ValueEnum)] |
fc512014 XL |
16 | pub enum Color { |
17 | Always, | |
18 | Never, | |
49aad941 | 19 | #[default] |
fc512014 XL |
20 | Auto, |
21 | } | |
22 | ||
49aad941 FG |
23 | /// Whether to deny warnings, emit them as warnings, or use the default behavior |
24 | #[derive(Copy, Clone, Default, Debug, ValueEnum)] | |
25 | pub enum Warnings { | |
26 | Deny, | |
27 | Warn, | |
28 | #[default] | |
29 | Default, | |
fc512014 XL |
30 | } |
31 | ||
a7813a04 | 32 | /// Deserialized version of all flags for this compile. |
49aad941 FG |
33 | #[derive(Debug, Parser)] |
34 | #[clap( | |
35 | override_usage = "x.py <subcommand> [options] [<paths>...]", | |
36 | disable_help_subcommand(true), | |
37 | about = "", | |
38 | next_line_help(false) | |
39 | )] | |
7453a54e | 40 | pub struct Flags { |
49aad941 FG |
41 | #[command(subcommand)] |
42 | pub cmd: Subcommand, | |
3b2f2976 | 43 | |
49aad941 FG |
44 | #[arg(global(true), short, long, action = clap::ArgAction::Count)] |
45 | /// use verbose output (-vv for very verbose) | |
46 | pub verbose: u8, // each extra -v after the first is passed to Cargo | |
47 | #[arg(global(true), short, long)] | |
48 | /// use incremental compilation | |
49 | pub incremental: bool, | |
50 | #[arg(global(true), long, value_hint = clap::ValueHint::FilePath, value_name = "FILE")] | |
51 | /// TOML configuration file for build | |
7453a54e | 52 | pub config: Option<PathBuf>, |
49aad941 FG |
53 | #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] |
54 | /// Build directory, overrides `build.build-dir` in `config.toml` | |
064997fb | 55 | pub build_dir: Option<PathBuf>, |
49aad941 FG |
56 | |
57 | #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "BUILD")] | |
58 | /// build target of the stage0 compiler | |
59 | pub build: Option<String>, | |
60 | ||
61 | #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "HOST", value_parser = target_selection_list)] | |
62 | /// host targets to build | |
63 | pub host: Option<TargetSelectionList>, | |
64 | ||
65 | #[arg(global(true), long, value_hint = clap::ValueHint::Other, value_name = "TARGET", value_parser = target_selection_list)] | |
66 | /// target targets to build | |
67 | pub target: Option<TargetSelectionList>, | |
68 | ||
69 | #[arg(global(true), long, value_name = "PATH")] | |
70 | /// build paths to exclude | |
add651ee FG |
71 | pub exclude: Vec<PathBuf>, // keeping for client backward compatibility |
72 | #[arg(global(true), long, value_name = "PATH")] | |
73 | /// build paths to skip | |
74 | pub skip: Vec<PathBuf>, | |
49aad941 FG |
75 | #[arg(global(true), long)] |
76 | /// include default paths in addition to the provided ones | |
1b1a35ee | 77 | pub include_default_paths: bool, |
49aad941 FG |
78 | |
79 | #[arg(global(true), value_hint = clap::ValueHint::Other, long)] | |
0531ce1d | 80 | pub rustc_error_format: Option<String>, |
49aad941 FG |
81 | |
82 | #[arg(global(true), long, value_hint = clap::ValueHint::CommandString, value_name = "CMD")] | |
83 | /// command to run on failure | |
84 | pub on_fail: Option<String>, | |
85 | #[arg(global(true), long)] | |
86 | /// dry run; don't build anything | |
83c7162d | 87 | pub dry_run: bool, |
4b012472 FG |
88 | /// Indicates whether to dump the work done from bootstrap shims |
89 | #[arg(global(true), long)] | |
90 | pub dump_bootstrap_shims: bool, | |
49aad941 FG |
91 | #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] |
92 | /// stage to build (indicates compiler to use/test, e.g., stage 0 uses the | |
93 | /// bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.) | |
94 | pub stage: Option<u32>, | |
83c7162d | 95 | |
49aad941 FG |
96 | #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] |
97 | /// stage(s) to keep without recompiling | |
98 | /// (pass multiple times to keep e.g., both stages 0 and 1) | |
99 | pub keep_stage: Vec<u32>, | |
100 | #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "N")] | |
101 | /// stage(s) of the standard library to keep without recompiling | |
102 | /// (pass multiple times to keep e.g., both stages 0 and 1) | |
103 | pub keep_stage_std: Vec<u32>, | |
104 | #[arg(global(true), long, value_hint = clap::ValueHint::DirPath, value_name = "DIR")] | |
105 | /// path to the root of the rust checkout | |
106 | pub src: Option<PathBuf>, | |
107 | ||
108 | #[arg( | |
109 | global(true), | |
110 | short, | |
111 | long, | |
112 | value_hint = clap::ValueHint::Other, | |
113 | default_value_t = std::thread::available_parallelism().map_or(1, std::num::NonZeroUsize::get), | |
114 | value_name = "JOBS" | |
115 | )] | |
116 | /// number of jobs to run in parallel | |
117 | pub jobs: usize, | |
74b04a01 | 118 | // This overrides the deny-warnings configuration option, |
416331ca | 119 | // which passes -Dwarnings to the compiler invocations. |
49aad941 FG |
120 | #[arg(global(true), long)] |
121 | #[clap(value_enum, default_value_t=Warnings::Default, value_name = "deny|warn")] | |
122 | /// if value is deny, will deny warnings | |
123 | /// if value is warn, will emit warnings | |
124 | /// otherwise, use the default configured behaviour | |
125 | pub warnings: Warnings, | |
126 | ||
127 | #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "FORMAT")] | |
128 | /// rustc error format | |
129 | pub error_format: Option<String>, | |
130 | #[arg(global(true), long)] | |
131 | /// use message-format=json | |
132 | pub json_output: bool, | |
dfeec247 | 133 | |
49aad941 FG |
134 | #[arg(global(true), long, value_name = "STYLE")] |
135 | #[clap(value_enum, default_value_t = Color::Auto)] | |
136 | /// whether to use color in cargo and rustc output | |
137 | pub color: Color, | |
94222f64 | 138 | |
4b012472 FG |
139 | #[arg(global(true), long)] |
140 | /// Bootstrap uses this value to decide whether it should bypass locking the build process. | |
141 | /// This is rarely needed (e.g., compiling the std library for different targets in parallel). | |
142 | /// | |
143 | /// Unless you know exactly what you are doing, you probably don't need this. | |
144 | pub bypass_bootstrap_lock: bool, | |
145 | ||
49aad941 FG |
146 | /// whether rebuilding llvm should be skipped, overriding `skip-rebuld` in config.toml |
147 | #[arg(global(true), long, value_name = "VALUE")] | |
148 | pub llvm_skip_rebuild: Option<bool>, | |
149 | /// generate PGO profile with rustc build | |
150 | #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] | |
151 | pub rust_profile_generate: Option<String>, | |
152 | /// use PGO profile for rustc build | |
153 | #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] | |
154 | pub rust_profile_use: Option<String>, | |
155 | /// use PGO profile for LLVM build | |
156 | #[arg(global(true), value_hint = clap::ValueHint::FilePath, long, value_name = "PROFILE")] | |
94222f64 XL |
157 | pub llvm_profile_use: Option<String>, |
158 | // LLVM doesn't support a custom location for generating profile | |
159 | // information. | |
160 | // | |
161 | // llvm_out/build/profiles/ is the location this writes to. | |
49aad941 FG |
162 | /// generate PGO profile with llvm built for rustc |
163 | #[arg(global(true), long)] | |
94222f64 | 164 | pub llvm_profile_generate: bool, |
ed00b5ec FG |
165 | /// Enable BOLT link flags |
166 | #[arg(global(true), long)] | |
167 | pub enable_bolt_settings: bool, | |
168 | /// Skip stage0 compiler validation | |
169 | #[arg(global(true), long)] | |
170 | pub skip_stage0_validation: bool, | |
add651ee | 171 | /// Additional reproducible artifacts that should be added to the reproducible artifacts archive. |
49aad941 | 172 | #[arg(global(true), long)] |
add651ee | 173 | pub reproducible_artifact: Vec<String>, |
49aad941 FG |
174 | #[arg(global(true))] |
175 | /// paths for the subcommand | |
176 | pub paths: Vec<PathBuf>, | |
177 | /// override options in config.toml | |
178 | #[arg(global(true), value_hint = clap::ValueHint::Other, long, value_name = "section.option=value")] | |
179 | pub set: Vec<String>, | |
180 | /// arguments passed to subcommands | |
181 | #[arg(global(true), last(true), value_name = "ARGS")] | |
182 | pub free_args: Vec<String>, | |
183 | } | |
184 | ||
185 | impl Flags { | |
186 | pub fn parse(args: &[String]) -> Self { | |
187 | let first = String::from("x.py"); | |
188 | let it = std::iter::once(&first).chain(args.iter()); | |
189 | // We need to check for `<cmd> -h -v`, in which case we list the paths | |
190 | #[derive(Parser)] | |
191 | #[clap(disable_help_flag(true))] | |
192 | struct HelpVerboseOnly { | |
193 | #[arg(short, long)] | |
194 | help: bool, | |
195 | #[arg(global(true), short, long, action = clap::ArgAction::Count)] | |
196 | pub verbose: u8, | |
197 | #[arg(value_enum)] | |
198 | cmd: Kind, | |
199 | } | |
200 | if let Ok(HelpVerboseOnly { help: true, verbose: 1.., cmd: subcommand }) = | |
201 | HelpVerboseOnly::try_parse_from(it.clone()) | |
202 | { | |
ed00b5ec | 203 | println!("NOTE: updating submodules before printing available paths"); |
49aad941 FG |
204 | let config = Config::parse(&[String::from("build")]); |
205 | let build = Build::new(config); | |
206 | let paths = Builder::get_help(&build, subcommand); | |
207 | if let Some(s) = paths { | |
add651ee | 208 | println!("{s}"); |
49aad941 FG |
209 | } else { |
210 | panic!("No paths available for subcommand `{}`", subcommand.as_str()); | |
211 | } | |
add651ee | 212 | crate::exit!(0); |
49aad941 | 213 | } |
9ffffee4 | 214 | |
49aad941 FG |
215 | Flags::parse_from(it) |
216 | } | |
32a655c1 SL |
217 | } |
218 | ||
49aad941 | 219 | #[derive(Debug, Clone, Default, clap::Subcommand)] |
c30ab7b3 | 220 | pub enum Subcommand { |
49aad941 FG |
221 | #[clap(aliases = ["b"], long_about = "\n |
222 | Arguments: | |
223 | This subcommand accepts a number of paths to directories to the crates | |
224 | and/or artifacts to compile. For example, for a quick build of a usable | |
225 | compiler: | |
226 | ./x.py build --stage 1 library/std | |
227 | This will build a compiler and standard library from the local source code. | |
228 | Once this is done, build/$ARCH/stage1 contains a usable compiler. | |
229 | If no arguments are passed then the default artifacts for that stage are | |
230 | compiled. For example: | |
231 | ./x.py build --stage 0 | |
232 | ./x.py build ")] | |
233 | /// Compile either the compiler or libraries | |
234 | #[default] | |
235 | Build, | |
236 | #[clap(aliases = ["c"], long_about = "\n | |
237 | Arguments: | |
238 | This subcommand accepts a number of paths to directories to the crates | |
239 | and/or artifacts to compile. For example: | |
240 | ./x.py check library/std | |
241 | If no arguments are passed then many artifacts are checked.")] | |
242 | /// Compile either the compiler or libraries, using cargo check | |
2c00a5a8 | 243 | Check { |
49aad941 FG |
244 | #[arg(long)] |
245 | /// Check all targets | |
246 | all_targets: bool, | |
2c00a5a8 | 247 | }, |
49aad941 FG |
248 | /// Run Clippy (uses rustup/cargo-installed clippy binary) |
249 | #[clap(long_about = "\n | |
250 | Arguments: | |
251 | This subcommand accepts a number of paths to directories to the crates | |
252 | and/or artifacts to run clippy against. For example: | |
253 | ./x.py clippy library/core | |
254 | ./x.py clippy library/core library/proc_macro")] | |
dc9dc135 | 255 | Clippy { |
49aad941 | 256 | #[arg(long)] |
29967ef6 | 257 | fix: bool, |
49aad941 FG |
258 | /// clippy lints to allow |
259 | #[arg(global(true), short = 'A', action = clap::ArgAction::Append, value_name = "LINT")] | |
260 | allow: Vec<String>, | |
261 | /// clippy lints to deny | |
262 | #[arg(global(true), short = 'D', action = clap::ArgAction::Append, value_name = "LINT")] | |
263 | deny: Vec<String>, | |
264 | /// clippy lints to warn on | |
265 | #[arg(global(true), short = 'W', action = clap::ArgAction::Append, value_name = "LINT")] | |
266 | warn: Vec<String>, | |
267 | /// clippy lints to forbid | |
268 | #[arg(global(true), short = 'F', action = clap::ArgAction::Append, value_name = "LINT")] | |
269 | forbid: Vec<String>, | |
dc9dc135 | 270 | }, |
49aad941 FG |
271 | /// Run cargo fix |
272 | #[clap(long_about = "\n | |
273 | Arguments: | |
274 | This subcommand accepts a number of paths to directories to the crates | |
275 | and/or artifacts to run `cargo fix` against. For example: | |
276 | ./x.py fix library/core | |
277 | ./x.py fix library/core library/proc_macro")] | |
278 | Fix, | |
279 | #[clap( | |
280 | name = "fmt", | |
281 | long_about = "\n | |
282 | Arguments: | |
283 | This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and | |
284 | fails if it is not. For example: | |
285 | ./x.py fmt | |
286 | ./x.py fmt --check" | |
287 | )] | |
288 | /// Run rustfmt | |
dfeec247 | 289 | Format { |
49aad941 FG |
290 | /// check formatting instead of applying |
291 | #[arg(long)] | |
dfeec247 XL |
292 | check: bool, |
293 | }, | |
49aad941 FG |
294 | #[clap(aliases = ["d"], long_about = "\n |
295 | Arguments: | |
296 | This subcommand accepts a number of paths to directories of documentation | |
297 | to build. For example: | |
298 | ./x.py doc src/doc/book | |
299 | ./x.py doc src/doc/nomicon | |
300 | ./x.py doc src/doc/book library/std | |
301 | ./x.py doc library/std --json | |
302 | ./x.py doc library/std --open | |
303 | If no arguments are passed then everything is documented: | |
304 | ./x.py doc | |
305 | ./x.py doc --stage 1")] | |
306 | /// Build documentation | |
c30ab7b3 | 307 | Doc { |
49aad941 FG |
308 | #[arg(long)] |
309 | /// open the docs in a browser | |
f9f354fc | 310 | open: bool, |
49aad941 FG |
311 | #[arg(long)] |
312 | /// render the documentation in JSON format in addition to the usual HTML format | |
2b03887a | 313 | json: bool, |
c30ab7b3 | 314 | }, |
49aad941 FG |
315 | #[clap(aliases = ["t"], long_about = "\n |
316 | Arguments: | |
317 | This subcommand accepts a number of paths to test directories that | |
318 | should be compiled and run. For example: | |
319 | ./x.py test tests/ui | |
320 | ./x.py test library/std --test-args hash_map | |
321 | ./x.py test library/std --stage 0 --no-doc | |
322 | ./x.py test tests/ui --bless | |
fe692bf9 | 323 | ./x.py test tests/ui --compare-mode next-solver |
49aad941 FG |
324 | Note that `test tests/* --stage N` does NOT depend on `build compiler/rustc --stage N`; |
325 | just like `build library/std --stage N` it tests the compiler produced by the previous | |
326 | stage. | |
327 | Execute tool tests with a tool name argument: | |
328 | ./x.py test tidy | |
329 | If no arguments are passed then the complete artifacts for that stage are | |
330 | compiled and tested. | |
331 | ./x.py test | |
332 | ./x.py test --stage 1")] | |
333 | /// Build and run some test suites | |
c30ab7b3 | 334 | Test { |
49aad941 FG |
335 | #[arg(long)] |
336 | /// run all tests regardless of failure | |
337 | no_fail_fast: bool, | |
338 | #[arg(long, value_name = "SUBSTRING")] | |
339 | /// skips tests matching SUBSTRING, if supported by test tool. May be passed multiple times | |
add651ee | 340 | skip: Vec<PathBuf>, |
49aad941 FG |
341 | #[arg(long, value_name = "ARGS", allow_hyphen_values(true))] |
342 | /// extra arguments to be passed for the test tool being used | |
343 | /// (e.g. libtest, compiletest or rustdoc) | |
344 | test_args: Vec<String>, | |
345 | /// extra options to pass the compiler when running tests | |
346 | #[arg(long, value_name = "ARGS", allow_hyphen_values(true))] | |
347 | rustc_args: Vec<String>, | |
348 | #[arg(long)] | |
349 | /// do not run doc tests | |
350 | no_doc: bool, | |
351 | #[arg(long)] | |
352 | /// only run doc tests | |
353 | doc: bool, | |
354 | #[arg(long)] | |
355 | /// whether to automatically update stderr/stdout files | |
94b46f34 | 356 | bless: bool, |
49aad941 | 357 | #[arg(long)] |
add651ee FG |
358 | /// comma-separated list of other files types to check (accepts py, py:lint, |
359 | /// py:fmt, shell) | |
360 | extra_checks: Option<String>, | |
361 | #[arg(long)] | |
49aad941 | 362 | /// rerun tests even if the inputs are unchanged |
94222f64 | 363 | force_rerun: bool, |
49aad941 FG |
364 | #[arg(long)] |
365 | /// only run tests that result has been changed | |
366 | only_modified: bool, | |
367 | #[arg(long, value_name = "COMPARE MODE")] | |
368 | /// mode describing what file the actual ui output will be compared to | |
94b46f34 | 369 | compare_mode: Option<String>, |
49aad941 FG |
370 | #[arg(long, value_name = "check | build | run")] |
371 | /// force {check,build,run}-pass tests to this mode. | |
dc9dc135 | 372 | pass: Option<String>, |
49aad941 FG |
373 | #[arg(long, value_name = "auto | always | never")] |
374 | /// whether to execute run-* tests | |
17df50a5 | 375 | run: Option<String>, |
49aad941 FG |
376 | #[arg(long)] |
377 | /// enable this to generate a Rustfix coverage file, which is saved in | |
378 | /// `/<build_base>/rustfix_missing_coverage.txt` | |
532ac7d7 | 379 | rustfix_coverage: bool, |
c30ab7b3 | 380 | }, |
49aad941 | 381 | /// Build and run some benchmarks |
476ff2be | 382 | Bench { |
49aad941 | 383 | #[arg(long, allow_hyphen_values(true))] |
476ff2be SL |
384 | test_args: Vec<String>, |
385 | }, | |
49aad941 | 386 | /// Clean out build directories |
ea8adc8c | 387 | Clean { |
49aad941 | 388 | #[arg(long)] |
add651ee | 389 | /// Clean the entire build directory (not used by default) |
ea8adc8c | 390 | all: bool, |
add651ee FG |
391 | #[arg(long, value_name = "N")] |
392 | /// Clean a specific stage without touching other artifacts. By default, every stage is cleaned if this option is not used. | |
393 | stage: Option<u32>, | |
ea8adc8c | 394 | }, |
49aad941 FG |
395 | /// Build distribution artifacts |
396 | Dist, | |
397 | /// Install distribution artifacts | |
398 | Install, | |
399 | #[clap(aliases = ["r"], long_about = "\n | |
400 | Arguments: | |
401 | This subcommand accepts a number of paths to tools to build and run. For | |
402 | example: | |
403 | ./x.py run src/tools/expand-yaml-anchors | |
404 | At least a tool needs to be called.")] | |
405 | /// Run tools contained in this repository | |
ba9703b0 | 406 | Run { |
49aad941 FG |
407 | /// arguments for the tool |
408 | #[arg(long, allow_hyphen_values(true))] | |
487cf647 | 409 | args: Vec<String>, |
ba9703b0 | 410 | }, |
49aad941 FG |
411 | /// Set up the environment for development |
412 | #[clap(long_about = format!( | |
413 | "\n | |
9ffffee4 | 414 | x.py setup creates a `config.toml` which changes the defaults for x.py itself, |
49aad941 | 415 | as well as setting up a git pre-push hook, VS Code config and toolchain link. |
1b1a35ee XL |
416 | Arguments: |
417 | This subcommand accepts a 'profile' to use for builds. For example: | |
1b1a35ee | 418 | ./x.py setup library |
29967ef6 XL |
419 | The profile is optional and you will be prompted interactively if it is not given. |
420 | The following profiles are available: | |
9ffffee4 | 421 | {} |
49aad941 | 422 | To only set up the git hook, VS Code config or toolchain link, you may use |
9ffffee4 FG |
423 | ./x.py setup hook |
424 | ./x.py setup vscode | |
49aad941 FG |
425 | ./x.py setup link", Profile::all_for_help(" ").trim_end()))] |
426 | Setup { | |
427 | /// Either the profile for `config.toml` or another setup action. | |
428 | /// May be omitted to set up interactively | |
429 | #[arg(value_name = "<PROFILE>|hook|vscode|link")] | |
430 | profile: Option<PathBuf>, | |
431 | }, | |
432 | /// Suggest a subset of tests to run, based on modified files | |
433 | #[clap(long_about = "\n")] | |
434 | Suggest { | |
435 | /// run suggested tests | |
436 | #[arg(long)] | |
437 | run: bool, | |
438 | }, | |
7453a54e SL |
439 | } |
440 | ||
c30ab7b3 | 441 | impl Subcommand { |
04454e1e FG |
442 | pub fn kind(&self) -> Kind { |
443 | match self { | |
444 | Subcommand::Bench { .. } => Kind::Bench, | |
445 | Subcommand::Build { .. } => Kind::Build, | |
446 | Subcommand::Check { .. } => Kind::Check, | |
447 | Subcommand::Clippy { .. } => Kind::Clippy, | |
448 | Subcommand::Doc { .. } => Kind::Doc, | |
449 | Subcommand::Fix { .. } => Kind::Fix, | |
450 | Subcommand::Format { .. } => Kind::Format, | |
451 | Subcommand::Test { .. } => Kind::Test, | |
452 | Subcommand::Clean { .. } => Kind::Clean, | |
453 | Subcommand::Dist { .. } => Kind::Dist, | |
454 | Subcommand::Install { .. } => Kind::Install, | |
455 | Subcommand::Run { .. } => Kind::Run, | |
456 | Subcommand::Setup { .. } => Kind::Setup, | |
353b0b11 | 457 | Subcommand::Suggest { .. } => Kind::Suggest, |
04454e1e FG |
458 | } |
459 | } | |
460 | ||
2c00a5a8 XL |
461 | pub fn rustc_args(&self) -> Vec<&str> { |
462 | match *self { | |
dfeec247 XL |
463 | Subcommand::Test { ref rustc_args, .. } => { |
464 | rustc_args.iter().flat_map(|s| s.split_whitespace()).collect() | |
465 | } | |
487cf647 FG |
466 | _ => vec![], |
467 | } | |
468 | } | |
469 | ||
041b39d2 | 470 | pub fn fail_fast(&self) -> bool { |
7cac9316 | 471 | match *self { |
49aad941 | 472 | Subcommand::Test { no_fail_fast, .. } => !no_fail_fast, |
7cac9316 XL |
473 | _ => false, |
474 | } | |
475 | } | |
0531ce1d | 476 | |
83c7162d | 477 | pub fn doc_tests(&self) -> DocTests { |
0531ce1d | 478 | match *self { |
49aad941 FG |
479 | Subcommand::Test { doc, no_doc, .. } => { |
480 | if doc { | |
481 | DocTests::Only | |
482 | } else if no_doc { | |
483 | DocTests::No | |
484 | } else { | |
485 | DocTests::Yes | |
486 | } | |
487 | } | |
83c7162d | 488 | _ => DocTests::Yes, |
0531ce1d XL |
489 | } |
490 | } | |
94b46f34 XL |
491 | |
492 | pub fn bless(&self) -> bool { | |
493 | match *self { | |
494 | Subcommand::Test { bless, .. } => bless, | |
495 | _ => false, | |
496 | } | |
497 | } | |
498 | ||
add651ee FG |
499 | pub fn extra_checks(&self) -> Option<&str> { |
500 | match *self { | |
501 | Subcommand::Test { ref extra_checks, .. } => extra_checks.as_ref().map(String::as_str), | |
502 | _ => None, | |
503 | } | |
504 | } | |
505 | ||
9ffffee4 FG |
506 | pub fn only_modified(&self) -> bool { |
507 | match *self { | |
508 | Subcommand::Test { only_modified, .. } => only_modified, | |
509 | _ => false, | |
510 | } | |
511 | } | |
512 | ||
94222f64 XL |
513 | pub fn force_rerun(&self) -> bool { |
514 | match *self { | |
515 | Subcommand::Test { force_rerun, .. } => force_rerun, | |
516 | _ => false, | |
517 | } | |
518 | } | |
519 | ||
532ac7d7 XL |
520 | pub fn rustfix_coverage(&self) -> bool { |
521 | match *self { | |
522 | Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage, | |
523 | _ => false, | |
524 | } | |
525 | } | |
526 | ||
94b46f34 XL |
527 | pub fn compare_mode(&self) -> Option<&str> { |
528 | match *self { | |
dfeec247 | 529 | Subcommand::Test { ref compare_mode, .. } => compare_mode.as_ref().map(|s| &s[..]), |
94b46f34 XL |
530 | _ => None, |
531 | } | |
532 | } | |
dc9dc135 XL |
533 | |
534 | pub fn pass(&self) -> Option<&str> { | |
535 | match *self { | |
dfeec247 | 536 | Subcommand::Test { ref pass, .. } => pass.as_ref().map(|s| &s[..]), |
dc9dc135 XL |
537 | _ => None, |
538 | } | |
539 | } | |
f9f354fc | 540 | |
17df50a5 XL |
541 | pub fn run(&self) -> Option<&str> { |
542 | match *self { | |
543 | Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]), | |
544 | _ => None, | |
545 | } | |
546 | } | |
547 | ||
f9f354fc XL |
548 | pub fn open(&self) -> bool { |
549 | match *self { | |
550 | Subcommand::Doc { open, .. } => open, | |
551 | _ => false, | |
552 | } | |
553 | } | |
2b03887a FG |
554 | |
555 | pub fn json(&self) -> bool { | |
556 | match *self { | |
557 | Subcommand::Doc { json, .. } => json, | |
558 | _ => false, | |
559 | } | |
560 | } | |
7453a54e | 561 | } |
32a655c1 | 562 | |
49aad941 FG |
563 | /// Returns the shell completion for a given shell, if the result differs from the current |
564 | /// content of `path`. If `path` does not exist, always returns `Some`. | |
565 | pub fn get_completion<G: clap_complete::Generator>(shell: G, path: &Path) -> Option<String> { | |
566 | let mut cmd = Flags::command(); | |
567 | let current = if !path.exists() { | |
568 | String::new() | |
569 | } else { | |
570 | std::fs::read_to_string(path).unwrap_or_else(|_| { | |
571 | eprintln!("couldn't read {}", path.display()); | |
add651ee | 572 | crate::exit!(1) |
49aad941 FG |
573 | }) |
574 | }; | |
575 | let mut buf = Vec::new(); | |
576 | clap_complete::generate(shell, &mut cmd, "x.py", &mut buf); | |
577 | if buf == current.as_bytes() { | |
578 | return None; | |
416331ca | 579 | } |
49aad941 | 580 | Some(String::from_utf8(buf).expect("completion script should be UTF-8")) |
416331ca | 581 | } |