diff options
author | David Wood <[email protected]> | 2019-03-05 21:29:23 +0000 |
---|---|---|
committer | David Wood <[email protected]> | 2019-03-07 00:05:03 +0000 |
commit | 00d927a1885ec2938d3365a8e136993445b437f5 (patch) | |
tree | e60f63e68def477d5b7ceb39dcc965ff128d6e19 /crates | |
parent | b1a1d20e067c25fb80fbab43b2956b6747a8dd3c (diff) |
Initial implementation of project-lock.json.
This commit adds a initial implementation of project-lock.json, a build
system agnostic method of specifying the crate graph and roots.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_batch/src/lib.rs | 7 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/cargo_target_spec.rs | 20 | ||||
-rw-r--r-- | crates/ra_lsp_server/src/server_world.rs | 9 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/main.rs | 65 | ||||
-rw-r--r-- | crates/ra_lsp_server/tests/heavy_tests/support.rs | 6 | ||||
-rw-r--r-- | crates/ra_project_model/Cargo.toml | 3 | ||||
-rw-r--r-- | crates/ra_project_model/src/json_project.rs | 49 | ||||
-rw-r--r-- | crates/ra_project_model/src/lib.rs | 238 |
8 files changed, 304 insertions, 93 deletions
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs index 89a234f4c..2db038063 100644 --- a/crates/ra_batch/src/lib.rs +++ b/crates/ra_batch/src/lib.rs | |||
@@ -99,12 +99,7 @@ impl BatchDatabase { | |||
99 | let ws = ProjectWorkspace::discover(root.as_ref())?; | 99 | let ws = ProjectWorkspace::discover(root.as_ref())?; |
100 | let mut roots = Vec::new(); | 100 | let mut roots = Vec::new(); |
101 | roots.push(root.clone()); | 101 | roots.push(root.clone()); |
102 | for pkg in ws.cargo.packages() { | 102 | ws.add_roots(&mut roots); |
103 | roots.push(pkg.root(&ws.cargo).to_path_buf()); | ||
104 | } | ||
105 | for krate in ws.sysroot.crates() { | ||
106 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) | ||
107 | } | ||
108 | let (mut vfs, roots) = Vfs::new(roots); | 103 | let (mut vfs, roots) = Vfs::new(roots); |
109 | let mut load = |path: &Path| { | 104 | let mut load = |path: &Path| { |
110 | let vfs_file = vfs.load(path); | 105 | let vfs_file = vfs.load(path); |
diff --git a/crates/ra_lsp_server/src/cargo_target_spec.rs b/crates/ra_lsp_server/src/cargo_target_spec.rs index e011eab7c..cdf2ec10b 100644 --- a/crates/ra_lsp_server/src/cargo_target_spec.rs +++ b/crates/ra_lsp_server/src/cargo_target_spec.rs | |||
@@ -1,5 +1,5 @@ | |||
1 | use crate::{ | 1 | use crate::{ |
2 | project_model::TargetKind, | 2 | project_model::{self, TargetKind}, |
3 | server_world::ServerWorld, | 3 | server_world::ServerWorld, |
4 | Result | 4 | Result |
5 | }; | 5 | }; |
@@ -65,14 +65,16 @@ impl CargoTargetSpec { | |||
65 | }; | 65 | }; |
66 | let file_id = world.analysis().crate_root(crate_id)?; | 66 | let file_id = world.analysis().crate_root(crate_id)?; |
67 | let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0.into())); | 67 | let path = world.vfs.read().file2path(ra_vfs::VfsFile(file_id.0.into())); |
68 | let res = world.workspaces.iter().find_map(|ws| { | 68 | let res = world.workspaces.iter().find_map(|ws| match ws { |
69 | let tgt = ws.cargo.target_by_root(&path)?; | 69 | project_model::ProjectWorkspace::Cargo { cargo, .. } => { |
70 | let res = CargoTargetSpec { | 70 | let tgt = cargo.target_by_root(&path)?; |
71 | package: tgt.package(&ws.cargo).name(&ws.cargo).to_string(), | 71 | Some(CargoTargetSpec { |
72 | target: tgt.name(&ws.cargo).to_string(), | 72 | package: tgt.package(&cargo).name(&cargo).to_string(), |
73 | target_kind: tgt.kind(&ws.cargo), | 73 | target: tgt.name(&cargo).to_string(), |
74 | }; | 74 | target_kind: tgt.kind(&cargo), |
75 | Some(res) | 75 | }) |
76 | } | ||
77 | project_model::ProjectWorkspace::Json { .. } => None, | ||
76 | }); | 78 | }); |
77 | Ok(res) | 79 | Ok(res) |
78 | } | 80 | } |
diff --git a/crates/ra_lsp_server/src/server_world.rs b/crates/ra_lsp_server/src/server_world.rs index 4a68c019f..4625a26a7 100644 --- a/crates/ra_lsp_server/src/server_world.rs +++ b/crates/ra_lsp_server/src/server_world.rs | |||
@@ -40,12 +40,7 @@ impl ServerWorldState { | |||
40 | let mut roots = Vec::new(); | 40 | let mut roots = Vec::new(); |
41 | roots.push(root.clone()); | 41 | roots.push(root.clone()); |
42 | for ws in workspaces.iter() { | 42 | for ws in workspaces.iter() { |
43 | for pkg in ws.cargo.packages() { | 43 | ws.add_roots(&mut roots); |
44 | roots.push(pkg.root(&ws.cargo).to_path_buf()); | ||
45 | } | ||
46 | for krate in ws.sysroot.crates() { | ||
47 | roots.push(krate.root_dir(&ws.sysroot).to_path_buf()) | ||
48 | } | ||
49 | } | 44 | } |
50 | let (mut vfs, roots) = Vfs::new(roots); | 45 | let (mut vfs, roots) = Vfs::new(roots); |
51 | let roots_to_scan = roots.len(); | 46 | let roots_to_scan = roots.len(); |
@@ -185,7 +180,7 @@ impl ServerWorld { | |||
185 | } else { | 180 | } else { |
186 | res.push_str("workspaces:\n"); | 181 | res.push_str("workspaces:\n"); |
187 | for w in self.workspaces.iter() { | 182 | for w in self.workspaces.iter() { |
188 | res += &format!("{} packages loaded\n", w.cargo.packages().count()); | 183 | res += &format!("{} packages loaded\n", w.count()); |
189 | } | 184 | } |
190 | } | 185 | } |
191 | res.push_str("\nanalysis:\n"); | 186 | res.push_str("\nanalysis:\n"); |
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs index 1c099a78f..641f84cfc 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/main.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs | |||
@@ -12,8 +12,9 @@ use ra_lsp_server::req::{ | |||
12 | CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion, | 12 | CodeActionParams, CodeActionRequest, Formatting, Runnables, RunnablesParams, CompletionParams, Completion, |
13 | }; | 13 | }; |
14 | use serde_json::json; | 14 | use serde_json::json; |
15 | use tempfile::TempDir; | ||
15 | 16 | ||
16 | use crate::support::project; | 17 | use crate::support::{project, project_with_tmpdir}; |
17 | 18 | ||
18 | const LOG: &'static str = ""; | 19 | const LOG: &'static str = ""; |
19 | 20 | ||
@@ -258,3 +259,65 @@ fn main() {} | |||
258 | json!([]), | 259 | json!([]), |
259 | ); | 260 | ); |
260 | } | 261 | } |
262 | |||
263 | #[test] | ||
264 | fn test_missing_module_code_action_in_json_project() { | ||
265 | let tmp_dir = TempDir::new().unwrap(); | ||
266 | let code = format!( | ||
267 | r#" | ||
268 | //- rust-project.json | ||
269 | {{ | ||
270 | "roots": [ "{PATH}" ], | ||
271 | "crates": [ {{ "root_module": "{PATH}/src/lib.rs", "deps": [], "edition": "2015" }} ] | ||
272 | }} | ||
273 | |||
274 | //- src/lib.rs | ||
275 | mod bar; | ||
276 | |||
277 | fn main() {} | ||
278 | "#, | ||
279 | PATH = tmp_dir.path().display() | ||
280 | ); | ||
281 | let server = project_with_tmpdir(tmp_dir, &code); | ||
282 | server.wait_for_feedback("workspace loaded"); | ||
283 | let empty_context = || CodeActionContext { diagnostics: Vec::new(), only: None }; | ||
284 | server.request::<CodeActionRequest>( | ||
285 | CodeActionParams { | ||
286 | text_document: server.doc_id("src/lib.rs"), | ||
287 | range: Range::new(Position::new(0, 4), Position::new(0, 7)), | ||
288 | context: empty_context(), | ||
289 | }, | ||
290 | json!([ | ||
291 | { | ||
292 | "command": { | ||
293 | "arguments": [ | ||
294 | { | ||
295 | "cursorPosition": null, | ||
296 | "label": "create module", | ||
297 | "workspaceEdit": { | ||
298 | "documentChanges": [ | ||
299 | { | ||
300 | "kind": "create", | ||
301 | "uri": "file:///[..]/src/bar.rs" | ||
302 | } | ||
303 | ] | ||
304 | } | ||
305 | } | ||
306 | ], | ||
307 | "command": "rust-analyzer.applySourceChange", | ||
308 | "title": "create module" | ||
309 | }, | ||
310 | "title": "create module" | ||
311 | } | ||
312 | ]), | ||
313 | ); | ||
314 | |||
315 | server.request::<CodeActionRequest>( | ||
316 | CodeActionParams { | ||
317 | text_document: server.doc_id("src/lib.rs"), | ||
318 | range: Range::new(Position::new(2, 4), Position::new(2, 7)), | ||
319 | context: empty_context(), | ||
320 | }, | ||
321 | json!([]), | ||
322 | ); | ||
323 | } | ||
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs index 8bfc8d622..e02d7858e 100644 --- a/crates/ra_lsp_server/tests/heavy_tests/support.rs +++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs | |||
@@ -27,12 +27,16 @@ use ra_lsp_server::{ | |||
27 | }; | 27 | }; |
28 | 28 | ||
29 | pub fn project(fixture: &str) -> Server { | 29 | pub fn project(fixture: &str) -> Server { |
30 | let tmp_dir = TempDir::new().unwrap(); | ||
31 | project_with_tmpdir(tmp_dir, fixture) | ||
32 | } | ||
33 | |||
34 | pub fn project_with_tmpdir(tmp_dir: TempDir, fixture: &str) -> Server { | ||
30 | static INIT: Once = Once::new(); | 35 | static INIT: Once = Once::new(); |
31 | INIT.call_once(|| { | 36 | INIT.call_once(|| { |
32 | let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); | 37 | let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); |
33 | }); | 38 | }); |
34 | 39 | ||
35 | let tmp_dir = TempDir::new().unwrap(); | ||
36 | let mut paths = vec![]; | 40 | let mut paths = vec![]; |
37 | 41 | ||
38 | for entry in parse_fixture(fixture) { | 42 | for entry in parse_fixture(fixture) { |
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 262406e99..487cdfaf1 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -17,5 +17,8 @@ cargo_metadata = "0.7.0" | |||
17 | ra_arena = { path = "../ra_arena" } | 17 | ra_arena = { path = "../ra_arena" } |
18 | ra_db = { path = "../ra_db" } | 18 | ra_db = { path = "../ra_db" } |
19 | 19 | ||
20 | serde = "1.0.89" | ||
21 | serde_json = "1.0.39" | ||
22 | |||
20 | [dev-dependencies] | 23 | [dev-dependencies] |
21 | test_utils = { path = "../test_utils" } | 24 | test_utils = { path = "../test_utils" } |
diff --git a/crates/ra_project_model/src/json_project.rs b/crates/ra_project_model/src/json_project.rs new file mode 100644 index 000000000..9a9eb9e1f --- /dev/null +++ b/crates/ra_project_model/src/json_project.rs | |||
@@ -0,0 +1,49 @@ | |||
1 | use std::path::PathBuf; | ||
2 | |||
3 | use serde::Deserialize; | ||
4 | |||
5 | /// A root points to the directory which contains Rust crates. rust-analyzer watches all files in | ||
6 | /// all roots. Roots might be nested. | ||
7 | #[derive(Clone, Debug, Deserialize)] | ||
8 | #[serde(transparent)] | ||
9 | pub struct Root { | ||
10 | pub(crate) path: PathBuf, | ||
11 | } | ||
12 | |||
13 | /// A crate points to the root module of a crate and lists the dependencies of the crate. This is | ||
14 | /// useful in creating the crate graph. | ||
15 | #[derive(Clone, Debug, Deserialize)] | ||
16 | pub struct Crate { | ||
17 | pub(crate) root_module: PathBuf, | ||
18 | pub(crate) edition: Edition, | ||
19 | pub(crate) deps: Vec<Dep>, | ||
20 | } | ||
21 | |||
22 | #[derive(Clone, Copy, Debug, Deserialize)] | ||
23 | #[serde(rename = "edition")] | ||
24 | pub enum Edition { | ||
25 | #[serde(rename = "2015")] | ||
26 | Edition2015, | ||
27 | #[serde(rename = "2018")] | ||
28 | Edition2018, | ||
29 | } | ||
30 | |||
31 | /// Identifies a crate by position in the crates array. | ||
32 | #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd)] | ||
33 | #[serde(transparent)] | ||
34 | pub struct CrateId(pub usize); | ||
35 | |||
36 | /// A dependency of a crate, identified by its id in the crates array and name. | ||
37 | #[derive(Clone, Debug, Deserialize)] | ||
38 | pub struct Dep { | ||
39 | #[serde(rename = "crate")] | ||
40 | pub(crate) krate: CrateId, | ||
41 | pub(crate) name: String, | ||
42 | } | ||
43 | |||
44 | /// Roots and crates that compose this Rust project. | ||
45 | #[derive(Clone, Debug, Deserialize)] | ||
46 | pub struct JsonProject { | ||
47 | pub(crate) roots: Vec<Root>, | ||
48 | pub(crate) crates: Vec<Crate>, | ||
49 | } | ||
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs index 1b18ac836..ded222446 100644 --- a/crates/ra_project_model/src/lib.rs +++ b/crates/ra_project_model/src/lib.rs | |||
@@ -1,15 +1,23 @@ | |||
1 | mod cargo_workspace; | 1 | mod cargo_workspace; |
2 | mod json_project; | ||
2 | mod sysroot; | 3 | mod sysroot; |
3 | 4 | ||
4 | use std::path::{Path, PathBuf}; | 5 | use std::{ |
6 | fs::File, | ||
7 | io::BufReader, | ||
8 | path::{Path, PathBuf}, | ||
9 | }; | ||
5 | 10 | ||
6 | use failure::bail; | 11 | use failure::bail; |
7 | use rustc_hash::FxHashMap; | 12 | use rustc_hash::FxHashMap; |
8 | 13 | ||
9 | use ra_db::{CrateGraph, FileId, Edition}; | 14 | use ra_db::{CrateGraph, FileId, Edition}; |
10 | 15 | ||
16 | use serde_json::from_reader; | ||
17 | |||
11 | pub use crate::{ | 18 | pub use crate::{ |
12 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, | 19 | cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, |
20 | json_project::JsonProject, | ||
13 | sysroot::Sysroot, | 21 | sysroot::Sysroot, |
14 | }; | 22 | }; |
15 | 23 | ||
@@ -17,105 +25,197 @@ pub use crate::{ | |||
17 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; | 25 | pub type Result<T> = ::std::result::Result<T, ::failure::Error>; |
18 | 26 | ||
19 | #[derive(Debug, Clone)] | 27 | #[derive(Debug, Clone)] |
20 | pub struct ProjectWorkspace { | 28 | pub enum ProjectWorkspace { |
21 | pub cargo: CargoWorkspace, | 29 | /// Project workspace was discovered by running `cargo metadata` and `rustc --print sysroot`. |
22 | pub sysroot: Sysroot, | 30 | Cargo { cargo: CargoWorkspace, sysroot: Sysroot }, |
31 | /// Project workspace was manually specified using a `rust-project.json` file. | ||
32 | Json { project: JsonProject }, | ||
23 | } | 33 | } |
24 | 34 | ||
25 | impl ProjectWorkspace { | 35 | impl ProjectWorkspace { |
26 | pub fn discover(path: &Path) -> Result<ProjectWorkspace> { | 36 | pub fn discover(path: &Path) -> Result<ProjectWorkspace> { |
27 | let cargo_toml = find_cargo_toml(path)?; | 37 | match find_rust_project_json(path) { |
28 | let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; | 38 | Some(json_path) => { |
29 | let sysroot = Sysroot::discover(&cargo_toml)?; | 39 | let file = File::open(json_path)?; |
30 | let res = ProjectWorkspace { cargo, sysroot }; | 40 | let reader = BufReader::new(file); |
31 | Ok(res) | 41 | Ok(ProjectWorkspace::Json { project: from_reader(reader)? }) |
42 | } | ||
43 | None => { | ||
44 | let cargo_toml = find_cargo_toml(path)?; | ||
45 | Ok(ProjectWorkspace::Cargo { | ||
46 | cargo: CargoWorkspace::from_cargo_metadata(&cargo_toml)?, | ||
47 | sysroot: Sysroot::discover(&cargo_toml)?, | ||
48 | }) | ||
49 | } | ||
50 | } | ||
32 | } | 51 | } |
33 | 52 | ||
34 | pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option<FileId>) -> CrateGraph { | 53 | pub fn add_roots(&self, roots: &mut Vec<PathBuf>) { |
35 | let mut crate_graph = CrateGraph::default(); | 54 | match self { |
36 | let mut sysroot_crates = FxHashMap::default(); | 55 | ProjectWorkspace::Json { project } => { |
37 | for krate in self.sysroot.crates() { | 56 | for root in &project.roots { |
38 | if let Some(file_id) = load(krate.root(&self.sysroot)) { | 57 | roots.push(root.path.clone()); |
39 | sysroot_crates | 58 | } |
40 | .insert(krate, crate_graph.add_crate_root(file_id, Edition::Edition2015)); | ||
41 | } | 59 | } |
42 | } | 60 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
43 | for from in self.sysroot.crates() { | 61 | for pkg in cargo.packages() { |
44 | for to in from.deps(&self.sysroot) { | 62 | roots.push(pkg.root(&cargo).to_path_buf()); |
45 | let name = to.name(&self.sysroot); | 63 | } |
46 | if let (Some(&from), Some(&to)) = | 64 | for krate in sysroot.crates() { |
47 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | 65 | roots.push(krate.root_dir(&sysroot).to_path_buf()) |
48 | { | ||
49 | if let Err(_) = crate_graph.add_dep(from, name.into(), to) { | ||
50 | log::error!("cyclic dependency between sysroot crates") | ||
51 | } | ||
52 | } | 66 | } |
53 | } | 67 | } |
54 | } | 68 | } |
69 | } | ||
55 | 70 | ||
56 | let libstd = self.sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | 71 | pub fn count(&self) -> usize { |
57 | 72 | match self { | |
58 | let mut pkg_to_lib_crate = FxHashMap::default(); | 73 | ProjectWorkspace::Json { project } => project.crates.len(), |
59 | let mut pkg_crates = FxHashMap::default(); | 74 | ProjectWorkspace::Cargo { cargo, .. } => cargo.packages().count(), |
60 | // Next, create crates for each package, target pair | 75 | } |
61 | for pkg in self.cargo.packages() { | 76 | } |
62 | let mut lib_tgt = None; | 77 | |
63 | for tgt in pkg.targets(&self.cargo) { | 78 | pub fn to_crate_graph(&self, load: &mut dyn FnMut(&Path) -> Option<FileId>) -> CrateGraph { |
64 | let root = tgt.root(&self.cargo); | 79 | let mut crate_graph = CrateGraph::default(); |
65 | if let Some(file_id) = load(root) { | 80 | match self { |
66 | let edition = pkg.edition(&self.cargo); | 81 | ProjectWorkspace::Json { project } => { |
67 | let crate_id = crate_graph.add_crate_root(file_id, edition); | 82 | let mut crates = FxHashMap::default(); |
68 | if tgt.kind(&self.cargo) == TargetKind::Lib { | 83 | for (id, krate) in project.crates.iter().enumerate() { |
69 | lib_tgt = Some(crate_id); | 84 | let crate_id = json_project::CrateId(id); |
70 | pkg_to_lib_crate.insert(pkg, crate_id); | 85 | if let Some(file_id) = load(&krate.root_module) { |
86 | let edition = match krate.edition { | ||
87 | json_project::Edition::Edition2015 => Edition::Edition2015, | ||
88 | json_project::Edition::Edition2018 => Edition::Edition2018, | ||
89 | }; | ||
90 | crates.insert(crate_id, crate_graph.add_crate_root(file_id, edition)); | ||
71 | } | 91 | } |
72 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
73 | } | 92 | } |
74 | } | ||
75 | 93 | ||
76 | // Set deps to the std and to the lib target of the current package | 94 | for (id, krate) in project.crates.iter().enumerate() { |
77 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 95 | for dep in &krate.deps { |
78 | if let Some(to) = lib_tgt { | 96 | let from_crate_id = json_project::CrateId(id); |
79 | if to != from { | 97 | let to_crate_id = dep.krate; |
80 | if let Err(_) = crate_graph.add_dep(from, pkg.name(&self.cargo).into(), to) | 98 | if let (Some(&from), Some(&to)) = |
99 | (crates.get(&from_crate_id), crates.get(&to_crate_id)) | ||
81 | { | 100 | { |
82 | log::error!( | 101 | if let Err(_) = crate_graph.add_dep(from, dep.name.clone().into(), to) { |
83 | "cyclic dependency between targets of {}", | 102 | log::error!( |
84 | pkg.name(&self.cargo) | 103 | "cyclic dependency {:?} -> {:?}", |
85 | ) | 104 | from_crate_id, |
105 | to_crate_id | ||
106 | ); | ||
107 | } | ||
86 | } | 108 | } |
87 | } | 109 | } |
88 | } | 110 | } |
89 | if let Some(std) = libstd { | 111 | } |
90 | if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { | 112 | ProjectWorkspace::Cargo { cargo, sysroot } => { |
91 | log::error!("cyclic dependency on std for {}", pkg.name(&self.cargo)) | 113 | let mut sysroot_crates = FxHashMap::default(); |
114 | for krate in sysroot.crates() { | ||
115 | if let Some(file_id) = load(krate.root(&sysroot)) { | ||
116 | sysroot_crates.insert( | ||
117 | krate, | ||
118 | crate_graph.add_crate_root(file_id, Edition::Edition2015), | ||
119 | ); | ||
92 | } | 120 | } |
93 | } | 121 | } |
94 | } | 122 | for from in sysroot.crates() { |
95 | } | 123 | for to in from.deps(&sysroot) { |
124 | let name = to.name(&sysroot); | ||
125 | if let (Some(&from), Some(&to)) = | ||
126 | (sysroot_crates.get(&from), sysroot_crates.get(&to)) | ||
127 | { | ||
128 | if let Err(_) = crate_graph.add_dep(from, name.into(), to) { | ||
129 | log::error!("cyclic dependency between sysroot crates") | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | } | ||
134 | |||
135 | let libstd = sysroot.std().and_then(|it| sysroot_crates.get(&it).map(|&it| it)); | ||
136 | |||
137 | let mut pkg_to_lib_crate = FxHashMap::default(); | ||
138 | let mut pkg_crates = FxHashMap::default(); | ||
139 | // Next, create crates for each package, target pair | ||
140 | for pkg in cargo.packages() { | ||
141 | let mut lib_tgt = None; | ||
142 | for tgt in pkg.targets(&cargo) { | ||
143 | let root = tgt.root(&cargo); | ||
144 | if let Some(file_id) = load(root) { | ||
145 | let edition = pkg.edition(&cargo); | ||
146 | let crate_id = crate_graph.add_crate_root(file_id, edition); | ||
147 | if tgt.kind(&cargo) == TargetKind::Lib { | ||
148 | lib_tgt = Some(crate_id); | ||
149 | pkg_to_lib_crate.insert(pkg, crate_id); | ||
150 | } | ||
151 | pkg_crates.entry(pkg).or_insert_with(Vec::new).push(crate_id); | ||
152 | } | ||
153 | } | ||
96 | 154 | ||
97 | // Now add a dep ednge from all targets of upstream to the lib | 155 | // Set deps to the std and to the lib target of the current package |
98 | // target of downstream. | ||
99 | for pkg in self.cargo.packages() { | ||
100 | for dep in pkg.dependencies(&self.cargo) { | ||
101 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
102 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | 156 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { |
103 | if let Err(_) = crate_graph.add_dep(from, dep.name.clone().into(), to) { | 157 | if let Some(to) = lib_tgt { |
104 | log::error!( | 158 | if to != from { |
105 | "cyclic dependency {} -> {}", | 159 | if let Err(_) = |
106 | pkg.name(&self.cargo), | 160 | crate_graph.add_dep(from, pkg.name(&cargo).into(), to) |
107 | dep.pkg.name(&self.cargo) | 161 | { |
108 | ) | 162 | log::error!( |
163 | "cyclic dependency between targets of {}", | ||
164 | pkg.name(&cargo) | ||
165 | ) | ||
166 | } | ||
167 | } | ||
168 | } | ||
169 | if let Some(std) = libstd { | ||
170 | if let Err(_) = crate_graph.add_dep(from, "std".into(), std) { | ||
171 | log::error!("cyclic dependency on std for {}", pkg.name(&cargo)) | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | // Now add a dep ednge from all targets of upstream to the lib | ||
178 | // target of downstream. | ||
179 | for pkg in cargo.packages() { | ||
180 | for dep in pkg.dependencies(&cargo) { | ||
181 | if let Some(&to) = pkg_to_lib_crate.get(&dep.pkg) { | ||
182 | for &from in pkg_crates.get(&pkg).into_iter().flatten() { | ||
183 | if let Err(_) = | ||
184 | crate_graph.add_dep(from, dep.name.clone().into(), to) | ||
185 | { | ||
186 | log::error!( | ||
187 | "cyclic dependency {} -> {}", | ||
188 | pkg.name(&cargo), | ||
189 | dep.pkg.name(&cargo) | ||
190 | ) | ||
191 | } | ||
192 | } | ||
109 | } | 193 | } |
110 | } | 194 | } |
111 | } | 195 | } |
112 | } | 196 | } |
113 | } | 197 | } |
114 | |||
115 | crate_graph | 198 | crate_graph |
116 | } | 199 | } |
117 | } | 200 | } |
118 | 201 | ||
202 | fn find_rust_project_json(path: &Path) -> Option<PathBuf> { | ||
203 | if path.ends_with("rust-project.json") { | ||
204 | return Some(path.to_path_buf()); | ||
205 | } | ||
206 | |||
207 | let mut curr = Some(path); | ||
208 | while let Some(path) = curr { | ||
209 | let candidate = path.join("rust-project.json"); | ||
210 | if candidate.exists() { | ||
211 | return Some(candidate); | ||
212 | } | ||
213 | curr = path.parent(); | ||
214 | } | ||
215 | |||
216 | None | ||
217 | } | ||
218 | |||
119 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { | 219 | fn find_cargo_toml(path: &Path) -> Result<PathBuf> { |
120 | if path.ends_with("Cargo.toml") { | 220 | if path.ends_with("Cargo.toml") { |
121 | return Ok(path.to_path_buf()); | 221 | return Ok(path.to_path_buf()); |