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