Skip to content

Commit

Permalink
Rust: cleanup workspace aggregation
Browse files Browse the repository at this point in the history
  • Loading branch information
Paolo Tranquilli committed Jan 17, 2025
1 parent 3c06428 commit bbaff8b
Showing 1 changed file with 43 additions and 27 deletions.
70 changes: 43 additions & 27 deletions rust/extractor/src/rust_analyzer.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use itertools::Itertools;
use log::{debug, error, info};
use log::{debug, error, info, warn};
use ra_ap_base_db::SourceDatabase;
use ra_ap_hir::Semantics;
use ra_ap_ide_db::RootDatabase;
Expand All @@ -16,6 +16,7 @@ use ra_ap_syntax::SyntaxError;
use ra_ap_vfs::Vfs;
use ra_ap_vfs::VfsPath;
use ra_ap_vfs::{AbsPathBuf, FileId};
use serde::Deserialize;
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::fs;
Expand Down Expand Up @@ -131,8 +132,19 @@ impl<'a> RustAnalyzer<'a> {
}
}

#[derive(Deserialize)]
struct CargoManifestMembersSlice {
#[serde(default)]
members: Vec<String>,
}

#[derive(Deserialize)]
struct CargoManifestSlice {
workspace: Option<CargoManifestMembersSlice>,
}

struct ToMlReader {
cache: HashMap<ManifestPath, Rc<toml::Table>>,
cache: HashMap<ManifestPath, Rc<CargoManifestSlice>>,
}

impl ToMlReader {
Expand All @@ -142,15 +154,15 @@ impl ToMlReader {
}
}

fn read(&mut self, manifest: &ManifestPath) -> anyhow::Result<Rc<toml::Table>> {
fn read(&mut self, manifest: &ManifestPath) -> anyhow::Result<Rc<CargoManifestSlice>> {
if let Some(table) = self.cache.get(manifest) {
return Ok(table.clone());
}
let content = fs::read_to_string(manifest).map_err(|e| {
error!("failed to read {} ({e})", manifest.as_str());
e
})?;
let table = Rc::<toml::Table>::new(content.parse().map_err(|e| {
let table = Rc::<CargoManifestSlice>::new(toml::from_str(&content).map_err(|e| {
error!("failed to parse {} ({e})", manifest.as_str());
e
})?);
Expand All @@ -159,46 +171,50 @@ impl ToMlReader {
}
}

fn find_workspace(
reader: &mut ToMlReader,
manifest: &ProjectManifest,
) -> anyhow::Result<ProjectManifest> {
fn find_workspace(reader: &mut ToMlReader, manifest: &ProjectManifest) -> Option<ProjectManifest> {
let ProjectManifest::CargoToml(cargo) = manifest else {
return Err(anyhow::anyhow!("{manifest} not a cargo manifest"));
return None;
};
let toml = reader.read(cargo)?;
if toml.contains_key("workspace") {
return Ok(manifest.clone());
let parsed_cargo = reader.read(cargo).ok()?;
if parsed_cargo.workspace.is_some() {
debug!("{cargo} is a workspace");
return Some(manifest.clone());
}
let Some(parent_dir) = cargo.parent().parent() else {
return Err(anyhow::anyhow!("no parent dir for {cargo}"));
warn!("no parent dir for {cargo}");
return None;
};
let discovered = ProjectManifest::discover(parent_dir)?;
let discovered = ProjectManifest::discover(parent_dir)
.map_err(|e| {
error!(
"encountered error while searching for manifests under {}: {e}",
parent_dir.as_str()
);
e
})
.ok()?;
discovered
.iter()
.filter_map(|it| match it {
.find_map(|it| match it {
ProjectManifest::CargoToml(other)
if cargo.starts_with(other.parent())
&& reader.read(other).is_ok_and(|it| {
it.get("workspace")
.and_then(|w| w.as_table())
.and_then(|t| t.get("members"))
.and_then(|ms| ms.as_array())
.is_some_and(|ms| {
ms.iter().any(|m| {
m.as_str()
.is_some_and(|s| other.parent().join(s) == cargo.parent())
})
})
it.workspace.as_ref().is_some_and(|w| {
w.members
.iter()
.any(|m| other.parent().join(m) == cargo.parent())
})
}) =>
{
debug!("found workspace {other} containing {cargo}");
Some(it.clone())
}
_ => None,
})
.next()
.ok_or(anyhow::anyhow!("no workspace found for {manifest}"))
.or_else(|| {
debug!("no workspace found for {cargo}");
None
})
}

pub fn find_project_manifests(
Expand Down

0 comments on commit bbaff8b

Please sign in to comment.