]> git.proxmox.com Git - rustc.git/blame - src/bootstrap/flags.rs
New upstream version 1.56.0~beta.4+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>,
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
c30ab7b3
SL
83pub enum Subcommand {
84 Build {
85 paths: Vec<PathBuf>,
86 },
2c00a5a8
XL
87 Check {
88 paths: Vec<PathBuf>,
89 },
dc9dc135 90 Clippy {
29967ef6 91 fix: bool,
dc9dc135
XL
92 paths: Vec<PathBuf>,
93 },
94 Fix {
95 paths: Vec<PathBuf>,
96 },
dfeec247 97 Format {
17df50a5 98 paths: Vec<PathBuf>,
dfeec247
XL
99 check: bool,
100 },
c30ab7b3
SL
101 Doc {
102 paths: Vec<PathBuf>,
f9f354fc 103 open: bool,
c30ab7b3
SL
104 },
105 Test {
106 paths: Vec<PathBuf>,
94b46f34
XL
107 /// Whether to automatically update stderr/stdout files
108 bless: bool,
94222f64 109 force_rerun: bool,
94b46f34 110 compare_mode: Option<String>,
dc9dc135 111 pass: Option<String>,
17df50a5 112 run: Option<String>,
c30ab7b3 113 test_args: Vec<String>,
2c00a5a8 114 rustc_args: Vec<String>,
041b39d2 115 fail_fast: bool,
83c7162d 116 doc_tests: DocTests,
532ac7d7 117 rustfix_coverage: bool,
c30ab7b3 118 },
476ff2be
SL
119 Bench {
120 paths: Vec<PathBuf>,
121 test_args: Vec<String>,
122 },
ea8adc8c
XL
123 Clean {
124 all: bool,
125 },
c30ab7b3 126 Dist {
32a655c1 127 paths: Vec<PathBuf>,
7cac9316
XL
128 },
129 Install {
130 paths: Vec<PathBuf>,
c30ab7b3 131 },
ba9703b0
XL
132 Run {
133 paths: Vec<PathBuf>,
134 },
1b1a35ee 135 Setup {
29967ef6 136 profile: Profile,
1b1a35ee 137 },
7453a54e
SL
138}
139
3b2f2976
XL
140impl Default for Subcommand {
141 fn default() -> Subcommand {
dfeec247 142 Subcommand::Build { paths: vec![PathBuf::from("nowhere")] }
3b2f2976
XL
143 }
144}
145
7453a54e
SL
146impl Flags {
147 pub fn parse(args: &[String]) -> Flags {
dfeec247
XL
148 let mut subcommand_help = String::from(
149 "\
cc61c64b
XL
150Usage: x.py <subcommand> [options] [<paths>...]
151
152Subcommands:
f9f354fc
XL
153 build, b Compile either the compiler or libraries
154 check, c Compile either the compiler or libraries, using cargo check
dfeec247 155 clippy Run clippy (uses rustup/cargo-installed clippy binary)
dc9dc135 156 fix Run cargo fix
dfeec247 157 fmt Run rustfmt
f9f354fc 158 test, t Build and run some test suites
cc61c64b 159 bench Build and run some benchmarks
136023e0 160 doc, d Build documentation
cc61c64b 161 clean Clean out build directories
7cac9316
XL
162 dist Build distribution artifacts
163 install Install distribution artifacts
f9f354fc 164 run, r Run tools contained in this repository
29967ef6 165 setup Create a config.toml (making it easier to use `x.py` itself)
cc61c64b 166
dfeec247 167To learn more about a subcommand, run `./x.py <subcommand> -h`",
94b46f34 168 );
cc61c64b 169
7453a54e 170 let mut opts = Options::new();
cc61c64b 171 // Options common to all subcommands
32a655c1
SL
172 opts.optflagmulti("v", "verbose", "use verbose output (-vv for very verbose)");
173 opts.optflag("i", "incremental", "use incremental compilation");
7453a54e 174 opts.optopt("", "config", "TOML configuration file for build", "FILE");
c30ab7b3 175 opts.optopt("", "build", "build target of the stage0 compiler", "BUILD");
7453a54e 176 opts.optmulti("", "host", "host targets to build", "HOST");
c30ab7b3 177 opts.optmulti("", "target", "target targets to build", "TARGET");
2c00a5a8 178 opts.optmulti("", "exclude", "build paths to exclude", "PATH");
1b1a35ee
XL
179 opts.optflag(
180 "",
181 "include-default-paths",
182 "include default paths in addition to the provided ones",
183 );
8bb4bdeb 184 opts.optopt("", "on-fail", "command to run on failure", "CMD");
83c7162d 185 opts.optflag("", "dry-run", "dry run; don't build anything");
dfeec247
XL
186 opts.optopt(
187 "",
188 "stage",
0731742a 189 "stage to build (indicates compiler to use/test, e.g., stage 0 uses the \
b7449926 190 bootstrap compiler, stage 1 the stage 0 rustc artifacts, etc.)",
dfeec247
XL
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 );
1b1a35ee
XL
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 );
c30ab7b3 207 opts.optopt("", "src", "path to the root of the rust checkout", "DIR");
f035d41b
XL
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");
7453a54e 214 opts.optflag("h", "help", "print this help message");
94b46f34
XL
215 opts.optopt(
216 "",
217 "warnings",
218 "if value is deny, will deny warnings, otherwise use default",
219 "VALUE",
220 );
0531ce1d 221 opts.optopt("", "error-format", "rustc error format", "FORMAT");
ba9703b0 222 opts.optflag("", "json-output", "use message-format=json");
fc512014 223 opts.optopt("", "color", "whether to use color in cargo and rustc output", "STYLE");
dfeec247
XL
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 );
94222f64
XL
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");
7453a54e 241
cc61c64b
XL
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.
94b46f34 247 let subcommand = args.iter().find(|&s| {
041b39d2 248 (s == "build")
f9f354fc 249 || (s == "b")
94b46f34 250 || (s == "check")
f9f354fc 251 || (s == "c")
dc9dc135
XL
252 || (s == "clippy")
253 || (s == "fix")
dfeec247 254 || (s == "fmt")
94b46f34 255 || (s == "test")
f9f354fc 256 || (s == "t")
94b46f34
XL
257 || (s == "bench")
258 || (s == "doc")
136023e0 259 || (s == "d")
94b46f34
XL
260 || (s == "clean")
261 || (s == "dist")
262 || (s == "install")
ba9703b0 263 || (s == "run")
f9f354fc 264 || (s == "r")
1b1a35ee 265 || (s == "setup")
94b46f34 266 });
041b39d2 267 let subcommand = match subcommand {
cc61c64b
XL
268 Some(s) => s,
269 None => {
abe05a73
XL
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.
cc61c64b 273 println!("{}\n", subcommand_help);
abe05a73
XL
274 let exit_code = if args.is_empty() { 0 } else { 1 };
275 process::exit(exit_code);
cc61c64b
XL
276 }
277 };
c30ab7b3 278
cc61c64b
XL
279 // Some subcommands get extra options
280 match subcommand.as_str() {
f9f354fc 281 "test" | "t" => {
7cac9316 282 opts.optflag("", "no-fail-fast", "Run all tests regardless of failure");
29967ef6
XL
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 );
2c00a5a8
XL
290 opts.optmulti(
291 "",
292 "rustc-args",
293 "extra options to pass the compiler when running tests",
294 "ARGS",
295 );
83c7162d
XL
296 opts.optflag("", "no-doc", "do not run doc tests");
297 opts.optflag("", "doc", "only run doc tests");
dfeec247 298 opts.optflag("", "bless", "update all stderr/stdout files of failing ui tests");
94222f64 299 opts.optflag("", "force-rerun", "rerun tests even if the inputs are unchanged");
94b46f34
XL
300 opts.optopt(
301 "",
302 "compare-mode",
303 "mode describing what file the actual ui output will be compared to",
304 "COMPARE MODE",
305 );
dc9dc135
XL
306 opts.optopt(
307 "",
308 "pass",
309 "force {check,build,run}-pass tests to this mode.",
dfeec247 310 "check | build | run",
dc9dc135 311 );
17df50a5 312 opts.optopt("", "run", "whether to execute run-* tests", "auto | always | never");
532ac7d7
XL
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 );
94b46f34 319 }
29967ef6
XL
320 "check" | "c" => {
321 opts.optflag("", "all-targets", "Check all targets");
322 }
94b46f34
XL
323 "bench" => {
324 opts.optmulti("", "test-args", "extra arguments", "ARGS");
325 }
29967ef6
XL
326 "clippy" => {
327 opts.optflag("", "fix", "automatically apply lint suggestions");
328 }
136023e0 329 "doc" | "d" => {
f9f354fc
XL
330 opts.optflag("", "open", "open the docs in a browser");
331 }
94b46f34
XL
332 "clean" => {
333 opts.optflag("", "all", "clean all build artifacts");
334 }
dfeec247
XL
335 "fmt" => {
336 opts.optflag("", "check", "check formatting instead of applying.");
337 }
94b46f34 338 _ => {}
cc61c64b
XL
339 };
340
1b1a35ee
XL
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
cc61c64b 366 // Done specifying what options are possible, so do the getopts parsing
6a06907d 367 let matches = opts.parse(args).unwrap_or_else(|e| {
cc61c64b
XL
368 // Invalid argument/option format
369 println!("\n{}\n", e);
1b1a35ee 370 usage(1, &opts, false, &subcommand_help);
cc61c64b 371 });
1b1a35ee 372
cc61c64b
XL
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) => {
041b39d2 381 if check_subcommand != subcommand {
cc61c64b
XL
382 pass_sanity_check = false;
383 }
94b46f34 384 }
cc61c64b
XL
385 None => {
386 pass_sanity_check = false;
387 }
388 }
389 if !pass_sanity_check {
390 println!("{}\n", subcommand_help);
94b46f34
XL
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 );
cc61c64b
XL
395 process::exit(1);
396 }
397 // Extra help text for some commands
398 match subcommand.as_str() {
f9f354fc 399 "build" | "b" => {
94b46f34
XL
400 subcommand_help.push_str(
401 "\n
c30ab7b3 402Arguments:
cc61c64b
XL
403 This subcommand accepts a number of paths to directories to the crates
404 and/or artifacts to compile. For example:
c30ab7b3 405
3dfed10e
XL
406 ./x.py build library/core
407 ./x.py build library/core library/proc_macro
408 ./x.py build library/std --stage 1
c30ab7b3
SL
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
041b39d2
XL
416 For a quick build of a usable compiler, you can pass:
417
3dfed10e 418 ./x.py build --stage 1 library/test
c30ab7b3 419
b7449926 420 This will first build everything once (like `--stage 0` without further
041b39d2 421 arguments would), and then use the compiler built in stage 0 to build
3dfed10e 422 library/test and its dependencies.
94b46f34
XL
423 Once this is done, build/$ARCH/stage1 contains a usable compiler.",
424 );
2c00a5a8 425 }
f9f354fc 426 "check" | "c" => {
94b46f34
XL
427 subcommand_help.push_str(
428 "\n
2c00a5a8
XL
429Arguments:
430 This subcommand accepts a number of paths to directories to the crates
431 and/or artifacts to compile. For example:
432
3dfed10e
XL
433 ./x.py check library/core
434 ./x.py check library/core library/proc_macro
2c00a5a8
XL
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
94b46f34
XL
440 the compiler.",
441 );
cc61c64b 442 }
dc9dc135
XL
443 "clippy" => {
444 subcommand_help.push_str(
445 "\n
446Arguments:
447 This subcommand accepts a number of paths to directories to the crates
448 and/or artifacts to run clippy against. For example:
449
3dfed10e
XL
450 ./x.py clippy library/core
451 ./x.py clippy library/core library/proc_macro",
dc9dc135
XL
452 );
453 }
454 "fix" => {
455 subcommand_help.push_str(
456 "\n
457Arguments:
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
3dfed10e
XL
461 ./x.py fix library/core
462 ./x.py fix library/core library/proc_macro",
dc9dc135
XL
463 );
464 }
dfeec247
XL
465 "fmt" => {
466 subcommand_help.push_str(
467 "\n
468Arguments:
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 }
f9f354fc 476 "test" | "t" => {
94b46f34
XL
477 subcommand_help.push_str(
478 "\n
c30ab7b3 479Arguments:
ba9703b0 480 This subcommand accepts a number of paths to test directories that
cc61c64b 481 should be compiled and run. For example:
c30ab7b3 482
416331ca 483 ./x.py test src/test/ui
3dfed10e
XL
484 ./x.py test library/std --test-args hash_map
485 ./x.py test library/std --stage 0 --no-doc
94b46f34
XL
486 ./x.py test src/test/ui --bless
487 ./x.py test src/test/ui --compare-mode nll
c30ab7b3 488
1b1a35ee 489 Note that `test src/test/* --stage N` does NOT depend on `build compiler/rustc --stage N`;
3dfed10e 490 just like `build library/std --stage N` it tests the compiler produced by the previous
b7449926
XL
491 stage.
492
ba9703b0
XL
493 Execute tool tests with a tool name argument:
494
495 ./x.py test tidy
496
c30ab7b3
SL
497 If no arguments are passed then the complete artifacts for that stage are
498 compiled and tested.
499
500 ./x.py test
94b46f34
XL
501 ./x.py test --stage 1",
502 );
cc61c64b 503 }
136023e0 504 "doc" | "d" => {
94b46f34
XL
505 subcommand_help.push_str(
506 "\n
c30ab7b3 507Arguments:
cc61c64b
XL
508 This subcommand accepts a number of paths to directories of documentation
509 to build. For example:
c30ab7b3
SL
510
511 ./x.py doc src/doc/book
512 ./x.py doc src/doc/nomicon
3dfed10e
XL
513 ./x.py doc src/doc/book library/std
514 ./x.py doc library/std --open
c30ab7b3
SL
515
516 If no arguments are passed then everything is documented:
517
518 ./x.py doc
94b46f34
XL
519 ./x.py doc --stage 1",
520 );
c30ab7b3 521 }
f9f354fc 522 "run" | "r" => {
ba9703b0
XL
523 subcommand_help.push_str(
524 "\n
525Arguments:
526 This subcommand accepts a number of paths to tools to build and run. For
527 example:
528
3dfed10e 529 ./x.py run src/tools/expand-yaml-anchors
ba9703b0
XL
530
531 At least a tool needs to be called.",
532 );
533 }
1b1a35ee 534 "setup" => {
29967ef6 535 subcommand_help.push_str(&format!(
1b1a35ee 536 "\n
29967ef6
XL
537x.py setup creates a `config.toml` which changes the defaults for x.py itself.
538
1b1a35ee
XL
539Arguments:
540 This subcommand accepts a 'profile' to use for builds. For example:
541
542 ./x.py setup library
543
29967ef6
XL
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 ));
1b1a35ee 550 }
94b46f34 551 _ => {}
7453a54e 552 };
cc61c64b 553 // Get any optional paths which occur after the subcommand
1b1a35ee 554 let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::<Vec<PathBuf>>();
cc61c64b 555
f035d41b 556 let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from);
1b1a35ee 557 let verbose = matches.opt_present("verbose");
c30ab7b3 558
cc61c64b
XL
559 // User passed in -h/--help?
560 if matches.opt_present("help") {
1b1a35ee 561 usage(0, &opts, verbose, &subcommand_help);
cc61c64b 562 }
c30ab7b3 563
cc61c64b 564 let cmd = match subcommand.as_str() {
f9f354fc 565 "build" | "b" => Subcommand::Build { paths },
29967ef6 566 "check" | "c" => {
94222f64
XL
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 }
29967ef6
XL
573 }
574 "clippy" => Subcommand::Clippy { paths, fix: matches.opt_present("fix") },
dc9dc135 575 "fix" => Subcommand::Fix { paths },
f9f354fc 576 "test" | "t" => Subcommand::Test {
94b46f34
XL
577 paths,
578 bless: matches.opt_present("bless"),
94222f64 579 force_rerun: matches.opt_present("force-rerun"),
94b46f34 580 compare_mode: matches.opt_str("compare-mode"),
dc9dc135 581 pass: matches.opt_str("pass"),
17df50a5 582 run: matches.opt_str("run"),
94b46f34
XL
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"),
532ac7d7 586 rustfix_coverage: matches.opt_present("rustfix-coverage"),
94b46f34
XL
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 },
dfeec247 595 "bench" => Subcommand::Bench { paths, test_args: matches.opt_strs("test-args") },
136023e0 596 "doc" | "d" => Subcommand::Doc { paths, open: matches.opt_present("open") },
c30ab7b3 597 "clean" => {
a1dfa0c6 598 if !paths.is_empty() {
ea8adc8c 599 println!("\nclean does not take a path argument\n");
1b1a35ee 600 usage(1, &opts, verbose, &subcommand_help);
c30ab7b3 601 }
ea8adc8c 602
dfeec247 603 Subcommand::Clean { all: matches.opt_present("all") }
c30ab7b3 604 }
17df50a5 605 "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths },
94b46f34
XL
606 "dist" => Subcommand::Dist { paths },
607 "install" => Subcommand::Install { paths },
f9f354fc 608 "run" | "r" => {
ba9703b0
XL
609 if paths.is_empty() {
610 println!("\nrun requires at least a path!\n");
1b1a35ee 611 usage(1, &opts, verbose, &subcommand_help);
ba9703b0
XL
612 }
613 Subcommand::Run { paths }
614 }
1b1a35ee 615 "setup" => {
29967ef6 616 let profile = if paths.len() > 1 {
1b1a35ee
XL
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() {
29967ef6
XL
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 })
1b1a35ee
XL
630 } else {
631 t!(crate::setup::interactive_path())
632 };
29967ef6 633 Subcommand::Setup { profile }
1b1a35ee 634 }
cc61c64b 635 _ => {
1b1a35ee 636 usage(1, &opts, verbose, &subcommand_help);
c30ab7b3
SL
637 }
638 };
639
f9f354fc 640 if let Subcommand::Check { .. } = &cmd {
1b1a35ee
XL
641 if matches.opt_str("keep-stage").is_some()
642 || matches.opt_str("keep-stage-std").is_some()
643 {
5869c6ff 644 println!("--keep-stage not yet supported for x.py check");
f9f354fc
XL
645 process::exit(1);
646 }
647 }
648
7453a54e 649 Flags {
cc61c64b 650 verbose: matches.opt_count("verbose"),
60c5eb7d 651 stage: matches.opt_str("stage").map(|j| j.parse().expect("`stage` should be a number")),
83c7162d 652 dry_run: matches.opt_present("dry-run"),
cc61c64b 653 on_fail: matches.opt_str("on-fail"),
0531ce1d 654 rustc_error_format: matches.opt_str("error-format"),
ba9703b0 655 json_output: matches.opt_present("json-output"),
dfeec247
XL
656 keep_stage: matches
657 .opt_strs("keep-stage")
658 .into_iter()
659 .map(|j| j.parse().expect("`keep-stage` should be a number"))
8faf50e0 660 .collect(),
1b1a35ee
XL
661 keep_stage_std: matches
662 .opt_strs("keep-stage-std")
94b46f34 663 .into_iter()
1b1a35ee
XL
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 },
7453a54e 686 config: cfg_file,
60c5eb7d 687 jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")),
3b2f2976 688 cmd,
cc61c64b 689 incremental: matches.opt_present("incremental"),
a1dfa0c6 690 exclude: split(&matches.opt_strs("exclude"))
94b46f34
XL
691 .into_iter()
692 .map(|p| p.into())
693 .collect::<Vec<_>>(),
1b1a35ee 694 include_default_paths: matches.opt_present("include-default-paths"),
416331ca 695 deny_warnings: parse_deny_warnings(&matches),
dfeec247
XL
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 ),
fc512014
XL
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"),
94222f64
XL
704 llvm_profile_use: matches.opt_str("llvm-profile-use"),
705 llvm_profile_generate: matches.opt_present("llvm-profile-generate"),
7453a54e
SL
706 }
707 }
708}
709
c30ab7b3
SL
710impl Subcommand {
711 pub fn test_args(&self) -> Vec<&str> {
712 match *self {
94b46f34 713 Subcommand::Test { ref test_args, .. } | Subcommand::Bench { ref test_args, .. } => {
dfeec247 714 test_args.iter().flat_map(|s| s.split_whitespace()).collect()
c30ab7b3
SL
715 }
716 _ => Vec::new(),
717 }
7453a54e 718 }
7cac9316 719
2c00a5a8
XL
720 pub fn rustc_args(&self) -> Vec<&str> {
721 match *self {
dfeec247
XL
722 Subcommand::Test { ref rustc_args, .. } => {
723 rustc_args.iter().flat_map(|s| s.split_whitespace()).collect()
724 }
2c00a5a8
XL
725 _ => Vec::new(),
726 }
727 }
728
041b39d2 729 pub fn fail_fast(&self) -> bool {
7cac9316 730 match *self {
041b39d2 731 Subcommand::Test { fail_fast, .. } => fail_fast,
7cac9316
XL
732 _ => false,
733 }
734 }
0531ce1d 735
83c7162d 736 pub fn doc_tests(&self) -> DocTests {
0531ce1d
XL
737 match *self {
738 Subcommand::Test { doc_tests, .. } => doc_tests,
83c7162d 739 _ => DocTests::Yes,
0531ce1d
XL
740 }
741 }
94b46f34
XL
742
743 pub fn bless(&self) -> bool {
744 match *self {
745 Subcommand::Test { bless, .. } => bless,
746 _ => false,
747 }
748 }
749
94222f64
XL
750 pub fn force_rerun(&self) -> bool {
751 match *self {
752 Subcommand::Test { force_rerun, .. } => force_rerun,
753 _ => false,
754 }
755 }
756
532ac7d7
XL
757 pub fn rustfix_coverage(&self) -> bool {
758 match *self {
759 Subcommand::Test { rustfix_coverage, .. } => rustfix_coverage,
760 _ => false,
761 }
762 }
763
94b46f34
XL
764 pub fn compare_mode(&self) -> Option<&str> {
765 match *self {
dfeec247 766 Subcommand::Test { ref compare_mode, .. } => compare_mode.as_ref().map(|s| &s[..]),
94b46f34
XL
767 _ => None,
768 }
769 }
dc9dc135
XL
770
771 pub fn pass(&self) -> Option<&str> {
772 match *self {
dfeec247 773 Subcommand::Test { ref pass, .. } => pass.as_ref().map(|s| &s[..]),
dc9dc135
XL
774 _ => None,
775 }
776 }
f9f354fc 777
17df50a5
XL
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
f9f354fc
XL
785 pub fn open(&self) -> bool {
786 match *self {
787 Subcommand::Doc { open, .. } => open,
788 _ => false,
789 }
790 }
7453a54e 791}
32a655c1 792
a1dfa0c6 793fn split(s: &[String]) -> Vec<String> {
1b1a35ee 794 s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect()
32a655c1 795}
416331ca
XL
796
797fn parse_deny_warnings(matches: &getopts::Matches) -> Option<bool> {
74b04a01 798 match matches.opt_str("warnings").as_deref() {
416331ca 799 Some("deny") => Some(true),
e1599b0c 800 Some("warn") => Some(false),
416331ca 801 Some(value) => {
dfeec247 802 eprintln!(r#"invalid value for --warnings: {:?}, expected "warn" or "deny""#, value,);
416331ca 803 process::exit(1);
dfeec247 804 }
416331ca
XL
805 None => None,
806 }
807}