Skip to content

Commit 248d47d

Browse files
committed
Fix issue-11010
1 parent 35ea623 commit 248d47d

File tree

21 files changed

+145
-0
lines changed

21 files changed

+145
-0
lines changed

src/cargo/ops/cargo_add/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ use std::collections::BTreeSet;
77
use std::collections::VecDeque;
88
use std::fmt::Write;
99
use std::path::Path;
10+
use std::str::FromStr;
1011

1112
use anyhow::Context as _;
1213
use cargo_util::paths;
@@ -196,6 +197,13 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
196197
print_dep_table_msg(&mut options.config.shell(), &dep)?;
197198

198199
manifest.insert_into_table(&dep_table, &dep)?;
200+
if dep.optional == Some(true) {
201+
let is_namespaced_features_supported =
202+
check_rust_version_for_optional_dependency(options.spec.rust_version())?;
203+
if is_namespaced_features_supported {
204+
manifest.explicit_activate_optional_dependency_as_feature(&dep)?;
205+
}
206+
}
199207
manifest.gc_dep(dep.toml_key());
200208
}
201209

@@ -469,6 +477,26 @@ fn check_invalid_ws_keys(toml_key: &str, arg: &DepOp) -> CargoResult<()> {
469477
Ok(())
470478
}
471479

480+
/// When the `--optional` option is added using `cargo add`, we need to
481+
/// check the current rust-version. As the `dep:` syntax is only avaliable
482+
/// starting with Rust 1.60.0
483+
///
484+
/// `true` means that the rust-version is None or the rust-version is higher
485+
/// than the version needed.
486+
///
487+
/// Note: Previous versions can only use the implicit feature name.
488+
fn check_rust_version_for_optional_dependency(
489+
rust_version: Option<&RustVersion>,
490+
) -> CargoResult<bool> {
491+
match rust_version {
492+
Some(version) => {
493+
let syntax_support_version = RustVersion::from_str("1.60.0")?;
494+
Ok(&syntax_support_version <= version)
495+
}
496+
None => Ok(true),
497+
}
498+
}
499+
472500
/// Provide the existing dependency for the target table
473501
///
474502
/// If it doesn't exist but exists in another table, let's use that as most likely users

src/cargo/util/toml_mut/manifest.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -363,6 +363,20 @@ impl LocalManifest {
363363
Ok(())
364364
}
365365

