diff options
Diffstat (limited to 'crates/ra_project_model/src/lib.rs')
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 51 |
1 files changed, 25 insertions, 26 deletions
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index fe3e81689..ac88532f0 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -7,11 +7,12 @@ mod sysroot; | |||
7 | use std::{ | 7 | use std::{ |
8 | fs::{read_dir, File, ReadDir}, | 8 | fs::{read_dir, File, ReadDir}, |
9 | io::{self, BufReader}, | 9 | io::{self, BufReader}, |
10 | path::{Path, PathBuf}, | 10 | path::Path, |
11 | process::{Command, Output}, | 11 | process::{Command, Output}, |
12 | }; | 12 | }; |
13 | 13 | ||
14 | use anyhow::{bail, Context, Result}; | 14 | use anyhow::{bail, Context, Result}; |
15 | use paths::{AbsPath, AbsPathBuf}; | ||
15 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
16 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; | 17 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; |
17 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -29,7 +30,7 @@ pub enum ProjectWorkspace { | |||
29 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. | 30 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
30 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, | 31 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, |
31 | /// Project workspace was manually specified using a `rust-project.json` file. | 32 | /// Project workspace was manually specified using a `rust-project.json` file. |
32 | Json { project: JsonProject, project_location: PathBuf }, | 33 | Json { project: JsonProject, project_location: AbsPathBuf }, |
33 | } | 34 | } |
34 | 35 | ||
35 | /// `PackageRoot` describes a package root folder. | 36 | /// `PackageRoot` describes a package root folder. |
@@ -38,22 +39,22 @@ pub enum ProjectWorkspace { | |||
38 | #[derive(Debug, Clone)] | 39 | #[derive(Debug, Clone)] |
39 | pub struct PackageRoot { | 40 | pub struct PackageRoot { |
40 | /// Path to the root folder | 41 | /// Path to the root folder |
41 | path: PathBuf, | 42 | path: AbsPathBuf, |
42 | /// Is a member of the current workspace | 43 | /// Is a member of the current workspace |
43 | is_member: bool, | 44 | is_member: bool, |
44 | out_dir: Option<PathBuf>, | 45 | out_dir: Option<AbsPathBuf>, |
45 | } | 46 | } |
46 | impl PackageRoot { | 47 | impl PackageRoot { |
47 | pub fn new_member(path: PathBuf) -> PackageRoot { | 48 | pub fn new_member(path: AbsPathBuf) -> PackageRoot { |
48 | Self { path, is_member: true, out_dir: None } | 49 | Self { path, is_member: true, out_dir: None } |
49 | } | 50 | } |
50 | pub fn new_non_member(path: PathBuf) -> PackageRoot { | 51 | pub fn new_non_member(path: AbsPathBuf) -> PackageRoot { |
51 | Self { path, is_member: false, out_dir: None } | 52 | Self { path, is_member: false, out_dir: None } |
52 | } | 53 | } |
53 | pub fn path(&self) -> &Path { | 54 | pub fn path(&self) -> &AbsPath { |
54 | &self.path | 55 | &self.path |
55 | } | 56 | } |
56 | pub fn out_dir(&self) -> Option<&Path> { | 57 | pub fn out_dir(&self) -> Option<&AbsPath> { |
57 | self.out_dir.as_deref() | 58 | self.out_dir.as_deref() |
58 | } | 59 | } |
59 | pub fn is_member(&self) -> bool { | 60 | pub fn is_member(&self) -> bool { |
@@ -63,12 +64,12 @@ impl PackageRoot { | |||
63 | 64 | ||
64 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] | 65 | #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] |
65 | pub enum ProjectManifest { | 66 | pub enum ProjectManifest { |
66 | ProjectJson(PathBuf), | 67 | ProjectJson(AbsPathBuf), |
67 | CargoToml(PathBuf), | 68 | CargoToml(AbsPathBuf), |
68 | } | 69 | } |
69 | 70 | ||
70 | impl ProjectManifest { | 71 | impl ProjectManifest { |
71 | pub fn from_manifest_file(path: PathBuf) -> Result<ProjectManifest> { | 72 | pub fn from_manifest_file(path: AbsPathBuf) -> Result<ProjectManifest> { |
72 | if path.ends_with("rust-project.json") { | 73 | if path.ends_with("rust-project.json") { |
73 | return Ok(ProjectManifest::ProjectJson(path)); | 74 | return Ok(ProjectManifest::ProjectJson(path)); |
74 | } | 75 | } |
@@ -78,7 +79,7 @@ impl ProjectManifest { | |||
78 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) | 79 | bail!("project root must point to Cargo.toml or rust-project.json: {}", path.display()) |
79 | } | 80 | } |
80 | 81 | ||
81 | pub fn discover_single(path: &Path) -> Result<ProjectManifest> { | 82 | pub fn discover_single(path: &AbsPath) -> Result<ProjectManifest> { |
82 | let mut candidates = ProjectManifest::discover(path)?; | 83 | let mut candidates = ProjectManifest::discover(path)?; |
83 | let res = match candidates.pop() { | 84 | let res = match candidates.pop() { |
84 | None => bail!("no projects"), | 85 | None => bail!("no projects"), |
@@ -91,23 +92,23 @@ impl ProjectManifest { | |||
91 | Ok(res) | 92 | Ok(res) |
92 | } | 93 | } |
93 | 94 | ||
94 | pub fn discover(path: &Path) -> io::Result<Vec<ProjectManifest>> { | 95 | pub fn discover(path: &AbsPath) -> io::Result<Vec<ProjectManifest>> { |
95 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { | 96 | if let Some(project_json) = find_in_parent_dirs(path, "rust-project.json") { |
96 | return Ok(vec![ProjectManifest::ProjectJson(project_json)]); | 97 | return Ok(vec![ProjectManifest::ProjectJson(project_json)]); |
97 | } | 98 | } |
98 | return find_cargo_toml(path) | 99 | return find_cargo_toml(path) |
99 | .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); | 100 | .map(|paths| paths.into_iter().map(ProjectManifest::CargoToml).collect()); |
100 | 101 | ||
101 | fn find_cargo_toml(path: &Path) -> io::Result<Vec<PathBuf>> { | 102 | fn find_cargo_toml(path: &AbsPath) -> io::Result<Vec<AbsPathBuf>> { |
102 | match find_in_parent_dirs(path, "Cargo.toml") { | 103 | match find_in_parent_dirs(path, "Cargo.toml") { |
103 | Some(it) => Ok(vec![it]), | 104 | Some(it) => Ok(vec![it]), |
104 | None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), | 105 | None => Ok(find_cargo_toml_in_child_dir(read_dir(path)?)), |
105 | } | 106 | } |
106 | } | 107 | } |
107 | 108 | ||
108 | fn find_in_parent_dirs(path: &Path, target_file_name: &str) -> Option<PathBuf> { | 109 | fn find_in_parent_dirs(path: &AbsPath, target_file_name: &str) -> Option<AbsPathBuf> { |
109 | if path.ends_with(target_file_name) { | 110 | if path.ends_with(target_file_name) { |
110 | return Some(path.to_owned()); | 111 | return Some(path.to_path_buf()); |
111 | } | 112 | } |
112 | 113 | ||
113 | let mut curr = Some(path); | 114 | let mut curr = Some(path); |
@@ -123,17 +124,18 @@ impl ProjectManifest { | |||
123 | None | 124 | None |
124 | } | 125 | } |
125 | 126 | ||
126 | fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<PathBuf> { | 127 | fn find_cargo_toml_in_child_dir(entities: ReadDir) -> Vec<AbsPathBuf> { |
127 | // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects | 128 | // Only one level down to avoid cycles the easy way and stop a runaway scan with large projects |
128 | entities | 129 | entities |
129 | .filter_map(Result::ok) | 130 | .filter_map(Result::ok) |
130 | .map(|it| it.path().join("Cargo.toml")) | 131 | .map(|it| it.path().join("Cargo.toml")) |
131 | .filter(|it| it.exists()) | 132 | .filter(|it| it.exists()) |
133 | .map(AbsPathBuf::assert) | ||
132 | .collect() | 134 | .collect() |
133 | } | 135 | } |
134 | } | 136 | } |
135 | 137 | ||
136 | pub fn discover_all(paths: &[impl AsRef<Path>]) -> Vec<ProjectManifest> { | 138 | pub fn discover_all(paths: &[impl AsRef<AbsPath>]) -> Vec<ProjectManifest> { |
137 | let mut res = paths | 139 | let mut res = paths |
138 | .iter() | 140 | .iter() |
139 | .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) | 141 | .filter_map(|it| ProjectManifest::discover(it.as_ref()).ok()) |
@@ -158,15 +160,12 @@ impl ProjectWorkspace { | |||
158 | format!("Failed to open json file {}", project_json.display()) | 160 | format!("Failed to open json file {}", project_json.display()) |
159 | })?; | 161 | })?; |
160 | let reader = BufReader::new(file); | 162 | let reader = BufReader::new(file); |
161 | let project_location = match project_json.parent() { | 163 | let project_location = project_json.parent().unwrap().to_path_buf(); |
162 | Some(parent) => PathBuf::from(parent), | ||
163 | None => PathBuf::new(), | ||
164 | }; | ||
165 | ProjectWorkspace::Json { | 164 | ProjectWorkspace::Json { |
166 | project: from_reader(reader).with_context(|| { | 165 | project: from_reader(reader).with_context(|| { |
167 | format!("Failed to deserialize json file {}", project_json.display()) | 166 | format!("Failed to deserialize json file {}", project_json.display()) |
168 | })?, | 167 | })?, |
169 | project_location: project_location, | 168 | project_location, |
170 | } | 169 | } |
171 | } | 170 | } |
172 | ProjectManifest::CargoToml(cargo_toml) => { | 171 | ProjectManifest::CargoToml(cargo_toml) => { |
@@ -218,13 +217,13 @@ impl ProjectWorkspace { | |||
218 | } | 217 | } |
219 | } | 218 | } |
220 | 219 | ||
221 | pub fn proc_macro_dylib_paths(&self) -> Vec<PathBuf> { | 220 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { |
222 | match self { | 221 | match self { |
223 | ProjectWorkspace::Json { project, .. } => project | 222 | ProjectWorkspace::Json { project, project_location } => project |
224 | .crates | 223 | .crates |
225 | .iter() | 224 | .iter() |
226 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) | 225 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) |
227 | .cloned() | 226 | .map(|it| project_location.join(it)) |
228 | .collect(), | 227 | .collect(), |
229 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo | 228 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo |
230 | .packages() | 229 | .packages() |