Skip to content

Commit 680a0f9

Browse files
committed
Auto merge of #12838 - epage:add, r=weihanglo
fix(add): Preserve more comments ### What does this PR try to resolve? This was fixed in killercup/cargo-edit#725 and I forgot to carry it over to here. I kept in some auto-formatting because there is little to preserve until the TOML 1.1 spec is out which will allow mult-line inline-tables which means there might be comments interspersed. We'll see which comes first, `cargo fmt` support for `Cargo.toml` or the 1.1 spec. Fixes #10850 ### How should we test and review this PR? First commit adds a test demonstrating the problem. The second makes a lot of noise that the third cleans up, so its a mixed bag as to which commit to look at. ### Additional information
2 parents 5225467 + 02dd917 commit 680a0f9

File tree

9 files changed

+99
-20
lines changed

9 files changed

+99
-20
lines changed

src/cargo/util/toml_mut/dependency.rs

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -464,17 +464,17 @@ impl Dependency {
464464
} else if let Some(table) = item.as_table_like_mut() {
465465
match &self.source {
466466
Some(Source::Registry(src)) => {
467-
table.insert("version", toml_edit::value(src.version.as_str()));
467+
overwrite_value(table, "version", src.version.as_str());
468468

469469
for key in ["path", "git", "branch", "tag", "rev", "workspace"] {
470470
table.remove(key);
471471
}
472472
}
473473
Some(Source::Path(src)) => {
474474
let relpath = path_field(crate_root, &src.path);
475-
table.insert("path", toml_edit::value(relpath));
475+
overwrite_value(table, "path", relpath);
476476
if let Some(r) = src.version.as_deref() {
477-
table.insert("version", toml_edit::value(r));
477+
overwrite_value(table, "version", r);
478478
} else {
479479
table.remove("version");
480480
}
@@ -484,24 +484,24 @@ impl Dependency {
484484
}
485485
}
486486
Some(Source::Git(src)) => {
487-
table.insert("git", toml_edit::value(src.git.as_str()));
487+
overwrite_value(table, "git", src.git.as_str());
488488
if let Some(branch) = src.branch.as_deref() {
489-
table.insert("branch", toml_edit::value(branch));
489+
overwrite_value(table, "branch", branch);
490490
} else {
491491
table.remove("branch");
492492
}
493493
if let Some(tag) = src.tag.as_deref() {
494-
table.insert("tag", toml_edit::value(tag));
494+
overwrite_value(table, "tag", tag);
495495
} else {
496496
table.remove("tag");
497497
}
498498
if let Some(rev) = src.rev.as_deref() {
499-
table.insert("rev", toml_edit::value(rev));
499+
overwrite_value(table, "rev", rev);
500500
} else {
501501
table.remove("rev");
502502
}
503503
if let Some(r) = src.version.as_deref() {
504-
table.insert("version", toml_edit::value(r));
504+
overwrite_value(table, "version", r);
505505
} else {
506506
table.remove("version");
507507
}
@@ -511,7 +511,7 @@ impl Dependency {
511511
}
512512
}
513513
Some(Source::Workspace(_)) => {
514-
table.insert("workspace", toml_edit::value(true));
514+
overwrite_value(table, "workspace", true);
515515
table.set_dotted(true);
516516
key.fmt();
517517
for key in [
@@ -533,7 +533,7 @@ impl Dependency {
533533
}
534534
if table.contains_key("version") {
535535
if let Some(r) = self.registry.as_deref() {
536-
table.insert("registry", toml_edit::value(r));
536+
overwrite_value(table, "registry", r);
537537
} else {
538538
table.remove("registry");
539539
}
@@ -542,11 +542,11 @@ impl Dependency {
542542
}
543543

544544
if self.rename.is_some() {
545-
table.insert("package", toml_edit::value(self.name.as_str()));
545+
overwrite_value(table, "package", self.name.as_str());
546546
}
547547
match self.default_features {
548548
Some(v) => {
549-
table.insert("default-features", toml_edit::value(v));
549+
overwrite_value(table, "default-features", v);
550550
}
551551
None => {
552552
table.remove("default-features");
@@ -564,29 +564,40 @@ impl Dependency {
564564
})
565565
.unwrap_or_default();
566566
features.extend(new_features.iter().map(|s| s.as_str()));
567-
let features = toml_edit::value(features.into_iter().collect::<toml_edit::Value>());
567+
let features = features.into_iter().collect::<toml_edit::Value>();
568568
table.set_dotted(false);
569-
table.insert("features", features);
569+
overwrite_value(table, "features", features);
570570
} else {
571571
table.remove("features");
572572
}
573573
match self.optional {
574574
Some(v) => {
575575
table.set_dotted(false);
576-
table.insert("optional", toml_edit::value(v));
576+
overwrite_value(table, "optional", v);
577577
}
578578
None => {
579579
table.remove("optional");
580580
}
581581
}
582-
583-
table.fmt();
584582
} else {
585583
unreachable!("Invalid dependency type: {}", item.type_name());
586584
}
587585
}
588586
}
589587

588+
fn overwrite_value(
589+
table: &mut dyn toml_edit::TableLike,
590+
key: &str,
591+
value: impl Into<toml_edit::Value>,
592+
) {
593+
let mut value = value.into();
594+
let existing = table.entry(key).or_insert_with(|| Default::default());
595+
if let Some(existing_value) = existing.as_value() {
596+
*value.decor_mut() = existing_value.decor().clone();
597+
}
598+
*existing = toml_edit::Item::Value(value);
599+
}
600+
590601
fn invalid_type(dep: &str, key: &str, actual: &str, expected: &str) -> anyhow::Error {
591602
anyhow::format_err!("Found {actual} for {key} when {expected} was expected for {dep}")
592603
}

src/cargo/util/toml_mut/manifest.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,13 +349,16 @@ impl LocalManifest {
349349
.get_key_value_mut(dep_key)
350350
{
351351
dep.update_toml(&crate_root, &mut dep_key, dep_item);
352+
if let Some(table) = dep_item.as_inline_table_mut() {
353+
// So long as we don't have `Cargo.toml` auto-formatting and inline-tables can only
354+
// be on one line, there isn't really much in the way of interesting formatting to
355+
// include (no comments), so let's just wipe it clean
356+
table.fmt();
357+
}
352358
} else {
353359
let new_dependency = dep.to_toml(&crate_root);
354360
table[dep_key] = new_dependency;
355361
}
356-
if let Some(t) = table.as_inline_table_mut() {
357-
t.fmt()
358-
}
359362

360363
Ok(())
361364
}

tests/testsuite/cargo_add/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ mod path_dev;
9999
mod path_inferred_name;
100100
mod path_inferred_name_conflicts_full_feature;
101101
mod path_normalized_name;
102+
mod preserve_dep_std_table;
102103
mod preserve_features_table;
103104
mod preserve_sorted;
104105
mod preserve_unsorted;
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
[package]
2+
name = "xxx"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies.your-face]
9+
# Leading version
10+
version = "99999.0.0" # Trailing version
11+
# Leading optional
12+
optional = true # Trailing optional
13+
# Leading features
14+
features = [] # Trailing features

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

Whitespace-only changes.
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
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+
cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
11+
.feature("nose", &[])
12+
.feature("mouth", &[])
13+
.feature("eyes", &[])
14+
.feature("ears", &[])
15+
.publish();
16+
17+
let project = Project::from_template(curr_dir!().join("in"));
18+
let project_root = project.root();
19+
let cwd = &project_root;
20+
21+
snapbox::cmd::Command::cargo_ui()
22+
.arg("add")
23+
.arg_line("your-face --no-optional")
24+
.current_dir(cwd)
25+
.assert()
26+
.success()
27+
.stdout_matches_path(curr_dir!().join("stdout.log"))
28+
.stderr_matches_path(curr_dir!().join("stderr.log"));
29+
30+
assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
31+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "xxx"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies.your-face]
9+
# Leading version
10+
version = "99999.0.0" # Trailing version
11+
# Leading features
12+
features = [] # Trailing features
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
Updating `dummy-registry` index
2+
Adding your-face v99999.0.0 to dependencies.
3+
Features:
4+
- ears
5+
- eyes
6+
- mouth
7+
- nose

tests/testsuite/cargo_add/preserve_dep_std_table/stdout.log

Whitespace-only changes.

0 commit comments

Comments
 (0)