aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_project_model
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_project_model')
-rw-r--r--crates/ra_project_model/Cargo.toml1
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs91
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"
16ra_arena = { path = "../ra_arena" } 16ra_arena = { path = "../ra_arena" }
17ra_db = { path = "../ra_db" } 17ra_db = { path = "../ra_db" }
18ra_cfg = { path = "../ra_cfg" } 18ra_cfg = { path = "../ra_cfg" }
19ra_cargo_watch = { path = "../ra_cargo_watch" }
20ra_proc_macro = { path = "../ra_proc_macro" } 19ra_proc_macro = { path = "../ra_proc_macro" }
21 20
22serde = { version = "1.0.104", features = ["derive"] } 21serde = { 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
3use std::{ 3use 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
8use anyhow::{Context, Result}; 11use anyhow::{Context, Result};
9use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; 12use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
10use ra_arena::{Arena, Idx}; 13use ra_arena::{Arena, Idx};
11use ra_cargo_watch::run_cargo;
12use ra_db::Edition; 14use ra_db::Edition;
13use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
14use serde::Deserialize; 16use serde::Deserialize;
@@ -75,6 +77,7 @@ pub type Target = Idx<TargetData>;
75 77
76#[derive(Debug, Clone)] 78#[derive(Debug, Clone)]
77pub struct PackageData { 79pub 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
260pub fn load_extern_resources(cargo_toml: &Path, cargo_features: &CargoFeatures) -> ExternResources { 276pub 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); 324fn 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 331fn cargo_binary() -> String {
332 env::var("CARGO").unwrap_or_else(|_| "cargo".to_string())
304} 333}