]> git.proxmox.com Git - cargo.git/blame - src/cargo/core/registry.rs
Auto merge of #6345 - dlaehnemann:docs_correct-profile-usage-info, r=ehuss
[cargo.git] / src / cargo / core / registry.rs
CommitLineData
fc0e6426 1use std::collections::HashMap;
7192e29a 2
61a3c68b
AC
3use semver::VersionReq;
4use url::Url;
5
2d25fcac 6use core::PackageSet;
e5a11190 7use core::{Dependency, PackageId, Source, SourceId, SourceMap, Summary};
8214bb95 8use sources::config::SourceConfigMap;
e5a11190
E
9use util::errors::{CargoResult, CargoResultExt};
10use util::{profile, Config};
f4d6d021 11
bacb6be3 12/// Source of information about a group of packages.
c7641c24
PK
13///
14/// See also `core::Source`.
f4d6d021 15pub trait Registry {
c7641c24 16 /// Attempt to find the packages that match a dependency request.
84cc3d8b 17 fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()>;
842c182e 18
84cc3d8b 19 fn query_vec(&mut self, dep: &Dependency, fuzzy: bool) -> CargoResult<Vec<Summary>> {
842c182e 20 let mut ret = Vec::new();
84cc3d8b 21 self.query(dep, &mut |s| ret.push(s), fuzzy)?;
842c182e
AC
22 Ok(ret)
23 }
20cfb41e 24
e5a11190
E
25 fn describe_source(&self, source: SourceId) -> String;
26 fn is_replaced(&self, source: SourceId) -> bool;
8f6d4afb
CL
27}
28
816373d9
AC
29/// This structure represents a registry of known packages. It internally
30/// contains a number of `Box<Source>` instances which are used to load a
31/// `Package` from.
32///
33/// The resolution phase of Cargo uses this to drive knowledge about new
34/// packages as well as querying for lists of new packages. It is here that
bacb6be3 35/// sources are updated (e.g. network operations) and overrides are
816373d9
AC
36/// handled.
37///
38/// The general idea behind this registry is that it is centered around the
bacb6be3 39/// `SourceMap` structure, contained within which is a mapping of a `SourceId` to
816373d9
AC
40/// a `Source`. Each `Source` in the map has been updated (using network
41/// operations if necessary) and is ready to be queried for packages.
2fe0bf83 42pub struct PackageRegistry<'cfg> {
c94804bd 43 config: &'cfg Config,
e3835f70 44 sources: SourceMap<'cfg>,
816373d9
AC
45
46 // A list of sources which are considered "overrides" which take precedent
47 // when querying for packages.
3b77b2c7 48 overrides: Vec<SourceId>,
6ab93117
AC
49
50 // Note that each SourceId does not take into account its `precise` field
51 // when hashing or testing for equality. When adding a new `SourceId`, we
52 // want to avoid duplicates in the `SourceMap` (to prevent re-updating the
53 // same git repo twice for example), but we also want to ensure that the
54 // loaded source is always updated.
55 //
56 // Sources with a `precise` field normally don't need to be updated because
57 // their contents are already on disk, but sources without a `precise` field
58 // almost always need to be updated. If we have a cached `Source` for a
59 // precise `SourceId`, then when we add a new `SourceId` that is not precise
60 // we want to ensure that the underlying source is updated.
61 //
62 // This is basically a long-winded way of saying that we want to know
63 // precisely what the keys of `sources` are, so this is a mapping of key to
64 // what exactly the key is.
65 source_ids: HashMap<SourceId, (SourceId, Kind)>,
66
e3835f70 67 locked: LockedMap,
8214bb95 68 source_config: SourceConfigMap<'cfg>,
eebddd37 69
61a3c68b 70 patches: HashMap<Url, Vec<Summary>>,
eebddd37
AC
71 patches_locked: bool,
72 patches_available: HashMap<Url, Vec<PackageId>>,
9b278af1
YKCL
73}
74
e3835f70
AC
75type LockedMap = HashMap<SourceId, HashMap<String, Vec<(PackageId, Vec<PackageId>)>>>;
76
abe56727 77#[derive(PartialEq, Eq, Clone, Copy)]
6ab93117
AC
78enum Kind {
79 Override,
80 Locked,
81 Normal,
82}
83
2fe0bf83 84impl<'cfg> PackageRegistry<'cfg> {
8214bb95 85 pub fn new(config: &'cfg Config) -> CargoResult<PackageRegistry<'cfg>> {
82655b46 86 let source_config = SourceConfigMap::new(config)?;
8214bb95 87 Ok(PackageRegistry {
c94804bd 88 config,
e3835f70 89 sources: SourceMap::new(),
6ab93117 90 source_ids: HashMap::new(),
54d738b0 91 overrides: Vec::new(),
0247dc42 92 source_config,
816373d9 93 locked: HashMap::new(),
61a3c68b 94 patches: HashMap::new(),
eebddd37
AC
95 patches_locked: false,
96 patches_available: HashMap::new(),
8214bb95 97 })
98322afd
YKCL
98 }
99
468f243e 100 pub fn get(self, package_ids: &[PackageId]) -> CargoResult<PackageSet<'cfg>> {
e3835f70 101 trace!("getting packages; sources={}", self.sources.len());
c94804bd 102 PackageSet::new(package_ids, self.sources, self.config)
5451f95d
CL
103 }
104
e5a11190
E
105 fn ensure_loaded(&mut self, namespace: SourceId, kind: Kind) -> CargoResult<()> {
106 match self.source_ids.get(&namespace) {
6ab93117
AC
107 // We've previously loaded this source, and we've already locked it,
108 // so we're not allowed to change it even if `namespace` has a
109 // slightly different precise version listed.
f162aed2
AC
110 Some(&(_, Kind::Locked)) => {
111 debug!("load/locked {}", namespace);
1e682848 112 return Ok(());
f162aed2 113 }
6ab93117
AC
114
115 // If the previous source was not a precise source, then we can be
116 // sure that it's already been updated if we've already loaded it.
7a2facba 117 Some(&(ref previous, _)) if previous.precise().is_none() => {
f162aed2 118 debug!("load/precise {}", namespace);
1e682848 119 return Ok(());
6ab93117
AC
120 }
121
122 // If the previous source has the same precise version as we do,
123 // then we're done, otherwise we need to need to move forward
124 // updating this source.
125 Some(&(ref previous, _)) => {
7a2facba 126 if previous.precise() == namespace.precise() {
f162aed2 127 debug!("load/match {}", namespace);
1e682848 128 return Ok(());
6ab93117 129 }
f162aed2
AC
130 debug!("load/mismatch {}", namespace);
131 }
132 None => {
133 debug!("load/missing {}", namespace);
6ab93117 134 }
6ab93117 135 }
5451f95d 136
82655b46 137 self.load(namespace, kind)?;
9b278af1
YKCL
138 Ok(())
139 }
140
e5a11190
E
141 pub fn add_sources(&mut self, ids: impl IntoIterator<Item = SourceId>) -> CargoResult<()> {
142 for id in ids {
82655b46 143 self.ensure_loaded(id, Kind::Locked)?;
1a35097a
AC
144 }
145 Ok(())
146 }
147
b02023ee
AK
148 pub fn add_preloaded(&mut self, source: Box<Source + 'cfg>) {
149 self.add_source(source, Kind::Locked);
bc60f64b
AC
150 }
151
68c6f2b0 152 fn add_source(&mut self, source: Box<Source + 'cfg>, kind: Kind) {
e5a11190 153 let id = source.source_id();
e3835f70 154 self.sources.insert(source);
e5a11190 155 self.source_ids.insert(id, (id, kind));
bc60f64b
AC
156 }
157
b02023ee 158 pub fn add_override(&mut self, source: Box<Source + 'cfg>) {
e5a11190 159 self.overrides.push(source.source_id());
b02023ee 160 self.add_source(source, Kind::Override);
e465ace4
TCS
161 }
162
816373d9 163 pub fn register_lock(&mut self, id: PackageId, deps: Vec<PackageId>) {
155dee54
AC
164 trace!("register_lock: {}", id);
165 for dep in deps.iter() {
166 trace!("\t-> {}", dep);
167 }
e5a11190
E
168 let sub_map = self
169 .locked
170 .entry(id.source_id())
1e682848
AC
171 .or_insert_with(HashMap::new);
172 let sub_vec = sub_map
173 .entry(id.name().to_string())
174 .or_insert_with(Vec::new);
816373d9
AC
175 sub_vec.push((id, deps));
176 }
177
eebddd37
AC
178 /// Insert a `[patch]` section into this registry.
179 ///
180 /// This method will insert a `[patch]` section for the `url` specified,
181 /// with the given list of dependencies. The `url` specified is the URL of
182 /// the source to patch (for example this is `crates-io` in the manifest).
183 /// The `deps` is an array of all the entries in the `[patch]` section of
184 /// the manifest.
185 ///
186 /// Here the `deps` will be resolved to a precise version and stored
187 /// internally for future calls to `query` below. It's expected that `deps`
188 /// have had `lock_to` call already, if applicable. (e.g. if a lock file was
189 /// already present).
190 ///
191 /// Note that the patch list specified here *will not* be available to
192 /// `query` until `lock_patches` is called below, which should be called
193 /// once all patches have been added.
61a3c68b 194 pub fn patch(&mut self, url: &Url, deps: &[Dependency]) -> CargoResult<()> {
eebddd37
AC
195 // First up we need to actually resolve each `deps` specification to
196 // precisely one summary. We're not using the `query` method below as it
197 // internally uses maps we're building up as part of this method
198 // (`patches_available` and `patches). Instead we're going straight to
199 // the source to load information from it.
200 //
201 // Remember that each dependency listed in `[patch]` has to resolve to
202 // precisely one package, so that's why we're just creating a flat list
203 // of summaries which should be the same length as `deps` above.
e5a11190
E
204 let unlocked_summaries = deps
205 .iter()
1e682848 206 .map(|dep| {
e5a11190
E
207 debug!(
208 "registring a patch for `{}` with `{}`",
209 url,
210 dep.package_name()
211 );
1e682848
AC
212
213 // Go straight to the source for resolving `dep`. Load it as we
214 // normally would and then ask it directly for the list of summaries
215 // corresponding to this `dep`.
216 self.ensure_loaded(dep.source_id(), Kind::Normal)
217 .chain_err(|| {
218 format_err!(
219 "failed to load source for a dependency \
220 on `{}`",
5295cadd 221 dep.package_name()
1e682848
AC
222 )
223 })?;
224
e5a11190
E
225 let mut summaries = self
226 .sources
1e682848
AC
227 .get_mut(dep.source_id())
228 .expect("loaded source not present")
229 .query_vec(dep)?
230 .into_iter();
231
232 let summary = match summaries.next() {
233 Some(summary) => summary,
234 None => bail!(
235 "patch for `{}` in `{}` did not resolve to any crates. If this is \
236 unexpected, you may wish to consult: \
237 https://github.com/rust-lang/cargo/issues/4678",
5295cadd 238 dep.package_name(),
1e682848
AC
239 url
240 ),
241 };
242 if summaries.next().is_some() {
243 bail!(
244 "patch for `{}` in `{}` resolved to more than one candidate",
5295cadd 245 dep.package_name(),
1e682848
AC
246 url
247 )
61a3c68b 248 }
1e682848
AC
249 if summary.package_id().source_id().url() == url {
250 bail!(
251 "patch for `{}` in `{}` points to the same source, but \
252 patches must point to different sources",
5295cadd 253 dep.package_name(),
1e682848
AC
254 url
255 );
256 }
257 Ok(summary)
258 })
259 .collect::<CargoResult<Vec<_>>>()
260 .chain_err(|| format_err!("failed to resolve patches for `{}`", url))?;
61a3c68b 261
eebddd37
AC
262 // Note that we do not use `lock` here to lock summaries! That step
263 // happens later once `lock_patches` is invoked. In the meantime though
264 // we want to fill in the `patches_available` map (later used in the
265 // `lock` method) and otherwise store the unlocked summaries in
266 // `patches` to get locked in a future call to `lock_patches`.
1e682848
AC
267 let ids = unlocked_summaries
268 .iter()
eebddd37
AC
269 .map(|s| s.package_id())
270 .cloned()
271 .collect();
272 self.patches_available.insert(url.clone(), ids);
273 self.patches.insert(url.clone(), unlocked_summaries);
61a3c68b
AC
274
275 Ok(())
276 }
277
eebddd37
AC
278 /// Lock all patch summaries added via `patch`, making them available to
279 /// resolution via `query`.
280 ///
281 /// This function will internally `lock` each summary added via `patch`
282 /// above now that the full set of `patch` packages are known. This'll allow
283 /// us to correctly resolve overridden dependencies between patches
284 /// hopefully!
285 pub fn lock_patches(&mut self) {
286 assert!(!self.patches_locked);
287 for summaries in self.patches.values_mut() {
288 for summary in summaries {
289 *summary = lock(&self.locked, &self.patches_available, summary.clone());
290 }
291 }
292 self.patches_locked = true;
293 }
294
61a3c68b
AC
295 pub fn patches(&self) -> &HashMap<Url, Vec<Summary>> {
296 &self.patches
297 }
298
e5a11190 299 fn load(&mut self, source_id: SourceId, kind: Kind) -> CargoResult<()> {
f2aa5b4c 300 (|| {
1868998b 301 debug!("loading source {}", source_id);
82655b46 302 let source = self.source_config.load(source_id)?;
b02023ee 303 assert_eq!(source.source_id(), source_id);
8214bb95 304
38d14a59 305 if kind == Kind::Override {
e5a11190 306 self.overrides.push(source_id);
f137281b 307 }
b02023ee 308 self.add_source(source, kind);
e465ace4 309
18e59304
AC
310 // Ensure the source has fetched all necessary remote data.
311 let _p = profile::start(format!("updating: {}", source_id));
e3835f70 312 self.sources.get_mut(source_id).unwrap().update()
1e682848 313 })()
e5a11190 314 .chain_err(|| format_err!("Unable to update {}", source_id))?;
37cffbe0 315 Ok(())
9b278af1 316 }
46f90ba5 317
1e682848 318 fn query_overrides(&mut self, dep: &Dependency) -> CargoResult<Option<Summary>> {
e5a11190 319 for &s in self.overrides.iter() {
e3835f70 320 let src = self.sources.get_mut(s).unwrap();
5295cadd 321 let dep = Dependency::new_override(&*dep.package_name(), s);
842c182e 322 let mut results = src.query_vec(&dep)?;
23591fe5 323 if !results.is_empty() {
1e682848 324 return Ok(Some(results.remove(0)));
fc0e6426 325 }
3b77b2c7 326 }
fc0e6426 327 Ok(None)
46f90ba5 328 }
816373d9 329
c0306a8a
AC
330 /// This function is used to transform a summary to another locked summary
331 /// if possible. This is where the concept of a lockfile comes into play.
332 ///
333 /// If a summary points at a package id which was previously locked, then we
334 /// override the summary's id itself, as well as all dependencies, to be
335 /// rewritten to the locked versions. This will transform the summary's
336 /// source to a precise source (listed in the locked version) as well as
337 /// transforming all of the dependencies from range requirements on
338 /// imprecise sources to exact requirements on precise sources.
339 ///
340 /// If a summary does not point at a package id which was previously locked,
341 /// or if any dependencies were added and don't have a previously listed
342 /// version, we still want to avoid updating as many dependencies as
343 /// possible to keep the graph stable. In this case we map all of the
344 /// summary's dependencies to be rewritten to a locked version wherever
345 /// possible. If we're unable to map a dependency though, we just pass it on
346 /// through.
347 pub fn lock(&self, summary: Summary) -> Summary {
eebddd37
AC
348 assert!(self.patches_locked);
349 lock(&self.locked, &self.patches_available, summary)
816373d9 350 }
fc0e6426 351
1e682848
AC
352 fn warn_bad_override(
353 &self,
354 override_summary: &Summary,
355 real_summary: &Summary,
356 ) -> CargoResult<()> {
772e1a17 357 let mut real_deps = real_summary.dependencies().iter().collect::<Vec<_>>();
fc0e6426
AC
358
359 let boilerplate = "\
360This is currently allowed but is known to produce buggy behavior with spurious
361recompiles and changes to the crate graph. Path overrides unfortunately were
362never intended to support this feature, so for now this message is just a
363warning. In the future, however, this message will become a hard error.
364
365To change the dependency graph via an override it's recommended to use the
366`[replace]` feature of Cargo instead of the path override feature. This is
367documented online at the url below for more information.
368
54159e84 369https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html#overriding-dependencies
fc0e6426
AC
370";
371
372 for dep in override_summary.dependencies() {
772e1a17 373 if let Some(i) = real_deps.iter().position(|d| dep == *d) {
fc0e6426 374 real_deps.remove(i);
1e682848 375 continue;
fc0e6426 376 }
1e682848
AC
377 let msg = format!(
378 "\
379 path override for crate `{}` has altered the original list of\n\
380 dependencies; the dependency on `{}` was either added or\n\
381 modified to not match the previously resolved version\n\n\
382 {}",
383 override_summary.package_id().name(),
5295cadd 384 dep.package_name(),
1e682848
AC
385 boilerplate
386 );
82655b46 387 self.source_config.config().shell().warn(&msg)?;
1e682848 388 return Ok(());
fc0e6426
AC
389 }
390
5295cadd 391 if let Some(dep) = real_deps.get(0) {
1e682848
AC
392 let msg = format!(
393 "\
fc0e6426
AC
394 path override for crate `{}` has altered the original list of
395 dependencies; the dependency on `{}` was removed\n\n
1e682848
AC
396 {}",
397 override_summary.package_id().name(),
5295cadd 398 dep.package_name(),
1e682848
AC
399 boilerplate
400 );
82655b46 401 self.source_config.config().shell().warn(&msg)?;
1e682848 402 return Ok(());
fc0e6426
AC
403 }
404
405 Ok(())
406 }
9b278af1
YKCL
407}
408
2fe0bf83 409impl<'cfg> Registry for PackageRegistry<'cfg> {
84cc3d8b 410 fn query(&mut self, dep: &Dependency, f: &mut FnMut(Summary), fuzzy: bool) -> CargoResult<()> {
eebddd37 411 assert!(self.patches_locked);
e3835f70
AC
412 let (override_summary, n, to_warn) = {
413 // Look for an override and get ready to query the real source.
23591fe5 414 let override_summary = self.query_overrides(dep)?;
61a3c68b
AC
415
416 // Next up on our list of candidates is to check the `[patch]`
417 // section of the manifest. Here we look through all patches
418 // relevant to the source that `dep` points to, and then we match
419 // name/version. Note that we don't use `dep.matches(..)` because
420 // the patches, by definition, come from a different source.
421 // This means that `dep.matches(..)` will always return false, when
422 // what we really care about is the name/version match.
423 let mut patches = Vec::<Summary>::new();
424 if let Some(extra) = self.patches.get(dep.source_id().url()) {
1e682848
AC
425 patches.extend(
426 extra
427 .iter()
51d23560 428 .filter(|s| dep.matches_ignoring_source(s.package_id()))
1e682848
AC
429 .cloned(),
430 );
61a3c68b
AC
431 }
432
433 // A crucial feature of the `[patch]` feature is that we *don't*
434 // query the actual registry if we have a "locked" dependency. A
435 // locked dep basically just means a version constraint of `=a.b.c`,
436 // and because patches take priority over the actual source then if
437 // we have a candidate we're done.
438 if patches.len() == 1 && dep.is_locked() {
439 let patch = patches.remove(0);
440 match override_summary {
441 Some(summary) => (summary, 1, Some(patch)),
442 None => {
443 f(patch);
1e682848 444 return Ok(());
61a3c68b
AC
445 }
446 }
447 } else {
23591fe5 448 if !patches.is_empty() {
1e682848
AC
449 debug!(
450 "found {} patches with an unlocked dep on `{}` at {} \
451 with `{}`, \
452 looking at sources",
453 patches.len(),
5295cadd 454 dep.package_name(),
1e682848
AC
455 dep.source_id(),
456 dep.version_req()
457 );
e3835f70
AC
458 }
459
61a3c68b 460 // Ensure the requested source_id is loaded
1e682848
AC
461 self.ensure_loaded(dep.source_id(), Kind::Normal)
462 .chain_err(|| {
463 format_err!(
464 "failed to load source for a dependency \
465 on `{}`",
5295cadd 466 dep.package_name()
1e682848
AC
467 )
468 })?;
61a3c68b
AC
469
470 let source = self.sources.get_mut(dep.source_id());
471 match (override_summary, source) {
472 (Some(_), None) => bail!("override found but no real ones"),
473 (None, None) => return Ok(()),
474
475 // If we don't have an override then we just ship
476 // everything upstairs after locking the summary
477 (None, Some(source)) => {
478 for patch in patches.iter() {
479 f(patch.clone());
480 }
481
482 // Our sources shouldn't ever come back to us with two
483 // summaries that have the same version. We could,
484 // however, have an `[patch]` section which is in use
485 // to override a version in the registry. This means
486 // that if our `summary` in this loop has the same
487 // version as something in `patches` that we've
488 // already selected, then we skip this `summary`.
489 let locked = &self.locked;
eebddd37 490 let all_patches = &self.patches_available;
84cc3d8b 491 let callback = &mut |summary: Summary| {
61a3c68b
AC
492 for patch in patches.iter() {
493 let patch = patch.package_id().version();
494 if summary.package_id().version() == patch {
1e682848 495 return;
61a3c68b
AC
496 }
497 }
498 f(lock(locked, all_patches, summary))
84cc3d8b
E
499 };
500 return if fuzzy {
501 source.fuzzy_query(dep, callback)
502 } else {
503 source.query(dep, callback)
504 };
61a3c68b
AC
505 }
506
507 // If we have an override summary then we query the source
508 // to sanity check its results. We don't actually use any of
509 // the summaries it gives us though.
510 (Some(override_summary), Some(source)) => {
23591fe5 511 if !patches.is_empty() {
61a3c68b
AC
512 bail!("found patches and a path override")
513 }
514 let mut n = 0;
515 let mut to_warn = None;
84cc3d8b
E
516 {
517 let callback = &mut |summary| {
518 n += 1;
519 to_warn = Some(summary);
520 };
521 if fuzzy {
522 source.fuzzy_query(dep, callback)?;
523 } else {
524 source.query(dep, callback)?;
525 }
526 }
61a3c68b
AC
527 (override_summary, n, to_warn)
528 }
e3835f70 529 }
86774bd8 530 }
816373d9
AC
531 };
532
842c182e
AC
533 if n > 1 {
534 bail!("found an override with a non-locked list");
535 } else if let Some(summary) = to_warn {
536 self.warn_bad_override(&override_summary, &summary)?;
537 }
538 f(self.lock(override_summary));
539 Ok(())
8f6d4afb 540 }
20cfb41e 541
e5a11190 542 fn describe_source(&self, id: SourceId) -> String {
20cfb41e
AC
543 match self.sources.get(id) {
544 Some(src) => src.describe(),
545 None => id.to_string(),
546 }
547 }
548
e5a11190 549 fn is_replaced(&self, id: SourceId) -> bool {
20cfb41e
AC
550 match self.sources.get(id) {
551 Some(src) => src.is_replaced(),
552 None => false,
553 }
554 }
f4d6d021 555}
e465ace4 556
1e682848
AC
557fn lock(locked: &LockedMap, patches: &HashMap<Url, Vec<PackageId>>, summary: Summary) -> Summary {
558 let pair = locked
e5a11190 559 .get(&summary.source_id())
1e682848
AC
560 .and_then(|map| map.get(&*summary.name()))
561 .and_then(|vec| vec.iter().find(|&&(ref id, _)| id == summary.package_id()));
e3835f70
AC
562
563 trace!("locking summary of {}", summary.package_id());
564
565 // Lock the summary's id if possible
566 let summary = match pair {
567 Some(&(ref precise, _)) => summary.override_id(precise.clone()),
568 None => summary,
569 };
61a3c68b 570 summary.map_dependencies(|dep| {
e5a11190
E
571 trace!(
572 "\t{}/{}/{}",
573 dep.package_name(),
574 dep.version_req(),
575 dep.source_id()
576 );
e3835f70
AC
577
578 // If we've got a known set of overrides for this summary, then
579 // one of a few cases can arise:
580 //
581 // 1. We have a lock entry for this dependency from the same
582 // source as it's listed as coming from. In this case we make
583 // sure to lock to precisely the given package id.
584 //
585 // 2. We have a lock entry for this dependency, but it's from a
586 // different source than what's listed, or the version
587 // requirement has changed. In this case we must discard the
588 // locked version because the dependency needs to be
589 // re-resolved.
590 //
591 // 3. We don't have a lock entry for this dependency, in which
592 // case it was likely an optional dependency which wasn't
593 // included previously so we just pass it through anyway.
594 //
595 // Cases 1/2 are handled by `matches_id` and case 3 is handled by
596 // falling through to the logic below.
597 if let Some(&(_, ref locked_deps)) = pair {
598 let locked = locked_deps.iter().find(|id| dep.matches_id(id));
599 if let Some(locked) = locked {
600 trace!("\tfirst hit on {}", locked);
61a3c68b 601 let mut dep = dep.clone();
e3835f70 602 dep.lock_to(locked);
1e682848 603 return dep;
e3835f70
AC
604 }
605 }
606
607 // If this dependency did not have a locked version, then we query
608 // all known locked packages to see if they match this dependency.
609 // If anything does then we lock it to that and move on.
1e682848 610 let v = locked
e5a11190 611 .get(&dep.source_id())
5295cadd 612 .and_then(|map| map.get(&*dep.package_name()))
1e682848 613 .and_then(|vec| vec.iter().find(|&&(ref id, _)| dep.matches_id(id)));
61a3c68b
AC
614 if let Some(&(ref id, _)) = v {
615 trace!("\tsecond hit on {}", id);
616 let mut dep = dep.clone();
617 dep.lock_to(id);
1e682848 618 return dep;
61a3c68b
AC
619 }
620
621 // Finally we check to see if any registered patches correspond to
622 // this dependency.
623 let v = patches.get(dep.source_id().url()).map(|vec| {
624 let dep2 = dep.clone();
e5a11190 625 let mut iter = vec.iter().filter(move |p| dep2.matches_ignoring_source(p));
61a3c68b
AC
626 (iter.next(), iter)
627 });
eebddd37 628 if let Some((Some(patch_id), mut remaining)) = v {
61a3c68b 629 assert!(remaining.next().is_none());
eebddd37 630 let patch_source = patch_id.source_id();
1e682848 631 let patch_locked = locked
e5a11190 632 .get(&patch_source)
1e682848
AC
633 .and_then(|m| m.get(&*patch_id.name()))
634 .map(|list| list.iter().any(|&(ref id, _)| id == patch_id))
635 .unwrap_or(false);
61a3c68b
AC
636
637 if patch_locked {
eebddd37
AC
638 trace!("\tthird hit on {}", patch_id);
639 let req = VersionReq::exact(patch_id.version());
61a3c68b
AC
640 let mut dep = dep.clone();
641 dep.set_version_req(req);
1e682848 642 return dep;
e3835f70 643 }
e3835f70 644 }
61a3c68b
AC
645
646 trace!("\tnope, unlocked");
23591fe5 647 dep
e3835f70
AC
648 })
649}