Skip to content

Commit 807e114

Browse files
committed
Consider public dependencies when choosing a version in cargo add (#13038)
1 parent 75768e0 commit 807e114

File tree

3 files changed

+119
-7
lines changed

3 files changed

+119
-7
lines changed

src/cargo/ops/cargo_add/mod.rs

Lines changed: 107 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use toml_edit::Item as TomlItem;
2020

2121
use crate::CargoResult;
2222
use crate::GlobalContext;
23+
use crate::core::Feature;
2324
use crate::core::FeatureValue;
2425
use crate::core::Features;
2526
use crate::core::Package;
@@ -29,6 +30,7 @@ use crate::core::Summary;
2930
use crate::core::Workspace;
3031
use crate::core::dependency::DepKind;
3132
use crate::core::registry::PackageRegistry;
33+
use crate::ops::resolve_ws;
3234
use crate::sources::source::QueryKind;
3335
use crate::util::cache_lock::CacheLockMode;
3436
use crate::util::edit_distance;
@@ -38,6 +40,7 @@ use crate::util::toml_mut::dependency::Dependency;
3840
use crate::util::toml_mut::dependency::GitSource;
3941
use crate::util::toml_mut::dependency::MaybeWorkspace;
4042
use crate::util::toml_mut::dependency::PathSource;
43+
use crate::util::toml_mut::dependency::RegistrySource;
4144
use crate::util::toml_mut::dependency::Source;
4245
use crate::util::toml_mut::dependency::WorkspaceSource;
4346
use crate::util::toml_mut::manifest::DepTable;
@@ -471,6 +474,13 @@ fn resolve_dependency(
471474
src = src.set_version(v);
472475
}
473476
dependency = dependency.set_source(src);
477+
} else if let Some((registry, public_source)) =
478+
get_public_dependency(spec, manifest, ws, section, gctx, &dependency)?
479+
{
480+
if let Some(registry) = registry {
481+
dependency = dependency.set_registry(registry);
482+
}
483+
dependency = dependency.set_source(public_source);
474484
} else {
475485
let latest =
476486
get_latest_dependency(spec, &dependency, honor_rust_version, gctx, registry)?;
@@ -507,11 +517,107 @@ fn resolve_dependency(
507517
Ok(dependency)
508518
}
509519

520+
fn get_public_dependency(
521+
spec: &Package,
522+
manifest: &LocalManifest,
523+
ws: &Workspace<'_>,
524+
section: &DepTable,
525+
gctx: &GlobalContext,
526+
dependency: &Dependency,
527+
) -> CargoResult<Option<(Option<String>, Source)>> {
528+
if spec
529+
.manifest()
530+
.unstable_features()
531+
.require(Feature::public_dependency())
532+
.is_err()
533+
{
534+
return Ok(None);
535+
}
536+
537+
let (package_set, resolve) = resolve_ws(ws, true)?;
538+
539+
let mut latest = None;
540+
541+
for (_, path, dep) in manifest.get_dependencies(ws, ws.unstable_features()) {
542+
if path != *section {
543+
continue;
544+
}
545+
546+
let Some(mut dep) = dep.ok() else {
547+
continue;
548+
};
549+
550+
let dep = query_dependency(ws, gctx, &mut dep)?;
551+
let Some(dep_pkgid) = package_set
552+
.package_ids()
553+
.filter(|package_id| {
554+
package_id.name() == dep.package_name()
555+
&& dep.version_req().matches(package_id.version())
556+
})
557+
.max_by_key(|x| x.version())
558+
else {
559+
continue;
560+
};
561+
562+
let pkg_ids_and_reqs = resolve.deps(dep_pkgid).filter_map(|(id, deps)| {
563+
deps.iter()
564+
.find(|dep| {
565+
dep.is_public()
566+
&& dep.kind() == DepKind::Normal
567+
&& dep.package_name() == dependency.name.as_str()
568+
})
569+
.map(|dep| (id, dep.version_req().clone()))
570+
});
571+
572+
for (pkg_id, req) in pkg_ids_and_reqs {
573+
if let Some((old_pkg_id, _)) = &latest
574+
&& *old_pkg_id >= pkg_id
575+
{
576+
continue;
577+
}
578+
latest = Some((pkg_id, req))
579+
}
580+
}
581+
582+
let Some((pkg_id, version_req)) = latest else {
583+
return Ok(None);
584+
};
585+
586+
let source = pkg_id.source_id();
587+
if source.is_git() {
588+
Ok(Some((
589+
Option::<String>::None,
590+
Source::Git(GitSource::new(source.as_encoded_url().to_string())),
591+
)))
592+
} else if let Some(path) = source.local_path() {
593+
Ok(Some((None, Source::Path(PathSource::new(path)))))
594+
} else {
595+
let toml_source = match version_req {
596+
crate::util::OptVersionReq::Any => Source::Registry(RegistrySource::new(format!(
597+
"={}",
598+
pkg_id.version().to_string()
599+
))),
600+
crate::util::OptVersionReq::Req(version_req)
601+
| crate::util::OptVersionReq::Locked(_, version_req)
602+
| crate::util::OptVersionReq::Precise(_, version_req) => {
603+
Source::Registry(RegistrySource::new(version_req.to_string()))
604+
}
605+
};
606+
Ok(Some((
607+
source
608+
.alt_registry_key()
609+
.map(|x| x.to_owned())
610+
.filter(|_| !source.is_crates_io()),
611+
toml_source,
612+
)))
613+
}
614+
}
615+
510616
fn query_dependency(
511617
ws: &Workspace<'_>,
512618
gctx: &GlobalContext,
513619
dependency: &mut Dependency,
514-
) -> Result<crate::core::Dependency, anyhow::Error> {
620+
) -> CargoResult<crate::core::Dependency> {
515621
let query = dependency.query(gctx)?;
516622
let query = match query {
517623
MaybeWorkspace::Workspace(_workspace) => {

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ edition = "2015"
88

99
[dependencies]
1010
my-package = "0.1.0"
11-
my-package-dep = "0.2.0"
11+
my-package-dep = "^0.1.0"

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

Lines changed: 11 additions & 5 deletions
Loading

0 commit comments

Comments
 (0)