]> git.lizzy.rs Git - rust.git/commitdiff
more generic, find rustc as well
authorCraig Disselkoen <craigdissel@gmail.com>
Tue, 5 May 2020 20:44:43 +0000 (13:44 -0700)
committerCraig Disselkoen <craigdissel@gmail.com>
Tue, 5 May 2020 23:12:56 +0000 (16:12 -0700)
crates/ra_project_model/src/cargo_workspace.rs
crates/ra_project_model/src/find_executables.rs [new file with mode: 0644]
crates/ra_project_model/src/lib.rs
crates/ra_project_model/src/sysroot.rs

index a15a8c68eda0381aa31aad506916b3df644cf254..c7350d1e021f900cbd978b020a5f4dc0a647a0e5 100644 (file)
@@ -1,14 +1,14 @@
 //! FIXME: write short doc here
 
 use std::{
-    env,
     ffi::OsStr,
     ops,
     path::{Path, PathBuf},
     process::Command,
 };
 
-use anyhow::{Context, Error, Result};
+use super::find_executables::get_path_for_executable;
+use anyhow::{Context, Result};
 use cargo_metadata::{BuildScript, CargoOpt, Message, MetadataCommand, PackageId};
 use ra_arena::{Arena, Idx};
 use ra_db::Edition;
@@ -146,7 +146,7 @@ pub fn from_cargo_metadata(
         cargo_features: &CargoConfig,
     ) -> Result<CargoWorkspace> {
         let mut meta = MetadataCommand::new();
-        meta.cargo_path(cargo_binary()?);
+        meta.cargo_path(get_path_for_executable("cargo")?);
         meta.manifest_path(cargo_toml);
         if cargo_features.all_features {
             meta.features(CargoOpt::AllFeatures);
@@ -284,7 +284,7 @@ pub fn load_extern_resources(
     cargo_toml: &Path,
     cargo_features: &CargoConfig,
 ) -> Result<ExternResources> {
-    let mut cmd = Command::new(cargo_binary()?);
+    let mut cmd = Command::new(get_path_for_executable("cargo")?);
     cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
     if cargo_features.all_features {
         cmd.arg("--all-features");
@@ -332,52 +332,3 @@ fn is_dylib(path: &Path) -> bool {
         Some(ext) => matches!(ext.as_str(), "dll" | "dylib" | "so"),
     }
 }
-
-/// 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<String> {
-    // 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<String> = 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 <dirname>` 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<Path>) -> bool {
-    Command::new(p.as_ref()).arg("--version").output().is_ok()
-}
diff --git a/crates/ra_project_model/src/find_executables.rs b/crates/ra_project_model/src/find_executables.rs
new file mode 100644 (file)
index 0000000..9b020d3
--- /dev/null
@@ -0,0 +1,63 @@
+use anyhow::{Error, Result};
+use std::env;
+use std::path::Path;
+use std::process::Command;
+
+/// Return a `String` to use for the given executable.
+///
+/// E.g., `get_path_for_executable("cargo")` may return just `cargo` if that
+/// gives a valid Cargo executable; or it may return a full path to a valid
+/// Cargo.
+pub fn get_path_for_executable(executable_name: impl AsRef<str>) -> Result<String> {
+    // The current implementation checks three places for an executable to use:
+    // 1) Appropriate environment variable (erroring if this is set but not a usable executable)
+    //      example: for cargo, this checks $CARGO environment variable; for rustc, $RUSTC; etc
+    // 2) `<executable_name>`
+    //      example: for cargo, this tries just `cargo`, which will succeed if `cargo` in on the $PATH
+    // 3) `~/.cargo/bin/<executable_name>`
+    //      example: for cargo, this tries ~/.cargo/bin/cargo
+    //      It seems that this is a reasonable place to try for cargo, rustc, and rustup
+    let executable_name = executable_name.as_ref();
+    let env_var = executable_name.to_ascii_uppercase();
+    if let Ok(path) = env::var(&env_var) {
+        if is_valid_executable(&path) {
+            Ok(path)
+        } else {
+            Err(Error::msg(format!("`{}` environment variable points to something that's not a valid executable", env_var)))
+        }
+    } else {
+        let final_path: Option<String> = if is_valid_executable(executable_name) {
+            Some(executable_name.to_owned())
+        } else {
+            if let Some(mut path) = dirs::home_dir() {
+                path.push(".cargo");
+                path.push("bin");
+                path.push(executable_name);
+                if is_valid_executable(&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/$RUSTC/etc 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 <dirname>` causes VSCode
+            // to inherit environment variables including $PATH, $CARGO, $RUSTC, etc from that terminal;
+            // but launching VSCode from Dock does not inherit environment variables from a terminal.
+            // For more discussion, see #3118.
+            Error::msg(format!("Failed to find `{}` executable. Make sure `{}` is in `$PATH`, or set `${}` to point to a valid executable.", executable_name, executable_name, env_var))
+        )
+    }
+}
+
+/// Does the given `Path` point to a usable executable?
+///
+/// (assumes the executable takes a `--version` switch and writes to stdout,
+/// which is true for `cargo`, `rustc`, and `rustup`)
+fn is_valid_executable(p: impl AsRef<Path>) -> bool {
+    Command::new(p.as_ref()).arg("--version").output().is_ok()
+}
index c2b33c1dcaf1b576e3eb4359bb195ca0f5b80b4b..5028b6b6df9392d5ababc57559f820115f875f77 100644 (file)
@@ -1,6 +1,7 @@
 //! FIXME: write short doc here
 
 mod cargo_workspace;
+mod find_executables;
 mod json_project;
 mod sysroot;
 
index 55ff5ad80bd960076d5d98d4de1d2c79748bd933..8d68032b2ab32785f5d343fbf05cef69d45be87a 100644 (file)
@@ -1,5 +1,6 @@
 //! FIXME: write short doc here
 
+use super::find_executables::get_path_for_executable;
 use anyhow::{bail, Context, Result};
 use std::{
     env, ops,
@@ -114,7 +115,8 @@ fn get_or_install_rust_src(cargo_toml: &Path) -> Result<PathBuf> {
     if let Ok(path) = env::var("RUST_SRC_PATH") {
         return Ok(path.into());
     }
-    let rustc_output = run_command_in_cargo_dir(cargo_toml, "rustc", &["--print", "sysroot"])?;
+    let rustc = get_path_for_executable("rustc")?;
+    let rustc_output = run_command_in_cargo_dir(cargo_toml, &rustc, &["--print", "sysroot"])?;
     let stdout = String::from_utf8(rustc_output.stdout)?;
     let sysroot_path = Path::new(stdout.trim());
     let src_path = sysroot_path.join("lib/rustlib/src/rust/src");