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