diff options
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 | 91 |
2 files changed, 60 insertions, 32 deletions
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index cdcdd63c9..b10644b4b 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml | |||
@@ -16,7 +16,6 @@ cargo_metadata = "0.9.1" | |||
16 | ra_arena = { path = "../ra_arena" } | 16 | ra_arena = { path = "../ra_arena" } |
17 | ra_db = { path = "../ra_db" } | 17 | ra_db = { path = "../ra_db" } |
18 | ra_cfg = { path = "../ra_cfg" } | 18 | ra_cfg = { path = "../ra_cfg" } |
19 | ra_cargo_watch = { path = "../ra_cargo_watch" } | ||
20 | ra_proc_macro = { path = "../ra_proc_macro" } | 19 | ra_proc_macro = { path = "../ra_proc_macro" } |
21 | 20 | ||
22 | serde = { version = "1.0.104", features = ["derive"] } | 21 | serde = { version = "1.0.104", features = ["derive"] } |
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 291594e2a..f4fd6ad28 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs | |||
@@ -1,14 +1,16 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use std::{ | 3 | use std::{ |
4 | env, | ||
5 | ffi::OsStr, | ||
4 | ops, | 6 | ops, |
5 | path::{Path, PathBuf}, | 7 | path::{Path, PathBuf}, |
8 | process::Command, | ||
6 | }; | 9 | }; |
7 | 10 | ||
8 | use anyhow::{Context, Result}; | 11 | use anyhow::{Context, Result}; |
9 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; | 12 | use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; |
10 | use ra_arena::{Arena, Idx}; | 13 | use ra_arena::{Arena, Idx}; |
11 | use ra_cargo_watch::run_cargo; | ||
12 | use ra_db::Edition; | 14 | use ra_db::Edition; |
13 | use rustc_hash::FxHashMap; | 15 | use rustc_hash::FxHashMap; |
14 | use serde::Deserialize; | 16 | use serde::Deserialize; |
@@ -75,6 +77,7 @@ pub type Target = Idx<TargetData>; | |||
75 | 77 | ||
76 | #[derive(Debug, Clone)] | 78 | #[derive(Debug, Clone)] |
77 | pub struct PackageData { | 79 | pub struct PackageData { |
80 | pub id: String, | ||
78 | pub name: String, | 81 | pub name: String, |
79 | pub manifest: PathBuf, | 82 | pub manifest: PathBuf, |
80 | pub targets: Vec<Target>, | 83 | pub targets: Vec<Target>, |
@@ -161,7 +164,7 @@ impl CargoWorkspace { | |||
161 | let mut out_dir_by_id = FxHashMap::default(); | 164 | let mut out_dir_by_id = FxHashMap::default(); |
162 | let mut proc_macro_dylib_paths = FxHashMap::default(); | 165 | let mut proc_macro_dylib_paths = FxHashMap::default(); |
163 | if cargo_features.load_out_dirs_from_check { | 166 | if cargo_features.load_out_dirs_from_check { |
164 | let resources = load_extern_resources(cargo_toml, cargo_features); | 167 | let resources = load_extern_resources(cargo_toml, cargo_features)?; |
165 | out_dir_by_id = resources.out_dirs; | 168 | out_dir_by_id = resources.out_dirs; |
166 | proc_macro_dylib_paths = resources.proc_dylib_paths; | 169 | proc_macro_dylib_paths = resources.proc_dylib_paths; |
167 | } | 170 | } |
@@ -180,6 +183,7 @@ impl CargoWorkspace { | |||
180 | .with_context(|| format!("Failed to parse edition {}", edition))?; | 183 | .with_context(|| format!("Failed to parse edition {}", edition))?; |
181 | let pkg = packages.alloc(PackageData { | 184 | let pkg = packages.alloc(PackageData { |
182 | name, | 185 | name, |
186 | id: id.to_string(), | ||
183 | manifest: manifest_path, | 187 | manifest: manifest_path, |
184 | targets: Vec::new(), | 188 | targets: Vec::new(), |
185 | is_member, | 189 | is_member, |
@@ -249,6 +253,18 @@ impl CargoWorkspace { | |||
249 | pub fn workspace_root(&self) -> &Path { | 253 | pub fn workspace_root(&self) -> &Path { |
250 | &self.workspace_root | 254 | &self.workspace_root |
251 | } | 255 | } |
256 | |||
257 | pub fn package_flag(&self, package: &PackageData) -> String { | ||
258 | if self.is_unique(&*package.name) { | ||
259 | package.name.clone() | ||
260 | } else { | ||
261 | package.id.clone() | ||
262 | } | ||
263 | } | ||
264 | |||
265 | fn is_unique(&self, name: &str) -> bool { | ||
266 | self.packages.iter().filter(|(_, v)| v.name == name).count() == 1 | ||
267 | } | ||
252 | } | 268 | } |
253 | 269 | ||
254 | #[derive(Debug, Clone, Default)] | 270 | #[derive(Debug, Clone, Default)] |
@@ -257,48 +273,61 @@ pub struct ExternResources { | |||
257 | proc_dylib_paths: FxHashMap<PackageId, PathBuf>, | 273 | proc_dylib_paths: FxHashMap<PackageId, PathBuf>, |
258 | } | 274 | } |
259 | 275 | ||
260 | pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) -> ExternResources { | 276 | pub fn load_extern_resources( |
261 | let mut args: Vec<String> = vec![ | 277 | cargo_toml: &Path, |
262 | "check".to_string(), | 278 | cargo_features: &CargoFeatures, |
263 | "--message-format=json".to_string(), | 279 | ) -> Result<ExternResources> { |
264 | "--manifest-path".to_string(), | 280 | let mut cmd = Command::new(cargo_binary()); |
265 | cargo_toml.display().to_string(), | 281 | cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); |
266 | ]; | ||
267 | |||
268 | if cargo_features.all_features { | 282 | if cargo_features.all_features { |
269 | args.push("--all-features".to_string()); | 283 | cmd.arg("--all-features"); |
270 | } else if cargo_features.no_default_features { | 284 | } else if cargo_features.no_default_features { |
271 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` | 285 | // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` |
272 | // https://github.com/oli-obk/cargo_metadata/issues/79 | 286 | // https://github.com/oli-obk/cargo_metadata/issues/79 |
273 | args.push("--no-default-features".to_string()); | 287 | cmd.arg("--no-default-features"); |
274 | } else { | 288 | } else { |
275 | args.extend(cargo_features.features.iter().cloned()); | 289 | cmd.args(&cargo_features.features); |
276 | } | 290 | } |
277 | 291 | ||
278 | let mut acc = ExternResources::default(); | 292 | let output = cmd.output()?; |
279 | let res = run_cargo(&args, cargo_toml.parent(), &mut |message| { | ||
280 | match message { | ||
281 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { | ||
282 | acc.out_dirs.insert(package_id, out_dir); | ||
283 | } | ||
284 | 293 | ||
285 | Message::CompilerArtifact(message) => { | 294 | let mut res = ExternResources::default(); |
286 | if message.target.kind.contains(&"proc-macro".to_string()) { | 295 | |
287 | let package_id = message.package_id; | 296 | let stdout = String::from_utf8(output.stdout)?; |
288 | if let Some(filename) = message.filenames.get(0) { | 297 | for line in stdout.lines() { |
289 | acc.proc_dylib_paths.insert(package_id, filename.clone()); | 298 | if let Ok(message) = serde_json::from_str::<cargo_metadata::Message>(&line) { |
299 | match message { | ||
300 | Message::BuildScriptExecuted(BuildScript { package_id, out_dir, .. }) => { | ||
301 | res.out_dirs.insert(package_id, out_dir); | ||
302 | } | ||
303 | |||
304 | Message::CompilerArtifact(message) => { | ||
305 | if message.target.kind.contains(&"proc-macro".to_string()) { | ||
306 | let package_id = message.package_id; | ||
307 | // Skip rmeta file | ||
308 | if let Some(filename) = | ||
309 | message.filenames.iter().filter(|name| is_dylib(name)).next() | ||
310 | { | ||
311 | res.proc_dylib_paths.insert(package_id, filename.clone()); | ||
312 | } | ||
290 | } | 313 | } |
291 | } | 314 | } |
315 | Message::CompilerMessage(_) => (), | ||
316 | Message::Unknown => (), | ||
292 | } | 317 | } |
293 | Message::CompilerMessage(_) => (), | ||
294 | Message::Unknown => (), | ||
295 | } | 318 | } |
296 | true | 319 | } |
297 | }); | 320 | Ok(res) |
321 | } | ||
298 | 322 | ||
299 | if let Err(err) = res { | 323 | // FIXME: File a better way to know if it is a dylib |
300 | log::error!("Failed to load outdirs: {:?}", err); | 324 | fn is_dylib(path: &Path) -> bool { |
325 | match path.extension().and_then(OsStr::to_str).map(|it| it.to_string().to_lowercase()) { | ||
326 | None => false, | ||
327 | Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"), | ||
301 | } | 328 | } |
329 | } | ||
302 | 330 | ||
303 | acc | 331 | fn cargo_binary() -> String { |
332 | env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()) | ||
304 | } | 333 | } |