]> git.proxmox.com Git - cargo.git/blame - src/cargo/core/registry.rs
Auto merge of #4272 - behnam:doc, r=alexcrichton
[cargo.git] / src / cargo / core / registry.rs
CommitLineData
fc0e6426 1use std::collections::HashMap;
7192e29a 2
d7c8c189 3use core::{Source, SourceId, SourceMap, Summary, Dependency, PackageId};
2d25fcac 4use core::PackageSet;
c7de4859 5use util::{Config, profile};
e95044e3 6use util::errors::{CargoResult, CargoResultExt};
8214bb95 7use sources::config::SourceConfigMap;
f4d6d021 8
bacb6be3 9/// Source of information about a group of packages.
c7641c24
PK
10///
11/// See also `core::Source`.
f4d6d021 12pub trait Registry {
c7641c24 13 /// Attempt to find the packages that match a dependency request.
842c182e
AC
14 fn query(&mut self,
15 dep: &Dependency,
16 f: &mut FnMut(Summary)) -> CargoResult<()>;
17
18 fn query_vec(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
19 let mut ret = Vec::new();
20 self.query(dep, &mut |s| ret.push(s))?;
21 Ok(ret)
22 }
5430db61
AC
23
24 /// Returns whether or not this registry will return summaries with
25 /// checksums listed.
26 ///
27 /// By default, registries do not support checksums.
28 fn supports_checksums(&self) -> bool {
29 false
30 }
8f6d4afb
CL
31}
32
7ff9cbeb 33impl<'a, T: ?Sized + Registry + 'a> Registry for Box<T> {
842c182e
AC
34 fn query(&mut self,
35 dep: &Dependency,
36 f: &mut FnMut(Summary)) -> CargoResult<()> {
37 (**self).query(dep, f)
7ff9cbeb
AC
38 }
39}
40
816373d9
AC
41/// This structure represents a registry of known packages. It internally
42/// contains a number of `Box<Source>` instances which are used to load a
43/// `Package` from.
44///
45/// The resolution phase of Cargo uses this to drive knowledge about new
46/// packages as well as querying for lists of new packages. It is here that
bacb6be3 47/// sources are updated (e.g. network operations) and overrides are
816373d9
AC
48/// handled.
49///
50/// The general idea behind this registry is that it is centered around the
bacb6be3 51/// `SourceMap` structure, contained within which is a mapping of a `SourceId` to
816373d9
AC
52/// a `Source`. Each `Source` in the map has been updated (using network
53/// operations if necessary) and is ready to be queried for packages.
2fe0bf83 54pub struct PackageRegistry<'cfg> {
e3835f70 55 sources: SourceMap<'cfg>,
816373d9
AC
56
57 // A list of sources which are considered "overrides" which take precedent
58 // when querying for packages.
3b77b2c7 59 overrides: Vec<SourceId>,
6ab93117
AC
60
61 // Note that each SourceId does not take into account its `precise` field
62 // when hashing or testing for equality. When adding a new `SourceId`, we
63 // want to avoid duplicates in the `SourceMap` (to prevent re-updating the
64 // same git repo twice for example), but we also want to ensure that the
65 // loaded source is always updated.
66 //
67 // Sources with a `precise` field normally don't need to be updated because
68 // their contents are already on disk, but sources without a `precise` field
69 // almost always need to be updated. If we have a cached `Source` for a
70 // precise `SourceId`, then when we add a new `SourceId` that is not precise
71 // we want to ensure that the underlying source is updated.
72 //
73 // This is basically a long-winded way of saying that we want to know
74 // precisely what the keys of `sources` are, so this is a mapping of key to
75 // what exactly the key is.
76 source_ids: HashMap<SourceId, (SourceId, Kind)>,
77
e3835f70 78 locked: LockedMap,
8214bb95 79 source_config: SourceConfigMap<'cfg>,
9b278af1
YKCL
80}
81
e3835f70
AC
82type LockedMap = HashMap<SourceId, HashMap<String, Vec<(PackageId, Vec<PackageId>)>>>;
83
abe56727 84#[derive(PartialEq, Eq, Clone, Copy)]
6ab93117
AC
85enum Kind {
86 Override,
87 Locked,
88 Normal,
89}
90
2fe0bf83 91impl<'cfg> PackageRegistry<'cfg> {
8214bb95 92 pub fn new(config: &'cfg Config) -> CargoResult<PackageRegistry<'cfg>> {
82655b46 93 let source_config = SourceConfigMap::new(config)?;
8214bb95 94 Ok(PackageRegistry {
e3835f70 95 sources: SourceMap::new(),
6ab93117 96 source_ids: HashMap::new(),
54d738b0 97 overrides: Vec::new(),
8214bb95 98 source_config: source_config,
816373d9 99 locked: HashMap::new(),
8214bb95 100 })
98322afd
YKCL
101 }
102
f9945926 103 pub fn get(self, package_ids: &[PackageId]) -> PackageSet<'cfg> {
e3835f70
AC
104 trace!("getting packages; sources={}", self.sources.len());
105 PackageSet::new(package_ids, self.sources)
5451f95d
CL
106 }
107
f0647ea2 108 fn ensure_loaded(&mut self, namespace: &SourceId, kind: Kind) -> CargoResult<()> {
edc6ebc5 109 match self.source_ids.get(namespace) {
6ab93117
AC
110 // We've previously loaded this source, and we've already locked it,
111 // so we're not allowed to change it even if `namespace` has a
112 // slightly different precise version listed.
f162aed2
AC
113 Some(&(_, Kind::Locked)) => {
114 debug!("load/locked {}", namespace);
115 return Ok(())
116 }
6ab93117
AC
117
118 // If the previous source was not a precise source, then we can be
119 // sure that it's already been updated if we've already loaded it.
7a2facba 120 Some(&(ref previous, _)) if previous.precise().is_none() => {
f162aed2 121 debug!("load/precise {}", namespace);
6ab93117
AC
122 return Ok(())
123 }
124
125 // If the previous source has the same precise version as we do,
126 // then we're done, otherwise we need to need to move forward
127 // updating this source.
128 Some(&(ref previous, _)) => {
7a2facba 129 if previous.precise() == namespace.precise() {
f162aed2 130 debug!("load/match {}", namespace);
6ab93117
AC
131 return Ok(())
132 }
f162aed2
AC
133 debug!("load/mismatch {}", namespace);
134 }
135 None => {
136 debug!("load/missing {}", namespace);
6ab93117 137 }
6ab93117 138 }
5451f95d 139
82655b46 140 self.load(namespace, kind)?;
9b278af1
YKCL
141 Ok(())
142 }
143
c94648ba
AC
144 pub fn add_sources(&mut self, ids: &[SourceId]) -> CargoResult<()> {
145 for id in ids.iter() {
82655b46 146 self.ensure_loaded(id, Kind::Locked)?;
1a35097a
AC
147 }
148 Ok(())
149 }
150
b02023ee
AK
151 pub fn add_preloaded(&mut self, source: Box<Source + 'cfg>) {
152 self.add_source(source, Kind::Locked);
bc60f64b
AC
153 }
154
68c6f2b0 155 fn add_source(&mut self, source: Box<Source + 'cfg>, kind: Kind) {
b02023ee 156 let id = source.source_id().clone();
e3835f70 157 self.sources.insert(source);
b02023ee 158 self.source_ids.insert(id.clone(), (id, kind));
bc60f64b
AC
159 }
160
b02023ee
AK
161 pub fn add_override(&mut self, source: Box<Source + 'cfg>) {
162 self.overrides.push(source.source_id().clone());
163 self.add_source(source, Kind::Override);
e465ace4
TCS
164 }
165
816373d9 166 pub fn register_lock(&mut self, id: PackageId, deps: Vec<PackageId>) {
155dee54
AC
167 trace!("register_lock: {}", id);
168 for dep in deps.iter() {
169 trace!("\t-> {}", dep);
170 }
6e6dec8a
AC
171 let sub_map = self.locked.entry(id.source_id().clone())
172 .or_insert(HashMap::new());
173 let sub_vec = sub_map.entry(id.name().to_string())
174 .or_insert(Vec::new());
816373d9
AC
175 sub_vec.push((id, deps));
176 }
177
6ab93117 178 fn load(&mut self, source_id: &SourceId, kind: Kind) -> CargoResult<()> {
f2aa5b4c 179 (|| {
82655b46 180 let source = self.source_config.load(source_id)?;
b02023ee 181 assert_eq!(source.source_id(), source_id);
8214bb95 182
38d14a59 183 if kind == Kind::Override {
3b77b2c7 184 self.overrides.push(source_id.clone());
f137281b 185 }
b02023ee 186 self.add_source(source, kind);
e465ace4 187
18e59304
AC
188 // Ensure the source has fetched all necessary remote data.
189 let _p = profile::start(format!("updating: {}", source_id));
e3835f70 190 self.sources.get_mut(source_id).unwrap().update()
c7de4859 191 })().chain_err(|| format!("Unable to update {}", source_id))
9b278af1 192 }
46f90ba5 193
3b77b2c7 194 fn query_overrides(&mut self, dep: &Dependency)
fc0e6426 195 -> CargoResult<Option<Summary>> {
3b77b2c7 196 for s in self.overrides.iter() {
e3835f70 197 let src = self.sources.get_mut(s).unwrap();
7a2facba 198 let dep = Dependency::new_override(dep.name(), s);
842c182e 199 let mut results = src.query_vec(&dep)?;
fc0e6426
AC
200 if results.len() > 0 {
201 return Ok(Some(results.remove(0)))
202 }
3b77b2c7 203 }
fc0e6426 204 Ok(None)
46f90ba5 205 }
816373d9 206
c0306a8a
AC
207 /// This function is used to transform a summary to another locked summary
208 /// if possible. This is where the concept of a lockfile comes into play.
209 ///
210 /// If a summary points at a package id which was previously locked, then we
211 /// override the summary's id itself, as well as all dependencies, to be
212 /// rewritten to the locked versions. This will transform the summary's
213 /// source to a precise source (listed in the locked version) as well as
214 /// transforming all of the dependencies from range requirements on
215 /// imprecise sources to exact requirements on precise sources.
216 ///
217 /// If a summary does not point at a package id which was previously locked,
218 /// or if any dependencies were added and don't have a previously listed
219 /// version, we still want to avoid updating as many dependencies as
220 /// possible to keep the graph stable. In this case we map all of the
221 /// summary's dependencies to be rewritten to a locked version wherever
222 /// possible. If we're unable to map a dependency though, we just pass it on
223 /// through.
224 pub fn lock(&self, summary: Summary) -> Summary {
e3835f70 225 lock(&self.locked, summary)
816373d9 226 }
fc0e6426
AC
227
228 fn warn_bad_override(&self,
229 override_summary: &Summary,
230 real_summary: &Summary) -> CargoResult<()> {
772e1a17 231 let mut real_deps = real_summary.dependencies().iter().collect::<Vec<_>>();
fc0e6426
AC
232
233 let boilerplate = "\
234This is currently allowed but is known to produce buggy behavior with spurious
235recompiles and changes to the crate graph. Path overrides unfortunately were
236never intended to support this feature, so for now this message is just a
237warning. In the future, however, this message will become a hard error.
238
239To change the dependency graph via an override it's recommended to use the
240`[replace]` feature of Cargo instead of the path override feature. This is
241documented online at the url below for more information.
242
243http://doc.crates.io/specifying-dependencies.html#overriding-dependencies
244";
245
246 for dep in override_summary.dependencies() {
772e1a17 247 if let Some(i) = real_deps.iter().position(|d| dep == *d) {
fc0e6426
AC
248 real_deps.remove(i);
249 continue
250 }
251 let msg = format!("\
252 path override for crate `{}` has altered the original list of\n\
253 dependencies; the dependency on `{}` was either added or\n\
254 modified to not match the previously resolved version\n\n\
255 {}", override_summary.package_id().name(), dep.name(), boilerplate);
82655b46 256 self.source_config.config().shell().warn(&msg)?;
fc0e6426
AC
257 return Ok(())
258 }
259
260 for id in real_deps {
261 let msg = format!("\
262 path override for crate `{}` has altered the original list of
263 dependencies; the dependency on `{}` was removed\n\n
264 {}", override_summary.package_id().name(), id.name(), boilerplate);
82655b46 265 self.source_config.config().shell().warn(&msg)?;
fc0e6426
AC
266 return Ok(())
267 }
268
269 Ok(())
270 }
9b278af1
YKCL
271}
272
2fe0bf83 273impl<'cfg> Registry for PackageRegistry<'cfg> {
842c182e
AC
274 fn query(&mut self,
275 dep: &Dependency,
276 f: &mut FnMut(Summary)) -> CargoResult<()> {
fc0e6426 277 // Ensure the requested source_id is loaded
e95044e3 278 self.ensure_loaded(dep.source_id(), Kind::Normal).chain_err(|| {
c7de4859 279 format!("failed to load source for a dependency \
280 on `{}`", dep.name())
82655b46 281 })?;
fc0e6426 282
fc0e6426 283
e3835f70
AC
284 let (override_summary, n, to_warn) = {
285 // Look for an override and get ready to query the real source.
286 let override_summary = self.query_overrides(&dep)?;
287 let source = self.sources.get_mut(dep.source_id());
288 match (override_summary, source) {
289 (Some(_), None) => bail!("override found but no real ones"),
290 (None, None) => return Ok(()),
842c182e 291
e3835f70
AC
292 // If we don't have an override then we just ship everything
293 // upstairs after locking the summary
294 (None, Some(source)) => {
295 let locked = &self.locked;
296 return source.query(dep, &mut |summary| f(lock(locked, summary)))
297 }
298
299 // If we have an override summary then we query the source to sanity
300 // check its results. We don't actually use any of the summaries it
301 // gives us though.
302 (Some(override_summary), Some(source)) => {
303 let mut n = 0;
304 let mut to_warn = None;
305 source.query(dep, &mut |summary| {
306 n += 1;
307 to_warn = Some(summary);
308 })?;
309 (override_summary, n, to_warn)
310 }
86774bd8 311 }
816373d9
AC
312 };
313
842c182e
AC
314 if n > 1 {
315 bail!("found an override with a non-locked list");
316 } else if let Some(summary) = to_warn {
317 self.warn_bad_override(&override_summary, &summary)?;
318 }
319 f(self.lock(override_summary));
320 Ok(())
8f6d4afb 321 }
f4d6d021 322}
e465ace4 323
e3835f70
AC
324fn lock(locked: &LockedMap, summary: Summary) -> Summary {
325 let pair = locked.get(summary.source_id()).and_then(|map| {
326 map.get(summary.name())
327 }).and_then(|vec| {
328 vec.iter().find(|&&(ref id, _)| id == summary.package_id())
329 });
330
331 trace!("locking summary of {}", summary.package_id());
332
333 // Lock the summary's id if possible
334 let summary = match pair {
335 Some(&(ref precise, _)) => summary.override_id(precise.clone()),
336 None => summary,
337 };
338 summary.map_dependencies(|mut dep| {
339 trace!("\t{}/{}/{}", dep.name(), dep.version_req(),
340 dep.source_id());
341
342 // If we've got a known set of overrides for this summary, then
343 // one of a few cases can arise:
344 //
345 // 1. We have a lock entry for this dependency from the same
346 // source as it's listed as coming from. In this case we make
347 // sure to lock to precisely the given package id.
348 //
349 // 2. We have a lock entry for this dependency, but it's from a
350 // different source than what's listed, or the version
351 // requirement has changed. In this case we must discard the
352 // locked version because the dependency needs to be
353 // re-resolved.
354 //
355 // 3. We don't have a lock entry for this dependency, in which
356 // case it was likely an optional dependency which wasn't
357 // included previously so we just pass it through anyway.
358 //
359 // Cases 1/2 are handled by `matches_id` and case 3 is handled by
360 // falling through to the logic below.
361 if let Some(&(_, ref locked_deps)) = pair {
362 let locked = locked_deps.iter().find(|id| dep.matches_id(id));
363 if let Some(locked) = locked {
364 trace!("\tfirst hit on {}", locked);
365 dep.lock_to(locked);
366 return dep
367 }
368 }
369
370 // If this dependency did not have a locked version, then we query
371 // all known locked packages to see if they match this dependency.
372 // If anything does then we lock it to that and move on.
373 let v = locked.get(dep.source_id()).and_then(|map| {
374 map.get(dep.name())
375 }).and_then(|vec| {
376 vec.iter().find(|&&(ref id, _)| dep.matches_id(id))
377 });
378 match v {
379 Some(&(ref id, _)) => {
380 trace!("\tsecond hit on {}", id);
381 dep.lock_to(id);
382 return dep
383 }
384 None => {
385 trace!("\tremaining unlocked");
386 dep
387 }
388 }
389 })
390}
391
e465ace4
TCS
392#[cfg(test)]
393pub mod test {
394 use core::{Summary, Registry, Dependency};
c810424c 395 use util::CargoResult;
e465ace4
TCS
396
397 pub struct RegistryBuilder {
398 summaries: Vec<Summary>,
399 overrides: Vec<Summary>
400 }
401
402 impl RegistryBuilder {
403 pub fn new() -> RegistryBuilder {
ab1cb51f 404 RegistryBuilder { summaries: vec![], overrides: vec![] }
e465ace4
TCS
405 }
406
407 pub fn summary(mut self, summary: Summary) -> RegistryBuilder {
408 self.summaries.push(summary);
409 self
410 }
411
412 pub fn summaries(mut self, summaries: Vec<Summary>) -> RegistryBuilder {
3cdca46b 413 self.summaries.extend(summaries.into_iter());
e465ace4
TCS
414 self
415 }
416
c12a64f9 417 pub fn add_override(mut self, summary: Summary) -> RegistryBuilder {
e465ace4
TCS
418 self.overrides.push(summary);
419 self
420 }
421
422 pub fn overrides(mut self, summaries: Vec<Summary>) -> RegistryBuilder {
3cdca46b 423 self.overrides.extend(summaries.into_iter());
e465ace4
TCS
424 self
425 }
426
427 fn query_overrides(&self, dep: &Dependency) -> Vec<Summary> {
428 self.overrides.iter()
7a2facba 429 .filter(|s| s.name() == dep.name())
e465ace4
TCS
430 .map(|s| s.clone())
431 .collect()
432 }
433 }
434
435 impl Registry for RegistryBuilder {
842c182e
AC
436 fn query(&mut self,
437 dep: &Dependency,
438 f: &mut FnMut(Summary)) -> CargoResult<()> {
55321111 439 debug!("querying; dep={:?}", dep);
e465ace4
TCS
440
441 let overrides = self.query_overrides(dep);
442
443 if overrides.is_empty() {
a389d483
AC
444 for s in self.summaries.iter() {
445 if dep.matches(s) {
446 f(s.clone());
447 }
448 }
449 Ok(())
e465ace4 450 } else {
842c182e
AC
451 for s in overrides {
452 f(s);
453 }
454 Ok(())
e465ace4
TCS
455 }
456 }
457 }
458}