aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_project_model/src
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2020-04-16 21:19:38 +0100
committerAleksey Kladov <[email protected]>2020-04-16 21:35:50 +0100
commit422ae477ce2a52c8d004ce629318f0b7c1d89638 (patch)
tree50b9ce2048599e53d68936ba317aa28c6231b4b1 /crates/ra_project_model/src
parentbe2654b0ed3e4eb51bc3745b2329d6264588549f (diff)
Unmix error handling when discovering workspaces
Hitting an io::Error is a legit problem. Finding more than one Cargo.toml is not.
Diffstat (limited to 'crates/ra_project_model/src')
-rw-r--r--crates/ra_project_model/src/lib.rs78
1 files changed, 23 insertions, 55 deletions
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index df4be94dc..03f2629da 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -5,9 +5,8 @@ mod json_project;
5mod sysroot; 5mod sysroot;
6 6
7use std::{ 7use std::{
8 error::Error,
9 fs::{read_dir, File, ReadDir}, 8 fs::{read_dir, File, ReadDir},
10 io::BufReader, 9 io::{self, BufReader},
11 path::{Path, PathBuf}, 10 path::{Path, PathBuf},
12 process::Command, 11 process::Command,
13}; 12};
@@ -25,25 +24,6 @@ pub use crate::{
25}; 24};
26pub use ra_proc_macro::ProcMacroClient; 25pub use ra_proc_macro::ProcMacroClient;
27 26
28#[derive(Clone, PartialEq, Eq, Hash, Debug)]
29pub struct CargoTomlNotFoundError {
30 pub searched_at: PathBuf,
31 pub reason: String,
32}
33
34impl 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
45impl Error for CargoTomlNotFoundError {}
46
47#[derive(Debug, Clone)] 27#[derive(Debug, Clone)]
48pub enum ProjectWorkspace { 28pub enum ProjectWorkspace {
49 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. 29 /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`.
@@ -94,11 +74,25 @@ impl ProjectRoot {
94 bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) 74 bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display())
95 } 75 }
96 76
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>> {
98 if let Some(project_json) = find_rust_project_json(path) { 91 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)]);
100 } 93 }
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());
102 96
103 fn find_rust_project_json(path: &Path) -> Option<PathBuf> { 97 fn find_rust_project_json(path: &Path) -> Option<PathBuf> {
104 if path.ends_with("rust-project.json") { 98 if path.ends_with("rust-project.json") {
@@ -117,43 +111,17 @@ impl ProjectRoot {
117 None 111 None
118 } 112 }
119 113
120 fn find_cargo_toml(path: &Path) -> Result<PathBuf, CargoTomlNotFoundError> { 114 fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> {
121 if path.ends_with("Cargo.toml") { 115 if path.ends_with("Cargo.toml") {
122 return Ok(path.to_path_buf()); 116 return Ok(vec![path.to_path_buf()]);
123 } 117 }
124 118
125 if let Some(p) = find_cargo_toml_in_parent_dir(path) { 119 if let Some(p) = find_cargo_toml_in_parent_dir(path) {
126 return Ok(p); 120 return Ok(vec![p]);
127 } 121 }
128 122
129 let entities = match read_dir(path) { 123 let entities = read_dir(path)?;
130 Ok(entities) => entities, 124 Ok(find_cargo_toml_in_child_dir(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 };
157 } 125 }
158 126
159 fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> { 127 fn find_cargo_toml_in_parent_dir(path: &Path) -> Option<PathBuf> {