]> git.proxmox.com Git - cargo.git/blob - src/cargo/core/compiler/unit_dependencies.rs
Auto merge of #7308 - guanqun:add-ssl-version, r=alexcrichton
[cargo.git] / src / cargo / core / compiler / unit_dependencies.rs
1 //! Constructs the dependency graph for compilation.
2 //!
3 //! Rust code is typically organized as a set of Cargo packages. The
4 //! dependencies between the packages themselves are stored in the
5 //! `Resolve` struct. However, we can't use that information as is for
6 //! compilation! A package typically contains several targets, or crates,
7 //! and these targets has inter-dependencies. For example, you need to
8 //! compile the `lib` target before the `bin` one, and you need to compile
9 //! `build.rs` before either of those.
10 //!
11 //! So, we need to lower the `Resolve`, which specifies dependencies between
12 //! *packages*, to a graph of dependencies between their *targets*, and this
13 //! is exactly what this module is doing! Well, almost exactly: another
14 //! complication is that we might want to compile the same target several times
15 //! (for example, with and without tests), so we actually build a dependency
16 //! graph of `Unit`s, which capture these properties.
17
18 use crate::core::compiler::Unit;
19 use crate::core::compiler::{BuildContext, CompileKind, CompileMode};
20 use crate::core::dependency::Kind as DepKind;
21 use crate::core::package::Downloads;
22 use crate::core::profiles::{Profile, UnitFor};
23 use crate::core::resolver::Resolve;
24 use crate::core::{InternedString, Package, PackageId, Target};
25 use crate::CargoResult;
26 use log::trace;
27 use std::collections::{HashMap, HashSet};
28
29 /// The dependency graph of Units.
30 pub type UnitGraph<'a> = HashMap<Unit<'a>, Vec<UnitDep<'a>>>;
31
32 /// A unit dependency.
33 #[derive(Debug, Clone, Hash, Eq, PartialEq, PartialOrd, Ord)]
34 pub struct UnitDep<'a> {
35 /// The dependency unit.
36 pub unit: Unit<'a>,
37 /// The purpose of this dependency (a dependency for a test, or a build
38 /// script, etc.).
39 pub unit_for: UnitFor,
40 /// The name the parent uses to refer to this dependency.
41 pub extern_crate_name: InternedString,
42 /// Whether or not this is a public dependency.
43 pub public: bool,
44 }
45
46 /// Collection of stuff used while creating the `UnitGraph`.
47 struct State<'a, 'cfg> {
48 bcx: &'a BuildContext<'a, 'cfg>,
49 waiting_on_download: HashSet<PackageId>,
50 downloads: Downloads<'a, 'cfg>,
51 unit_dependencies: UnitGraph<'a>,
52 package_cache: HashMap<PackageId, &'a Package>,
53 usr_resolve: &'a Resolve,
54 std_resolve: Option<&'a Resolve>,
55 /// This flag is `true` while generating the dependencies for the standard
56 /// library.
57 is_std: bool,
58 }
59
60 pub fn build_unit_dependencies<'a, 'cfg>(
61 bcx: &'a BuildContext<'a, 'cfg>,
62 resolve: &'a Resolve,
63 std_resolve: Option<&'a Resolve>,
64 roots: &[Unit<'a>],
65 std_roots: &[Unit<'a>],
66 ) -> CargoResult<UnitGraph<'a>> {
67 let mut state = State {
68 bcx,
69 downloads: bcx.packages.enable_download()?,
70 waiting_on_download: HashSet::new(),
71 unit_dependencies: HashMap::new(),
72 package_cache: HashMap::new(),
73 usr_resolve: resolve,
74 std_resolve,
75 is_std: false,
76 };
77
78 let std_unit_deps = calc_deps_of_std(&mut state, std_roots)?;
79
80 deps_of_roots(roots, &mut state)?;
81 super::links::validate_links(state.resolve(), &state.unit_dependencies)?;
82 // Hopefully there aren't any links conflicts with the standard library?
83
84 if let Some(std_unit_deps) = std_unit_deps {
85 attach_std_deps(&mut state, std_roots, std_unit_deps);
86 }
87
88 connect_run_custom_build_deps(&mut state.unit_dependencies);
89
90 // Dependencies are used in tons of places throughout the backend, many of
91 // which affect the determinism of the build itself. As a result be sure
92 // that dependency lists are always sorted to ensure we've always got a
93 // deterministic output.
94 for list in state.unit_dependencies.values_mut() {
95 list.sort();
96 }
97 trace!("ALL UNIT DEPENDENCIES {:#?}", state.unit_dependencies);
98
99 Ok(state.unit_dependencies)
100 }
101
102 /// Compute all the dependencies for the standard library.
103 fn calc_deps_of_std<'a, 'cfg>(
104 mut state: &mut State<'a, 'cfg>,
105 std_roots: &[Unit<'a>],
106 ) -> CargoResult<Option<UnitGraph<'a>>> {
107 if std_roots.is_empty() {
108 return Ok(None);
109 }
110 // Compute dependencies for the standard library.
111 state.is_std = true;
112 deps_of_roots(std_roots, &mut state)?;
113 state.is_std = false;
114 Ok(Some(std::mem::replace(
115 &mut state.unit_dependencies,
116 HashMap::new(),
117 )))
118 }
119
120 /// Add the standard library units to the `unit_dependencies`.
121 fn attach_std_deps<'a, 'cfg>(
122 state: &mut State<'a, 'cfg>,
123 std_roots: &[Unit<'a>],
124 std_unit_deps: UnitGraph<'a>,
125 ) {
126 // Attach the standard library as a dependency of every target unit.
127 for (unit, deps) in state.unit_dependencies.iter_mut() {
128 if !unit.kind.is_host() && !unit.mode.is_run_custom_build() {
129 deps.extend(std_roots.iter().map(|unit| UnitDep {
130 unit: *unit,
131 unit_for: UnitFor::new_normal(),
132 extern_crate_name: unit.pkg.name(),
133 // TODO: Does this `public` make sense?
134 public: true,
135 }));
136 }
137 }
138 // And also include the dependencies of the standard library itself.
139 for (unit, deps) in std_unit_deps.into_iter() {
140 if let Some(other_unit) = state.unit_dependencies.insert(unit, deps) {
141 panic!("std unit collision with existing unit: {:?}", other_unit);
142 }
143 }
144 }
145
146 /// Compute all the dependencies of the given root units.
147 /// The result is stored in state.unit_dependencies.
148 fn deps_of_roots<'a, 'cfg>(roots: &[Unit<'a>], mut state: &mut State<'a, 'cfg>) -> CargoResult<()> {
149 // Loop because we are downloading while building the dependency graph.
150 // The partially-built unit graph is discarded through each pass of the
151 // loop because it is incomplete because not all required Packages have
152 // been downloaded.
153 loop {
154 for unit in roots.iter() {
155 state.get(unit.pkg.package_id())?;
156
157 // Dependencies of tests/benches should not have `panic` set.
158 // We check the global test mode to see if we are running in `cargo
159 // test` in which case we ensure all dependencies have `panic`
160 // cleared, and avoid building the lib thrice (once with `panic`, once
161 // without, once for `--test`). In particular, the lib included for
162 // Doc tests and examples are `Build` mode here.
163 let unit_for = if unit.mode.is_any_test() || state.bcx.build_config.test() {
164 UnitFor::new_test()
165 } else if unit.target.is_custom_build() {
166 // This normally doesn't happen, except `clean` aggressively
167 // generates all units.
168 UnitFor::new_build()
169 } else if unit.target.for_host() {
170 // Proc macro / plugin should never have panic set.
171 UnitFor::new_compiler()
172 } else {
173 UnitFor::new_normal()
174 };
175 deps_of(unit, &mut state, unit_for)?;
176 }
177
178 if !state.waiting_on_download.is_empty() {
179 state.finish_some_downloads()?;
180 state.unit_dependencies.clear();
181 } else {
182 break;
183 }
184 }
185 Ok(())
186 }
187
188 /// Compute the dependencies of a single unit.
189 fn deps_of<'a, 'cfg>(
190 unit: &Unit<'a>,
191 state: &mut State<'a, 'cfg>,
192 unit_for: UnitFor,
193 ) -> CargoResult<()> {
194 // Currently the `unit_dependencies` map does not include `unit_for`. This should
195 // be safe for now. `TestDependency` only exists to clear the `panic`
196 // flag, and you'll never ask for a `unit` with `panic` set as a
197 // `TestDependency`. `CustomBuild` should also be fine since if the
198 // requested unit's settings are the same as `Any`, `CustomBuild` can't
199 // affect anything else in the hierarchy.
200 if !state.unit_dependencies.contains_key(unit) {
201 let unit_deps = compute_deps(unit, state, unit_for)?;
202 state.unit_dependencies.insert(*unit, unit_deps.clone());
203 for unit_dep in unit_deps {
204 deps_of(&unit_dep.unit, state, unit_dep.unit_for)?;
205 }
206 }
207 Ok(())
208 }
209
210 /// For a package, returns all targets that are registered as dependencies
211 /// for that package.
212 /// This returns a `Vec` of `(Unit, UnitFor)` pairs. The `UnitFor`
213 /// is the profile type that should be used for dependencies of the unit.
214 fn compute_deps<'a, 'cfg>(
215 unit: &Unit<'a>,
216 state: &mut State<'a, 'cfg>,
217 unit_for: UnitFor,
218 ) -> CargoResult<Vec<UnitDep<'a>>> {
219 if unit.mode.is_run_custom_build() {
220 return compute_deps_custom_build(unit, state);
221 } else if unit.mode.is_doc() {
222 // Note: this does not include doc test.
223 return compute_deps_doc(unit, state);
224 }
225
226 let bcx = state.bcx;
227 let id = unit.pkg.package_id();
228 let deps = state.resolve().deps(id).filter(|&(_id, deps)| {
229 assert!(!deps.is_empty());
230 deps.iter().any(|dep| {
231 // If this target is a build command, then we only want build
232 // dependencies, otherwise we want everything *other than* build
233 // dependencies.
234 if unit.target.is_custom_build() != dep.is_build() {
235 return false;
236 }
237
238 // If this dependency is **not** a transitive dependency, then it
239 // only applies to test/example targets.
240 if !dep.is_transitive()
241 && !unit.target.is_test()
242 && !unit.target.is_example()
243 && !unit.mode.is_any_test()
244 {
245 return false;
246 }
247
248 // If this dependency is only available for certain platforms,
249 // make sure we're only enabling it for that platform.
250 if !bcx.dep_platform_activated(dep, unit.kind) {
251 return false;
252 }
253
254 // If we've gotten past all that, then this dependency is
255 // actually used!
256 true
257 })
258 });
259
260 let mut ret = Vec::new();
261 for (id, _) in deps {
262 let pkg = match state.get(id)? {
263 Some(pkg) => pkg,
264 None => continue,
265 };
266 let lib = match pkg.targets().iter().find(|t| t.is_lib()) {
267 Some(t) => t,
268 None => continue,
269 };
270 let mode = check_or_build_mode(unit.mode, lib);
271 let dep_unit_for = unit_for.with_for_host(lib.for_host());
272
273 if bcx.config.cli_unstable().dual_proc_macros && lib.proc_macro() && !unit.kind.is_host() {
274 let unit_dep = new_unit_dep(state, unit, pkg, lib, dep_unit_for, unit.kind, mode)?;
275 ret.push(unit_dep);
276 let unit_dep =
277 new_unit_dep(state, unit, pkg, lib, dep_unit_for, CompileKind::Host, mode)?;
278 ret.push(unit_dep);
279 } else {
280 let unit_dep = new_unit_dep(
281 state,
282 unit,
283 pkg,
284 lib,
285 dep_unit_for,
286 unit.kind.for_target(lib),
287 mode,
288 )?;
289 ret.push(unit_dep);
290 }
291 }
292
293 // If this target is a build script, then what we've collected so far is
294 // all we need. If this isn't a build script, then it depends on the
295 // build script if there is one.
296 if unit.target.is_custom_build() {
297 return Ok(ret);
298 }
299 ret.extend(dep_build_script(unit, state)?);
300
301 // If this target is a binary, test, example, etc, then it depends on
302 // the library of the same package. The call to `resolve.deps` above
303 // didn't include `pkg` in the return values, so we need to special case
304 // it here and see if we need to push `(pkg, pkg_lib_target)`.
305 if unit.target.is_lib() && unit.mode != CompileMode::Doctest {
306 return Ok(ret);
307 }
308 ret.extend(maybe_lib(unit, state, unit_for)?);
309
310 // If any integration tests/benches are being run, make sure that
311 // binaries are built as well.
312 if !unit.mode.is_check()
313 && unit.mode.is_any_test()
314 && (unit.target.is_test() || unit.target.is_bench())
315 {
316 ret.extend(
317 unit.pkg
318 .targets()
319 .iter()
320 .filter(|t| {
321 let no_required_features = Vec::new();
322
323 t.is_bin() &&
324 // Skip binaries with required features that have not been selected.
325 t.required_features().unwrap_or(&no_required_features).iter().all(|f| {
326 unit.features.contains(&f.as_str())
327 })
328 })
329 .map(|t| {
330 new_unit_dep(
331 state,
332 unit,
333 unit.pkg,
334 t,
335 UnitFor::new_normal(),
336 unit.kind.for_target(t),
337 CompileMode::Build,
338 )
339 })
340 .collect::<CargoResult<Vec<UnitDep<'a>>>>()?,
341 );
342 }
343
344 Ok(ret)
345 }
346
347 /// Returns the dependencies needed to run a build script.
348 ///
349 /// The `unit` provided must represent an execution of a build script, and
350 /// the returned set of units must all be run before `unit` is run.
351 fn compute_deps_custom_build<'a, 'cfg>(
352 unit: &Unit<'a>,
353 state: &mut State<'a, 'cfg>,
354 ) -> CargoResult<Vec<UnitDep<'a>>> {
355 if let Some(links) = unit.pkg.manifest().links() {
356 if state.bcx.script_override(links, unit.kind).is_some() {
357 // Overridden build scripts don't have any dependencies.
358 return Ok(Vec::new());
359 }
360 }
361 // When not overridden, then the dependencies to run a build script are:
362 //
363 // 1. Compiling the build script itself.
364 // 2. For each immediate dependency of our package which has a `links`
365 // key, the execution of that build script.
366 //
367 // We don't have a great way of handling (2) here right now so this is
368 // deferred until after the graph of all unit dependencies has been
369 // constructed.
370 let unit_dep = new_unit_dep(
371 state,
372 unit,
373 unit.pkg,
374 unit.target,
375 // All dependencies of this unit should use profiles for custom
376 // builds.
377 UnitFor::new_build(),
378 // Build scripts always compiled for the host.
379 CompileKind::Host,
380 CompileMode::Build,
381 )?;
382 Ok(vec![unit_dep])
383 }
384
385 /// Returns the dependencies necessary to document a package.
386 fn compute_deps_doc<'a, 'cfg>(
387 unit: &Unit<'a>,
388 state: &mut State<'a, 'cfg>,
389 ) -> CargoResult<Vec<UnitDep<'a>>> {
390 let bcx = state.bcx;
391 let deps = state
392 .resolve()
393 .deps(unit.pkg.package_id())
394 .filter(|&(_id, deps)| {
395 deps.iter().any(|dep| match dep.kind() {
396 DepKind::Normal => bcx.dep_platform_activated(dep, unit.kind),
397 _ => false,
398 })
399 });
400
401 // To document a library, we depend on dependencies actually being
402 // built. If we're documenting *all* libraries, then we also depend on
403 // the documentation of the library being built.
404 let mut ret = Vec::new();
405 for (id, _deps) in deps {
406 let dep = match state.get(id)? {
407 Some(dep) => dep,
408 None => continue,
409 };
410 let lib = match dep.targets().iter().find(|t| t.is_lib()) {
411 Some(lib) => lib,
412 None => continue,
413 };
414 // Rustdoc only needs rmeta files for regular dependencies.
415 // However, for plugins/proc macros, deps should be built like normal.
416 let mode = check_or_build_mode(unit.mode, lib);
417 let dep_unit_for = UnitFor::new_normal().with_for_host(lib.for_host());
418 let lib_unit_dep = new_unit_dep(
419 state,
420 unit,
421 dep,
422 lib,
423 dep_unit_for,
424 unit.kind.for_target(lib),
425 mode,
426 )?;
427 ret.push(lib_unit_dep);
428 if let CompileMode::Doc { deps: true } = unit.mode {
429 // Document this lib as well.
430 let doc_unit_dep = new_unit_dep(
431 state,
432 unit,
433 dep,
434 lib,
435 dep_unit_for,
436 unit.kind.for_target(lib),
437 unit.mode,
438 )?;
439 ret.push(doc_unit_dep);
440 }
441 }
442
443 // Be sure to build/run the build script for documented libraries.
444 ret.extend(dep_build_script(unit, state)?);
445
446 // If we document a binary/example, we need the library available.
447 if unit.target.is_bin() || unit.target.is_example() {
448 ret.extend(maybe_lib(unit, state, UnitFor::new_normal())?);
449 }
450 Ok(ret)
451 }
452
453 fn maybe_lib<'a>(
454 unit: &Unit<'a>,
455 state: &mut State<'a, '_>,
456 unit_for: UnitFor,
457 ) -> CargoResult<Option<UnitDep<'a>>> {
458 unit.pkg
459 .targets()
460 .iter()
461 .find(|t| t.linkable())
462 .map(|t| {
463 let mode = check_or_build_mode(unit.mode, t);
464 new_unit_dep(
465 state,
466 unit,
467 unit.pkg,
468 t,
469 unit_for,
470 unit.kind.for_target(t),
471 mode,
472 )
473 })
474 .transpose()
475 }
476
477 /// If a build script is scheduled to be run for the package specified by
478 /// `unit`, this function will return the unit to run that build script.
479 ///
480 /// Overriding a build script simply means that the running of the build
481 /// script itself doesn't have any dependencies, so even in that case a unit
482 /// of work is still returned. `None` is only returned if the package has no
483 /// build script.
484 fn dep_build_script<'a>(
485 unit: &Unit<'a>,
486 state: &State<'a, '_>,
487 ) -> CargoResult<Option<UnitDep<'a>>> {
488 unit.pkg
489 .targets()
490 .iter()
491 .find(|t| t.is_custom_build())
492 .map(|t| {
493 // The profile stored in the Unit is the profile for the thing
494 // the custom build script is running for.
495 let profile = state
496 .bcx
497 .profiles
498 .get_profile_run_custom_build(&unit.profile);
499 new_unit_dep_with_profile(
500 state,
501 unit,
502 unit.pkg,
503 t,
504 UnitFor::new_build(),
505 unit.kind,
506 CompileMode::RunCustomBuild,
507 profile,
508 )
509 })
510 .transpose()
511 }
512
513 /// Choose the correct mode for dependencies.
514 fn check_or_build_mode(mode: CompileMode, target: &Target) -> CompileMode {
515 match mode {
516 CompileMode::Check { .. } | CompileMode::Doc { .. } => {
517 if target.for_host() {
518 // Plugin and proc macro targets should be compiled like
519 // normal.
520 CompileMode::Build
521 } else {
522 // Regular dependencies should not be checked with --test.
523 // Regular dependencies of doc targets should emit rmeta only.
524 CompileMode::Check { test: false }
525 }
526 }
527 _ => CompileMode::Build,
528 }
529 }
530
531 /// Create a new Unit for a dependency from `parent` to `pkg` and `target`.
532 fn new_unit_dep<'a>(
533 state: &State<'a, '_>,
534 parent: &Unit<'a>,
535 pkg: &'a Package,
536 target: &'a Target,
537 unit_for: UnitFor,
538 kind: CompileKind,
539 mode: CompileMode,
540 ) -> CargoResult<UnitDep<'a>> {
541 let profile = state.bcx.profiles.get_profile(
542 pkg.package_id(),
543 state.bcx.ws.is_member(pkg),
544 unit_for,
545 mode,
546 state.bcx.build_config.release,
547 );
548 new_unit_dep_with_profile(state, parent, pkg, target, unit_for, kind, mode, profile)
549 }
550
551 fn new_unit_dep_with_profile<'a>(
552 state: &State<'a, '_>,
553 parent: &Unit<'a>,
554 pkg: &'a Package,
555 target: &'a Target,
556 unit_for: UnitFor,
557 kind: CompileKind,
558 mode: CompileMode,
559 profile: Profile,
560 ) -> CargoResult<UnitDep<'a>> {
561 // TODO: consider making extern_crate_name return InternedString?
562 let extern_crate_name = InternedString::new(&state.resolve().extern_crate_name(
563 parent.pkg.package_id(),
564 pkg.package_id(),
565 target,
566 )?);
567 let public = state
568 .resolve()
569 .is_public_dep(parent.pkg.package_id(), pkg.package_id());
570 let features = state.resolve().features_sorted(pkg.package_id());
571 let unit = state
572 .bcx
573 .units
574 .intern(pkg, target, profile, kind, mode, features, state.is_std);
575 Ok(UnitDep {
576 unit,
577 unit_for,
578 extern_crate_name,
579 public,
580 })
581 }
582
583 /// Fill in missing dependencies for units of the `RunCustomBuild`
584 ///
585 /// As mentioned above in `compute_deps_custom_build` each build script
586 /// execution has two dependencies. The first is compiling the build script
587 /// itself (already added) and the second is that all crates the package of the
588 /// build script depends on with `links` keys, their build script execution. (a
589 /// bit confusing eh?)
590 ///
591 /// Here we take the entire `deps` map and add more dependencies from execution
592 /// of one build script to execution of another build script.
593 fn connect_run_custom_build_deps(unit_dependencies: &mut UnitGraph<'_>) {
594 let mut new_deps = Vec::new();
595
596 {
597 // First up build a reverse dependency map. This is a mapping of all
598 // `RunCustomBuild` known steps to the unit which depends on them. For
599 // example a library might depend on a build script, so this map will
600 // have the build script as the key and the library would be in the
601 // value's set.
602 let mut reverse_deps_map = HashMap::new();
603 for (unit, deps) in unit_dependencies.iter() {
604 for dep in deps {
605 if dep.unit.mode == CompileMode::RunCustomBuild {
606 reverse_deps_map
607 .entry(dep.unit)
608 .or_insert_with(HashSet::new)
609 .insert(unit);
610 }
611 }
612 }
613
614 // Next, we take a look at all build scripts executions listed in the
615 // dependency map. Our job here is to take everything that depends on
616 // this build script (from our reverse map above) and look at the other
617 // package dependencies of these parents.
618 //
619 // If we depend on a linkable target and the build script mentions
620 // `links`, then we depend on that package's build script! Here we use
621 // `dep_build_script` to manufacture an appropriate build script unit to
622 // depend on.
623 for unit in unit_dependencies
624 .keys()
625 .filter(|k| k.mode == CompileMode::RunCustomBuild)
626 {
627 // This is the lib that runs this custom build.
628 let reverse_deps = match reverse_deps_map.get(unit) {
629 Some(set) => set,
630 None => continue,
631 };
632
633 let to_add = reverse_deps
634 .iter()
635 // Get all deps for lib.
636 .flat_map(|reverse_dep| unit_dependencies[reverse_dep].iter())
637 // Only deps with `links`.
638 .filter(|other| {
639 other.unit.pkg != unit.pkg
640 && other.unit.target.linkable()
641 && other.unit.pkg.manifest().links().is_some()
642 })
643 // Get the RunCustomBuild for other lib.
644 .filter_map(|other| {
645 unit_dependencies[&other.unit]
646 .iter()
647 .find(|other_dep| other_dep.unit.mode == CompileMode::RunCustomBuild)
648 .cloned()
649 })
650 .collect::<HashSet<_>>();
651
652 if !to_add.is_empty() {
653 // (RunCustomBuild, set(other RunCustomBuild))
654 new_deps.push((*unit, to_add));
655 }
656 }
657 }
658
659 // And finally, add in all the missing dependencies!
660 for (unit, new_deps) in new_deps {
661 unit_dependencies.get_mut(&unit).unwrap().extend(new_deps);
662 }
663 }
664
665 impl<'a, 'cfg> State<'a, 'cfg> {
666 fn resolve(&self) -> &'a Resolve {
667 if self.is_std {
668 self.std_resolve.unwrap()
669 } else {
670 self.usr_resolve
671 }
672 }
673
674 fn get(&mut self, id: PackageId) -> CargoResult<Option<&'a Package>> {
675 if let Some(pkg) = self.package_cache.get(&id) {
676 return Ok(Some(pkg));
677 }
678 if !self.waiting_on_download.insert(id) {
679 return Ok(None);
680 }
681 if let Some(pkg) = self.downloads.start(id)? {
682 self.package_cache.insert(id, pkg);
683 self.waiting_on_download.remove(&id);
684 return Ok(Some(pkg));
685 }
686 Ok(None)
687 }
688
689 /// Completes at least one downloading, maybe waiting for more to complete.
690 ///
691 /// This function will block the current thread waiting for at least one
692 /// crate to finish downloading. The function may continue to download more
693 /// crates if it looks like there's a long enough queue of crates to keep
694 /// downloading. When only a handful of packages remain this function
695 /// returns, and it's hoped that by returning we'll be able to push more
696 /// packages to download into the queue.
697 fn finish_some_downloads(&mut self) -> CargoResult<()> {
698 assert!(self.downloads.remaining() > 0);
699 loop {
700 let pkg = self.downloads.wait()?;
701 self.waiting_on_download.remove(&pkg.package_id());
702 self.package_cache.insert(pkg.package_id(), pkg);
703
704 // Arbitrarily choose that 5 or more packages concurrently download
705 // is a good enough number to "fill the network pipe". If we have
706 // less than this let's recompute the whole unit dependency graph
707 // again and try to find some more packages to download.
708 if self.downloads.remaining() < 5 {
709 break;
710 }
711 }
712 Ok(())
713 }
714 }