Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

--{example,bin,bench,test} with no argument now lists all available targets #6505

Merged
merged 4 commits into from
Jan 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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