aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_project_model/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_project_model/src/lib.rs')
-rw-r--r--crates/ra_project_model/src/lib.rs51
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;
7use std::{ 7use 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
14use anyhow::{bail, Context, Result}; 14use anyhow::{bail, Context, Result};
15use paths::{AbsPath, AbsPathBuf};
15use ra_cfg::CfgOptions; 16use ra_cfg::CfgOptions;
16use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; 17use ra_db::{CrateGraph, CrateName, Edition, Env, FileId};
17use rustc_hash::{FxHashMap, FxHashSet}; 18use 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)]
39pub struct PackageRoot { 40pub 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}
46impl PackageRoot { 47impl 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)]
65pub enum ProjectManifest { 66pub enum ProjectManifest {
66 ProjectJson(PathBuf), 67 ProjectJson(AbsPathBuf),
67 CargoToml(PathBuf), 68 CargoToml(AbsPathBuf),
68} 69}
69 70
70impl ProjectManifest { 71impl 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()