Skip to content

Commit acd05f0

Browse files
dohseepage
authored andcommitted
fix(add): Lookup existing dependencies with fuzzy logic
Fixes #10680 Fixes #13702
1 parent c3e54e3 commit acd05f0

File tree

5 files changed

+48
-11
lines changed

5 files changed

+48
-11
lines changed

src/cargo/ops/cargo_add/mod.rs

Lines changed: 39 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -361,7 +361,9 @@ fn resolve_dependency(
361361
};
362362
selected_dep = populate_dependency(selected_dep, arg);
363363

364-
let old_dep = get_existing_dependency(manifest, selected_dep.toml_key(), section)?;
364+
let lookup = |dep_key: &_| get_existing_dependency(manifest, dep_key, section);
365+
let old_dep = fuzzy_lookup(&mut selected_dep, lookup, gctx)?;
366+
365367
let mut dependency = if let Some(mut old_dep) = old_dep.clone() {
366368
if old_dep.name != selected_dep.name {
367369
// Assuming most existing keys are not relevant when the package changes
@@ -383,7 +385,8 @@ fn resolve_dependency(
383385
if dependency.source().is_none() {
384386
// Checking for a workspace dependency happens first since a member could be specified
385387
// in the workspace dependencies table as a dependency
386-
if let Some(_dep) = find_workspace_dep(dependency.toml_key(), ws.root_manifest()).ok() {
388+
let lookup = |toml_key: &_| Ok(find_workspace_dep(toml_key, ws.root_manifest()).ok());
389+
if let Some(_dep) = fuzzy_lookup(&mut dependency, lookup, gctx)? {
387390
dependency = dependency.set_source(WorkspaceSource::new());
388391
} else if let Some(package) = ws.members().find(|p| p.name().as_str() == dependency.name) {
389392
// Only special-case workspaces when the user doesn't provide any extra
@@ -449,6 +452,40 @@ fn resolve_dependency(
449452
Ok(dependency)
450453
}
451454

455+
fn fuzzy_lookup(
456+
dependency: &mut Dependency,
457+
lookup: impl Fn(&str) -> CargoResult<Option<Dependency>>,
458+
gctx: &GlobalContext,
459+
) -> CargoResult<Option<Dependency>> {
460+
if let Some(rename) = dependency.rename() {
461+
return lookup(rename);
462+
}
463+
464+
for name_permutation in [
465+
dependency.name.clone(),
466+
dependency.name.replace('-', "_"),
467+
dependency.name.replace('_', "-"),
468+
] {
469+
let Some(dep) = lookup(&name_permutation)? else {
470+
continue;
471+
};
472+
473+
if dependency.name != name_permutation {
474+
if !matches!(dep.source, Some(Source::Registry(_))) {
475+
continue;
476+
}
477+
gctx.shell().warn(format!(
478+
"translating `{}` to `{}`",
479+
dependency.name, &name_permutation,
480+
))?;
481+
dependency.name = name_permutation;
482+
}
483+
return Ok(Some(dep));
484+
}
485+
486+
Ok(None)
487+
}
488+
452489
/// When { workspace = true } you cannot define other keys that configure
453490
/// the source of the dependency such as `version`, `registry`, `registry-index`,
454491
/// `path`, `git`, `branch`, `tag`, `rev`, or `package`. You can also not define

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@ version = "0.0.0"
44
edition = "2015"
55

66
[dependencies]
7-
fuzzy_dependency = "1.0.0"
7+
fuzzy_dependency.workspace = true

tests/testsuite/cargo_add/detect_workspace_inherit_fuzzy/stderr.term.svg

Lines changed: 3 additions & 3 deletions
Loading

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ version = "0.0.0"
66
edition = "2015"
77

88
[dependencies]
9-
your_face = { version = "99999.0.0" }
9+
your_face = { version = "99999.0.0", features = ["eyes"] }

tests/testsuite/cargo_add/features_fuzzy/stderr.term.svg

Lines changed: 4 additions & 4 deletions
Loading

0 commit comments

Comments
 (0)