Skip to content

Commit

Permalink
Auto merge of #6505 - DamianX:print_examples, r=ehuss
Browse files Browse the repository at this point in the history
--{example,bin,bench,test} with no argument now lists all available targets

```
cargo run --bin
error: "--bin" takes one argument.
Available binaries:
    cargo

error: process didn't exit successfully: `target\debug\cargo.exe run --bin` (exit code: 101)
```

Previous PR: #5062
Closes #2548

Notes:
- `optional_opt` is a weird name, can someone come up with a better one?
- Should I call clap's `usage()` as well when printing the error message?
  • Loading branch information
bors committed Jan 7, 2019
2 parents b84e625 + a51759c commit d92bd3a
Show file tree
Hide file tree
Showing 15 changed files with 347 additions and 19 deletions.
3 changes: 2 additions & 1 deletion src/bin/cargo/commands/bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ Compilation can be customized with the `bench` profile in the manifest.

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let mut compile_opts = args.compile_options(config, CompileMode::Bench)?;
let mut compile_opts = args.compile_options(config, CompileMode::Bench, Some(&ws))?;

compile_opts.build_config.release = true;

let ops = TestOptions {
Expand Down
3 changes: 2 additions & 1 deletion src/bin/cargo/commands/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ the --release flag will use the `release` profile instead.

pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
let mut compile_opts = args.compile_options(config, CompileMode::Build, Some(&ws))?;

compile_opts.export_dir = args.value_of_path("out-dir", config);
if compile_opts.export_dir.is_some() && !config.cli_unstable().unstable_options {
Err(failure::format_err!(
Expand Down
3 changes: 2 additions & 1 deletion src/bin/cargo/commands/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
}
};
let mode = CompileMode::Check { test };
let compile_opts = args.compile_options(config, mode)?;
let compile_opts = args.compile_options(config, mode, Some(&ws))?;

ops::compile(&ws, &compile_opts)?;
Ok(())
}
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let mode = CompileMode::Doc {
deps: !args.is_present("no-deps"),
};
let mut compile_opts = args.compile_options(config, mode)?;
let mut compile_opts = args.compile_options(config, mode, Some(&ws))?;
compile_opts.local_rustdoc_args = if args.is_present("document-private-items") {
Some(vec!["--document-private-items".to_string()])
} else {
Expand Down
3 changes: 2 additions & 1 deletion src/bin/cargo/commands/fix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,8 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {

// Unlike other commands default `cargo fix` to all targets to fix as much
// code as we can.
let mut opts = args.compile_options(config, mode)?;
let mut opts = args.compile_options(config, mode, Some(&ws))?;

if let CompileFilter::Default { .. } = opts.filter {
opts.filter = CompileFilter::Only {
all_targets: true,
Expand Down
4 changes: 3 additions & 1 deletion src/bin/cargo/commands/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,9 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let registry = args.registry(config)?;

config.reload_rooted_at_cargo_home()?;
let mut compile_opts = args.compile_options(config, CompileMode::Build)?;

let workspace = args.workspace(config).ok();
let mut compile_opts = args.compile_options(config, CompileMode::Build, workspace.as_ref())?;

compile_opts.build_config.release = !args.is_present("debug");

Expand Down
3 changes: 2 additions & 1 deletion src/bin/cargo/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ run. If you're passing arguments to both Cargo and the binary, the ones after
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;

let mut compile_opts = args.compile_options(config, CompileMode::Build)?;
let mut compile_opts = args.compile_options(config, CompileMode::Build, Some(&ws))?;

if !args.is_present("example") && !args.is_present("bin") {
let default_runs: Vec<_> = compile_opts
.spec
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/rustc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
return Err(CliError::new(err, 101));
}
};
let mut compile_opts = args.compile_options_for_single_package(config, mode)?;
let mut compile_opts = args.compile_options_for_single_package(config, mode, Some(&ws))?;
let target_args = values(args, "args");
compile_opts.target_rustc_args = if target_args.is_empty() {
None
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ the `cargo help pkgid` command.
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;
let mut compile_opts =
args.compile_options_for_single_package(config, CompileMode::Doc { deps: false })?;
args.compile_options_for_single_package(config, CompileMode::Doc { deps: false }, Some(&ws))?;
let target_args = values(args, "args");
compile_opts.target_rustdoc_args = if target_args.is_empty() {
None
Expand Down
2 changes: 1 addition & 1 deletion src/bin/cargo/commands/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ To get the list of all options available for the test binaries use this:
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
let ws = args.workspace(config)?;

let mut compile_opts = args.compile_options(config, CompileMode::Test)?;
let mut compile_opts = args.compile_options(config, CompileMode::Test, Some(&ws))?;

let doc = args.is_present("doc");
if doc {
Expand Down
69 changes: 60 additions & 9 deletions src/cargo/util/command_prelude.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionCon
use crate::sources::CRATES_IO_REGISTRY;
use crate::util::important_paths::find_root_manifest_for_wd;
use crate::util::{paths, validate_package_name};
use crate::util::{
print_available_benches, print_available_binaries, print_available_examples,
print_available_tests,
};
use crate::CargoResult;
use clap::{self, SubCommand};

Expand Down Expand Up @@ -60,18 +64,18 @@ pub trait AppExt: Sized {
all: &'static str,
) -> Self {
self.arg_targets_lib_bin(lib, bin, bins)
._arg(multi_opt("example", "NAME", example))
._arg(optional_multi_opt("example", "NAME", example))
._arg(opt("examples", examples))
._arg(multi_opt("test", "NAME", test))
._arg(optional_multi_opt("test", "NAME", test))
._arg(opt("tests", tests))
._arg(multi_opt("bench", "NAME", bench))
._arg(optional_multi_opt("bench", "NAME", bench))
._arg(opt("benches", benches))
._arg(opt("all-targets", all))
}

fn arg_targets_lib_bin(self, lib: &'static str, bin: &'static str, bins: &'static str) -> Self {
self._arg(opt("lib", lib))
._arg(multi_opt("bin", "NAME", bin))
._arg(optional_multi_opt("bin", "NAME", bin))
._arg(opt("bins", bins))
}

Expand All @@ -82,15 +86,15 @@ pub trait AppExt: Sized {
example: &'static str,
examples: &'static str,
) -> Self {
self._arg(multi_opt("bin", "NAME", bin))
self._arg(optional_multi_opt("bin", "NAME", bin))
._arg(opt("bins", bins))
._arg(multi_opt("example", "NAME", example))
._arg(optional_multi_opt("example", "NAME", example))
._arg(opt("examples", examples))
}

fn arg_targets_bin_example(self, bin: &'static str, example: &'static str) -> Self {
self._arg(multi_opt("bin", "NAME", bin))
._arg(multi_opt("example", "NAME", example))
self._arg(optional_multi_opt("bin", "NAME", bin))
._arg(optional_multi_opt("example", "NAME", example))
}

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

pub fn optional_multi_opt(
name: &'static str,
value_name: &'static str,
help: &'static str,
) -> Arg<'static, 'static> {
opt(name, help)
.value_name(value_name)
.multiple(true)
.min_values(0)
.number_of_values(1)
}

pub fn multi_opt(
name: &'static str,
value_name: &'static str,
Expand Down Expand Up @@ -272,6 +288,7 @@ pub trait ArgMatchesExt {
&self,
config: &'a Config,
mode: CompileMode,
workspace: Option<&Workspace<'a>>,
) -> CargoResult<CompileOptions<'a>> {
let spec = Packages::from_flags(
self._is_present("all"),
Expand Down Expand Up @@ -328,15 +345,21 @@ pub trait ArgMatchesExt {
local_rustdoc_args: None,
export_dir: None,
};

if let Some(ws) = workspace {
self.check_optional_opts(ws, &opts)?;
}

Ok(opts)
}

fn compile_options_for_single_package<'a>(
&self,
config: &'a Config,
mode: CompileMode,
workspace: Option<&Workspace<'a>>,
) -> CargoResult<CompileOptions<'a>> {
let mut compile_opts = self.compile_options(config, mode)?;
let mut compile_opts = self.compile_options(config, mode, workspace)?;
compile_opts.spec = Packages::Packages(self._values_of("package"));
Ok(compile_opts)
}
Expand Down Expand Up @@ -413,6 +436,34 @@ about this warning.";
Ok(index)
}

fn check_optional_opts(
&self,
workspace: &Workspace<'_>,
compile_opts: &CompileOptions<'_>,
) -> CargoResult<()> {
if self.is_present_with_zero_values("example") {
print_available_examples(&workspace, &compile_opts)?;
}

if self.is_present_with_zero_values("bin") {
print_available_binaries(&workspace, &compile_opts)?;
}

if self.is_present_with_zero_values("bench") {
print_available_benches(&workspace, &compile_opts)?;
}

if self.is_present_with_zero_values("test") {
print_available_tests(&workspace, &compile_opts)?;
}

Ok(())
}

fn is_present_with_zero_values(&self, name: &str) -> bool {
self._is_present(name) && self._value_of(name).is_none()
}

fn _value_of(&self, name: &str) -> Option<&str>;

fn _values_of(&self, name: &str) -> Vec<String>;
Expand Down
5 changes: 5 additions & 0 deletions src/cargo/util/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ pub use self::sha256::Sha256;
pub use self::to_semver::ToSemver;
pub use self::to_url::ToUrl;
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
pub use self::workspace::{
print_available_benches, print_available_binaries, print_available_examples,
print_available_tests,
};

mod cfg;
pub mod command_prelude;
Expand Down Expand Up @@ -49,6 +53,7 @@ pub mod to_semver;
pub mod to_url;
pub mod toml;
mod vcs;
mod workspace;

pub fn elapsed(duration: Duration) -> String {
let secs = duration.as_secs();
Expand Down
75 changes: 75 additions & 0 deletions src/cargo/util/workspace.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
use crate::core::{Target, Workspace};
use crate::ops::CompileOptions;
use crate::util::CargoResult;

use std::fmt::Write;

fn get_available_targets<'a>(
filter_fn: fn(&Target) -> bool,
ws: &'a Workspace<'_>,
options: &'a CompileOptions<'_>,
) -> CargoResult<Vec<&'a Target>> {
let packages = options.spec.get_packages(ws)?;

let mut targets: Vec<_> = packages
.into_iter()
.flat_map(|pkg| {
pkg.manifest()
.targets()
.into_iter()
.filter(|target| filter_fn(target))
})
.collect();

targets.sort();

Ok(targets)
}

fn print_available(
filter_fn: fn(&Target) -> bool,
ws: &Workspace<'_>,
options: &CompileOptions<'_>,
option_name: &str,
plural_name: &str,
) -> CargoResult<()> {
let targets = get_available_targets(filter_fn, ws, options)?;

let mut output = String::new();
writeln!(output, "\"{}\" takes one argument.", option_name)?;

if targets.is_empty() {
writeln!(output, "No {} available.", plural_name)?;
} else {
writeln!(output, "Available {}:", plural_name)?;
for target in targets {
writeln!(output, " {}", target.name())?;
}
}
Err(failure::err_msg(output))?
}

pub fn print_available_examples(
ws: &Workspace<'_>,
options: &CompileOptions<'_>,
) -> CargoResult<()> {
print_available(Target::is_example, ws, options, "--example", "examples")
}

pub fn print_available_binaries(
ws: &Workspace<'_>,
options: &CompileOptions<'_>,
) -> CargoResult<()> {
print_available(Target::is_bin, ws, options, "--bin", "binaries")
}

pub fn print_available_benches(
ws: &Workspace<'_>,
options: &CompileOptions<'_>,
) -> CargoResult<()> {
print_available(Target::is_bench, ws, options, "--bench", "benches")
}

pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions<'_>) -> CargoResult<()> {
print_available(Target::is_test, ws, options, "--test", "tests")
}
Loading

0 comments on commit d92bd3a

Please sign in to comment.