Skip to content

Commit 56b6a80

Browse files
committed
--example with no argument now lists all available examples
1 parent 15e3b5a commit 56b6a80

File tree

12 files changed

+404
-8
lines changed

12 files changed

+404
-8
lines changed

src/bin/cargo/commands/bench.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,9 @@ Compilation can be customized with the `bench` profile in the manifest.
7373
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
7474
let ws = args.workspace(config)?;
7575
let mut compile_opts = args.compile_options(config, CompileMode::Bench)?;
76+
77+
args.check_optional_opts_all(&ws, &compile_opts)?;
78+
7679
compile_opts.build_config.release = true;
7780

7881
let ops = TestOptions {

src/bin/cargo/commands/build.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ the --release flag will use the `release` profile instead.
4949
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
5050
let ws = args.workspace(config)?;
5151
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
52+
53+
args.check_optional_opts_all(&ws, &compile_opts)?;
54+
5255
compile_opts.export_dir = args.value_of_path("out-dir", config);
5356
if compile_opts.export_dir.is_some() && !config.cli_unstable().unstable_options {
5457
Err(failure::format_err!(

src/bin/cargo/commands/check.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
6969
};
7070
let mode = CompileMode::Check { test };
7171
let compile_opts = args.compile_options(config, mode)?;
72+
73+
args.check_optional_opts_all(&ws, &compile_opts)?;
74+
7275
ops::compile(&ws, &compile_opts)?;
7376
Ok(())
7477
}

src/bin/cargo/commands/fix.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
123123
// Unlike other commands default `cargo fix` to all targets to fix as much
124124
// code as we can.
125125
let mut opts = args.compile_options(config, mode)?;
126+
127+
args.check_optional_opts_all(&ws, &opts)?;
128+
126129
if let CompileFilter::Default { .. } = opts.filter {
127130
opts.filter = CompileFilter::Only {
128131
all_targets: true,

src/bin/cargo/commands/install.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,10 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
8080
config.reload_rooted_at_cargo_home()?;
8181
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
8282

83+
let ws = args.workspace(config)?;
84+
85+
args.check_optional_opts_example_and_bin(&ws, &compile_opts)?;
86+
8387
compile_opts.build_config.release = !args.is_present("debug");
8488

8589
let krates = args

src/bin/cargo/commands/run.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
4040
let ws = args.workspace(config)?;
4141

4242
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
43+
44+
args.check_optional_opts_example_and_bin(&ws, &compile_opts)?;
45+
4346
if !args.is_present("example") && !args.is_present("bin") {
4447
let default_runs: Vec<_> = compile_opts
4548
.spec

src/bin/cargo/commands/test.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
9494

9595
let mut compile_opts = args.compile_options(config, CompileMode::Test)?;
9696

97+
args.check_optional_opts_all(&ws, &compile_opts)?;
98+
9799
let doc = args.is_present("doc");
98100
if doc {
99101
if let CompileFilter::Only { .. } = compile_opts.filter {

src/cargo/util/command_prelude.rs

Lines changed: 68 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@ use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionCon
77
use crate::sources::CRATES_IO_REGISTRY;
88
use crate::util::important_paths::find_root_manifest_for_wd;
99
use crate::util::{paths, validate_package_name};
10+
use crate::util::{
11+
print_available_benches, print_available_binaries, print_available_examples,
12+
print_available_tests,
13+
};
1014
use crate::CargoResult;
1115
use clap::{self, SubCommand};
1216

@@ -60,18 +64,18 @@ pub trait AppExt: Sized {
6064
all: &'static str,
6165
) -> Self {
6266
self.arg_targets_lib_bin(lib, bin, bins)
63-
._arg(multi_opt("example", "NAME", example))
67+
._arg(optional_multi_opt("example", "NAME", example))
6468
._arg(opt("examples", examples))
65-
._arg(multi_opt("test", "NAME", test))
69+
._arg(optional_multi_opt("test", "NAME", test))
6670
._arg(opt("tests", tests))
67-
._arg(multi_opt("bench", "NAME", bench))
71+
._arg(optional_multi_opt("bench", "NAME", bench))
6872
._arg(opt("benches", benches))
6973
._arg(opt("all-targets", all))
7074
}
7175

7276
fn arg_targets_lib_bin(self, lib: &'static str, bin: &'static str, bins: &'static str) -> Self {
7377
self._arg(opt("lib", lib))
74-
._arg(multi_opt("bin", "NAME", bin))
78+
._arg(optional_multi_opt("bin", "NAME", bin))
7579
._arg(opt("bins", bins))
7680
}
7781

@@ -82,15 +86,15 @@ pub trait AppExt: Sized {
8286
example: &'static str,
8387
examples: &'static str,
8488
) -> Self {
85-
self._arg(multi_opt("bin", "NAME", bin))
89+
self._arg(optional_multi_opt("bin", "NAME", bin))
8690
._arg(opt("bins", bins))
87-
._arg(multi_opt("example", "NAME", example))
91+
._arg(optional_multi_opt("example", "NAME", example))
8892
._arg(opt("examples", examples))
8993
}
9094

9195
fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
92-
self._arg(multi_opt("bin", "NAME", bin))
93-
._arg(multi_opt("example", "NAME", example))
96+
self._arg(optional_multi_opt("bin", "NAME", bin))
97+
._arg(optional_multi_opt("example", "NAME", example))
9498
}
9599

96100
fn arg_features(self) -> Self {
@@ -193,6 +197,18 @@ pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
193197
Arg::with_name(name).long(name).help(help)
194198
}
195199

200+
pub fn optional_multi_opt(
201+
name: &'static str,
202+
value_name: &'static str,
203+
help: &'static str,
204+
) -> Arg<'static, 'static> {
205+
opt(name, help)
206+
.value_name(value_name)
207+
.multiple(true)
208+
.min_values(0)
209+
.max_values(1)
210+
}
211+
196212
pub fn multi_opt(
197213
name: &'static str,
198214
value_name: &'static str,
@@ -413,6 +429,50 @@ about this warning.";
413429
Ok(index)
414430
}
415431

432+
fn check_optional_opts_example_and_bin(
433+
&self,
434+
workspace: &Workspace<'_>,
435+
compile_opts: &CompileOptions<'_>,
436+
) -> CliResult {
437+
if self.is_present_with_zero_values("example") {
438+
print_available_examples(&workspace, &compile_opts)?;
439+
}
440+
441+
if self.is_present_with_zero_values("bin") {
442+
print_available_binaries(&workspace, &compile_opts)?;
443+
}
444+
445+
Ok(())
446+
}
447+
448+
fn check_optional_opts_all(
449+
&self,
450+
workspace: &Workspace<'_>,
451+
compile_opts: &CompileOptions<'_>,
452+
) -> CliResult {
453+
if self.is_present_with_zero_values("example") {
454+
print_available_examples(&workspace, &compile_opts)?;
455+
}
456+
457+
if self.is_present_with_zero_values("bin") {
458+
print_available_binaries(&workspace, &compile_opts)?;
459+
}
460+
461+
if self.is_present_with_zero_values("bench") {
462+
print_available_benches(&workspace, &compile_opts)?;
463+
}
464+
465+
if self.is_present_with_zero_values("test") {
466+
print_available_tests(&workspace, &compile_opts)?;
467+
}
468+
469+
Ok(())
470+
}
471+
472+
fn is_present_with_zero_values(&self, name: &str) -> bool {
473+
self._is_present(name) && self._value_of(name).is_none()
474+
}
475+
416476
fn _value_of(&self, name: &str) -> Option<&str>;
417477

418478
fn _values_of(&self, name: &str) -> Vec<String>;

src/cargo/util/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ pub use self::sha256::Sha256;
2222
pub use self::to_semver::ToSemver;
2323
pub use self::to_url::ToUrl;
2424
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
25+
pub use self::workspace::{
26+
print_available_benches, print_available_binaries, print_available_examples,
27+
print_available_tests,
28+
};
2529

2630
mod cfg;
2731
pub mod command_prelude;
@@ -49,6 +53,7 @@ pub mod to_semver;
4953
pub mod to_url;
5054
pub mod toml;
5155
mod vcs;
56+
mod workspace;
5257

5358
pub fn elapsed(duration: Duration) -> String {
5459
let secs = duration.as_secs();

src/cargo/util/workspace.rs

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
use crate::core::{Target, Workspace};
2+
use crate::ops::CompileOptions;
3+
use crate::util::CargoResult;
4+
5+
use std::fmt::Write;
6+
7+
fn get_available_targets<'a>(
8+
filter_fn: fn(&Target) -> bool,
9+
ws: &'a Workspace<'_>,
10+
options: &'a CompileOptions<'_>,
11+
) -> CargoResult<Vec<&'a Target>> {
12+
let packages = options.spec.get_packages(ws)?;
13+
14+
let targets: Vec<_> = packages
15+
.into_iter()
16+
.flat_map(|pkg| {
17+
pkg.manifest()
18+
.targets()
19+
.into_iter()
20+
.filter(|target| filter_fn(target))
21+
})
22+
.collect();
23+
Ok(targets)
24+
}
25+
26+
fn print_available(
27+
filter_fn: fn(&Target) -> bool,
28+
ws: &Workspace<'_>,
29+
options: &CompileOptions<'_>,
30+
option_name: &str,
31+
plural_name: &str,
32+
) -> CargoResult<()> {
33+
let targets = get_available_targets(filter_fn, ws, options)?;
34+
35+
let mut output = String::new();
36+
writeln!(output, "\"{}\" takes one argument.", option_name)?;
37+
38+
if targets.is_empty() {
39+
writeln!(output, "No {} available.", plural_name)?;
40+
} else {
41+
writeln!(output, "Available {}:", plural_name)?;
42+
for target in targets {
43+
writeln!(output, " {}", target.name())?;
44+
}
45+
}
46+
Err(failure::err_msg(output))?
47+
}
48+
49+
pub fn print_available_examples(
50+
ws: &Workspace<'_>,
51+
options: &CompileOptions<'_>,
52+
) -> CargoResult<()> {
53+
print_available(Target::is_example, ws, options, "--example", "examples")
54+
}
55+
56+
pub fn print_available_binaries(
57+
ws: &Workspace<'_>,
58+
options: &CompileOptions<'_>,
59+
) -> CargoResult<()> {
60+
print_available(Target::is_bin, ws, options, "--bin", "binaries")
61+
}
62+
63+
pub fn print_available_benches(
64+
ws: &Workspace<'_>,
65+
options: &CompileOptions<'_>,
66+
) -> CargoResult<()> {
67+
print_available(Target::is_bench, ws, options, "--bench", "benches")
68+
}
69+
70+
pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions<'_>) -> CargoResult<()> {
71+
print_available(Target::is_test, ws, options, "--test", "tests")
72+
}

0 commit comments

Comments
 (0)