Skip to content

Commit

Permalink
WIP: fix(add): Ensure comments are preserved
Browse files Browse the repository at this point in the history
  • Loading branch information
epage committed Jul 13, 2022
1 parent b78f918 commit 3e8384d
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 17 deletions.
51 changes: 34 additions & 17 deletions src/cargo/ops/cargo_add/dependency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -490,17 +490,17 @@ impl Dependency {
} else if let Some(table) = item.as_table_like_mut() {
match &self.source {
Some(Source::Registry(src)) => {
table.insert("version", toml_edit::value(src.version.as_str()));
overwrite_value(table, "version", src.version.as_str());

for key in ["path", "git", "branch", "tag", "rev", "workspace"] {
table.remove(key);
}
}
Some(Source::Path(src)) => {
let relpath = path_field(crate_root, &src.path);
table.insert("path", toml_edit::value(relpath));
overwrite_value(table, "path", relpath);
if let Some(r) = src.version.as_deref() {
table.insert("version", toml_edit::value(r));
overwrite_value(table, "version", r);
} else {
table.remove("version");
}
Expand All @@ -510,24 +510,24 @@ impl Dependency {
}
}
Some(Source::Git(src)) => {
table.insert("git", toml_edit::value(src.git.as_str()));
overwrite_value(table, "git", src.git.as_str());
if let Some(branch) = src.branch.as_deref() {
table.insert("branch", toml_edit::value(branch));
overwrite_value(table, "branch", branch);
} else {
table.remove("branch");
}
if let Some(tag) = src.tag.as_deref() {
table.insert("tag", toml_edit::value(tag));
overwrite_value(table, "tag", tag);
} else {
table.remove("tag");
}
if let Some(rev) = src.rev.as_deref() {
table.insert("rev", toml_edit::value(rev));
overwrite_value(table, "rev", rev);
} else {
table.remove("rev");
}
if let Some(r) = src.version.as_deref() {
table.insert("version", toml_edit::value(r));
overwrite_value(table, "version", r);
} else {
table.remove("version");
}
Expand All @@ -537,7 +537,7 @@ impl Dependency {
}
}
Some(Source::Workspace(_)) => {
table.insert("workspace", toml_edit::value(true));
overwrite_value(table, "workspace", true);
table.set_dotted(true);
key.fmt();
for key in [
Expand All @@ -559,7 +559,7 @@ impl Dependency {
}
if table.contains_key("version") {
if let Some(r) = self.registry.as_deref() {
table.insert("registry", toml_edit::value(r));
overwrite_value(table, "registry", r);
} else {
table.remove("registry");
}
Expand All @@ -568,11 +568,11 @@ impl Dependency {
}

if self.rename.is_some() {
table.insert("package", toml_edit::value(self.name.as_str()));
overwrite_value(table, "package", self.name.as_str());
}
match self.default_features {
Some(v) => {
table.insert("default-features", toml_edit::value(v));
overwrite_value(table, "default-features", v);
}
None => {
table.remove("default-features");
Expand All @@ -590,29 +590,46 @@ impl Dependency {
})
.unwrap_or_default();
features.extend(new_features.iter().map(|s| s.as_str()));
let features = toml_edit::value(features.into_iter().collect::<toml_edit::Value>());
let features = features.into_iter().collect::<toml_edit::Value>();
table.set_dotted(false);
table.insert("features", features);
overwrite_value(table, "features", features);
} else {
table.remove("features");
}
match self.optional {
Some(v) => {
table.set_dotted(false);
table.insert("optional", toml_edit::value(v));
overwrite_value(table, "optional", v);
}
None => {
table.remove("optional");
}
}

table.fmt();
} else {
unreachable!("Invalid dependency type: {}", item.type_name());
}
}
}

/// Overwrite a value while preserving the original formatting
fn overwrite_value(
table: &mut dyn toml_edit::TableLike,
key: &str,
value: impl Into<toml_edit::Value>,
) {
let mut value = value.into();

let existing = table.entry(key).or_insert(toml_edit::Item::None);
let existing_decor = existing
.as_value()
.map(|v| v.decor().clone())
.unwrap_or_default();

*value.decor_mut() = existing_decor;

*existing = toml_edit::Item::Value(value);
}

fn invalid_type(dep: &str, key: &str, actual: &str, expected: &str) -> anyhow::Error {
anyhow::format_err!("Found {actual} for {key} when {expected} was expected for {dep}")
}
Expand Down
1 change: 1 addition & 0 deletions tests/testsuite/cargo_add/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ mod overwrite_optional_with_no_optional;
mod overwrite_path_noop;
mod overwrite_path_with_version;
mod overwrite_preserves_inline_table;
mod overwrite_preserves_std_table;
mod overwrite_rename_with_no_rename;
mod overwrite_rename_with_rename;
mod overwrite_rename_with_rename_noop;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[workspace]

[package]
name = "cargo-list-test-fixture"
version = "0.0.0"

[dependencies.your-face]
version="99999.0.0" # Hello world
features=["eyes"] # Goodbye moon
Empty file.
25 changes: 25 additions & 0 deletions tests/testsuite/cargo_add/overwrite_preserves_std_table/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use cargo_test_support::compare::assert_ui;
use cargo_test_support::prelude::*;
use cargo_test_support::Project;

use crate::cargo_add::init_registry;
use cargo_test_support::curr_dir;

#[cargo_test]
fn overwrite_preserves_std_table() {
init_registry();
let project = Project::from_template(curr_dir!().join("in"));
let project_root = project.root();
let cwd = &project_root;

snapbox::cmd::Command::cargo_ui()
.arg("add")
.arg_line("your-face --features nose")
.current_dir(cwd)
.assert()
.success()
.stdout_matches_path(curr_dir!().join("stdout.log"))
.stderr_matches_path(curr_dir!().join("stderr.log"));

assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[workspace]

[package]
name = "cargo-list-test-fixture"
version = "0.0.0"

[dependencies.your-face]
version="99999.0.0" # Hello world
features=["eyes", "nose"] # Goodbye moon
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
Updating `dummy-registry` index
Adding your-face v99999.0.0 to dependencies.
Features:
+ eyes
+ nose
- ears
- mouth
Empty file.

0 comments on commit 3e8384d

Please sign in to comment.