366+
/// Add feature entry to a Cargo.toml.
367+
pub fn explicit_activate_optional_dependency_as_feature(&mut self, dep: &Dependency) -> CargoResult<()> {
368+
let dep_key = dep.toml_key();
369+
// Check whether `dep:<dep>` is defined in the [features] section.
370+
if !self.is_explicit_dep_activation(dep_key) {
371+
let table = self.get_table_mut(&vec![String::from("features")])?;
372+
let dep_name = dep.rename.as_deref().unwrap_or(&dep.name);
373+
let new_feature: toml_edit::Value = [format!("dep:{dep_name}")].iter().collect();
374+
table[dep_key] = toml_edit::value(new_feature);
375+
}
376+
377+
Ok(())
378+
}
379+
366380
/// Remove entry from a Cargo.toml.
367381
pub fn remove_from_table(&mut self, table_path: &[String], name: &str) -> CargoResult<()> {
368382
let parent_table = self.get_table_mut(table_path)?;

tests/testsuite/cargo_add/change_rename_target/out/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
some-package = { package = "my-package2", version = "99999.0.0", optional = true }
9+
10+
[features]
11+
some-package = ["dep:some-package"]

tests/testsuite/cargo_add/detect_workspace_inherit_optional/out/primary/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ version = "0.0.0"
44

55
[dependencies]
66
foo = { workspace = true, optional = true }
7+
8+
[features]
9+
foo = ["dep:foo"]

tests/testsuite/cargo_add/optional/out/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ version = "0.0.0"
77
[dependencies]
88
my-package1 = { version = "99999.0.0", optional = true }
99
my-package2 = { version = "0.4.1", optional = true }
10+
11+
[features]
12+
my-package1 = ["dep:my-package1"]
13+
my-package2 = ["dep:my-package2"]

tests/testsuite/cargo_add/overwrite_git_with_path/out/primary/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
cargo-list-test-fixture-dependency = { optional = true, path = "../dependency", version = "0.0.0" }
9+
10+
[features]
11+
cargo-list-test-fixture-dependency = ["dep:cargo-list-test-fixture-dependency"]

tests/testsuite/cargo_add/overwrite_inherit_optional_noop/out/primary/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ version = "0.0.0"
44

55
[dependencies]
66
foo = { workspace = true, optional = true }
7+
8+
[features]
9+
foo = ["dep:foo"]

tests/testsuite/cargo_add/overwrite_name_noop/out/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ version = "0.0.0"
77

88
[dependencies]
99
your-face = { version = "0.0.0", path = "dependency", optional = true, default-features = false, features = ["nose", "mouth"], registry = "alternative" }
10+
11+
[features]
12+
your-face = ["dep:your-face"]

tests/testsuite/cargo_add/overwrite_no_optional_with_optional/out/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ version = "0.0.0"
77
[dependencies]
88
my-package1 = { version = "99999.0.0", optional = true }
99
my-package2 = { version = "0.4.1", optional = true }
10+
11+
[features]
12+
my-package1 = ["dep:my-package1"]
13+
my-package2 = ["dep:my-package2"]

tests/testsuite/cargo_add/overwrite_optional/out/Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,7 @@ version = "0.0.0"
77
[dependencies]
88
my-package1 = { version = "99999.0.0", optional = true }
99
my-package2 = { version = "0.4.1", optional = true }
10+
11+
[features]
12+
my-package1 = ["dep:my-package1"]
13+
my-package2 = ["dep:my-package2"]
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[workspace]
2+
3+
[package]
4+
name = "cargo-list-test-fixture"
5+
version = "0.0.0"
6+
7+
[dependencies]
8+
my-package1 = { version = "99999.0.0", optional = true }
9+
10+
[features]
11+
default = ["dep:my-package1"]

tests/testsuite/cargo_add/overwrite_optional_with_optional/in/src/lib.rs

Whitespace-only changes.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
use cargo_test_support::compare::assert_ui;
2+
use cargo_test_support::prelude::*;
3+
use cargo_test_support::Project;
4+
5+
use cargo_test_support::curr_dir;
6+
7+
#[cargo_test]
8+
fn case() {
9+
cargo_test_support::registry::init();
10+
for ver in [
11+
"0.1.1+my-package",
12+
"0.2.0+my-package",
13+
"0.2.3+my-package",
14+
"0.4.1+my-package",
15+
"20.0.0+my-package",
16+
"99999.0.0+my-package",
17+
"99999.0.0-alpha.1+my-package",
18+
] {
19+
cargo_test_support::registry::Package::new("my-package1", ver).publish();
20+
}
21+
22+
let project = Project::from_template(curr_dir!().join("in"));
23+
let project_root = project.root();
24+
let cwd = &project_root;
25+
26+
snapbox::cmd::Command::cargo_ui()
27+
.arg("add")
28+
.arg_line("my-package1 --optional")
29+
.current_dir(cwd)
30+
.assert()
31+
.success()
32+
.stdout_matches_path(curr_dir!().join("stdout.log"))
33+
.stderr_matches_path(curr_dir!().join("stderr.log"));
34+
35+
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
36+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[workspace]
2+
3+
[package]
4+
name = "cargo-list-test-fixture"
5+
version = "0.0.0"
6+
7+
[dependencies]
8+
my-package1 = { version = "99999.0.0", optional = true }
9+
10+
[features]
11+
default = ["dep:my-package1"]
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Updating `dummy-registry` index
2+
Adding my-package1 v99999.0.0 to optional dependencies.
3+
Adding my-package2 v0.4.1 to optional dependencies.

tests/testsuite/cargo_add/overwrite_optional_with_optional/stdout.log

Whitespace-only changes.

tests/testsuite/cargo_add/overwrite_path_noop/out/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,6 @@ version = "0.0.0"
77

88
[dependencies]
99
your-face = { version = "0.0.0", path = "dependency", optional = true, default-features = false, features = ["nose", "mouth"], registry = "alternative" }
10+
11+
[features]
12+
your-face = ["dep:your-face"]

tests/testsuite/cargo_add/overwrite_path_with_version/out/primary/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
cargo-list-test-fixture-dependency = { optional = true, version = "20.0" }
9+
10+
[features]
11+
cargo-list-test-fixture-dependency = ["dep:cargo-list-test-fixture-dependency"]

tests/testsuite/cargo_add/overwrite_rename_with_rename_noop/out/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
a1 = { package = "versioned-package", version = "0.1.1", optional = true }
9+
10+
[features]
11+
a1 = ["dep:a1"]

tests/testsuite/cargo_add/overwrite_version_with_git/out/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
versioned-package = { version = "0.3.0", optional = true, git = "[ROOTURL]/versioned-package" }
9+
10+
[features]
11+
versioned-package = ["dep:versioned-package"]

tests/testsuite/cargo_add/overwrite_version_with_path/out/primary/Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ version = "0.0.0"
66

77
[dependencies]
88
cargo-list-test-fixture-dependency = { version = "0.0.0", optional = true, path = "../dependency" }
9+
10+
[features]
11+
cargo-list-test-fixture-dependency = ["dep:cargo-list-test-fixture-dependency"]

0 commit comments

Comments
 (0)