Skip to content

Commit 20cb700

Browse files
committed
Handle options-with-arguments before subcommands such as './x.py -j 10 build' and detect pathological cases like './x.py --option-that-takes-argument clean build'
1 parent 1e53898 commit 20cb700

File tree

1 file changed

+44
-16
lines changed

1 file changed

+44
-16
lines changed

src/bootstrap/flags.rs

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,13 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
119119
// complete the definition of the options. Then we can use the getopt::Matches object from
120120
// there on out.
121121
let mut possible_subcommands = args.iter().collect::<Vec<_>>();
122-
possible_subcommands.retain(|&s| !s.starts_with('-'));
122+
possible_subcommands.retain(|&s|
123+
(s == "build")
124+
|| (s == "test")
125+
|| (s == "bench")
126+
|| (s == "doc")
127+
|| (s == "clean")
128+
|| (s == "dist"));
123129
let subcommand = match possible_subcommands.first() {
124130
Some(s) => s,
125131
None => {
@@ -129,7 +135,43 @@ To learn more about a subcommand, run `./x.py <subcommand> -h`");
129135
}
130136
};
131137

132-
// Some subcommands have specific arguments help text
138+
// Some subcommands get extra options
139+
match subcommand.as_str() {
140+
"test" => opts.optmulti("", "test-args", "extra arguments", "ARGS"),
141+
"bench" => opts.optmulti("", "test-args", "extra arguments", "ARGS"),
142+
"dist" => opts.optflag("", "install", "run installer as well"),
143+
_ => { }
144+
};
145+
146+
// Done specifying what options are possible, so do the getopts parsing
147+
let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
148+
// Invalid argument/option format
149+
println!("\n{}\n", e);
150+
usage(1, &opts, &subcommand_help, &extra_help);
151+
});
152+
// Extra sanity check to make sure we didn't hit this crazy corner case:
153+
//
154+
// ./x.py --frobulate clean build
155+
// ^-- option ^ ^- actual subcommand
156+
// \_ arg to option could be mistaken as subcommand
157+
let mut pass_sanity_check = true;
158+
match matches.free.get(0) {
159+
Some(check_subcommand) => {
160+
if &check_subcommand != subcommand {
161+
pass_sanity_check = false;
162+
}
163+
},
164+
None => {
165+
pass_sanity_check = false;
166+
}
167+
}
168+
if !pass_sanity_check {
169+
println!("{}\n", subcommand_help);
170+
println!("Sorry, I couldn't figure out which subcommand you were trying to specify.\n\
171+
You may need to move some options to after the subcommand.\n");
172+
process::exit(1);
173+
}
174+
// Extra help text for some commands
133175
match subcommand.as_str() {
134176
"build" => {
135177
subcommand_help.push_str("\n
@@ -152,7 +194,6 @@ Arguments:
152194
./x.py build --stage 1 src/libtest");
153195
}
154196
"test" => {
155-
opts.optmulti("", "test-args", "extra arguments", "ARGS");
156197
subcommand_help.push_str("\n
157198
Arguments:
158199
This subcommand accepts a number of paths to directories to tests that
@@ -168,9 +209,6 @@ Arguments:
168209
./x.py test
169210
./x.py test --stage 1");
170211
}
171-
"bench" => {
172-
opts.optmulti("", "test-args", "extra arguments", "ARGS");
173-
}
174212
"doc" => {
175213
subcommand_help.push_str("\n
176214
Arguments:
@@ -186,18 +224,8 @@ Arguments:
186224
./x.py doc
187225
./x.py doc --stage 1");
188226
}
189-
"dist" => {
190-
opts.optflag("", "install", "run installer as well");
191-
}
192227
_ => { }
193228
};
194-
195-
// Done specifying what options are possible, so do the getopts parsing
196-
let matches = opts.parse(&args[..]).unwrap_or_else(|e| {
197-
// Invalid argument/option format
198-
println!("\n{}\n", e);
199-
usage(1, &opts, &subcommand_help, &extra_help);
200-
});
201229
// Get any optional paths which occur after the subcommand
202230
let cwd = t!(env::current_dir());
203231
let paths = matches.free[1..].iter().map(|p| cwd.join(p)).collect::<Vec<_>>();

0 commit comments

Comments
 (0)