]> git.proxmox.com Git - cargo.git/blame - src/cargo/core/registry.rs
Add support for multiple -p options to `cargo clean`
[cargo.git] / src / cargo / core / registry.rs
CommitLineData
f9b2f5e1 1use std::collections::HashSet;
d058d24a 2use std::collections::hash_map::HashMap;
7192e29a 3
5451f95d 4use core::{Source, SourceId, SourceMap, Summary, Dependency, PackageId, Package};
4f12a2b5 5use util::{CargoResult, ChainError, Config, human, profile};
f4d6d021 6
bacb6be3 7/// Source of information about a group of packages.
c7641c24
PK
8///
9/// See also `core::Source`.
f4d6d021 10pub trait Registry {
c7641c24 11 /// Attempt to find the packages that match a dependency request.
9b278af1 12 fn query(&mut self, name: &Dependency) -> CargoResult<Vec<Summary>>;
8f6d4afb
CL
13}
14
15impl Registry for Vec<Summary> {
46f90ba5 16 fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
3b77b2c7
AC
17 Ok(self.iter().filter(|summary| dep.matches(*summary))
18 .map(|summary| summary.clone()).collect())
9b278af1
YKCL
19 }
20}
21
348c7389
AC
22impl Registry for Vec<Package> {
23 fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
24 Ok(self.iter().filter(|pkg| dep.matches(pkg.summary()))
25 .map(|pkg| pkg.summary().clone()).collect())
26 }
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
AC
42pub struct PackageRegistry<'cfg> {
43 sources: SourceMap<'cfg>,
44 config: &'cfg Config,
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
816373d9 67 locked: HashMap<SourceId, HashMap<String, Vec<(PackageId, Vec<PackageId>)>>>,
9b278af1
YKCL
68}
69
abe56727 70#[derive(PartialEq, Eq, Clone, Copy)]
6ab93117
AC
71enum Kind {
72 Override,
73 Locked,
74 Normal,
75}
76
2fe0bf83
AC
77impl<'cfg> PackageRegistry<'cfg> {
78 pub fn new(config: &'cfg Config) -> PackageRegistry<'cfg> {
98322afd 79 PackageRegistry {
5451f95d 80 sources: SourceMap::new(),
6ab93117 81 source_ids: HashMap::new(),
98322afd 82 overrides: vec!(),
816373d9
AC
83 config: config,
84 locked: HashMap::new(),
98322afd
YKCL
85 }
86 }
87
18e884d8 88 pub fn get(&mut self, package_ids: &[PackageId]) -> CargoResult<Vec<Package>> {
98854f6f 89 trace!("getting packages; sources={}", self.sources.len());
98322afd 90
64ff29ff
AC
91 // TODO: Only call source with package ID if the package came from the
92 // source
98322afd
YKCL
93 let mut ret = Vec::new();
94
aa97b32e 95 for (_, source) in self.sources.sources_mut() {
98322afd
YKCL
96 try!(source.download(package_ids));
97 let packages = try!(source.get(package_ids));
98
3cdca46b 99 ret.extend(packages.into_iter());
98322afd
YKCL
100 }
101
102 // TODO: Return earlier if fail
64ff29ff 103 assert!(package_ids.len() == ret.len(),
55321111 104 "could not get packages from registry; ids={:?}; ret={:?}",
3b77b2c7 105 package_ids, ret);
98322afd
YKCL
106
107 Ok(ret)
9b278af1
YKCL
108 }
109
2fe0bf83 110 pub fn move_sources(self) -> SourceMap<'cfg> {
5451f95d
CL
111 self.sources
112 }
113
9b278af1 114 fn ensure_loaded(&mut self, namespace: &SourceId) -> CargoResult<()> {
edc6ebc5 115 match self.source_ids.get(namespace) {
6ab93117
AC
116 // We've previously loaded this source, and we've already locked it,
117 // so we're not allowed to change it even if `namespace` has a
118 // slightly different precise version listed.
f162aed2
AC
119 Some(&(_, Kind::Locked)) => {
120 debug!("load/locked {}", namespace);
121 return Ok(())
122 }
6ab93117
AC
123
124 // If the previous source was not a precise source, then we can be
125 // sure that it's already been updated if we've already loaded it.
7a2facba 126 Some(&(ref previous, _)) if previous.precise().is_none() => {
f162aed2 127 debug!("load/precise {}", namespace);
6ab93117
AC
128 return Ok(())
129 }
130
131 // If the previous source has the same precise version as we do,
132 // then we're done, otherwise we need to need to move forward
133 // updating this source.
134 Some(&(ref previous, _)) => {
7a2facba 135 if previous.precise() == namespace.precise() {
f162aed2 136 debug!("load/match {}", namespace);
6ab93117
AC
137 return Ok(())
138 }
f162aed2
AC
139 debug!("load/mismatch {}", namespace);
140 }
141 None => {
142 debug!("load/missing {}", namespace);
6ab93117 143 }
6ab93117 144 }
5451f95d 145
38d14a59 146 try!(self.load(namespace, Kind::Normal));
9b278af1
YKCL
147 Ok(())
148 }
149
c94648ba
AC
150 pub fn add_sources(&mut self, ids: &[SourceId]) -> CargoResult<()> {
151 for id in ids.iter() {
38d14a59 152 try!(self.load(id, Kind::Locked));
1a35097a
AC
153 }
154 Ok(())
155 }
156
3b77b2c7
AC
157 pub fn add_overrides(&mut self, ids: Vec<SourceId>) -> CargoResult<()> {
158 for id in ids.iter() {
38d14a59 159 try!(self.load(id, Kind::Override));
3b77b2c7 160 }
e465ace4
TCS
161 Ok(())
162 }
163
816373d9 164 pub fn register_lock(&mut self, id: PackageId, deps: Vec<PackageId>) {
6e6dec8a
AC
165 let sub_map = self.locked.entry(id.source_id().clone())
166 .or_insert(HashMap::new());
167 let sub_vec = sub_map.entry(id.name().to_string())
168 .or_insert(Vec::new());
816373d9
AC
169 sub_vec.push((id, deps));
170 }
171
6ab93117 172 fn load(&mut self, source_id: &SourceId, kind: Kind) -> CargoResult<()> {
f2aa5b4c 173 (|| {
e465ace4 174 let mut source = source_id.load(self.config);
9b278af1 175
f137281b 176 // Ensure the source has fetched all necessary remote data.
4f12a2b5 177 let p = profile::start(format!("updating: {}", source_id));
f137281b 178 try!(source.update());
4f12a2b5 179 drop(p);
9b278af1 180
38d14a59 181 if kind == Kind::Override {
3b77b2c7 182 self.overrides.push(source_id.clone());
f137281b 183 }
98322afd 184
f137281b 185 // Save off the source
3b77b2c7 186 self.sources.insert(source_id, source);
6ab93117 187 self.source_ids.insert(source_id.clone(), (source_id.clone(), kind));
e465ace4 188
f137281b 189 Ok(())
e465ace4 190 }).chain_error(|| human(format!("Unable to update {}", source_id)))
9b278af1 191 }
46f90ba5 192
3b77b2c7
AC
193 fn query_overrides(&mut self, dep: &Dependency)
194 -> CargoResult<Vec<Summary>> {
7192e29a 195 let mut seen = HashSet::new();
3b77b2c7
AC
196 let mut ret = Vec::new();
197 for s in self.overrides.iter() {
198 let src = self.sources.get_mut(s).unwrap();
7a2facba 199 let dep = Dependency::new_override(dep.name(), s);
03e3dba1 200 ret.extend(try!(src.query(&dep)).into_iter().filter(|s| {
7a2facba 201 seen.insert(s.name().to_string())
7192e29a 202 }));
3b77b2c7
AC
203 }
204 Ok(ret)
46f90ba5 205 }
816373d9
AC
206
207 // This function is used to transform a summary to another locked summary if
b186d2f5 208 // possible. This is where the concept of a lockfile comes into play.
816373d9
AC
209 //
210 // If a summary points at a package id which was previously locked, then we
bacb6be3 211 // override the summary's id itself, as well as all dependencies, to be
816373d9
AC
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 imprecise
215 // sources to exact requirements on precise sources.
216 //
217 // If a summary does not point at a package id which was previously locked,
218 // we still want to avoid updating as many dependencies as possible to keep
219 // the graph stable. In this case we map all of the summary's dependencies
220 // to be rewritten to a locked version wherever possible. If we're unable to
221 // map a dependency though, we just pass it on through.
222 fn lock(&self, summary: Summary) -> Summary {
7a2facba
AC
223 let pair = self.locked.get(summary.source_id()).and_then(|map| {
224 map.get(summary.name())
816373d9 225 }).and_then(|vec| {
7a2facba 226 vec.iter().find(|&&(ref id, _)| id == summary.package_id())
816373d9
AC
227 });
228
229 // Lock the summary's id if possible
230 let summary = match pair {
231 Some(&(ref precise, _)) => summary.override_id(precise.clone()),
232 None => summary,
233 };
234 summary.map_dependencies(|dep| {
235 match pair {
2ba5c5ec
AC
236 // If we've got a known set of overrides for this summary, then
237 // one of a few cases can arise:
238 //
239 // 1. We have a lock entry for this dependency from the same
bacb6be3 240 // source as it's listed as coming from. In this case we make
2ba5c5ec
AC
241 // sure to lock to precisely the given package id.
242 //
243 // 2. We have a lock entry for this dependency, but it's from a
493d3108
AC
244 // different source than what's listed, or the version
245 // requirement has changed. In this case we must discard the
246 // locked version because the dependency needs to be
247 // re-resolved.
2ba5c5ec
AC
248 //
249 // 3. We don't have a lock entry for this dependency, in which
250 // case it was likely an optional dependency which wasn't
251 // included previously so we just pass it through anyway.
816373d9 252 Some(&(_, ref deps)) => {
7a2facba 253 match deps.iter().find(|d| d.name() == dep.name()) {
2ba5c5ec 254 Some(lock) => {
493d3108 255 if dep.matches_id(lock) {
2ba5c5ec
AC
256 dep.lock_to(lock)
257 } else {
258 dep
259 }
260 }
816373d9
AC
261 None => dep,
262 }
263 }
264
265 // If this summary did not have a locked version, then we query
266 // all known locked packages to see if they match this
267 // dependency. If anything does then we lock it to that and move
268 // on.
269 None => {
7a2facba
AC
270 let v = self.locked.get(dep.source_id()).and_then(|map| {
271 map.get(dep.name())
816373d9
AC
272 }).and_then(|vec| {
273 vec.iter().find(|&&(ref id, _)| dep.matches_id(id))
274 });
275 match v {
276 Some(&(ref id, _)) => dep.lock_to(id),
277 None => dep
278 }
279 }
280 }
281 })
282 }
9b278af1
YKCL
283}
284
2fe0bf83 285impl<'cfg> Registry for PackageRegistry<'cfg> {
9b278af1 286 fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
3b77b2c7 287 let overrides = try!(self.query_overrides(dep));
9b278af1 288
816373d9 289 let ret = if overrides.len() == 0 {
e465ace4 290 // Ensure the requested source_id is loaded
7a2facba 291 try!(self.ensure_loaded(dep.source_id()));
3b77b2c7 292 let mut ret = Vec::new();
aa97b32e 293 for (id, src) in self.sources.sources_mut() {
7a2facba 294 if id == dep.source_id() {
aa97b32e
AC
295 ret.extend(try!(src.query(dep)).into_iter());
296 }
3b77b2c7 297 }
816373d9 298 ret
9b278af1 299 } else {
816373d9
AC
300 overrides
301 };
302
303 // post-process all returned summaries to ensure that we lock all
304 // relevant summaries to the right versions and sources
305 Ok(ret.into_iter().map(|summary| self.lock(summary)).collect())
8f6d4afb 306 }
f4d6d021 307}
e465ace4
TCS
308
309#[cfg(test)]
310pub mod test {
311 use core::{Summary, Registry, Dependency};
312 use util::{CargoResult};
313
314 pub struct RegistryBuilder {
315 summaries: Vec<Summary>,
316 overrides: Vec<Summary>
317 }
318
319 impl RegistryBuilder {
320 pub fn new() -> RegistryBuilder {
321 RegistryBuilder { summaries: vec!(), overrides: vec!() }
322 }
323
324 pub fn summary(mut self, summary: Summary) -> RegistryBuilder {
325 self.summaries.push(summary);
326 self
327 }
328
329 pub fn summaries(mut self, summaries: Vec<Summary>) -> RegistryBuilder {
3cdca46b 330 self.summaries.extend(summaries.into_iter());
e465ace4
TCS
331 self
332 }
333
c12a64f9 334 pub fn add_override(mut self, summary: Summary) -> RegistryBuilder {
e465ace4
TCS
335 self.overrides.push(summary);
336 self
337 }
338
339 pub fn overrides(mut self, summaries: Vec<Summary>) -> RegistryBuilder {
3cdca46b 340 self.overrides.extend(summaries.into_iter());
e465ace4
TCS
341 self
342 }
343
344 fn query_overrides(&self, dep: &Dependency) -> Vec<Summary> {
345 self.overrides.iter()
7a2facba 346 .filter(|s| s.name() == dep.name())
e465ace4
TCS
347 .map(|s| s.clone())
348 .collect()
349 }
350 }
351
352 impl Registry for RegistryBuilder {
353 fn query(&mut self, dep: &Dependency) -> CargoResult<Vec<Summary>> {
55321111 354 debug!("querying; dep={:?}", dep);
e465ace4
TCS
355
356 let overrides = self.query_overrides(dep);
357
358 if overrides.is_empty() {
359 self.summaries.query(dep)
360 } else {
361 Ok(overrides)
362 }
363 }
364 }
365}