@@ -5,9 +5,8 @@ mod json_project;
55mod sysroot;
66
77use 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} ;
2625pub 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 ) ]
4828pub 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 > {
0 commit comments