diff options
Diffstat (limited to 'crates/ra_project_model/src/cargo_workspace.rs')
-rw-r--r-- | crates/ra_project_model/src/cargo_workspace.rs | 67 |
1 files changed, 65 insertions, 2 deletions
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 4fea459d5..10ecfa951 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -3,8 +3,9 @@ | |||
3 | use std::path::{Path, PathBuf}; | 3 | use std::path::{Path, PathBuf}; |
4 | 4 | ||
5 | use anyhow::{Context, Result}; | 5 | use anyhow::{Context, Result}; |
6 | use cargo_metadata::{CargoOpt, MetadataCommand}; | 6 | use cargo_metadata::{CargoOpt, Message, MetadataCommand, PackageId}; |
7 | use ra_arena::{impl_arena_id, Arena, RawId}; | 7 | use ra_arena::{impl_arena_id, Arena, RawId}; |
8 | use ra_cargo_watch::run_cargo; | ||
8 | use ra_db::Edition; | 9 | use ra_db::Edition; |
9 | use rustc_hash::FxHashMap; | 10 | use rustc_hash::FxHashMap; |
10 | use serde::Deserialize; | 11 | use serde::Deserialize; |
@@ -35,11 +36,19 @@ pub struct CargoFeatures { | |||
35 | /// List of features to activate. | 36 | /// List of features to activate. |
36 | /// This will be ignored if `cargo_all_features` is true. | 37 | /// This will be ignored if `cargo_all_features` is true. |
37 | pub features: Vec<String>, | 38 | pub features: Vec<String>, |
39 | |||
40 | /// Runs cargo check on launch to figure out the correct values of OUT_DIR | ||
41 | pub load_out_dirs_from_check: bool, | ||
38 | } | 42 | } |
39 | 43 | ||
40 | impl Default for CargoFeatures { | 44 | impl Default for CargoFeatures { |
41 | fn default() -> Self { | 45 | fn default() -> Self { |
42 | CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() } | 46 | CargoFeatures { |
47 | no_default_features: false, | ||
48 | all_features: true, | ||
49 | features: Vec::new(), | ||
50 | load_out_dirs_from_check: false, | ||
51 | } | ||
43 | } | 52 | } |
44 | } | 53 | } |
45 | 54 | ||
@@ -60,6 +69,7 @@ struct PackageData { | |||
60 | dependencies: Vec<PackageDependency>, | 69 | dependencies: Vec<PackageDependency>, |
61 | edition: Edition, | 70 | edition: Edition, |
62 | features: Vec<String>, | 71 | features: Vec<String>, |
72 | out_dir: Option<PathBuf>, | ||
63 | } | 73 | } |
64 | 74 | ||
65 | #[derive(Debug, Clone)] | 75 | #[derive(Debug, Clone)] |
@@ -131,6 +141,9 @@ impl Package { | |||
131 | ) -> impl Iterator<Item = &'a PackageDependency> + 'a { | 141 | ) -> impl Iterator<Item = &'a PackageDependency> + 'a { |
132 | ws.packages[self].dependencies.iter() | 142 | ws.packages[self].dependencies.iter() |
133 | } | 143 | } |
144 | pub fn out_dir(self, ws: &CargoWorkspace) -> Option<&Path> { | ||
145 | ws.packages[self].out_dir.as_ref().map(PathBuf::as_path) | ||
146 | } | ||
134 | } | 147 | } |
135 | 148 | ||
136 | impl Target { | 149 | impl Target { |
@@ -173,6 +186,12 @@ impl CargoWorkspace { | |||
173 | let meta = meta.exec().with_context(|| { | 186 | let meta = meta.exec().with_context(|| { |
174 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) | 187 | format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display()) |
175 | })?; | 188 | })?; |
189 | |||
190 | let mut out_dir_by_id = FxHashMap::default(); | ||
191 | if cargo_features.load_out_dirs_from_check { | ||
192 | out_dir_by_id = load_out_dirs(cargo_toml, cargo_features); | ||
193 | } | ||
194 | |||
176 | let mut pkg_by_id = FxHashMap::default(); | 195 | let mut pkg_by_id = FxHashMap::default(); |
177 | let mut packages = Arena::default(); | 196 | let mut packages = Arena::default(); |
178 | let mut targets = Arena::default(); | 197 | let mut targets = Arena::default(); |
@@ -193,6 +212,7 @@ impl CargoWorkspace { | |||
193 | edition, | 212 | edition, |
194 | dependencies: Vec::new(), | 213 | dependencies: Vec::new(), |
195 | features: Vec::new(), | 214 | features: Vec::new(), |
215 | out_dir: out_dir_by_id.get(&id).cloned(), | ||
196 | }); | 216 | }); |
197 | let pkg_data = &mut packages[pkg]; | 217 | let pkg_data = &mut packages[pkg]; |
198 | pkg_by_id.insert(id, pkg); | 218 | pkg_by_id.insert(id, pkg); |
@@ -252,3 +272,46 @@ impl CargoWorkspace { | |||
252 | &self.workspace_root | 272 | &self.workspace_root |
253 | } | 273 | } |
254 | } | 274 | } |
275 | |||
276 | pub fn load_out_dirs( | ||
277 | cargo_toml: &Path, | ||
278 | cargo_features: &CargoFeatures, | ||
279 | ) -> FxHashMap<PackageId, PathBuf> { | ||
280 | let mut args: Vec<String> = vec![ | ||
281 | "check".to_string(), | ||
282 | "--message-format=json".to_string(), | ||
283 | "--manifest-path".to_string(), | ||
284 | format!("{}", cargo_toml.display()), | ||
285 | ]; | ||
286 | |||
287 | if cargo_features.all_features { | ||
288 | args.push("--all-features".to_string()); | ||
289 | } else if cargo_features.no_default_features { | ||
290 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | ||
291 | // https://github.com/oli-obk/cargo_metadata/issues/79 | ||
292 | args.push("--no-default-features".to_string()); | ||
293 | } else if !cargo_features.features.is_empty() { | ||
294 | for feature in &cargo_features.features { | ||
295 | args.push(feature.clone()); | ||
296 | } | ||
297 | } | ||
298 | |||
299 | let mut res = FxHashMap::default(); | ||
300 | let mut child = run_cargo(&args, cargo_toml.parent(), &mut |message| { | ||
301 | match message { | ||
302 | Message::BuildScriptExecuted(message) => { | ||
303 | let package_id = message.package_id; | ||
304 | let out_dir = message.out_dir; | ||
305 | res.insert(package_id, out_dir); | ||
306 | } | ||
307 | |||
308 | Message::CompilerArtifact(_) => (), | ||
309 | Message::CompilerMessage(_) => (), | ||
310 | Message::Unknown => (), | ||
311 | } | ||
312 | true | ||
313 | }); | ||
314 | |||
315 | let _ = child.wait(); | ||
316 | res | ||
317 | } | ||