|
1 |
| -use std::collections::hash_map::{Entry, HashMap}; |
| 1 | +use std::cell::RefCell; |
2 | 2 | use std::collections::BTreeMap;
|
| 3 | +use std::collections::hash_map::{Entry, HashMap}; |
3 | 4 | use std::path::{Path, PathBuf};
|
4 | 5 | use std::slice;
|
5 | 6 |
|
6 | 7 | use glob::glob;
|
7 | 8 | use url::Url;
|
8 | 9 |
|
| 10 | +use core::registry::PackageRegistry; |
9 | 11 | use core::{EitherManifest, Package, SourceId, VirtualManifest};
|
10 | 12 | use core::{Dependency, PackageIdSpec, Profile, Profiles};
|
11 |
| -use util::{Config, Filesystem}; |
| 13 | +use ops; |
| 14 | +use sources::PathSource; |
12 | 15 | use util::errors::{CargoResult, CargoResultExt};
|
13 | 16 | use util::paths;
|
14 | 17 | use util::toml::read_manifest;
|
| 18 | +use util::{Config, Filesystem}; |
15 | 19 |
|
16 | 20 | /// The core abstraction in Cargo for working with a workspace of crates.
|
17 | 21 | ///
|
@@ -67,6 +71,10 @@ pub struct Workspace<'cfg> {
|
67 | 71 | // needed by the current configuration (such as in cargo install). In some
|
68 | 72 | // cases `false` also results in the non-enforcement of dev-dependencies.
|
69 | 73 | require_optional_deps: bool,
|
| 74 | + |
| 75 | + // A cache of lodaed packages for particular paths which is disjoint from |
| 76 | + // `packages` up above, used in the `load` method down below. |
| 77 | + loaded_packages: RefCell<HashMap<PathBuf, Package>>, |
70 | 78 | }
|
71 | 79 |
|
72 | 80 | // Separate structure for tracking loaded packages (to avoid loading anything
|
@@ -137,6 +145,7 @@ impl<'cfg> Workspace<'cfg> {
|
137 | 145 | default_members: Vec::new(),
|
138 | 146 | is_ephemeral: false,
|
139 | 147 | require_optional_deps: true,
|
| 148 | + loaded_packages: RefCell::new(HashMap::new()), |
140 | 149 | };
|
141 | 150 | ws.root_manifest = ws.find_root(manifest_path)?;
|
142 | 151 | ws.find_members()?;
|
@@ -172,6 +181,7 @@ impl<'cfg> Workspace<'cfg> {
|
172 | 181 | default_members: Vec::new(),
|
173 | 182 | is_ephemeral: true,
|
174 | 183 | require_optional_deps,
|
| 184 | + loaded_packages: RefCell::new(HashMap::new()), |
175 | 185 | };
|
176 | 186 | {
|
177 | 187 | let key = ws.current_manifest.parent().unwrap();
|
@@ -669,11 +679,63 @@ impl<'cfg> Workspace<'cfg> {
|
669 | 679 |
|
670 | 680 | Ok(())
|
671 | 681 | }
|
| 682 | + |
| 683 | + pub fn load(&self, manifest_path: &Path) -> CargoResult<Package> { |
| 684 | + match self.packages.maybe_get(manifest_path) { |
| 685 | + Some(&MaybePackage::Package(ref p)) => return Ok(p.clone()), |
| 686 | + Some(&MaybePackage::Virtual(_)) => bail!("cannot load workspace root"), |
| 687 | + None => {} |
| 688 | + } |
| 689 | + |
| 690 | + let mut loaded = self.loaded_packages.borrow_mut(); |
| 691 | + if let Some(p) = loaded.get(manifest_path).cloned() { |
| 692 | + return Ok(p); |
| 693 | + } |
| 694 | + let source_id = SourceId::for_path(manifest_path.parent().unwrap())?; |
| 695 | + let (package, _nested_paths) = ops::read_package(manifest_path, &source_id, self.config)?; |
| 696 | + loaded.insert(manifest_path.to_path_buf(), package.clone()); |
| 697 | + Ok(package) |
| 698 | + } |
| 699 | + |
| 700 | + /// Preload the provided registry with already loaded packages. |
| 701 | + /// |
| 702 | + /// A workspace may load packages during construction/parsing/early phases |
| 703 | + /// for various operations, and this preload step avoids doubly-loading and |
| 704 | + /// parsing crates on the filesystem by inserting them all into the registry |
| 705 | + /// with their in-memory formats. |
| 706 | + pub fn preload(&self, registry: &mut PackageRegistry<'cfg>) { |
| 707 | + // These can get weird as this generally represents a workspace during |
| 708 | + // `cargo install`. Things like git repositories will actually have a |
| 709 | + // `PathSource` with multiple entries in it, so the logic below is |
| 710 | + // mostly just an optimization for normal `cargo build` in workspaces |
| 711 | + // during development. |
| 712 | + if self.is_ephemeral { |
| 713 | + return; |
| 714 | + } |
| 715 | + |
| 716 | + for pkg in self.packages.packages.values() { |
| 717 | + let pkg = match *pkg { |
| 718 | + MaybePackage::Package(ref p) => p.clone(), |
| 719 | + MaybePackage::Virtual(_) => continue, |
| 720 | + }; |
| 721 | + let mut src = PathSource::new( |
| 722 | + pkg.manifest_path(), |
| 723 | + pkg.package_id().source_id(), |
| 724 | + self.config, |
| 725 | + ); |
| 726 | + src.preload_with(pkg); |
| 727 | + registry.add_preloaded(Box::new(src)); |
| 728 | + } |
| 729 | + } |
672 | 730 | }
|
673 | 731 |
|
674 | 732 | impl<'cfg> Packages<'cfg> {
|
675 | 733 | fn get(&self, manifest_path: &Path) -> &MaybePackage {
|
676 |
| - &self.packages[manifest_path.parent().unwrap()] |
| 734 | + self.maybe_get(manifest_path).unwrap() |
| 735 | + } |
| 736 | + |
| 737 | + fn maybe_get(&self, manifest_path: &Path) -> Option<&MaybePackage> { |
| 738 | + self.packages.get(manifest_path.parent().unwrap()) |
677 | 739 | }
|
678 | 740 |
|
679 | 741 | fn load(&mut self, manifest_path: &Path) -> CargoResult<&MaybePackage> {
|
|
0 commit comments