Skip to content

Commit 1cc21b6

Browse files
committed
make unknown features on cargo add more discoverable
1 parent d924a25 commit 1cc21b6

File tree

11 files changed

+115
-24
lines changed

11 files changed

+115
-24
lines changed

src/cargo/ops/cargo_add/mod.rs

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use std::path::Path;
1111
use anyhow::Context as _;
1212
use cargo_util::paths;
1313
use indexmap::IndexSet;
14+
use itertools::Itertools;
1415
use termcolor::Color::Green;
1516
use termcolor::Color::Red;
1617
use termcolor::ColorSpec;
@@ -101,7 +102,6 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
101102
});
102103
for dep in deps {
103104
print_action_msg(&mut options.config.shell(), &dep, &dep_table)?;
104-
print_dep_table_msg(&mut options.config.shell(), &dep)?;
105105
if let Some(Source::Path(src)) = dep.source() {
106106
if src.path == manifest.path.parent().unwrap_or_else(|| Path::new("")) {
107107
anyhow::bail!(
@@ -126,11 +126,63 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
126126
inherited_features.iter().map(|s| s.as_str()).collect();
127127
unknown_features.extend(inherited_features.difference(&available_features).copied());
128128
}
129+
129130
unknown_features.sort();
131+
130132
if !unknown_features.is_empty() {
131-
anyhow::bail!("unrecognized features: {unknown_features:?}");
133+
let (mut activated, mut deactivated) = dep.features();
134+
// Since the unknown features have been added to the DependencyUI we need to remove
135+
// them to present the "correct" features that can be specified for the crate.
136+
deactivated.retain(|f| !unknown_features.contains(f));
137+
activated.retain(|f| !unknown_features.contains(f));
138+
139+
let mut message = format!(
140+
"unrecognized feature{} for crate {}: {}\n",
141+
if unknown_features.len() == 1 { "" } else { "s" },
142+
dep.name,
143+
unknown_features.iter().format(", "),
144+
);
145+
if activated.is_empty() && deactivated.is_empty() {
146+
write!(message, "no features available for crate {}", dep.name)?;
147+
} else {
148+
if !deactivated.is_empty() {
149+
writeln!(
150+
message,
151+
"disabled features:\n {}",
152+
deactivated
153+
.iter()
154+
.map(|s| s.to_string())
155+
.coalesce(|x, y| if x.len() + y.len() < 78 {
156+
Ok(format!("{x}, {y}"))
157+
} else {
158+
Err((x, y))
159+
})
160+
.into_iter()
161+
.format("\n ")
162+
)?
163+
}
164+
if !activated.is_empty() {
165+
writeln!(
166+
message,
167+
"enabled features:\n {}",
168+
activated
169+
.iter()
170+
.map(|s| s.to_string())
171+
.coalesce(|x, y| if x.len() + y.len() < 78 {
172+
Ok(format!("{x}, {y}"))
173+
} else {
174+
Err((x, y))
175+
})
176+
.into_iter()
177+
.format("\n ")
178+
)?
179+
}
180+
}
181+
anyhow::bail!(message.trim().to_owned());
132182
}
133183

184+
print_dep_table_msg(&mut options.config.shell(), &dep)?;
185+
134186
manifest.insert_into_table(&dep_table, &dep)?;
135187
manifest.gc_dep(dep.toml_key());
136188
}
Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,5 @@
11
Updating `dummy-registry` index
22
Adding your-face v99999.0.0 to dependencies.
3-
Features:
4-
+ noze
5-
- ears
6-
- eyes
7-
- mouth
8-
- nose
9-
error: unrecognized features: ["noze"]
3+
error: unrecognized feature for crate your-face: noze
4+
disabled features:
5+
ears, eyes, mouth, nose
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../add-basic.in
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
use cargo_test_support::compare::assert_ui;
2+
use cargo_test_support::prelude::*;
3+
use cargo_test_support::Project;
4+
5+
use crate::cargo_add::init_registry;
6+
use cargo_test_support::curr_dir;
7+
8+
#[cargo_test]
9+
fn features_unknown_no_features() {
10+
init_registry();
11+
let project = Project::from_template(curr_dir!().join("in"));
12+
let project_root = project.root();
13+
let cwd = &project_root;
14+
15+
snapbox::cmd::Command::cargo_ui()
16+
.arg("add")
17+
.arg_line("my-package --features noze")
18+
.current_dir(cwd)
19+
.assert()
20+
.code(101)
21+
.stdout_matches_path(curr_dir!().join("stdout.log"))
22+
.stderr_matches_path(curr_dir!().join("stderr.log"));
23+
24+
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
25+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
[workspace]
2+
3+
[package]
4+
name = "cargo-list-test-fixture"
5+
version = "0.0.0"
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
Updating `dummy-registry` index
2+
Adding my-package v99999.0.0 to dependencies.
3+
error: unrecognized feature for crate my-package: noze
4+
no features available for crate my-package

tests/testsuite/cargo_add/features_unknown_no_features/stdout.log

Whitespace-only changes.

tests/testsuite/cargo_add/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ mod features_multiple_occurrences;
2020
mod features_preserve;
2121
mod features_spaced_values;
2222
mod features_unknown;
23+
mod features_unknown_no_features;
2324
mod git;
2425
mod git_branch;
2526
mod git_conflicts_namever;

tests/testsuite/cargo_add/unknown_inherited_feature/in/dependency/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ version = "0.0.0"
66
default-base = []
77
default-test-base = []
88
default-merge-base = []
9-
default = ["default-base", "default-test-base", "default-merge-base"]
9+
long-feature-name-because-of-formatting-reasons = []
10+
default = [
11+
"default-base",
12+
"default-test-base",
13+
"default-merge-base",
14+
"long-feature-name-because-of-formatting-reasons",
15+
]
1016
test-base = []
1117
test = ["test-base", "default-test-base"]
1218
merge-base = []
1319
merge = ["merge-base", "default-merge-base"]
14-
unrelated = []
20+
unrelated = []

tests/testsuite/cargo_add/unknown_inherited_feature/out/dependency/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,15 @@ version = "0.0.0"
66
default-base = []
77
default-test-base = []
88
default-merge-base = []
9-
default = ["default-base", "default-test-base", "default-merge-base"]
9+
long-feature-name-because-of-formatting-reasons = []
10+
default = [
11+
"default-base",
12+
"default-test-base",
13+
"default-merge-base",
14+
"long-feature-name-because-of-formatting-reasons",
15+
]
1016
test-base = []
1117
test = ["test-base", "default-test-base"]
1218
merge-base = []
1319
merge = ["merge-base", "default-merge-base"]
14-
unrelated = []
20+
unrelated = []
Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,7 @@
11
Adding foo (workspace) to dependencies.
2-
Features as of v0.0.0:
3-
+ default-base
4-
+ default-merge-base
5-
+ default-test-base
6-
+ not_recognized
7-
+ test
8-
+ test-base
9-
- merge
10-
- merge-base
11-
- unrelated
12-
error: unrecognized features: ["not_recognized"]
2+
error: unrecognized feature for crate foo: not_recognized
3+
disabled features:
4+
merge, merge-base, unrelated
5+
enabled features:
6+
default-base, default-merge-base, default-test-base
7+
long-feature-name-because-of-formatting-reasons, test, test-base

0 commit comments

Comments
 (0)