]> git.proxmox.com Git - rustc.git/blob - src/bootstrap/flags.rs
2fddda74a28e924bfd3e7db776bdc38e67a15933
[rustc.git] / src / bootstrap / flags.rs
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
6 use std::env;
7 use std::path::PathBuf;
8 use std::process;
9
10 use build_helper::t;
11 use getopts::Options;
12
13 use crate::builder::Builder;
14 use crate::config::{Config, TargetSelection};
15 use crate::setup::Profile;
16 use crate::{Build, DocTests};
17
18 pub enum Color {
19 Always,
20 Never,
21 Auto,
22 }
23
24 impl Default for Color {
25 fn default() -> Self {
26 Self::Auto
27 }
28 }
29
30 impl std::str::FromStr for Color {
31 type Err = ();
32
33 fn from_str(s: &str) -> Result<Self, Self::Err> {
34 match s.to_lowercase().as_str() {
35 "always" => Ok(Self::Always),
36 "never" => Ok(Self::Never),
37 "auto" => Ok(Self::Auto),
38 _ => Err(()),
39 }
40 }
41 }
42
43 /// Deserialized version of all flags for this compile.
44 pub struct Flags {
45 pub verbose: usize, // number of -v args; each extra -v after the first is passed to Cargo
46 pub on_fail: Option<String>,
47 pub stage: Option<u32>,
48 pub keep_stage: Vec<u32>,
49 pub keep_stage_std: Vec<u32>,
50
51 pub host: Option<Vec<TargetSelection>>,
52 pub target: Option<Vec<TargetSelection>>,
53 pub config: Option<PathBuf>,
54 pub jobs: Option<u32>,
55 pub cmd: Subcommand,
56 pub incremental: bool,
57 pub exclude: Vec<PathBuf>,
58 pub include_default_paths: bool,
59 pub rustc_error_format: Option<String>,
60 pub json_output: bool,
61 pub dry_run: bool,
62 pub color: Color,
63
64 // This overrides the deny-warnings configuration option,
65 // which passes -Dwarnings to the compiler invocations.
66 //
67 // true => deny, false => warn
68 pub deny_warnings: Option<bool>,
69
70 pub llvm_skip_rebuild: Option<bool>,
71
72 pub rust_profile_use: Option<String>,
73 pub rust_profile_generate: Option<String>,
74
75 pub llvm_profile_use: Option<String>,
76 // LLVM doesn't support a custom location for generating profile
77 // information.
78 //
79 // llvm_out/build/profiles/ is the location this writes to.
80 pub llvm_profile_generate: bool,
81 }
82
83 pub enum Subcommand {
84 Build {
85 paths: Vec<PathBuf>,
86 },
87 Check {
88 paths: Vec<PathBuf>,
89 },
90 Clippy {
91 fix: bool,
92 paths: Vec<PathBuf>,
93 },
94 Fix {
95 paths: Vec<PathBuf>,
96 },
97 Format {
98 paths: Vec<PathBuf>,
99 check: bool,
100 },
101 Doc {
102 paths: Vec<PathBuf>,
103 open: bool,
104 },
105 Test {
106 paths: Vec<PathBuf>,
107 /// Whether to automatically update stderr/stdout files
108 bless: bool,
109 force_rerun: bool,
110 compare_mode: Option<String>,
111 pass: Option<String>,
112 run: Option<String>,
113 test_args: Vec<String>,
114 rustc_args: Vec<String>,
115 fail_fast: bool,
116 doc_tests: DocTests,
117 rustfix_coverage: bool,
118 },
119 Bench {
120 paths: Vec<PathBuf>,
121 test_args: Vec<String>,
122 },
123 Clean {
124 all: bool,
125 },
126 Dist {
127 paths: Vec<PathBuf>,
128 },
129 Install {
130 paths: Vec<PathBuf>,
131 },
132 Run {
133 paths: Vec<PathBuf>,
134 },
135 Setup {
136 profile: Profile,
137 },
138 }
139
140 impl Default for Subcommand {
141 fn default() -> Subcommand {
142 Subcommand::Build { paths: vec![PathBuf::from("nowhere")] }
143 }
144 }
145
146 impl Flags {
147 pub fn parse(args: &[String]) -> Flags {
148 let mut subcommand_help = String::from(
149 "\
150 Usage: x.py <subcommand> [options] [<paths>...]
151
152 Subcommands:
153 build, b Compile either the compiler or libraries
154 check, c Compile either the compiler or libraries, using cargo check
155 clippy Run clippy (uses rustup/cargo-installed clippy binary)
156 fix Run cargo fix
157 fmt Run rustfmt
158 test, t Build and run some test suites
159 bench Build and run some benchmarks
160 doc, d Build documentation
161 clean Clean out build directories
162 dist Build distribution artifacts
163 install Install distribution artifacts
164 run, r Run tools contained in this repository
165 setup Create a config.toml (making it easier to use `x.py` itself)
166
167 To learn more about a subcommand, run `./x.py <subcommand> -h`",
168 );
169
170 let mut opts = Options::new();
171 // Options common to all subcommands
172 opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
173 opts.optflag("i", "incremental", "use incremental compilation");
174 opts.optopt("", "config", "TOML configuration file for build", "FILE");
175 opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
176 opts.optmulti("", "host", "host targets to build", "HOST");
177 opts.optmulti("", "target", "target targets to build", "TARGET");
178 opts.optmulti("", "exclude", "build paths to exclude", "PATH");
179 opts.optflag(
180 "",
181 "include-default-paths",
182 "include default paths in addition to the provided ones",
183 );
184 opts.optopt("", "on-fail", "command to run on failure", "CMD");
185 opts.optflag("", "dry-run", "dry run; don't build anything");
186 opts.optopt(
187 "",
188 "stage",
189 "stage to build (indicates compiler to use/test, e.g., stage 0 uses the \
190 bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)",
191 "N",
192 );
193 opts.optmulti(
194 "",
195 "keep-stage",
196 "stage(s) to keep without recompiling \
197 (pass multiple times to keep e.g., both stages 0 and 1)",
198 "N",
199 );
200 opts.optmulti(
201 "",
202 "keep-stage-std",
203 "stage(s) of the standard library to keep without recompiling \
204 (pass multiple times to keep e.g., both stages 0 and 1)",
205 "N",
206 );
207 opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
208 let j_msg = format!(
209 "number of jobs to run in parallel; \
210 defaults to {} (this host's logical CPU count)",
211 num_cpus::get()
212 );
213 opts.optopt("j", "jobs", &j_msg, "JOBS");
214 opts.optflag("h", "help", "print this help message");
215 opts.optopt(
216 "",
217 "warnings",
218 "if value is deny, will deny warnings, otherwise use default",
219 "VALUE",
220 );
221 opts.optopt("", "error-format", "rustc error format", "FORMAT");
222 opts.optflag("", "json-output", "use message-format=json");
223 opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
224 opts.optopt(
225 "",
226 "llvm-skip-rebuild",
227 "whether rebuilding llvm should be skipped \
228 a VALUE of TRUE indicates that llvm will not be rebuilt \
229 VALUE overrides the skip-rebuild option in config.toml.",
230 "VALUE",
231 );
232 opts.optopt(
233 "",
234 "rust-profile-generate",
235 "generate PGO profile with rustc build",
236 "PROFILE",
237 );
238 opts.optopt("", "rust-profile-use", "use PGO profile for rustc build", "PROFILE");
239 opts.optflag("", "llvm-profile-generate", "generate PGO profile with llvm built for rustc");
240 opts.optopt("", "llvm-profile-use", "use PGO profile for llvm build", "PROFILE");
241
242 // We can't use getopt to parse the options until we have completed specifying which
243 // options are valid, but under the current implementation, some options are conditional on
244 // the subcommand. Therefore we must manually identify the subcommand first, so that we can
245 // complete the definition of the options. Then we can use the getopt::Matches object from
246 // there on out.
247 let subcommand = args.iter().find(|&s| {
248 (s == "build")
249 || (s == "b")
250 || (s == "check")
251 || (s == "c")
252 || (s == "clippy")
253 || (s == "fix")
254 || (s == "fmt")
255 || (s == "test")
256 || (s == "t")
257 || (s == "bench")
258 || (s == "doc")
259 || (s == "d")
260 || (s == "clean")
261 || (s == "dist")
262 || (s == "install")
263 || (s == "run")
264 || (s == "r")
265 || (s == "setup")
266 });
267 let subcommand = match subcommand {
268 Some(s) => s,
269 None => {
270 // No or an invalid subcommand -- show the general usage and subcommand help
271 // An exit code will be 0 when no subcommand is given, and 1 in case of an invalid
272 // subcommand.
273 println!("{}\n", subcommand_help);
274 let exit_code = if args.is_empty() { 0 } else { 1 };
275 process::exit(exit_code);
276 }
277 };
278
279 // Some subcommands get extra options
280 match subcommand.as_str() {
281 "test" | "t" => {
282 opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
283 opts.optmulti(
284 "",
285 "test-args",
286 "extra arguments to be passed for the test tool being used \
287 (e.g. libtest, compiletest or rustdoc)",
288 "ARGS",
289 );
290 opts.optmulti(
291 "",
292 "rustc-args",
293 "extra options to pass the compiler when running tests",
294 "ARGS",
295 );
296 opts.optflag("", "no-doc", "do not run doc tests");
297 opts.optflag("", "doc", "only run doc tests");
298 opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
299 opts.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged");
300 opts.optopt(
301 "",
302 "compare-mode",
303 "mode describing what file the actual ui output will be compared to",
304 "COMPARE MODE",
305 );
306 opts.optopt(
307 "",
308 "pass",
309 "force {check,build,run}-pass tests to this mode.",
310 "check | build | run",
311 );
312 opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
313 opts.optflag(
314 "",
315 "rustfix-coverage",
316 "enable this to generate a Rustfix coverage file, which is saved in \
317 `/<build_base>/rustfix_missing_coverage.txt`",
318 );
319 }
320 "check" | "c" => {
321 opts.optflag("", "all-targets", "Check all targets");
322 }
323 "bench" => {
324 opts.optmulti("", "test-args", "extra arguments", "ARGS");
325 }
326 "clippy" => {
327 opts.optflag("", "fix", "automatically apply lint suggestions");
328 }
329 "doc" | "d" => {
330 opts.optflag("", "open", "open the docs in a browser");
331 }
332 "clean" => {
333 opts.optflag("", "all", "clean all build artifacts");
334 }
335 "fmt" => {
336 opts.optflag("", "check", "check formatting instead of applying.");
337 }
338 _ => {}
339 };
340
341 // fn usage()
342 let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! {
343 let mut extra_help = String::new();
344
345 // All subcommands except `clean` can have an optional "Available paths" section
346 if verbose {
347 let config = Config::parse(&["build".to_string()]);
348 let build = Build::new(config);
349
350 let maybe_rules_help = Builder::get_help(&build, subcommand.as_str());
351 extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str());
352 } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") {
353 extra_help.push_str(
354 format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand)
355 .as_str(),
356 );
357 }
358
359 println!("{}", opts.usage(subcommand_help));
360 if !extra_help.is_empty() {
361 println!("{}", extra_help);
362 }
363 process::exit(exit_code);
364 };
365
366 // Done specifying what options are possible, so do the getopts parsing
367 let matches = opts.parse(args).unwrap_or_else(|e| {
368 // Invalid argument/option format
369 println!("\n{}\n", e);
370 usage(1, &opts, false, &subcommand_help);
371 });
372
373 // Extra sanity check to make sure we didn't hit this crazy corner case:
374 //
375 // ./x.py --frobulate clean build
376 // ^-- option ^ ^- actual subcommand
377 // \_ arg to option could be mistaken as subcommand
378 let mut pass_sanity_check = true;
379 match matches.free.get(0) {
380 Some(check_subcommand) => {
381 if check_subcommand != subcommand {
382 pass_sanity_check = false;
383 }
384 }
385 None => {
386 pass_sanity_check = false;
387 }
388 }
389 if !pass_sanity_check {
390 println!("{}\n", subcommand_help);
391 println!(
392 "Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
393 You may need to move some options to after the subcommand.\n"
394 );
395 process::exit(1);
396 }
397 // Extra help text for some commands
398 match subcommand.as_str() {
399 "build" | "b" => {
400 subcommand_help.push_str(
401 "\n
402 Arguments:
403 This subcommand accepts a number of paths to directories to the crates
404 and/or artifacts to compile. For example:
405
406 ./x.py build library/core
407 ./x.py build library/core library/proc_macro
408 ./x.py build library/std --stage 1
409
410 If no arguments are passed then the complete artifacts for that stage are
411 also compiled.
412
413 ./x.py build
414 ./x.py build --stage 1
415
416 For a quick build of a usable compiler, you can pass:
417
418 ./x.py build --stage 1 library/test
419
420 This will first build everything once (like `--stage 0` without further
421 arguments would), and then use the compiler built in stage 0 to build
422 library/test and its dependencies.
423 Once this is done, build/$ARCH/stage1 contains a usable compiler.",
424 );
425 }
426 "check" | "c" => {
427 subcommand_help.push_str(
428 "\n
429 Arguments:
430 This subcommand accepts a number of paths to directories to the crates
431 and/or artifacts to compile. For example:
432
433 ./x.py check library/core
434 ./x.py check library/core library/proc_macro
435
436 If no arguments are passed then the complete artifacts are compiled: std, test, and rustc. Note
437 also that since we use `cargo check`, by default this will automatically enable incremental
438 compilation, so there's no need to pass it separately, though it won't hurt. We also completely
439 ignore the stage passed, as there's no way to compile in non-stage 0 without actually building
440 the compiler.",
441 );
442 }
443 "clippy" => {
444 subcommand_help.push_str(
445 "\n
446 Arguments:
447 This subcommand accepts a number of paths to directories to the crates
448 and/or artifacts to run clippy against. For example:
449
450 ./x.py clippy library/core
451 ./x.py clippy library/core library/proc_macro",
452 );
453 }
454 "fix" => {
455 subcommand_help.push_str(
456 "\n
457 Arguments:
458 This subcommand accepts a number of paths to directories to the crates
459 and/or artifacts to run `cargo fix` against. For example:
460
461 ./x.py fix library/core
462 ./x.py fix library/core library/proc_macro",
463 );
464 }
465 "fmt" => {
466 subcommand_help.push_str(
467 "\n
468 Arguments:
469 This subcommand optionally accepts a `--check` flag which succeeds if formatting is correct and
470 fails if it is not. For example:
471
472 ./x.py fmt
473 ./x.py fmt --check",
474 );
475 }
476 "test" | "t" => {
477 subcommand_help.push_str(
478 "\n
479 Arguments:
480 This subcommand accepts a number of paths to test directories that
481 should be compiled and run. For example:
482
483 ./x.py test src/test/ui
484 ./x.py test library/std --test-args hash_map
485 ./x.py test library/std --stage 0 --no-doc
486 ./x.py test src/test/ui --bless
487 ./x.py test src/test/ui --compare-mode nll
488
489 Note that `test src/test/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
490 just like `build library/std --stage N` it tests the compiler produced by the previous
491 stage.
492
493 Execute tool tests with a tool name argument:
494
495 ./x.py test tidy
496
497 If no arguments are passed then the complete artifacts for that stage are
498 compiled and tested.
499
500 ./x.py test
501 ./x.py test --stage 1",
502 );
503 }
504 "doc" | "d" => {
505 subcommand_help.push_str(
506 "\n
507 Arguments:
508 This subcommand accepts a number of paths to directories of documentation
509 to build. For example:
510
511 ./x.py doc src/doc/book
512 ./x.py doc src/doc/nomicon
513 ./x.py doc src/doc/book library/std
514 ./x.py doc library/std --open
515
516 If no arguments are passed then everything is documented:
517
518 ./x.py doc
519 ./x.py doc --stage 1",
520 );
521 }
522 "run" | "r" => {
523 subcommand_help.push_str(
524 "\n
525 Arguments:
526 This subcommand accepts a number of paths to tools to build and run. For
527 example:
528
529 ./x.py run src/tools/expand-yaml-anchors
530
531 At least a tool needs to be called.",
532 );
533 }
534 "setup" => {
535 subcommand_help.push_str(&format!(
536 "\n
537 x.py setup creates a `config.toml` which changes the defaults for x.py itself.
538
539 Arguments:
540 This subcommand accepts a 'profile' to use for builds. For example:
541
542 ./x.py setup library
543
544 The profile is optional and you will be prompted interactively if it is not given.
545 The following profiles are available:
546
547 {}",
548 Profile::all_for_help(" ").trim_end()
549 ));
550 }
551 _ => {}
552 };
553 // Get any optional paths which occur after the subcommand
554 let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
555
556 let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
557 let verbose = matches.opt_present("verbose");
558
559 // User passed in -h/--help?
560 if matches.opt_present("help") {
561 usage(0, &opts, verbose, &subcommand_help);
562 }
563
564 let cmd = match subcommand.as_str() {
565 "build" | "b" => Subcommand::Build { paths },
566 "check" | "c" => {
567 if matches.opt_present("all-targets") {
568 eprintln!(
569 "Warning: --all-targets is now on by default and does not need to be passed explicitly."
570 );
571 }
572 Subcommand::Check { paths }
573 }
574 "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
575 "fix" => Subcommand::Fix { paths },
576 "test" | "t" => Subcommand::Test {
577 paths,
578 bless: matches.opt_present("bless"),
579 force_rerun: matches.opt_present("force-rerun"),
580 compare_mode: matches.opt_str("compare-mode"),
581 pass: matches.opt_str("pass"),
582 run: matches.opt_str("run"),
583 test_args: matches.opt_strs("test-args"),
584 rustc_args: matches.opt_strs("rustc-args"),
585 fail_fast: !matches.opt_present("no-fail-fast"),
586 rustfix_coverage: matches.opt_present("rustfix-coverage"),
587 doc_tests: if matches.opt_present("doc") {
588 DocTests::Only
589 } else if matches.opt_present("no-doc") {
590 DocTests::No
591 } else {
592 DocTests::Yes
593 },
594 },
595 "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
596 "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
597 "clean" => {
598 if !paths.is_empty() {
599 println!("\nclean does not take a path argument\n");
600 usage(1, &opts, verbose, &subcommand_help);
601 }
602
603 Subcommand::Clean { all: matches.opt_present("all") }
604 }
605 "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths },
606 "dist" => Subcommand::Dist { paths },
607 "install" => Subcommand::Install { paths },
608 "run" | "r" => {
609 if paths.is_empty() {
610 println!("\nrun requires at least a path!\n");
611 usage(1, &opts, verbose, &subcommand_help);
612 }
613 Subcommand::Run { paths }
614 }
615 "setup" => {
616 let profile = if paths.len() > 1 {
617 println!("\nat most one profile can be passed to setup\n");
618 usage(1, &opts, verbose, &subcommand_help)
619 } else if let Some(path) = paths.pop() {
620 let profile_string = t!(path.into_os_string().into_string().map_err(
621 |path| format!("{} is not a valid UTF8 string", path.to_string_lossy())
622 ));
623
624 profile_string.parse().unwrap_or_else(|err| {
625 eprintln!("error: {}", err);
626 eprintln!("help: the available profiles are:");
627 eprint!("{}", Profile::all_for_help("- "));
628 std::process::exit(1);
629 })
630 } else {
631 t!(crate::setup::interactive_path())
632 };
633 Subcommand::Setup { profile }
634 }
635 _ => {
636 usage(1, &opts, verbose, &subcommand_help);
637 }
638 };
639
640 if let Subcommand::Check { .. } = &cmd {
641 if matches.opt_str("keep-stage").is_some()
642 || matches.opt_str("keep-stage-std").is_some()
643 {
644 println!("--keep-stage not yet supported for x.py check");
645 process::exit(1);
646 }
647 }
648
649 Flags {
650 verbose: matches.opt_count("verbose"),
651 stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
652 dry_run: matches.opt_present("dry-run"),
653 on_fail: matches.opt_str("on-fail"),
654 rustc_error_format: matches.opt_str("error-format"),
655 json_output: matches.opt_present("json-output"),
656 keep_stage: matches
657 .opt_strs("keep-stage")
658 .into_iter()
659 .map(|j| j.parse().expect("`keep-stage` should be a number"))
660 .collect(),
661 keep_stage_std: matches
662 .opt_strs("keep-stage-std")
663 .into_iter()
664 .map(|j| j.parse().expect("`keep-stage-std` should be a number"))
665 .collect(),
666 host: if matches.opt_present("host") {
667 Some(
668 split(&matches.opt_strs("host"))
669 .into_iter()
670 .map(|x| TargetSelection::from_user(&x))
671 .collect::<Vec<_>>(),
672 )
673 } else {
674 None
675 },
676 target: if matches.opt_present("target") {
677 Some(
678 split(&matches.opt_strs("target"))
679 .into_iter()
680 .map(|x| TargetSelection::from_user(&x))
681 .collect::<Vec<_>>(),
682 )
683 } else {
684 None
685 },
686 config: cfg_file,
687 jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
688 cmd,
689 incremental: matches.opt_present("incremental"),
690 exclude: split(&matches.opt_strs("exclude"))
691 .into_iter()
692 .map(|p| p.into())
693 .collect::<Vec<_>>(),
694 include_default_paths: matches.opt_present("include-default-paths"),
695 deny_warnings: parse_deny_warnings(&matches),
696 llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map(
697 |s| s.parse::<bool>().expect("`llvm-skip-rebuild` should be either true or false"),
698 ),
699 color: matches
700 .opt_get_default("color", Color::Auto)
701 .expect("`color` should be `always`, `never`, or `auto`"),
702 rust_profile_use: matches.opt_str("rust-profile-use"),
703 rust_profile_generate: matches.opt_str("rust-profile-generate"),
704 llvm_profile_use: matches.opt_str("llvm-profile-use"),
705 llvm_profile_generate: matches.opt_present("llvm-profile-generate"),
706 }
707 }
708 }
709
710 impl Subcommand {
711 pub fn test_args(&self) -> Vec<&str> {
712 match *self {
713 Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
714 test_args.iter().flat_map(|s| s.split_whitespace()).collect()
715 }
716 _ => Vec::new(),
717 }
718 }
719
720 pub fn rustc_args(&self) -> Vec<&str> {
721 match *self {
722 Subcommand::Test { ref rustc_args, .. } => {
723 rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
724 }
725 _ => Vec::new(),
726 }
727 }
728
729 pub fn fail_fast(&self) -> bool {
730 match *self {
731 Subcommand::Test { fail_fast, .. } => fail_fast,
732 _ => false,
733 }
734 }
735
736 pub fn doc_tests(&self) -> DocTests {
737 match *self {
738 Subcommand::Test { doc_tests, .. } => doc_tests,
739 _ => DocTests::Yes,
740 }
741 }
742
743 pub fn bless(&self) -> bool {
744 match *self {
745 Subcommand::Test { bless, .. } => bless,
746 _ => false,
747 }
748 }
749
750 pub fn force_rerun(&self) -> bool {
751 match *self {
752 Subcommand::Test { force_rerun, .. } => force_rerun,
753 _ => false,
754 }
755 }
756
757 pub fn rustfix_coverage(&self) -> bool {
758 match *self {
759 Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
760 _ => false,
761 }
762 }
763
764 pub fn compare_mode(&self) -> Option<&str> {
765 match *self {
766 Subcommand::Test { ref compare_mode, .. } => compare_mode.as_ref().map(|s| &s[..]),
767 _ => None,
768 }
769 }
770
771 pub fn pass(&self) -> Option<&str> {
772 match *self {
773 Subcommand::Test { ref pass, .. } => pass.as_ref().map(|s| &s[..]),
774 _ => None,
775 }
776 }
777
778 pub fn run(&self) -> Option<&str> {
779 match *self {
780 Subcommand::Test { ref run, .. } => run.as_ref().map(|s| &s[..]),
781 _ => None,
782 }
783 }
784
785 pub fn open(&self) -> bool {
786 match *self {
787 Subcommand::Doc { open, .. } => open,
788 _ => false,
789 }
790 }
791 }
792
793 fn split(s: &[String]) -> Vec<String> {
794 s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect()
795 }
796
797 fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
798 match matches.opt_str("warnings").as_deref() {
799 Some("deny") => Some(true),
800 Some("warn") => Some(false),
801 Some(value) => {
802 eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,);
803 process::exit(1);
804 }
805 None => None,
806 }
807 }