warnings: RcList::new(),
};
let _p = profile::start("resolving");
- let cx = activate_deps_loop(cx, registry, summaries, config)?;
+ let cx = activate_deps_loop(cx, &mut RegistryQueryer::new(registry, replacements), summaries, config)?;
let mut resolve = Resolve {
graph: cx.graph(),
/// If `candidate` was activated, this function returns the dependency frame to
/// iterate through next.
fn activate(cx: &mut Context,
- registry: &mut Registry,
+ registry: &mut RegistryQueryer,
parent: Option<&Summary>,
candidate: Candidate,
method: &Method)
}
}
+struct RegistryQueryer<'a> {
+ registry: &'a mut (Registry + 'a),
+ replacements: &'a [(PackageIdSpec, Dependency)],
+ // TODO: with nll the Rc can be removed
+ cache: BTreeMap<Dependency, Rc<Vec<Candidate>>>,
+}
+
+impl<'a> RegistryQueryer<'a> {
+ fn new(registry: &'a mut Registry, replacements: &'a [(PackageIdSpec, Dependency)],) -> Self {
+ RegistryQueryer {
+ registry,
+ replacements,
+ cache: BTreeMap::new(),
+ }
+ }
+
+ /// Queries the `registry` to return a list of candidates for `dep`.
+ ///
+ /// This method is the location where overrides are taken into account. If
+ /// any candidates are returned which match an override then the override is
+ /// applied by performing a second query for what the override should
+ /// return.
+ fn query(&mut self, dep: &Dependency) -> CargoResult<Rc<Vec<Candidate>>> {
+ if let Some(out) = self.cache.get(dep).cloned() {
+ return Ok(out);
+ }
+
+ let mut ret = Vec::new();
+ self.registry.query(dep, &mut |s| {
+ ret.push(Candidate { summary: s, replace: None });
+ })?;
+ for candidate in ret.iter_mut() {
+ let summary = &candidate.summary;
+
+ let mut potential_matches = self.replacements.iter()
+ .filter(|&&(ref spec, _)| spec.matches(summary.package_id()));
+
+ let &(ref spec, ref dep) = match potential_matches.next() {
+ None => continue,
+ Some(replacement) => replacement,
+ };
+ debug!("found an override for {} {}", dep.name(), dep.version_req());
+
+ let mut summaries = self.registry.query_vec(dep)?.into_iter();
+ let s = summaries.next().ok_or_else(|| {
+ format_err!("no matching package for override `{}` found\n\
+ location searched: {}\n\
+ version required: {}",
+ spec, dep.source_id(), dep.version_req())
+ })?;
+ let summaries = summaries.collect::<Vec<_>>();
+ if !summaries.is_empty() {
+ let bullets = summaries.iter().map(|s| {
+ format!(" * {}", s.package_id())
+ }).collect::<Vec<_>>();
+ bail!("the replacement specification `{}` matched \
+ multiple packages:\n * {}\n{}", spec, s.package_id(),
+ bullets.join("\n"));
+ }
+
+ // The dependency should be hard-coded to have the same name and an
+ // exact version requirement, so both of these assertions should
+ // never fail.
+ assert_eq!(s.version(), summary.version());
+ assert_eq!(s.name(), summary.name());
+
+ let replace = if s.source_id() == summary.source_id() {
+ debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
+ None
+ } else {
+ Some(s)
+ };
+ let matched_spec = spec.clone();
+
+ // Make sure no duplicates
+ if let Some(&(ref spec, _)) = potential_matches.next() {
+ bail!("overlapping replacement specifications found:\n\n \
+ * {}\n * {}\n\nboth specifications match: {}",
+ matched_spec, spec, summary.package_id());
+ }
+
+ for dep in summary.dependencies() {
+ debug!("\t{} => {}", dep.name(), dep.version_req());
+ }
+
+ candidate.replace = replace;
+ }
+
+ // When we attempt versions for a package, we'll want to start at
+ // the maximum version and work our way down.
+ ret.sort_unstable_by(|a, b| {
+ b.summary.version().cmp(a.summary.version())
+ });
+
+ let out = Rc::new(ret);
+
+ self.cache.insert(dep.clone(), out.clone());
+
+ Ok(out)
+ }
+}
+
#[derive(Clone)]
struct BacktrackFrame<'a> {
cur: usize,
/// dependency graph, cx.resolve is returned.
fn activate_deps_loop<'a>(
mut cx: Context<'a>,
- registry: &mut Registry,
+ registry: &mut RegistryQueryer,
summaries: &[(Summary, Method)],
config: Option<&Config>,
) -> CargoResult<Context<'a>> {
).ok_or_else(|| {
activation_error(
&cx,
- registry,
+ registry.registry,
&parent,
&dep,
&conflicting_activations,
}
fn build_deps(&mut self,
- registry: &mut Registry,
+ registry: &mut RegistryQueryer,
parent: Option<&Summary>,
candidate: &Summary,
method: &Method) -> ActivateResult<Vec<DepInfo>> {
// Next, transform all dependencies into a list of possible candidates
// which can satisfy that dependency.
let mut deps = deps.into_iter().map(|(dep, features)| {
- let candidates = self.query(registry, &dep)?;
+ let candidates = registry.query(&dep)?;
Ok((dep, candidates, Rc::new(features)))
}).collect::<CargoResult<Vec<DepInfo>>>()?;
Ok(deps)
}
- /// Queries the `registry` to return a list of candidates for `dep`.
- ///
- /// This method is the location where overrides are taken into account. If
- /// any candidates are returned which match an override then the override is
- /// applied by performing a second query for what the override should
- /// return.
- fn query(&self,
- registry: &mut Registry,
- dep: &Dependency) -> CargoResult<Rc<Vec<Candidate>>> {
- use ::std::cell::RefCell;
- thread_local!(static CACHE: RefCell<BTreeMap<Dependency, Rc<Vec<Candidate>>>> = RefCell::new(BTreeMap::new()));
- if let Some(out) = CACHE.with(|m| m.borrow().get(dep).cloned()) {
- return Ok(out);
- }
-
- let mut ret = Vec::new();
- registry.query(dep, &mut |s| {
- ret.push(Candidate { summary: s, replace: None });
- })?;
- for candidate in ret.iter_mut() {
- let summary = &candidate.summary;
-
- let mut potential_matches = self.replacements.iter()
- .filter(|&&(ref spec, _)| spec.matches(summary.package_id()));
-
- let &(ref spec, ref dep) = match potential_matches.next() {
- None => continue,
- Some(replacement) => replacement,
- };
- debug!("found an override for {} {}", dep.name(), dep.version_req());
-
- let mut summaries = registry.query_vec(dep)?.into_iter();
- let s = summaries.next().ok_or_else(|| {
- format_err!("no matching package for override `{}` found\n\
- location searched: {}\n\
- version required: {}",
- spec, dep.source_id(), dep.version_req())
- })?;
- let summaries = summaries.collect::<Vec<_>>();
- if !summaries.is_empty() {
- let bullets = summaries.iter().map(|s| {
- format!(" * {}", s.package_id())
- }).collect::<Vec<_>>();
- bail!("the replacement specification `{}` matched \
- multiple packages:\n * {}\n{}", spec, s.package_id(),
- bullets.join("\n"));
- }
-
- // The dependency should be hard-coded to have the same name and an
- // exact version requirement, so both of these assertions should
- // never fail.
- assert_eq!(s.version(), summary.version());
- assert_eq!(s.name(), summary.name());
-
- let replace = if s.source_id() == summary.source_id() {
- debug!("Preventing\n{:?}\nfrom replacing\n{:?}", summary, s);
- None
- } else {
- Some(s)
- };
- let matched_spec = spec.clone();
-
- // Make sure no duplicates
- if let Some(&(ref spec, _)) = potential_matches.next() {
- bail!("overlapping replacement specifications found:\n\n \
- * {}\n * {}\n\nboth specifications match: {}",
- matched_spec, spec, summary.package_id());
- }
-
- for dep in summary.dependencies() {
- debug!("\t{} => {}", dep.name(), dep.version_req());
- }
-
- candidate.replace = replace;
- }
-
- // When we attempt versions for a package, we'll want to start at
- // the maximum version and work our way down.
- ret.sort_unstable_by(|a, b| {
- b.summary.version().cmp(a.summary.version())
- });
-
- let out = Rc::new(ret);
-
- CACHE.with(|m| m.borrow_mut().insert(dep.clone(), out.clone()));
-
- Ok(out)
- }
-
fn prev_active(&self, dep: &Dependency) -> &[Summary] {
self.activations.get(dep.name())
.and_then(|v| v.get(dep.source_id()))