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