Skip to content

Commit fd8bcf9

Browse files
committed
add a cache for discovered workspace roots
1 parent 971caf5 commit fd8bcf9

File tree

3 files changed

+74
-45
lines changed

3 files changed

+74
-45
lines changed

src/cargo/core/workspace.rs

+22-20
Original file line numberDiff line numberDiff line change
@@ -620,27 +620,23 @@ impl<'cfg> Workspace<'cfg> {
620620
/// Returns an error if `manifest_path` isn't actually a valid manifest or
621621
/// if some other transient error happens.
622622
fn find_root(&mut self, manifest_path: &Path) -> CargoResult<Option<PathBuf>> {
623+
let current = self.packages.load(manifest_path)?;
624+
match current
625+
.workspace_config()
626+
.get_ws_root(manifest_path, manifest_path)
623627
{
624-
let current = self.packages.load(manifest_path)?;
625-
match *current.workspace_config() {
626-
WorkspaceConfig::Root(_) => {
627-
debug!("find_root - is root {}", manifest_path.display());
628-
return Ok(Some(manifest_path.to_path_buf()));
629-
}
630-
WorkspaceConfig::Member {
631-
root: Some(ref path_to_root),
632-
} => return Ok(Some(read_root_pointer(manifest_path, path_to_root))),
633-
WorkspaceConfig::Member { root: None } => {}
628+
Some(root_path) => {
629+
debug!("find_root - is root {}", manifest_path.display());
630+
Ok(Some(root_path))
634631
}
632+
None => find_workspace_root_with_loader(manifest_path, self.config, |self_path| {
633+
Ok(self
634+
.packages
635+
.load(self_path)?
636+
.workspace_config()
637+
.get_ws_root(self_path, manifest_path))
638+
}),
635639
}
636-
637-
find_workspace_root_with_loader(manifest_path, self.config, |self_path| {
638-
Ok(self
639-
.packages
640-
.load(self_path)?
641-
.workspace_config()
642-
.get_ws_root(self_path, manifest_path))
643-
})
644640
}
645641

646642
/// After the root of a workspace has been located, probes for all members
@@ -1686,8 +1682,6 @@ pub fn resolve_relative_path(
16861682

16871683
/// Finds the path of the root of the workspace.
16881684
pub fn find_workspace_root(manifest_path: &Path, config: &Config) -> CargoResult<Option<PathBuf>> {
1689-
// FIXME(ehuss): Loading and parsing manifests just to find the root seems
1690-
// very inefficient. I think this should be reconsidered.
16911685
find_workspace_root_with_loader(manifest_path, config, |self_path| {
16921686
let key = self_path.parent().unwrap();
16931687
let source_id = SourceId::for_path(key)?;
@@ -1707,6 +1701,14 @@ fn find_workspace_root_with_loader(
17071701
config: &Config,
17081702
mut loader: impl FnMut(&Path) -> CargoResult<Option<PathBuf>>,
17091703
) -> CargoResult<Option<PathBuf>> {
1704+
// Check if there are any workspace roots that have already been found that would work
1705+
for (ws_root, ws_root_config) in config.ws_roots.borrow().iter() {
1706+
if manifest_path.starts_with(ws_root) && !ws_root_config.is_excluded(manifest_path) {
1707+
// Add `Cargo.toml` since ws_root is the root and not the file
1708+
return Ok(Some(ws_root.join("Cargo.toml").clone()));
1709+
}
1710+
}
1711+
17101712
for ances_manifest_path in find_root_iter(manifest_path, config) {
17111713
debug!("find_root - trying {}", ances_manifest_path.display());
17121714
if let Some(ws_root_path) = loader(&ances_manifest_path)? {

src/cargo/util/config/mod.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ use std::time::Instant;
6868
use self::ConfigValue as CV;
6969
use crate::core::compiler::rustdoc::RustdocExternMap;
7070
use crate::core::shell::Verbosity;
71-
use crate::core::{features, CliUnstable, Shell, SourceId, Workspace};
71+
use crate::core::{features, CliUnstable, Shell, SourceId, Workspace, WorkspaceRootConfig};
7272
use crate::ops;
7373
use crate::util::errors::CargoResult;
7474
use crate::util::toml as cargo_toml;
@@ -202,6 +202,8 @@ pub struct Config {
202202
/// NOTE: this should be set before `configure()`. If calling this from an integration test,
203203
/// consider using `ConfigBuilder::enable_nightly_features` instead.
204204
pub nightly_features_allowed: bool,
205+
/// WorkspaceRootConfigs that have been found
206+
pub ws_roots: RefCell<HashMap<PathBuf, WorkspaceRootConfig>>,
205207
}
206208

207209
impl Config {
@@ -285,6 +287,7 @@ impl Config {
285287
progress_config: ProgressConfig::default(),
286288
env_config: LazyCell::new(),
287289
nightly_features_allowed: matches!(&*features::channel(), "nightly" | "dev"),
290+
ws_roots: RefCell::new(HashMap::new()),
288291
}
289292
}
290293

src/cargo/util/toml/mod.rs

+48-24
Original file line numberDiff line numberDiff line change
@@ -1549,18 +1549,23 @@ impl TomlManifest {
15491549
let project = &mut project.ok_or_else(|| anyhow!("no `package` section found"))?;
15501550

15511551
let workspace_config = match (me.workspace.as_ref(), project.workspace.as_ref()) {
1552-
(Some(config), None) => {
1553-
let mut inheritable = config.package.clone().unwrap_or_default();
1552+
(Some(toml_config), None) => {
1553+
let mut inheritable = toml_config.package.clone().unwrap_or_default();
15541554
inheritable.update_ws_path(package_root.to_path_buf());
1555-
inheritable.update_deps(config.dependencies.clone());
1556-
WorkspaceConfig::Root(WorkspaceRootConfig::new(
1555+
inheritable.update_deps(toml_config.dependencies.clone());
1556+
let ws_root_config = WorkspaceRootConfig::new(
15571557
package_root,
1558-
&config.members,
1559-
&config.default_members,
1560-
&config.exclude,
1558+
&toml_config.members,
1559+
&toml_config.default_members,
1560+
&toml_config.exclude,
15611561
&Some(inheritable),
1562-
&config.metadata,
1563-
))
1562+
&toml_config.metadata,
1563+
);
1564+
config
1565+
.ws_roots
1566+
.borrow_mut()
1567+
.insert(package_root.to_path_buf(), ws_root_config.clone());
1568+
WorkspaceConfig::Root(ws_root_config)
15641569
}
15651570
(None, root) => WorkspaceConfig::Member {
15661571
root: root.cloned(),
@@ -2206,18 +2211,23 @@ impl TomlManifest {
22062211
.map(|r| ResolveBehavior::from_manifest(r))
22072212
.transpose()?;
22082213
let workspace_config = match me.workspace {
2209-
Some(ref config) => {
2210-
let mut inheritable = config.package.clone().unwrap_or_default();
2214+
Some(ref toml_config) => {
2215+
let mut inheritable = toml_config.package.clone().unwrap_or_default();
22112216
inheritable.update_ws_path(root.to_path_buf());
2212-
inheritable.update_deps(config.dependencies.clone());
2213-
WorkspaceConfig::Root(WorkspaceRootConfig::new(
2217+
inheritable.update_deps(toml_config.dependencies.clone());
2218+
let ws_root_config = WorkspaceRootConfig::new(
22142219
root,
2215-
&config.members,
2216-
&config.default_members,
2217-
&config.exclude,
2220+
&toml_config.members,
2221+
&toml_config.default_members,
2222+
&toml_config.exclude,
22182223
&Some(inheritable),
2219-
&config.metadata,
2220-
))
2224+
&toml_config.metadata,
2225+
);
2226+
config
2227+
.ws_roots
2228+
.borrow_mut()
2229+
.insert(root.to_path_buf(), ws_root_config.clone());
2230+
WorkspaceConfig::Root(ws_root_config)
22212231
}
22222232
None => {
22232233
bail!("virtual manifests must be configured with [workspace]");
@@ -2334,16 +2344,30 @@ impl TomlManifest {
23342344

23352345
fn inheritable_from_path(
23362346
config: &Config,
2337-
resolved_path: PathBuf,
2347+
workspace_path: PathBuf,
23382348
) -> CargoResult<InheritableFields> {
2339-
let key = resolved_path.parent().unwrap();
2340-
let source_id = SourceId::for_path(key)?;
2341-
let (man, _) = read_manifest(&resolved_path, source_id, config)?;
2349+
// Workspace path should have Cargo.toml at the end
2350+
let workspace_path_root = workspace_path.parent().unwrap();
2351+
2352+
// Let the borrow exit scope so that it can be picked up if there is a need to
2353+
// read a manifest
2354+
if let Some(ws_root) = config.ws_roots.borrow().get(workspace_path_root) {
2355+
return Ok(ws_root.inheritable().clone());
2356+
};
2357+
2358+
let source_id = SourceId::for_path(workspace_path_root)?;
2359+
let (man, _) = read_manifest(&workspace_path, source_id, config)?;
23422360
match man.workspace_config() {
2343-
WorkspaceConfig::Root(root) => Ok(root.inheritable().clone()),
2361+
WorkspaceConfig::Root(root) => {
2362+
config
2363+
.ws_roots
2364+
.borrow_mut()
2365+
.insert(workspace_path, root.clone());
2366+
Ok(root.inheritable().clone())
2367+
}
23442368
_ => bail!(
23452369
"root of a workspace inferred but wasn't a root: {}",
2346-
resolved_path.display()
2370+
workspace_path.display()
23472371
),
23482372
}
23492373
}

0 commit comments

Comments
 (0)