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