diff options
author | Aleksey Kladov <[email protected]> | 2020-06-24 14:52:07 +0100 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2020-06-24 15:16:52 +0100 |
commit | e6c61d5072e600372ba4a38ad8893af37aaa77e6 (patch) | |
tree | fd9b9d3295963b17f65d2a0960189adeae38c3a2 /crates/ra_project_model | |
parent | a07cad16ab6271809d30ecf723420b3e41ec42ef (diff) |
Cleanup project.json deserialization
Diffstat (limited to 'crates/ra_project_model')
-rw-r--r-- | crates/ra_project_model/Cargo.toml | 1 | ||||
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 2 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 77 | ||||
-rw-r--r-- | crates/ra_project_model/src/project_json.rs | 140 |
4 files changed, 110 insertions, 110 deletions
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 818947014..b1b44dcf7 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -19,6 +19,7 @@ ra_db = { path = "../ra_db" } | |||
19 | ra_toolchain = { path = "../ra_toolchain" } | 19 | ra_toolchain = { path = "../ra_toolchain" } |
20 | ra_proc_macro = { path = "../ra_proc_macro" } | 20 | ra_proc_macro = { path = "../ra_proc_macro" } |
21 | paths = { path = "../paths" } | 21 | paths = { path = "../paths" } |
22 | stdx = { path = "../stdx" } | ||
22 | 23 | ||
23 | serde = { version = "1.0.106", features = ["derive"] } | 24 | serde = { version = "1.0.106", features = ["derive"] } |
24 | serde_json = "1.0.48" | 25 | serde_json = "1.0.48" |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 8ce63ab3c..3b124020d 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -260,7 +260,7 @@ impl CargoWorkspace { | |||
260 | .copied() | 260 | .copied() |
261 | } | 261 | } |
262 | 262 | ||
263 | pub fn workspace_root(&self) -> &Path { | 263 | pub fn workspace_root(&self) -> &AbsPath { |
264 | &self.workspace_root | 264 | &self.workspace_root |
265 | } | 265 | } |
266 | 266 | ||
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 7e8e00df8..8b85b4831 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -5,8 +5,8 @@ mod project_json; | |||
5 | mod sysroot; | 5 | mod sysroot; |
6 | 6 | ||
7 | use std::{ | 7 | use std::{ |
8 | fs::{read_dir, File, ReadDir}, | 8 | fs::{self, read_dir, ReadDir}, |
9 | io::{self, BufReader}, | 9 | io, |
10 | path::Path, | 10 | path::Path, |
11 | process::{Command, Output}, | 11 | process::{Command, Output}, |
12 | }; | 12 | }; |
@@ -14,13 +14,12 @@ use std::{ | |||
14 | use anyhow::{bail, Context, Result}; | 14 | use anyhow::{bail, Context, Result}; |
15 | use paths::{AbsPath, AbsPathBuf}; | 15 | use paths::{AbsPath, AbsPathBuf}; |
16 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
17 | use ra_db::{CrateGraph, CrateName, Edition, Env, FileId}; | 17 | use ra_db::{CrateGraph, CrateId, CrateName, Edition, Env, FileId}; |
18 | use rustc_hash::{FxHashMap, FxHashSet}; | 18 | use rustc_hash::{FxHashMap, FxHashSet}; |
19 | use serde_json::from_reader; | ||
20 | 19 | ||
21 | pub use crate::{ | 20 | pub use crate::{ |
22 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, | 21 | cargo_workspace::{CargoConfig, CargoWorkspace, Package, Target, TargetKind}, |
23 | project_json::ProjectJson, | 22 | project_json::{ProjectJson, ProjectJsonData}, |
24 | sysroot::Sysroot, | 23 | sysroot::Sysroot, |
25 | }; | 24 | }; |
26 | pub use ra_proc_macro::ProcMacroClient; | 25 | pub use ra_proc_macro::ProcMacroClient; |
@@ -30,7 +29,7 @@ pub enum ProjectWorkspace { | |||
30 | /// 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`. |
31 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, | 30 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, |
32 | /// Project workspace was manually specified using a `rust-project.json` file. | 31 | /// Project workspace was manually specified using a `rust-project.json` file. |
33 | Json { project: ProjectJson, project_location: AbsPathBuf }, | 32 | Json { project: ProjectJson }, |
34 | } | 33 | } |
35 | 34 | ||
36 | /// `PackageRoot` describes a package root folder. | 35 | /// `PackageRoot` describes a package root folder. |
@@ -156,17 +155,15 @@ impl ProjectWorkspace { | |||
156 | ) -> Result<ProjectWorkspace> { | 155 | ) -> Result<ProjectWorkspace> { |
157 | let res = match manifest { | 156 | let res = match manifest { |
158 | ProjectManifest::ProjectJson(project_json) => { | 157 | ProjectManifest::ProjectJson(project_json) => { |
159 | let file = File::open(&project_json).with_context(|| { | 158 | let file = fs::read_to_string(&project_json).with_context(|| { |
160 | format!("Failed to open json file {}", project_json.display()) | 159 | format!("Failed to read json file {}", project_json.display()) |
160 | })?; | ||
161 | let data = serde_json::from_str(&file).with_context(|| { | ||
162 | format!("Failed to deserialize json file {}", project_json.display()) | ||
161 | })?; | 163 | })?; |
162 | let reader = BufReader::new(file); | ||
163 | let project_location = project_json.parent().unwrap().to_path_buf(); | 164 | let project_location = project_json.parent().unwrap().to_path_buf(); |
164 | ProjectWorkspace::Json { | 165 | let project = ProjectJson::new(&project_location, data); |
165 | project: from_reader(reader).with_context(|| { | 166 | ProjectWorkspace::Json { project } |
166 | format!("Failed to deserialize json file {}", project_json.display()) | ||
167 | })?, | ||
168 | project_location, | ||
169 | } | ||
170 | } | 167 | } |
171 | ProjectManifest::CargoToml(cargo_toml) => { | 168 | ProjectManifest::CargoToml(cargo_toml) => { |
172 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) | 169 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features) |
@@ -198,11 +195,9 @@ impl ProjectWorkspace { | |||
198 | /// the root is a member of the current workspace | 195 | /// the root is a member of the current workspace |
199 | pub fn to_roots(&self) -> Vec<PackageRoot> { | 196 | pub fn to_roots(&self) -> Vec<PackageRoot> { |
200 | match self { | 197 | match self { |
201 | ProjectWorkspace::Json { project, project_location } => project | 198 | ProjectWorkspace::Json { project } => { |
202 | .roots | 199 | project.roots.iter().map(|r| PackageRoot::new_member(r.path.clone())).collect() |
203 | .iter() | 200 | } |
204 | .map(|r| PackageRoot::new_member(project_location.join(&r.path))) | ||
205 | .collect(), | ||
206 | ProjectWorkspace::Cargo { cargo, sysroot } => cargo | 201 | ProjectWorkspace::Cargo { cargo, sysroot } => cargo |
207 | .packages() | 202 | .packages() |
208 | .map(|pkg| PackageRoot { | 203 | .map(|pkg| PackageRoot { |
@@ -219,11 +214,11 @@ impl ProjectWorkspace { | |||
219 | 214 | ||
220 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { | 215 | pub fn proc_macro_dylib_paths(&self) -> Vec<AbsPathBuf> { |
221 | match self { | 216 | match self { |
222 | ProjectWorkspace::Json { project, project_location } => project | 217 | ProjectWorkspace::Json { project } => project |
223 | .crates | 218 | .crates |
224 | .iter() | 219 | .iter() |
225 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) | 220 | .filter_map(|krate| krate.proc_macro_dylib_path.as_ref()) |
226 | .map(|it| project_location.join(it)) | 221 | .cloned() |
227 | .collect(), | 222 | .collect(), |
228 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo | 223 | ProjectWorkspace::Cargo { cargo, sysroot: _sysroot } => cargo |
229 | .packages() | 224 | .packages() |
@@ -246,36 +241,18 @@ impl ProjectWorkspace { | |||
246 | &self, | 241 | &self, |
247 | target: Option<&str>, | 242 | target: Option<&str>, |
248 | proc_macro_client: &ProcMacroClient, | 243 | proc_macro_client: &ProcMacroClient, |
249 | load: &mut dyn FnMut(&Path) -> Option<FileId>, | 244 | load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, |
250 | ) -> CrateGraph { | 245 | ) -> CrateGraph { |
251 | let mut crate_graph = CrateGraph::default(); | 246 | let mut crate_graph = CrateGraph::default(); |
252 | match self { | 247 | match self { |
253 | ProjectWorkspace::Json { project, project_location } => { | 248 | ProjectWorkspace::Json { project } => { |
254 | let crates: FxHashMap<_, _> = project | 249 | let crates: FxHashMap<_, _> = project |
255 | .crates | 250 | .crates |
256 | .iter() | 251 | .iter() |
257 | .enumerate() | 252 | .enumerate() |
258 | .filter_map(|(seq_index, krate)| { | 253 | .filter_map(|(seq_index, krate)| { |
259 | let file_path = project_location.join(&krate.root_module); | 254 | let file_path = &krate.root_module; |
260 | let file_id = load(&file_path)?; | 255 | let file_id = load(&file_path)?; |
261 | let edition = match krate.edition { | ||
262 | project_json::Edition::Edition2015 => Edition::Edition2015, | ||
263 | project_json::Edition::Edition2018 => Edition::Edition2018, | ||
264 | }; | ||
265 | let cfg_options = { | ||
266 | let mut opts = CfgOptions::default(); | ||
267 | for cfg in &krate.cfg { | ||
268 | match cfg.find('=') { | ||
269 | None => opts.insert_atom(cfg.into()), | ||
270 | Some(pos) => { | ||
271 | let key = &cfg[..pos]; | ||
272 | let value = cfg[pos + 1..].trim_matches('"'); | ||
273 | opts.insert_key_value(key.into(), value.into()); | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | opts | ||
278 | }; | ||
279 | 256 | ||
280 | let mut env = Env::default(); | 257 | let mut env = Env::default(); |
281 | if let Some(out_dir) = &krate.out_dir { | 258 | if let Some(out_dir) = &krate.out_dir { |
@@ -290,13 +267,13 @@ impl ProjectWorkspace { | |||
290 | .map(|it| proc_macro_client.by_dylib_path(&it)); | 267 | .map(|it| proc_macro_client.by_dylib_path(&it)); |
291 | // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env | 268 | // FIXME: No crate name in json definition such that we cannot add OUT_DIR to env |
292 | Some(( | 269 | Some(( |
293 | project_json::CrateId(seq_index), | 270 | CrateId(seq_index as u32), |
294 | crate_graph.add_crate_root( | 271 | crate_graph.add_crate_root( |
295 | file_id, | 272 | file_id, |
296 | edition, | 273 | krate.edition, |
297 | // FIXME json definitions can store the crate name | 274 | // FIXME json definitions can store the crate name |
298 | None, | 275 | None, |
299 | cfg_options, | 276 | krate.cfg.clone(), |
300 | env, | 277 | env, |
301 | proc_macro.unwrap_or_default(), | 278 | proc_macro.unwrap_or_default(), |
302 | ), | 279 | ), |
@@ -306,8 +283,8 @@ impl ProjectWorkspace { | |||
306 | 283 | ||
307 | for (id, krate) in project.crates.iter().enumerate() { | 284 | for (id, krate) in project.crates.iter().enumerate() { |
308 | for dep in &krate.deps { | 285 | for dep in &krate.deps { |
309 | let from_crate_id = project_json::CrateId(id); | 286 | let from_crate_id = CrateId(id as u32); |
310 | let to_crate_id = dep.krate; | 287 | let to_crate_id = dep.crate_id; |
311 | if let (Some(&from), Some(&to)) = | 288 | if let (Some(&from), Some(&to)) = |
312 | (crates.get(&from_crate_id), crates.get(&to_crate_id)) | 289 | (crates.get(&from_crate_id), crates.get(&to_crate_id)) |
313 | { | 290 | { |
@@ -523,7 +500,7 @@ impl ProjectWorkspace { | |||
523 | crate_graph | 500 | crate_graph |
524 | } | 501 | } |
525 | 502 | ||
526 | pub fn workspace_root_for(&self, path: &Path) -> Option<&Path> { | 503 | pub fn workspace_root_for(&self, path: &Path) -> Option<&AbsPath> { |
527 | match self { | 504 | match self { |
528 | ProjectWorkspace::Cargo { cargo, .. } => { | 505 | ProjectWorkspace::Cargo { cargo, .. } => { |
529 | Some(cargo.workspace_root()).filter(|root| path.starts_with(root)) | 506 | Some(cargo.workspace_root()).filter(|root| path.starts_with(root)) |
@@ -531,7 +508,7 @@ impl ProjectWorkspace { | |||
531 | ProjectWorkspace::Json { project: ProjectJson { roots, .. }, .. } => roots | 508 | ProjectWorkspace::Json { project: ProjectJson { roots, .. }, .. } => roots |
532 | .iter() | 509 | .iter() |
533 | .find(|root| path.starts_with(&root.path)) | 510 | .find(|root| path.starts_with(&root.path)) |
534 | .map(|root| root.path.as_ref()), | 511 | .map(|root| root.path.as_path()), |
535 | } | 512 | } |
536 | } | 513 | } |
537 | } | 514 | } |
diff --git a/crates/ra_project_model/src/project_json.rs b/crates/ra_project_model/src/project_json.rs index e663bb4d7..4b5dcd634 100644 --- a/crates/ra_project_model/src/project_json.rs +++ b/crates/ra_project_model/src/project_json.rs | |||
@@ -2,11 +2,15 @@ | |||
2 | 2 | ||
3 | use std::path::PathBuf; | 3 | use std::path::PathBuf; |
4 | 4 | ||
5 | use paths::{AbsPath, AbsPathBuf}; | ||
6 | use ra_cfg::CfgOptions; | ||
7 | use ra_db::{CrateId, Dependency, Edition}; | ||
5 | use rustc_hash::FxHashSet; | 8 | use rustc_hash::FxHashSet; |
6 | use serde::Deserialize; | 9 | use serde::Deserialize; |
10 | use stdx::split_delim; | ||
7 | 11 | ||
8 | /// Roots and crates that compose this Rust project. | 12 | /// Roots and crates that compose this Rust project. |
9 | #[derive(Clone, Debug, Deserialize)] | 13 | #[derive(Clone, Debug)] |
10 | pub struct ProjectJson { | 14 | pub struct ProjectJson { |
11 | pub(crate) roots: Vec<Root>, | 15 | pub(crate) roots: Vec<Root>, |
12 | pub(crate) crates: Vec<Crate>, | 16 | pub(crate) crates: Vec<Crate>, |
@@ -14,82 +18,100 @@ pub struct ProjectJson { | |||
14 | 18 | ||
15 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in | 19 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in |
16 | /// all roots. Roots might be nested. | 20 | /// all roots. Roots might be nested. |
17 | #[derive(Clone, Debug, Deserialize)] | 21 | #[derive(Clone, Debug)] |
18 | #[serde(transparent)] | ||
19 | pub struct Root { | 22 | pub struct Root { |
20 | pub(crate) path: PathBuf, | 23 | pub(crate) path: AbsPathBuf, |
21 | } | 24 | } |
22 | 25 | ||
23 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is | 26 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is |
24 | /// useful in creating the crate graph. | 27 | /// useful in creating the crate graph. |
25 | #[derive(Clone, Debug, Deserialize)] | 28 | #[derive(Clone, Debug)] |
26 | pub struct Crate { | 29 | pub struct Crate { |
27 | pub(crate) root_module: PathBuf, | 30 | pub(crate) root_module: AbsPathBuf, |
28 | pub(crate) edition: Edition, | 31 | pub(crate) edition: Edition, |
29 | pub(crate) deps: Vec<Dep>, | 32 | pub(crate) deps: Vec<Dependency>, |
33 | pub(crate) cfg: CfgOptions, | ||
34 | pub(crate) out_dir: Option<AbsPathBuf>, | ||
35 | pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, | ||
36 | } | ||
30 | 37 | ||
31 | #[serde(default)] | 38 | impl ProjectJson { |
32 | pub(crate) cfg: FxHashSet<String>, | 39 | pub fn new(base: &AbsPath, data: ProjectJsonData) -> ProjectJson { |
40 | ProjectJson { | ||
41 | roots: data.roots.into_iter().map(|path| Root { path: base.join(path) }).collect(), | ||
42 | crates: data | ||
43 | .crates | ||
44 | .into_iter() | ||
45 | .map(|crate_data| Crate { | ||
46 | root_module: base.join(crate_data.root_module), | ||
47 | edition: crate_data.edition.into(), | ||
48 | deps: crate_data | ||
49 | .deps | ||
50 | .into_iter() | ||
51 | .map(|dep_data| Dependency { | ||
52 | crate_id: CrateId(dep_data.krate as u32), | ||
53 | name: dep_data.name.into(), | ||
54 | }) | ||
55 | .collect::<Vec<_>>(), | ||
56 | cfg: { | ||
57 | let mut cfg = CfgOptions::default(); | ||
58 | for entry in &crate_data.cfg { | ||
59 | match split_delim(entry, '=') { | ||
60 | Some((key, value)) => { | ||
61 | cfg.insert_key_value(key.into(), value.into()); | ||
62 | } | ||
63 | None => cfg.insert_atom(entry.into()), | ||
64 | } | ||
65 | } | ||
66 | cfg | ||
67 | }, | ||
68 | out_dir: crate_data.out_dir.map(|it| base.join(it)), | ||
69 | proc_macro_dylib_path: crate_data.proc_macro_dylib_path.map(|it| base.join(it)), | ||
70 | }) | ||
71 | .collect::<Vec<_>>(), | ||
72 | } | ||
73 | } | ||
74 | } | ||
33 | 75 | ||
34 | pub(crate) out_dir: Option<PathBuf>, | 76 | #[derive(Deserialize)] |
35 | pub(crate) proc_macro_dylib_path: Option<PathBuf>, | 77 | pub struct ProjectJsonData { |
78 | roots: Vec<PathBuf>, | ||
79 | crates: Vec<CrateData>, | ||
36 | } | 80 | } |
37 | 81 | ||
38 | #[derive(Clone, Copy, Debug, Deserialize)] | 82 | #[derive(Deserialize)] |
83 | struct CrateData { | ||
84 | root_module: PathBuf, | ||
85 | edition: EditionData, | ||
86 | deps: Vec<DepData>, | ||
87 | #[serde(default)] | ||
88 | cfg: FxHashSet<String>, | ||
89 | out_dir: Option<PathBuf>, | ||
90 | proc_macro_dylib_path: Option<PathBuf>, | ||
91 | } | ||
92 | |||
93 | #[derive(Deserialize)] | ||
39 | #[serde(rename = "edition")] | 94 | #[serde(rename = "edition")] |
40 | pub enum Edition { | 95 | enum EditionData { |
41 | #[serde(rename = "2015")] | 96 | #[serde(rename = "2015")] |
42 | Edition2015, | 97 | Edition2015, |
43 | #[serde(rename = "2018")] | 98 | #[serde(rename = "2018")] |
44 | Edition2018, | 99 | Edition2018, |
45 | } | 100 | } |
46 | 101 | ||
47 | /// Identifies a crate by position in the crates array. | 102 | impl From<EditionData> for Edition { |
48 | #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)] | 103 | fn from(data: EditionData) -> Self { |
49 | #[serde(transparent)] | 104 | match data { |
50 | pub struct CrateId(pub usize); | 105 | EditionData::Edition2015 => Edition::Edition2015, |
51 | 106 | EditionData::Edition2018 => Edition::Edition2018, | |
52 | /// A dependency of a crate, identified by its id in the crates array and name. | 107 | } |
53 | #[derive(Clone, Debug, Deserialize)] | 108 | } |
54 | pub struct Dep { | ||
55 | #[serde(rename = "crate")] | ||
56 | pub(crate) krate: CrateId, | ||
57 | pub(crate) name: String, | ||
58 | } | 109 | } |
59 | 110 | ||
60 | #[cfg(test)] | 111 | #[derive(Deserialize)] |
61 | mod tests { | 112 | struct DepData { |
62 | use super::*; | 113 | /// Identifies a crate by position in the crates array. |
63 | use serde_json::json; | 114 | #[serde(rename = "crate")] |
64 | 115 | krate: usize, | |
65 | #[test] | 116 | name: String, |
66 | fn test_crate_deserialization() { | ||
67 | let raw_json = json!( { | ||
68 | "crate_id": 2, | ||
69 | "root_module": "this/is/a/file/path.rs", | ||
70 | "deps": [ | ||
71 | { | ||
72 | "crate": 1, | ||
73 | "name": "some_dep_crate" | ||
74 | }, | ||
75 | ], | ||
76 | "edition": "2015", | ||
77 | "cfg": [ | ||
78 | "atom_1", | ||
79 | "atom_2", | ||
80 | "feature=feature_1", | ||
81 | "feature=feature_2", | ||
82 | "other=value", | ||
83 | ], | ||
84 | |||
85 | }); | ||
86 | |||
87 | let krate: Crate = serde_json::from_value(raw_json).unwrap(); | ||
88 | |||
89 | assert!(krate.cfg.contains(&"atom_1".to_string())); | ||
90 | assert!(krate.cfg.contains(&"atom_2".to_string())); | ||
91 | assert!(krate.cfg.contains(&"feature=feature_1".to_string())); | ||
92 | assert!(krate.cfg.contains(&"feature=feature_2".to_string())); | ||
93 | assert!(krate.cfg.contains(&"other=value".to_string())); | ||
94 | } | ||
95 | } | 117 | } |