From c9b395be2bfcd67e045c1031143b7e8c27a6d3fb Mon Sep 17 00:00:00 2001 From: veetaha Date: Wed, 6 May 2020 01:42:04 +0300 Subject: [PATCH] Fix cargo not found on macos bug at vscode extension side --- editors/code/src/cargo.ts | 36 +++++++++++++++++++++++++++++++++++- editors/code/src/main.ts | 8 ++------ editors/code/src/util.ts | 11 +++++++++++ 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/editors/code/src/cargo.ts b/editors/code/src/cargo.ts index 613aa82da9..2a2c2e0e1b 100644 --- a/editors/code/src/cargo.ts +++ b/editors/code/src/cargo.ts @@ -1,6 +1,9 @@ import * as cp from 'child_process'; +import * as os from 'os'; +import * as path from 'path'; import * as readline from 'readline'; import { OutputChannel } from 'vscode'; +import { isValidExecutable } from './util'; interface CompilationArtifact { fileName: string; @@ -63,7 +66,14 @@ export class Cargo { onStderrString: (data: string) => void ): Promise { return new Promise((resolve, reject) => { - const cargo = cp.spawn('cargo', cargoArgs, { + let cargoPath; + try { + cargoPath = getCargoPathOrFail(); + } catch (err) { + return reject(err); + } + + const cargo = cp.spawn(cargoPath, cargoArgs, { stdio: ['ignore', 'pipe', 'pipe'], cwd: this.rootFolder }); @@ -87,3 +97,27 @@ export class Cargo { }); } } + +// Mirrors `ra_env::get_path_for_executable` implementation +function getCargoPathOrFail(): string { + const envVar = process.env.CARGO; + const executableName = "cargo"; + + if (envVar) { + if (isValidExecutable(envVar)) return envVar; + + throw new Error(`\`${envVar}\` environment variable points to something that's not a valid executable`); + } + + if (isValidExecutable(executableName)) return executableName; + + const standardLocation = path.join(os.homedir(), '.cargo', 'bin', executableName); + + if (isValidExecutable(standardLocation)) return standardLocation; + + throw new Error( + `Failed to find \`${executableName}\` executable. ` + + `Make sure \`${executableName}\` is in \`$PATH\`, ` + + `or set \`${envVar}\` to point to a valid executable.` + ); +} diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts index efd56a84b5..9b020d0019 100644 --- a/editors/code/src/main.ts +++ b/editors/code/src/main.ts @@ -8,10 +8,9 @@ import { activateInlayHints } from './inlay_hints'; import { activateStatusDisplay } from './status_display'; import { Ctx } from './ctx'; import { Config, NIGHTLY_TAG } from './config'; -import { log, assert } from './util'; +import { log, assert, isValidExecutable } from './util'; import { PersistentState } from './persistent_state'; import { fetchRelease, download } from './net'; -import { spawnSync } from 'child_process'; import { activateTaskProvider } from './tasks'; let ctx: Ctx | undefined; @@ -179,10 +178,7 @@ async function bootstrapServer(config: Config, state: PersistentState): Promise< log.debug("Using server binary at", path); - const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); - log.debug("Checked binary availability via --version", res); - log.debug(res, "--version output:", res.output); - if (res.status !== 0) { + if (!isValidExecutable(path)) { throw new Error(`Failed to execute ${path} --version`); } diff --git a/editors/code/src/util.ts b/editors/code/src/util.ts index 6f91f81d63..127a9e9112 100644 --- a/editors/code/src/util.ts +++ b/editors/code/src/util.ts @@ -1,6 +1,7 @@ import * as lc from "vscode-languageclient"; import * as vscode from "vscode"; import { strict as nativeAssert } from "assert"; +import { spawnSync } from "child_process"; export function assert(condition: boolean, explanation: string): asserts condition { try { @@ -82,3 +83,13 @@ export function isRustDocument(document: vscode.TextDocument): document is RustD export function isRustEditor(editor: vscode.TextEditor): editor is RustEditor { return isRustDocument(editor.document); } + +export function isValidExecutable(path: string): boolean { + log.debug("Checking availability of a binary at", path); + + const res = spawnSync(path, ["--version"], { encoding: 'utf8' }); + + log.debug(res, "--version output:", res.output); + + return res.status === 0; +}