Skip to content

Commit becb4c2

Browse files
committed
Auto merge of #8808 - weihanglo:fix/8591, r=ehuss
List available packages if providing `--package` with an empty value May resolves #8591 ## How First we need to take the responsibility of check command line arguments from claps. I've examine all 10 build commands and all of them call [`ArgMatchesExt::compile_options`](https://github.com/rust-lang/cargo/blob/2f115a76e5a1e5eb11cd29e95f972ed107267847/src/cargo/util/command_prelude.rs#L389-L395) directly or indirectly. And `compile_options` [calls `check_optional_opts`](https://github.com/rust-lang/cargo/blob/2f115a76e5a1e5eb11cd29e95f972ed107267847/src/cargo/util/command_prelude.rs#L499-L501) to check if target selection options given an empty value. So we can do the same logic there. I've also add a error message for an edge case though that one would never trigger at this moment.
2 parents 358ee54 + 4b9c503 commit becb4c2

File tree

11 files changed

+167
-38
lines changed

11 files changed

+167
-38
lines changed

src/bin/cargo/commands/clean.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::command_prelude::*;
22

33
use cargo::ops::{self, CleanOptions};
4+
use cargo::util::print_available_packages;
45

56
pub fn cli() -> App {
67
subcommand("clean")
@@ -18,6 +19,11 @@ pub fn cli() -> App {
1819

1920
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
2021
let ws = args.workspace(config)?;
22+
23+
if args.is_present_with_zero_values("package") {
24+
print_available_packages(&ws)?;
25+
}
26+
2127
let opts = CleanOptions {
2228
config,
2329
spec: values(args, "package"),

src/bin/cargo/commands/pkgid.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::command_prelude::*;
22

33
use cargo::ops;
4+
use cargo::util::print_available_packages;
45

56
pub fn cli() -> App {
67
subcommand("pkgid")
@@ -14,6 +15,9 @@ pub fn cli() -> App {
1415

1516
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
1617
let ws = args.workspace(config)?;
18+
if args.is_present_with_zero_values("package") {
19+
print_available_packages(&ws)?
20+
}
1721
let spec = args.value_of("spec").or_else(|| args.value_of("package"));
1822
let spec = ops::pkgid(&ws, spec)?;
1923
cargo::drop_println!(config, "{}", spec);

src/bin/cargo/commands/tree.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use anyhow::{bail, format_err};
44
use cargo::core::dependency::DepKind;
55
use cargo::ops::tree::{self, EdgeKind};
66
use cargo::ops::Packages;
7+
use cargo::util::print_available_packages;
78
use cargo::util::CargoResult;
89
use std::collections::HashSet;
910
use std::str::FromStr;
@@ -176,6 +177,11 @@ subtree of the package given to -p.\n\
176177
}
177178

178179
let ws = args.workspace(config)?;
180+
181+
if args.is_present_with_zero_values("package") {
182+
print_available_packages(&ws)?;
183+
}
184+
179185
let charset = tree::Charset::from_str(args.value_of("charset").unwrap())
180186
.map_err(|e| anyhow::anyhow!("{}", e))?;
181187
let opts = tree::TreeOptions {

src/bin/cargo/commands/uninstall.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ pub fn cli() -> App {
1515

1616
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
1717
let root = args.value_of("root");
18+
19+
if args.is_present_with_zero_values("package") {
20+
return Err(anyhow::anyhow!(
21+
"\"--package <SPEC>\" requires a SPEC format value.\n\
22+
Run `cargo help pkgid` for more information about SPEC format."
23+
)
24+
.into());
25+
}
26+
1827
let specs = args
1928
.values_of("spec")
2029
.unwrap_or_else(|| args.values_of("package").unwrap_or_default())

src/bin/cargo/commands/update.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use crate::command_prelude::*;
22

33
use cargo::ops::{self, UpdateOptions};
4+
use cargo::util::print_available_packages;
45

56
pub fn cli() -> App {
67
subcommand("update")
@@ -20,6 +21,10 @@ pub fn cli() -> App {
2021
pub fn exec(config: &mut Config, args: &ArgMatches<'_>) -> CliResult {
2122
let ws = args.workspace(config)?;
2223

24+
if args.is_present_with_zero_values("package") {
25+
print_available_packages(&ws)?;
26+
}
27+
2328
let update_opts = UpdateOptions {
2429
aggressive: args.is_present("aggressive"),
2530
precise: args.value_of("precise"),

src/cargo/util/command_prelude.rs

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::util::restricted_names::is_glob_pattern;
88
use crate::util::{paths, toml::TomlProfile, validate_package_name};
99
use crate::util::{
1010
print_available_benches, print_available_binaries, print_available_examples,
11-
print_available_tests,
11+
print_available_packages, print_available_tests,
1212
};
1313
use crate::CargoResult;
1414
use anyhow::bail;
@@ -52,11 +52,15 @@ pub trait AppExt: Sized {
5252
}
5353

5454
fn arg_package_spec_simple(self, package: &'static str) -> Self {
55-
self._arg(multi_opt("package", "SPEC", package).short("p"))
55+
self._arg(optional_multi_opt("package", "SPEC", package).short("p"))
5656
}
5757

5858
fn arg_package(self, package: &'static str) -> Self {
59-
self._arg(opt("package", package).short("p").value_name("SPEC"))
59+
self._arg(
60+
optinal_opt("package", package)
61+
.short("p")
62+
.value_name("SPEC"),
63+
)
6064
}
6165

6266
fn arg_jobs(self) -> Self {
@@ -220,6 +224,10 @@ pub fn opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
220224
Arg::with_name(name).long(name).help(help)
221225
}
222226

227+
pub fn optinal_opt(name: &'static str, help: &'static str) -> Arg<'static, 'static> {
228+
opt(name, help).min_values(0)
229+
}
230+
223231
pub fn optional_multi_opt(
224232
name: &'static str,
225233
value_name: &'static str,
@@ -498,6 +506,14 @@ pub trait ArgMatchesExt {
498506

499507
if let Some(ws) = workspace {
500508
self.check_optional_opts(ws, &opts)?;
509+
} else if self.is_present_with_zero_values("package") {
510+
// As for cargo 0.50.0, this won't occur but if someone sneaks in
511+
// we can still provide this informative message for them.
512+
anyhow::bail!(
513+
"\"--package <SPEC>\" requires a SPEC format value, \
514+
which can be any package ID specifier in the dependency graph.\n\
515+
Run `cargo help pkgid` for more information about SPEC format."
516+
)
501517
}
502518

503519
Ok(opts)
@@ -588,6 +604,10 @@ about this warning.";
588604
workspace: &Workspace<'_>,
589605
compile_opts: &CompileOptions,
590606
) -> CargoResult<()> {
607+
if self.is_present_with_zero_values("package") {
608+
print_available_packages(workspace)?
609+
}
610+
591611
if self.is_present_with_zero_values("example") {
592612
print_available_examples(workspace, compile_opts)?;
593613
}

src/cargo/util/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ pub use self::to_semver::ToSemver;
2828
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
2929
pub use self::workspace::{
3030
print_available_benches, print_available_binaries, print_available_examples,
31-
print_available_tests,
31+
print_available_packages, print_available_tests,
3232
};
3333

3434
mod canonical_url;

src/cargo/util/workspace.rs

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ fn get_available_targets<'a>(
88
filter_fn: fn(&Target) -> bool,
99
ws: &'a Workspace<'_>,
1010
options: &'a CompileOptions,
11-
) -> CargoResult<Vec<&'a Target>> {
11+
) -> CargoResult<Vec<&'a str>> {
1212
let packages = options.spec.get_packages(ws)?;
1313

1414
let mut targets: Vec<_> = packages
@@ -19,14 +19,15 @@ fn get_available_targets<'a>(
1919
.iter()
2020
.filter(|target| filter_fn(target))
2121
})
22+
.map(Target::name)
2223
.collect();
2324

2425
targets.sort();
2526

2627
Ok(targets)
2728
}
2829

29-
fn print_available(
30+
fn print_available_targets(
3031
filter_fn: fn(&Target) -> bool,
3132
ws: &Workspace<'_>,
3233
options: &CompileOptions,
@@ -43,24 +44,48 @@ fn print_available(
4344
} else {
4445
writeln!(output, "Available {}:", plural_name)?;
4546
for target in targets {
46-
writeln!(output, " {}", target.name())?;
47+
writeln!(output, " {}", target)?;
48+
}
49+
}
50+
bail!("{}", output)
51+
}
52+
53+
pub fn print_available_packages(ws: &Workspace<'_>) -> CargoResult<()> {
54+
let packages = ws
55+
.members()
56+
.map(|pkg| pkg.name().as_str())
57+
.collect::<Vec<_>>();
58+
59+
let mut output = "\"--package <SPEC>\" requires a SPEC format value, \
60+
which can be any package ID specifier in the dependency graph.\n\
61+
Run `cargo help pkgid` for more information about SPEC format.\n\n"
62+
.to_string();
63+
64+
if packages.is_empty() {
65+
// This would never happen.
66+
// Just in case something regresses we covers it here.
67+
writeln!(output, "No packages available.")?;
68+
} else {
69+
writeln!(output, "Possible packages/workspace members:")?;
70+
for package in packages {
71+
writeln!(output, " {}", package)?;
4772
}
4873
}
4974
bail!("{}", output)
5075
}
5176

5277
pub fn print_available_examples(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
53-
print_available(Target::is_example, ws, options, "--example", "examples")
78+
print_available_targets(Target::is_example, ws, options, "--example", "examples")
5479
}
5580

5681
pub fn print_available_binaries(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
57-
print_available(Target::is_bin, ws, options, "--bin", "binaries")
82+
print_available_targets(Target::is_bin, ws, options, "--bin", "binaries")
5883
}
5984

6085
pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
61-
print_available(Target::is_bench, ws, options, "--bench", "benches")
86+
print_available_targets(Target::is_bench, ws, options, "--bench", "benches")
6287
}
6388

6489
pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
65-
print_available(Target::is_test, ws, options, "--test", "tests")
90+
print_available_targets(Target::is_test, ws, options, "--test", "tests")
6691
}

tests/testsuite/install.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1181,6 +1181,19 @@ fn uninstall_multiple_and_specifying_bin() {
11811181
.run();
11821182
}
11831183

1184+
#[cargo_test]
1185+
fn uninstall_with_empty_pakcage_option() {
1186+
cargo_process("uninstall -p")
1187+
.with_status(101)
1188+
.with_stderr(
1189+
"\
1190+
[ERROR] \"--package <SPEC>\" requires a SPEC format value.
1191+
Run `cargo help pkgid` for more information about SPEC format.
1192+
",
1193+
)
1194+
.run();
1195+
}
1196+
11841197
#[cargo_test]
11851198
fn uninstall_multiple_and_some_pkg_does_not_exist() {
11861199
pkg("foo", "0.0.1");

0 commit comments

Comments
 (0)