Skip to content

Commit b451f15

Browse files
committed
Fix redundant index fetching
1 parent 9d9ca52 commit b451f15

File tree

1 file changed

+97
-59
lines changed

1 file changed

+97
-59
lines changed

src/cargo/core/resolver/encode.rs

+97-59
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ impl EncodableResolve {
154154
/// primary uses is to be used with `resolve_with_previous` to guide the
155155
/// resolver to create a complete Resolve.
156156
pub fn into_resolve(self, original: &str, ws: &Workspace<'_>) -> CargoResult<Resolve> {
157-
let path_deps = build_path_deps(ws)?;
157+
let path_deps = PathDeps::from_workspace(ws)?;
158158
let mut checksums = HashMap::new();
159159

160160
let mut version = match self.version {
@@ -202,14 +202,18 @@ impl EncodableResolve {
202202
if !all_pkgs.insert(enc_id.clone()) {
203203
anyhow::bail!("package `{}` is specified twice in the lockfile", pkg.name);
204204
}
205-
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
205+
let id = match pkg.source.as_deref().copied().or_else(|| {
206+
path_deps
207+
.get_path_dep(&pkg.name, &pkg.version)
208+
.map(|package_id| package_id.source_id())
209+
}) {
206210
// We failed to find a local package in the workspace.
207211
// It must have been removed and should be ignored.
208212
None => {
209213
debug!("path dependency now missing {} v{}", pkg.name, pkg.version);
210214
continue;
211215
}
212-
Some(&source) => PackageId::try_new(&pkg.name, &pkg.version, source)?,
216+
Some(source) => PackageId::try_new(&pkg.name, &pkg.version, source)?,
213217
};
214218

215219
// If a package has a checksum listed directly on it then record
@@ -364,8 +368,12 @@ impl EncodableResolve {
364368

365369
let mut unused_patches = Vec::new();
366370
for pkg in self.patch.unused {
367-
let id = match pkg.source.as_deref().or_else(|| path_deps.get(&pkg.name)) {
368-
Some(&src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
371+
let id = match pkg.source.as_deref().copied().or_else(|| {
372+
path_deps
373+
.get_path_dep(&pkg.name, &pkg.version)
374+
.map(|package_id| package_id.source_id())
375+
}) {
376+
Some(src) => PackageId::try_new(&pkg.name, &pkg.version, src)?,
369377
None => continue,
370378
};
371379
unused_patches.push(id);
@@ -408,68 +416,98 @@ impl EncodableResolve {
408416
}
409417
}
410418

411-
fn build_path_deps(ws: &Workspace<'_>) -> CargoResult<HashMap<String, SourceId>> {
412-
// If a crate is **not** a path source, then we're probably in a situation
413-
// such as `cargo install` with a lock file from a remote dependency. In
414-
// that case we don't need to fixup any path dependencies (as they're not
415-
// actually path dependencies any more), so we ignore them.
416-
let members = ws
417-
.members()
418-
.filter(|p| p.package_id().source_id().is_path())
419-
.collect::<Vec<_>>();
420-
421-
let mut ret = HashMap::new();
422-
let mut visited = HashSet::new();
423-
for member in members.iter() {
424-
ret.insert(
425-
member.package_id().name().to_string(),
426-
member.package_id().source_id(),
427-
);
428-
visited.insert(member.package_id().source_id());
429-
}
430-
for member in members.iter() {
431-
build_pkg(member, ws, &mut ret, &mut visited);
419+
struct PathDeps {
420+
path_deps: HashMap<String, Vec<PackageId>>,
421+
}
422+
423+
impl PathDeps {
424+
/// Get a best-effort path dependency with given constraints.
425+
///
426+
/// If no exact version match, pickup a random version for patch updating trial
427+
fn get_path_dep(&self, name: &str, version: &str) -> Option<&PackageId> {
428+
let pkg_version = semver::Version::parse(version).ok()?;
429+
self.path_deps.get(name).and_then(|versions| {
430+
versions
431+
.iter()
432+
.find(|package_id| {
433+
package_id.version().cmp_precedence(&pkg_version) == std::cmp::Ordering::Equal
434+
})
435+
.or_else(|| versions.last())
436+
})
432437
}
433-
for deps in ws.root_patch()?.values() {
434-
for dep in deps {
438+
439+
/// Return all path dependencies recursively in given workspace
440+
fn from_workspace(ws: &Workspace<'_>) -> CargoResult<Self> {
441+
// If a crate is **not** a path source, then we're probably in a situation
442+
// such as `cargo install` with a lock file from a remote dependency. In
443+
// that case we don't need to fixup any path dependencies (as they're not
444+
// actually path dependencies any more), so we ignore them.
445+
let members = ws
446+
.members()
447+
.filter(|p| p.package_id().source_id().is_path())
448+
.collect::<Vec<_>>();
449+
450+
let mut ret = HashSet::new();
451+
let mut visited = HashSet::new();
452+
for member in members.iter() {
453+
ret.insert(member.package_id());
454+
visited.insert(member.package_id().source_id());
455+
}
456+
for member in members.iter() {
457+
build_pkg(member, ws, &mut ret, &mut visited);
458+
}
459+
for deps in ws.root_patch()?.values() {
460+
for dep in deps {
461+
build_dep(dep, ws, &mut ret, &mut visited);
462+
}
463+
}
464+
for (_, dep) in ws.root_replace() {
435465
build_dep(dep, ws, &mut ret, &mut visited);
436466
}
437-
}
438-
for (_, dep) in ws.root_replace() {
439-
build_dep(dep, ws, &mut ret, &mut visited);
440-
}
441467

442-
return Ok(ret);
468+
let path_deps = {
469+
// Mapping from package name to package ids
470+
let mut deps: HashMap<String, Vec<PackageId>> = HashMap::new();
471+
for package_id in ret {
472+
deps.entry(package_id.name().to_string())
473+
.or_default()
474+
.push(package_id);
475+
}
476+
deps
477+
};
478+
479+
return Ok(Self { path_deps });
443480

444-
fn build_pkg(
445-
pkg: &Package,
446-
ws: &Workspace<'_>,
447-
ret: &mut HashMap<String, SourceId>,
448-
visited: &mut HashSet<SourceId>,
449-
) {
450-
for dep in pkg.dependencies() {
451-
build_dep(dep, ws, ret, visited);
481+
fn build_pkg(
482+
pkg: &Package,
483+
ws: &Workspace<'_>,
484+
ret: &mut HashSet<PackageId>,
485+
visited: &mut HashSet<SourceId>,
486+
) {
487+
for dep in pkg.dependencies() {
488+
build_dep(dep, ws, ret, visited);
489+
}
452490
}
453-
}
454491

455-
fn build_dep(
456-
dep: &Dependency,
457-
ws: &Workspace<'_>,
458-
ret: &mut HashMap<String, SourceId>,
459-
visited: &mut HashSet<SourceId>,
460-
) {
461-
let id = dep.source_id();
462-
if visited.contains(&id) || !id.is_path() {
463-
return;
492+
fn build_dep(
493+
dep: &Dependency,
494+
ws: &Workspace<'_>,
495+
ret: &mut HashSet<PackageId>,
496+
visited: &mut HashSet<SourceId>,
497+
) {
498+
let id = dep.source_id();
499+
if visited.contains(&id) || !id.is_path() {
500+
return;
501+
}
502+
let path = match id.url().to_file_path() {
503+
Ok(p) => p.join("Cargo.toml"),
504+
Err(_) => return,
505+
};
506+
let Ok(pkg) = ws.load(&path) else { return };
507+
ret.insert(pkg.package_id());
508+
visited.insert(pkg.package_id().source_id());
509+
build_pkg(&pkg, ws, ret, visited);
464510
}
465-
let path = match id.url().to_file_path() {
466-
Ok(p) => p.join("Cargo.toml"),
467-
Err(_) => return,
468-
};
469-
let Ok(pkg) = ws.load(&path) else { return };
470-
ret.insert(pkg.name().to_string(), pkg.package_id().source_id());
471-
visited.insert(pkg.package_id().source_id());
472-
build_pkg(&pkg, ws, ret, visited);
473511
}
474512
}
475513

0 commit comments

Comments
 (0)