From ffaef1b7aeb61984992e231d9af20f39486403ea Mon Sep 17 00:00:00 2001 From: Craig Disselkoen Date: Tue, 5 May 2020 11:59:41 -0700 Subject: [PATCH] ra_project_model: look for Cargo in more places See #3118 --- Cargo.lock | 77 ++++++++++++++++++- crates/ra_project_model/Cargo.toml | 2 + .../ra_project_model/src/cargo_workspace.rs | 59 +++++++++++--- 3 files changed, 128 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5d50a766fe5..b2d4569b386 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,6 +21,12 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344" +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + [[package]] name = "arrayvec" version = "0.5.1" @@ -66,6 +72,12 @@ dependencies = [ "libc", ] +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + [[package]] name = "base64" version = "0.12.0" @@ -78,6 +90,17 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + [[package]] name = "bstr" version = "0.2.12" @@ -212,6 +235,12 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + [[package]] name = "crossbeam" version = "0.7.3" @@ -289,6 +318,28 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi 0.3.8", +] + [[package]] name = "drop_bomb" version = "0.1.4" @@ -659,7 +710,7 @@ version = "0.74.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0e6a2b8837d27b29deb3f3e6dc1c6d2f57947677f9be1024e482ec5b59525" dependencies = [ - "base64", + "base64 0.12.0", "bitflags", "serde", "serde_json", @@ -1158,6 +1209,7 @@ version = "0.1.0" dependencies = [ "anyhow", "cargo_metadata", + "dirs", "log", "ra_arena", "ra_cfg", @@ -1298,6 +1350,17 @@ version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +[[package]] +name = "redox_users" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + [[package]] name = "regex" version = "1.3.7" @@ -1382,6 +1445,18 @@ dependencies = [ "winapi 0.3.8", ] +[[package]] +name = "rust-argon2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +dependencies = [ + "base64 0.11.0", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + [[package]] name = "rustc-ap-rustc_lexer" version = "656.0.0" diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml index 5e651fe70d9..91958ed947c 100644 --- a/crates/ra_project_model/Cargo.toml +++ b/crates/ra_project_model/Cargo.toml @@ -22,3 +22,5 @@ serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.48" anyhow = "1.0.26" + +dirs = "2.0" diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs index 59f46a2a05e..a15a8c68eda 100644 --- a/crates/ra_project_model/src/cargo_workspace.rs +++ b/crates/ra_project_model/src/cargo_workspace.rs @@ -8,7 +8,7 @@ process::Command, }; -use anyhow::{Context, Result}; +use anyhow::{Context, Error, Result}; use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId}; use ra_arena::{Arena, Idx}; use ra_db::Edition; @@ -145,12 +145,8 @@ pub fn from_cargo_metadata( cargo_toml: &Path, cargo_features: &CargoConfig, ) -> Result { - let _ = Command::new(cargo_binary()) - .arg("--version") - .output() - .context("failed to run `cargo --version`, is `cargo` in PATH?")?; - let mut meta = MetadataCommand::new(); + meta.cargo_path(cargo_binary()?); meta.manifest_path(cargo_toml); if cargo_features.all_features { meta.features(CargoOpt::AllFeatures); @@ -288,7 +284,7 @@ pub fn load_extern_resources( cargo_toml: &Path, cargo_features: &CargoConfig, ) -> Result { - let mut cmd = Command::new(cargo_binary()); + let mut cmd = Command::new(cargo_binary()?); cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml); if cargo_features.all_features { cmd.arg("--all-features"); @@ -337,6 +333,51 @@ fn is_dylib(path: &Path) -> bool { } } -fn cargo_binary() -> String { - env::var("CARGO").unwrap_or_else(|_| "cargo".to_string()) +/// Return a `String` to use for executable `cargo`. +/// +/// E.g., this may just be `cargo` if that gives a valid Cargo executable; or it +/// may be a full path to a valid Cargo. +fn cargo_binary() -> Result { + // The current implementation checks three places for a `cargo` to use: + // 1) $CARGO environment variable (erroring if this is set but not a usable Cargo) + // 2) `cargo` + // 3) `~/.cargo/bin/cargo` + if let Ok(path) = env::var("CARGO") { + if is_valid_cargo(&path) { + Ok(path) + } else { + Err(Error::msg("`CARGO` environment variable points to something that's not a valid Cargo executable")) + } + } else { + let final_path: Option = if is_valid_cargo("cargo") { + Some("cargo".to_owned()) + } else { + if let Some(mut path) = dirs::home_dir() { + path.push(".cargo"); + path.push("bin"); + path.push("cargo"); + if is_valid_cargo(&path) { + Some(path.into_os_string().into_string().expect("Invalid Unicode in path")) + } else { + None + } + } else { + None + } + }; + final_path.ok_or( + // This error message may also be caused by $PATH or $CARGO not being set correctly for VSCode, + // even if they are set correctly in a terminal. + // On macOS in particular, launching VSCode from terminal with `code ` causes VSCode + // to inherit environment variables including $PATH and $CARGO from that terminal; but + // launching VSCode from Dock does not inherit environment variables from a terminal. + // For more discussion, see #3118. + Error::msg("Failed to find `cargo` executable. Make sure `cargo` is in `$PATH`, or set `$CARGO` to point to a valid Cargo executable.") + ) + } +} + +/// Does the given `Path` point to a usable `Cargo`? +fn is_valid_cargo(p: impl AsRef) -> bool { + Command::new(p.as_ref()).arg("--version").output().is_ok() }