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