]> git.lizzy.rs Git - rust.git/commitdiff
Unmix error handling when discovering workspaces
authorAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 16 Apr 2020 20:19:38 +0000 (22:19 +0200)
committerAleksey Kladov <aleksey.kladov@gmail.com>
Thu, 16 Apr 2020 20:35:50 +0000 (22:35 +0200)
Hitting an io::Error is a legit problem. Finding more than one
Cargo.toml is not.

crates/ra_project_model/src/lib.rs
crates/rust-analyzer/src/cli/load_cargo.rs
crates/rust-analyzer/src/main_loop.rs

index df4be94dc4a4c26d5b8fc07b362b67f19bed6831..03f2629dae0c76f970e503d92b0bd544d28e449e 100644 (file)
@@ -5,9 +5,8 @@
 mod sysroot;
 
 use std::{
-    error::Error,
     fs::{read_dir, File, ReadDir},
-    io::BufReader,
+    io::{self, BufReader},
     path::{Path, PathBuf},
     process::Command,
 };
 };
 pub use ra_proc_macro::ProcMacroClient;
 
-#[derive(Clone, PartialEq, Eq, Hash, Debug)]
-pub struct CargoTomlNotFoundError {
-    pub searched_at: PathBuf,
-    pub reason: String,
-}
-
-impl std::fmt::Display for CargoTomlNotFoundError {
-    fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        write!(
-            fmt,
-            "can't find Cargo.toml at {}, due to {}",
-            self.searched_at.display(),
-            self.reason
-        )
-    }
-}
-
-impl Error for CargoTomlNotFoundError {}
-
 #[derive(Debug, Clone)]
 pub enum ProjectWorkspace {
     /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
@@ -94,11 +74,25 @@ pub fn from_manifest_file(path: PathBuf) -> Result<ProjectRoot> {
         bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
     }
 
-    pub fn discover(path: &Path) -> Result<ProjectRoot, CargoTomlNotFoundError> {
+    pub fn discover_single(path: &Path) -> Result<ProjectRoot> {
+        let mut candidates = ProjectRoot::discover(path)?;
+        let res = match candidates.pop() {
+            None => bail!("no projects"),
+            Some(it) => it,
+        };
+
+        if !candidates.is_empty() {
+            bail!("more than one project")
+        }
+        Ok(res)
+    }
+
+    pub fn discover(path: &Path) -> io::Result<Vec<ProjectRoot>> {
         if let Some(project_json) = find_rust_project_json(path) {
-            return Ok(ProjectRoot::ProjectJson(project_json));
+            return Ok(vec![ProjectRoot::ProjectJson(project_json)]);
         }
-        return find_cargo_toml(path).map(ProjectRoot::CargoToml);
+        return find_cargo_toml(path)
+            .map(|paths| paths.into_iter().map(ProjectRoot::CargoToml).collect());
 
         fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
             if path.ends_with("rust-project.json") {
@@ -117,43 +111,17 @@ fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
             None
         }
 
-        fn find_cargo_toml(path: &Path) -> Result<PathBuf, CargoTomlNotFoundError> {
+        fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> {
             if path.ends_with("Cargo.toml") {
-                return Ok(path.to_path_buf());
+                return Ok(vec![path.to_path_buf()]);
             }
 
             if let Some(p) = find_cargo_toml_in_parent_dir(path) {
-                return Ok(p);
+                return Ok(vec![p]);
             }
 
-            let entities = match read_dir(path) {
-                Ok(entities) => entities,
-                Err(e) => {
-                    return Err(CargoTomlNotFoundError {
-                        searched_at: path.to_path_buf(),
-                        reason: format!("file system error: {}", e),
-                    }
-                    .into());
-                }
-            };
-
-            let mut valid_canditates = find_cargo_toml_in_child_dir(entities);
-            return match valid_canditates.len() {
-                1 => Ok(valid_canditates.remove(0)),
-                0 => Err(CargoTomlNotFoundError {
-                    searched_at: path.to_path_buf(),
-                    reason: "no Cargo.toml file found".to_string(),
-                }
-                .into()),
-                _ => Err(CargoTomlNotFoundError {
-                    searched_at: path.to_path_buf(),
-                    reason: format!(
-                        "multiple equally valid Cargo.toml files found: {:?}",
-                        valid_canditates
-                    ),
-                }
-                .into()),
-            };
+            let entities = read_dir(path)?;
+            Ok(find_cargo_toml_in_child_dir(entities))
         }
 
         fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> {
index f3f266ee444e00a558f7e8a8445505afd51ba6e1..e620712add63178a65d47df08102e658ce54f410 100644 (file)
@@ -27,7 +27,7 @@ pub(crate) fn load_cargo(
     load_out_dirs_from_check: bool,
 ) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
     let root = std::env::current_dir()?.join(root);
-    let root = ProjectRoot::discover(&root)?;
+    let root = ProjectRoot::discover_single(&root)?;
     let ws = ProjectWorkspace::load(
         root,
         &CargoConfig { load_out_dirs_from_check, ..Default::default() },
index 9c345601cb061440e1b2b0d0e470a9ff129e5ead..fc4c77f8aa5cab89b926cff3c0c468cb9574d3f7 100644 (file)
@@ -15,6 +15,7 @@
 };
 
 use crossbeam_channel::{never, select, unbounded, RecvError, Sender};
+use itertools::Itertools;
 use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestId, Response};
 use lsp_types::{
     NumberOrString, WorkDoneProgress, WorkDoneProgressBegin, WorkDoneProgressCreateParams,
@@ -93,27 +94,24 @@ pub fn main_loop(ws_roots: Vec<PathBuf>, config: Config, connection: Connection)
             let mut visited = FxHashSet::default();
             let project_roots = ws_roots
                 .iter()
-                .map(|it| ra_project_model::ProjectRoot::discover(it))
-                .filter_map(|dir| {
-                    dir.map_err(|cargo_toml_not_found| {
-                        log::error!("discovering workspace failed: {:?}", cargo_toml_not_found);
-
-                        if config.notifications.cargo_toml_not_found {
-                            show_message(
-                                req::MessageType::Error,
-                                format!(
-                                    "rust-analyzer failed to discover workspace: {:?}",
-                                    cargo_toml_not_found
-                                ),
-                                &connection.sender,
-                            );
-                        }
-                    })
-                    .ok()
-                })
-                .filter(|it| visited.insert(it.clone()));
+                .filter_map(|it| ra_project_model::ProjectRoot::discover(it).ok())
+                .flatten()
+                .filter(|it| visited.insert(it.clone()))
+                .collect::<Vec<_>>();
+
+            if project_roots.is_empty() && config.notifications.cargo_toml_not_found {
+                show_message(
+                        req::MessageType::Error,
+                        format!(
+                            "rust-analyzer failed to discover workspace, no Cargo.toml found, dirs searched: {}",
+                            ws_roots.iter().format_with(", ", |it, f| f(&it.display()))
+                        ),
+                        &connection.sender,
+                    );
+            };
 
             project_roots
+                .into_iter()
                 .filter_map(|root| {
                     ra_project_model::ProjectWorkspace::load(
                         root,