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