Skip to content

Commit 450e16e

Browse files
committed
Cache workspaces in cargo metadata --no-deps
Workspace::new is very expensive. Doing it over and over again like the initial implementation made cargo metadata --no-deps take several minutes in a big workspace. By only calling Workspace::new once per workspace, we can save a lot of time. Now the same command in the same workspace takes only 0.16 seconds.
1 parent c4a6528 commit 450e16e

File tree

1 file changed

+21
-5
lines changed

1 file changed

+21
-5
lines changed

src/cargo/ops/cargo_output_metadata.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use cargo_platform::Platform;
1111
use serde::Serialize;
1212
use std::collections::{BTreeMap, BTreeSet};
1313
use std::path::PathBuf;
14+
use std::rc::Rc;
1415

1516
const VERSION: u32 = 1;
1617

@@ -107,10 +108,11 @@ impl From<&Dependency> for DepKindInfo {
107108
}
108109
}
109110

110-
fn path_packages_r(
111-
package: &Package,
112-
config: &Config,
111+
fn path_packages_r<'p, 'cfg: 'p>(
112+
package: &'p Package,
113+
config: &'cfg Config,
113114
found: &mut BTreeSet<Package>,
115+
workspace_cache: &mut BTreeMap<PathBuf, Rc<Workspace<'cfg>>>,
114116
) -> CargoResult<()> {
115117
if found.contains(package) {
116118
return Ok(());
@@ -126,7 +128,20 @@ fn path_packages_r(
126128

127129
if let Ok(mut path) = source_id.url().to_file_path() {
128130
path.push("Cargo.toml");
129-
path_packages_r(Workspace::new(&path, &config)?.current()?, config, found)?;
131+
132+
let workspace = if let Some(workspace) = workspace_cache.get(&path) {
133+
workspace
134+
} else {
135+
let workspace = Rc::new(Workspace::new(&path, config)?);
136+
// Cache the workspace of every crate in this workspace, because Workspace::new
137+
// does a full scan for members every time it's called, and so is slow.
138+
for member in workspace.members() {
139+
workspace_cache.insert(member.manifest_path().to_path_buf(), workspace.clone());
140+
}
141+
workspace_cache.get(&path).unwrap()
142+
};
143+
144+
path_packages_r(&workspace.load(&path)?, config, found, workspace_cache)?;
130145
}
131146
}
132147

@@ -135,9 +150,10 @@ fn path_packages_r(
135150

136151
fn path_packages(ws: &Workspace<'_>) -> CargoResult<BTreeSet<Package>> {
137152
let mut found = BTreeSet::new();
153+
let mut workspace_cache = BTreeMap::new();
138154

139155
for package in ws.members() {
140-
path_packages_r(package, ws.config(), &mut found)?;
156+
path_packages_r(package, ws.config(), &mut found, &mut workspace_cache)?;
141157
}
142158

143159
Ok(found)

0 commit comments

Comments
 (0)