Skip to content

Commit 422ae47

Browse files
committed
Unmix error handling when discovering workspaces
Hitting an io::Error is a legit problem. Finding more than one Cargo.toml is not.
1 parent be2654b commit 422ae47

File tree

3 files changed

+41
-75
lines changed

3 files changed

+41
-75
lines changed

crates/ra_project_model/src/lib.rs

Lines changed: 23 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,8 @@ mod json_project;
55
mod sysroot;
66

77
use std::{
8-
error::Error,
98
fs::{read_dir, File, ReadDir},
10-
io::BufReader,
9+
io::{self, BufReader},
1110
path::{Path, PathBuf},
1211
process::Command,
1312
};
@@ -25,25 +24,6 @@ pub use crate::{
2524
};
2625
pub use ra_proc_macro::ProcMacroClient;
2726

28-
#[derive(Clone, PartialEq, Eq, Hash, Debug)]
29-
pub struct CargoTomlNotFoundError {
30-
pub searched_at: PathBuf,
31-
pub reason: String,
32-
}
33-
34-
impl std::fmt::Display for CargoTomlNotFoundError {
35-
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
36-
write!(
37-
fmt,
38-
"can't find Cargo.toml at {}, due to {}",
39-
self.searched_at.display(),
40-
self.reason
41-
)
42-
}
43-
}
44-
45-
impl Error for CargoTomlNotFoundError {}
46-
4727
#[derive(Debug, Clone)]
4828
pub enum ProjectWorkspace {
4929
/// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
@@ -94,11 +74,25 @@ impl ProjectRoot {
9474
bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
9575
}
9676

97-
pub fn discover(path: &Path) -> Result<ProjectRoot, CargoTomlNotFoundError> {
77+
pub fn discover_single(path: &Path) -> Result<ProjectRoot> {
78+
let mut candidates = ProjectRoot::discover(path)?;
79+
let res = match candidates.pop() {
80+
None => bail!("no projects"),
81+
Some(it) => it,
82+
};
83+
84+
if !candidates.is_empty() {
85+
bail!("more than one project")
86+
}
87+
Ok(res)
88+
}
89+
90+
pub fn discover(path: &Path) -> io::Result<Vec<ProjectRoot>> {
9891
if let Some(project_json) = find_rust_project_json(path) {
99-
return Ok(ProjectRoot::ProjectJson(project_json));
92+
return Ok(vec![ProjectRoot::ProjectJson(project_json)]);
10093
}
101-
return find_cargo_toml(path).map(ProjectRoot::CargoToml);
94+
return find_cargo_toml(path)
95+
.map(|paths| paths.into_iter().map(ProjectRoot::CargoToml).collect());
10296

10397
fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
10498
if path.ends_with("rust-project.json") {
@@ -117,43 +111,17 @@ impl ProjectRoot {
117111
None
118112
}
119113

120-
fn find_cargo_toml(path: &Path) -> Result<PathBuf, CargoTomlNotFoundError> {
114+
fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> {
121115
if path.ends_with("Cargo.toml") {
122-
return Ok(path.to_path_buf());
116+
return Ok(vec![path.to_path_buf()]);
123117
}
124118

125119
if let Some(p) = find_cargo_toml_in_parent_dir(path) {
126-
return Ok(p);
120+
return Ok(vec![p]);
127121
}
128122

129-
let entities = match read_dir(path) {
130-
Ok(entities) => entities,
131-
Err(e) => {
132-
return Err(CargoTomlNotFoundError {
133-
searched_at: path.to_path_buf(),
134-
reason: format!("file system error: {}", e),
135-
}
136-
.into());
137-
}
138-
};
139-
140-
let mut valid_canditates = find_cargo_toml_in_child_dir(entities);
141-
return match valid_canditates.len() {
142-
1 => Ok(valid_canditates.remove(0)),
143-
0 => Err(CargoTomlNotFoundError {
144-
searched_at: path.to_path_buf(),
145-
reason: "no Cargo.toml file found".to_string(),
146-
}
147-
.into()),
148-
_ => Err(CargoTomlNotFoundError {
149-
searched_at: path.to_path_buf(),
150-
reason: format!(
151-
"multiple equally valid Cargo.toml files found: {:?}",
152-
valid_canditates
153-
),
154-
}
155-
.into()),
156-
};
123+
let entities = read_dir(path)?;
124+
Ok(find_cargo_toml_in_child_dir(entities))
157125
}
158126

159127
fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> {

crates/rust-analyzer/src/cli/load_cargo.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ pub(crate) fn load_cargo(
2727
load_out_dirs_from_check: bool,
2828
) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
2929
let root = std::env::current_dir()?.join(root);
30-
let root = ProjectRoot::discover(&root)?;
30+
let root = ProjectRoot::discover_single(&root)?;
3131
let ws = ProjectWorkspace::load(
3232
root,
3333
&CargoConfig { load_out_dirs_from_check, ..Default::default() },

crates/rust-analyzer/src/main_loop.rs

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use std::{
1515
};
1616

1717
use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
18+
use itertools::Itertools;
1819
use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
1920
use lsp_types::{
2021
NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams,
@@ -93,27 +94,24 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
9394
let mut visited = FxHashSet::default();
9495
let project_roots = ws_roots
9596
.iter()
96-
.map(|it| ra_project_model::ProjectRoot::discover(it))
97-
.filter_map(|dir| {
98-
dir.map_err(|cargo_toml_not_found| {
99-
log::error!("discovering workspace failed: {:?}", cargo_toml_not_found);
100-
101-
if config.notifications.cargo_toml_not_found {
102-
show_message(
103-
req::MessageType::Error,
104-
format!(
105-
"rust-analyzer failed to discover workspace: {:?}",
106-
cargo_toml_not_found
107-
),
108-
&connection.sender,
109-
);
110-
}
111-
})
112-
.ok()
113-
})
114-
.filter(|it| visited.insert(it.clone()));
97+
.filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok())
98+
.flatten()
99+
.filter(|it| visited.insert(it.clone()))
100+
.collect::<Vec<_>>();
101+
102+
if project_roots.is_empty() && config.notifications.cargo_toml_not_found {
103+
show_message(
104+
req::MessageType::Error,
105+
format!(
106+
"rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}",
107+
ws_roots.iter().format_with(", ", |it, f| f(&it.display()))
108+
),
109+
&connection.sender,
110+
);
111+
};
115112

116113
project_roots
114+
.into_iter()
117115
.filter_map(|root| {
118116
ra_project_model::ProjectWorkspace::load(
119117
root,

0 commit comments

Comments
 (0)