Skip to content

Commit 95de3a1

Browse files
committed
move RegistryQueryer to a dedicated mod
1 parent 77a7e3f commit 95de3a1

File tree

4 files changed

+183
-185
lines changed

4 files changed

+183
-185
lines changed

src/cargo/core/resolver/context.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ use crate::core::{Dependency, FeatureValue, PackageId, SourceId, Summary};
1212
use crate::util::CargoResult;
1313
use crate::util::Graph;
1414

15+
use super::dep_cache::RegistryQueryer;
1516
use super::errors::ActivateResult;
16-
use super::types::{ConflictMap, ConflictReason, DepInfo, Method, RegistryQueryer};
17+
use super::types::{ConflictMap, ConflictReason, DepInfo, Method};
1718

1819
pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
1920
pub use super::encode::{Metadata, WorkspaceResolve};

src/cargo/core/resolver/dep_cache.rs

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
use std::cmp::Ordering;
2+
use std::collections::{HashMap, HashSet};
3+
use std::rc::Rc;
4+
5+
use log::debug;
6+
7+
use crate::core::{Dependency, PackageId, PackageIdSpec, Registry};
8+
use crate::util::errors::CargoResult;
9+
10+
use crate::core::resolver::types::Candidate;
11+
12+
pub struct RegistryQueryer<'a> {
13+
pub registry: &'a mut (dyn Registry + 'a),
14+
replacements: &'a [(PackageIdSpec, Dependency)],
15+
try_to_use: &'a HashSet<PackageId>,
16+
// If set the list of dependency candidates will be sorted by minimal
17+
// versions first. That allows `cargo update -Z minimal-versions` which will
18+
// specify minimum dependency versions to be used.
19+
minimal_versions: bool,
20+
cache: HashMap<Dependency, Rc<Vec<Candidate>>>,
21+
used_replacements: HashMap<PackageId, PackageId>,
22+
}
23+
24+
impl<'a> RegistryQueryer<'a> {
25+
pub fn new(
26+
registry: &'a mut dyn Registry,
27+
replacements: &'a [(PackageIdSpec, Dependency)],
28+
try_to_use: &'a HashSet<PackageId>,
29+
minimal_versions: bool,
30+
) -> Self {
31+
RegistryQueryer {
32+
registry,
33+
replacements,
34+
try_to_use,
35+
minimal_versions,
36+
cache: HashMap::new(),
37+
used_replacements: HashMap::new(),
38+
}
39+
}
40+
41+
pub fn used_replacement_for(&self, p: PackageId) -> Option<(PackageId, PackageId)> {
42+
self.used_replacements.get(&p).map(|&r| (p, r))
43+
}
44+
45+
/// Queries the `registry` to return a list of candidates for `dep`.
46+
///
47+
/// This method is the location where overrides are taken into account. If
48+
/// any candidates are returned which match an override then the override is
49+
/// applied by performing a second query for what the override should
50+
/// return.
51+
pub fn query(&mut self, dep: &Dependency) -> CargoResult<Rc<Vec<Candidate>>> {
52+
if let Some(out) = self.cache.get(dep).cloned() {
53+
return Ok(out);
54+
}
55+
56+
let mut ret = Vec::new();
57+
self.registry.query(
58+
dep,
59+
&mut |s| {
60+
ret.push(Candidate {
61+
summary: s,
62+
replace: None,
63+
});
64+
},
65+
false,
66+
)?;
67+
for candidate in ret.iter_mut() {
68+
let summary = &candidate.summary;
69+
70+
let mut potential_matches = self
71+
.replacements
72+
.iter()
73+
.filter(|&&(ref spec, _)| spec.matches(summary.package_id()));
74+
75+
let &(ref spec, ref dep) = match potential_matches.next() {
76+
None => continue,
77+
Some(replacement) => replacement,
78+
};
79+
debug!(
80+
"found an override for {} {}",
81+
dep.package_name(),
82+
dep.version_req()
83+
);
84+
85+
let mut summaries = self.registry.query_vec(dep, false)?.into_iter();
86+
let s = summaries.next().ok_or_else(|| {
87+
failure::format_err!(
88+
"no matching package for override `{}` found\n\
89+
location searched: {}\n\
90+
version required: {}",
91+
spec,
92+
dep.source_id(),
93+
dep.version_req()
94+
)
95+
})?;
96+
let summaries = summaries.collect::<Vec<_>>();
97+
if !summaries.is_empty() {
98+
let bullets = summaries
99+
.iter()
100+
.map(|s| format!(" * {}", s.package_id()))
101+
.collect::<Vec<_>>();
102+
failure::bail!(
103+
"the replacement specification `{}` matched \
104+
multiple packages:\n * {}\n{}",
105+
spec,
106+
s.package_id(),
107+
bullets.join("\n")
108+
);
109+
}
110+
111+
// The dependency should be hard-coded to have the same name and an
112+
// exact version requirement, so both of these assertions should
113+
// never fail.
114+
assert_eq!(s.version(), summary.version());
115+
assert_eq!(s.name(), summary.name());
116+
117+
let replace = if s.source_id() == summary.source_id() {
118+
debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
119+
None
120+
} else {
121+
Some(s)
122+
};
123+
let matched_spec = spec.clone();
124+
125+
// Make sure no duplicates
126+
if let Some(&(ref spec, _)) = potential_matches.next() {
127+
failure::bail!(
128+
"overlapping replacement specifications found:\n\n \
129+
* {}\n * {}\n\nboth specifications match: {}",
130+
matched_spec,
131+
spec,
132+
summary.package_id()
133+
);
134+
}
135+
136+
for dep in summary.dependencies() {
137+
debug!("\t{} => {}", dep.package_name(), dep.version_req());
138+
}
139+
if let Some(r) = &replace {
140+
self.used_replacements
141+
.insert(summary.package_id(), r.package_id());
142+
}
143+
144+
candidate.replace = replace;
145+
}
146+
147+
// When we attempt versions for a package we'll want to do so in a
148+
// sorted fashion to pick the "best candidates" first. Currently we try
149+
// prioritized summaries (those in `try_to_use`) and failing that we
150+
// list everything from the maximum version to the lowest version.
151+
ret.sort_unstable_by(|a, b| {
152+
let a_in_previous = self.try_to_use.contains(&a.summary.package_id());
153+
let b_in_previous = self.try_to_use.contains(&b.summary.package_id());
154+
let previous_cmp = a_in_previous.cmp(&b_in_previous).reverse();
155+
match previous_cmp {
156+
Ordering::Equal => {
157+
let cmp = a.summary.version().cmp(b.summary.version());
158+
if self.minimal_versions {
159+
// Lower version ordered first.
160+
cmp
161+
} else {
162+
// Higher version ordered first.
163+
cmp.reverse()
164+
}
165+
}
166+
_ => previous_cmp,
167+
}
168+
});
169+
170+
let out = Rc::new(ret);
171+
172+
self.cache.insert(dep.clone(), out.clone());
173+
174+
Ok(out)
175+
}
176+
}

src/cargo/core/resolver/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,9 @@ use crate::util::errors::CargoResult;
6262
use crate::util::profile;
6363

6464
use self::context::{Activations, Context};
65+
use self::dep_cache::RegistryQueryer;
6566
use self::types::{Candidate, ConflictMap, ConflictReason, DepsFrame};
66-
use self::types::{RcVecIter, RegistryQueryer, RemainingDeps, ResolverProgress};
67+
use self::types::{RcVecIter, RemainingDeps, ResolverProgress};
6768

6869
pub use self::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
6970
pub use self::encode::{Metadata, WorkspaceResolve};
@@ -73,6 +74,7 @@ pub use self::types::Method;
7374

7475
mod conflict_cache;
7576
mod context;
77+
mod dep_cache;
7678
mod encode;
7779
mod errors;
7880
mod resolve;

0 commit comments

Comments
 (0)