From 5d88c1db38200896d2e4af7836fec95097adf509 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 8 Feb 2020 04:22:44 +0200 Subject: vscode: amended config to use binary from globalStoragePath, added ui for downloading --- editors/code/src/installation/language_server.ts | 119 +++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 editors/code/src/installation/language_server.ts (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts new file mode 100644 index 000000000..2b3ce6621 --- /dev/null +++ b/editors/code/src/installation/language_server.ts @@ -0,0 +1,119 @@ +import { unwrapNotNil } from "ts-not-nil"; +import { spawnSync } from "child_process"; +import * as vscode from "vscode"; +import * as path from "path"; +import { strict as assert } from "assert"; +import { promises as fs } from "fs"; + +import { BinarySource, BinarySourceType, GithubBinarySource } from "./interfaces"; +import { fetchLatestArtifactMetadata } from "./fetch_latest_artifact_metadata"; +import { downloadFile } from "./download_file"; + +export async function downloadLatestLanguageServer( + {file: artifactFileName, dir: installationDir, repo}: GithubBinarySource +) { + const binaryMetadata = await fetchLatestArtifactMetadata({ artifactFileName, repo }); + + const { + releaseName, + downloadUrl + } = unwrapNotNil(binaryMetadata, `Latest GitHub release lacks "${artifactFileName}" file`); + + await fs.mkdir(installationDir).catch(err => assert.strictEqual( + err && err.code, + "EEXIST", + `Couldn't create directory "${installationDir}" to download `+ + `language server binary: ${err.message}` + )); + + const installationPath = path.join(installationDir, artifactFileName); + + await vscode.window.withProgress( + { + location: vscode.ProgressLocation.Notification, + cancellable: false, // FIXME: add support for canceling download? + title: `Downloading language server ${releaseName}` + }, + async (progress, _) => { + let lastPrecentage = 0; + await downloadFile(downloadUrl, installationPath, (readBytes, totalBytes) => { + const newPercentage = (readBytes / totalBytes) * 100; + progress.report({ + message: newPercentage.toFixed(0) + "%", + increment: newPercentage - lastPrecentage + }); + + lastPrecentage = newPercentage; + }); + } + ); + + await fs.chmod(installationPath, 111); // Set xxx permissions +} +export async function ensureLanguageServerBinary( + langServerSource: null | BinarySource +): Promise { + + if (!langServerSource) { + vscode.window.showErrorMessage( + "Unfortunately we don't ship binaries for your platform yet. " + + "You need to manually clone rust-analyzer repository and " + + "run `cargo xtask install --server` to build the language server from sources. " + + "If you feel that your platform should be supported, please create an issue " + + "about that [here](https://github.com/rust-analyzer/rust-analyzer/issues) and we " + + "will consider it." + ); + return null; + } + + switch (langServerSource.type) { + case BinarySourceType.ExplicitPath: { + if (isBinaryAvailable(langServerSource.path)) { + return langServerSource.path; + } + vscode.window.showErrorMessage( + `Unable to execute ${'`'}${langServerSource.path} --version${'`'}. ` + + "To use the bundled language server, set `rust-analyzer.raLspServerPath` " + + "value to `null` or remove it from the settings to use it by default." + ); + return null; + } + case BinarySourceType.GithubBinary: { + const bundledBinaryPath = path.join(langServerSource.dir, langServerSource.file); + + if (!isBinaryAvailable(bundledBinaryPath)) { + const userResponse = await vscode.window.showInformationMessage( + `Language server binary for rust-analyzer was not found. ` + + `Do you want to download it now?`, + "Download now", "Cancel" + ); + if (userResponse !== "Download now") return null; + + try { + await downloadLatestLanguageServer(langServerSource); + } catch (err) { + await vscode.window.showErrorMessage( + `Failed to download language server from ${langServerSource.repo.name} ` + + `GitHub repository: ${err.message}` + ); + return null; + } + + + assert( + isBinaryAvailable(bundledBinaryPath), + "Downloaded language server binary is not functional" + ); + + vscode.window.showInformationMessage( + "Rust analyzer language server was successfully installed" + ); + } + return bundledBinaryPath; + } + } + + function isBinaryAvailable(binaryPath: string) { + return spawnSync(binaryPath, ["--version"]).status === 0; + } +} -- cgit v1.2.3 From f7ef72db64e75dadf6f7cae9d739a0a6e8d8f4b4 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 8 Feb 2020 20:07:00 +0200 Subject: vscode: changed chmod value to 755 as per @lnicola --- editors/code/src/installation/language_server.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index 2b3ce6621..8d8c62952 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -12,7 +12,7 @@ import { downloadFile } from "./download_file"; export async function downloadLatestLanguageServer( {file: artifactFileName, dir: installationDir, repo}: GithubBinarySource ) { - const binaryMetadata = await fetchLatestArtifactMetadata({ artifactFileName, repo }); + const binaryMetadata = await fetchLatestArtifactMetadata(repo, artifactFileName); const { releaseName, @@ -20,7 +20,7 @@ export async function downloadLatestLanguageServer( } = unwrapNotNil(binaryMetadata, `Latest GitHub release lacks "${artifactFileName}" file`); await fs.mkdir(installationDir).catch(err => assert.strictEqual( - err && err.code, + err?.code, "EEXIST", `Couldn't create directory "${installationDir}" to download `+ `language server binary: ${err.message}` @@ -48,7 +48,7 @@ export async function downloadLatestLanguageServer( } ); - await fs.chmod(installationPath, 111); // Set xxx permissions + await fs.chmod(installationPath, 755); // Set (rwx, r_x, r_x) permissions } export async function ensureLanguageServerBinary( langServerSource: null | BinarySource -- cgit v1.2.3 From 9791b6a8de7149d97cdf9880d86bfc9e640c8297 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sat, 8 Feb 2020 21:24:29 +0200 Subject: vscode: add name to the second unused argument of withProgress() callback --- editors/code/src/installation/language_server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index 8d8c62952..b75d3a00a 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -34,7 +34,7 @@ export async function downloadLatestLanguageServer( cancellable: false, // FIXME: add support for canceling download? title: `Downloading language server ${releaseName}` }, - async (progress, _) => { + async (progress, _cancellationToken) => { let lastPrecentage = 0; await downloadFile(downloadUrl, installationPath, (readBytes, totalBytes) => { const newPercentage = (readBytes / totalBytes) * 100; -- cgit v1.2.3 From 539daf4454e3f11424a469e8fba26cacb325176a Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 00:27:04 +0200 Subject: vscode: refactor platform artifact name query to switch statement, move BinarySource union variants into a namespace --- editors/code/src/installation/language_server.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index b75d3a00a..522d59eb5 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -5,12 +5,12 @@ import * as path from "path"; import { strict as assert } from "assert"; import { promises as fs } from "fs"; -import { BinarySource, BinarySourceType, GithubBinarySource } from "./interfaces"; +import { BinarySource } from "./interfaces"; import { fetchLatestArtifactMetadata } from "./fetch_latest_artifact_metadata"; import { downloadFile } from "./download_file"; export async function downloadLatestLanguageServer( - {file: artifactFileName, dir: installationDir, repo}: GithubBinarySource + {file: artifactFileName, dir: installationDir, repo}: BinarySource.GithubRelease ) { const binaryMetadata = await fetchLatestArtifactMetadata(repo, artifactFileName); @@ -67,7 +67,7 @@ export async function ensureLanguageServerBinary( } switch (langServerSource.type) { - case BinarySourceType.ExplicitPath: { + case BinarySource.Type.ExplicitPath: { if (isBinaryAvailable(langServerSource.path)) { return langServerSource.path; } @@ -78,7 +78,7 @@ export async function ensureLanguageServerBinary( ); return null; } - case BinarySourceType.GithubBinary: { + case BinarySource.Type.GithubRelease: { const bundledBinaryPath = path.join(langServerSource.dir, langServerSource.file); if (!isBinaryAvailable(bundledBinaryPath)) { @@ -106,7 +106,7 @@ export async function ensureLanguageServerBinary( ); vscode.window.showInformationMessage( - "Rust analyzer language server was successfully installed" + "Rust analyzer language server was successfully installed 🦀" ); } return bundledBinaryPath; -- cgit v1.2.3 From d08ae7e82f9eb4abb92f1274ea361acb21fd7b87 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 00:58:53 +0200 Subject: vscode: minor names and message contents changes --- editors/code/src/installation/language_server.ts | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index 522d59eb5..d09fc63a7 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -72,19 +72,19 @@ export async function ensureLanguageServerBinary( return langServerSource.path; } vscode.window.showErrorMessage( - `Unable to execute ${'`'}${langServerSource.path} --version${'`'}. ` + - "To use the bundled language server, set `rust-analyzer.raLspServerPath` " + + `Unable to run ${langServerSource.path} binary. ` + + "To use the pre-built language server, set `rust-analyzer.raLspServerPath` " + "value to `null` or remove it from the settings to use it by default." ); return null; } case BinarySource.Type.GithubRelease: { - const bundledBinaryPath = path.join(langServerSource.dir, langServerSource.file); + const prebuiltBinaryPath = path.join(langServerSource.dir, langServerSource.file); - if (!isBinaryAvailable(bundledBinaryPath)) { + if (!isBinaryAvailable(prebuiltBinaryPath)) { const userResponse = await vscode.window.showInformationMessage( - `Language server binary for rust-analyzer was not found. ` + - `Do you want to download it now?`, + "Language server binary for rust-analyzer was not found. " + + "Do you want to download it now?", "Download now", "Cancel" ); if (userResponse !== "Download now") return null; @@ -101,7 +101,7 @@ export async function ensureLanguageServerBinary( assert( - isBinaryAvailable(bundledBinaryPath), + isBinaryAvailable(prebuiltBinaryPath), "Downloaded language server binary is not functional" ); @@ -109,7 +109,7 @@ export async function ensureLanguageServerBinary( "Rust analyzer language server was successfully installed 🦀" ); } - return bundledBinaryPath; + return prebuiltBinaryPath; } } -- cgit v1.2.3 From a3e3fba7bf9cbaa51d39ecfd2b111472fdbf4cb3 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 12:54:51 +0200 Subject: vscode: fix chmod to octal literal Co-Authored-By: Aleksey Kladov --- editors/code/src/installation/language_server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index d09fc63a7..ea1228e46 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -48,7 +48,7 @@ export async function downloadLatestLanguageServer( } ); - await fs.chmod(installationPath, 755); // Set (rwx, r_x, r_x) permissions + await fs.chmod(installationPath, 0o755); // Set (rwx, r_x, r_x) permissions } export async function ensureLanguageServerBinary( langServerSource: null | BinarySource -- cgit v1.2.3 From 3159e87c49cd43677927ba7baa8f12c1232183a1 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 13:36:36 +0200 Subject: vscode: refactor levels of code nesting and string literals quotes --- editors/code/src/installation/language_server.ts | 56 +++++++++++++----------- 1 file changed, 30 insertions(+), 26 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index ea1228e46..e571cbc98 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -71,9 +71,10 @@ export async function ensureLanguageServerBinary( if (isBinaryAvailable(langServerSource.path)) { return langServerSource.path; } + vscode.window.showErrorMessage( `Unable to run ${langServerSource.path} binary. ` + - "To use the pre-built language server, set `rust-analyzer.raLspServerPath` " + + `To use the pre-built language server, set "rust-analyzer.raLspServerPath" ` + "value to `null` or remove it from the settings to use it by default." ); return null; @@ -81,34 +82,37 @@ export async function ensureLanguageServerBinary( case BinarySource.Type.GithubRelease: { const prebuiltBinaryPath = path.join(langServerSource.dir, langServerSource.file); - if (!isBinaryAvailable(prebuiltBinaryPath)) { - const userResponse = await vscode.window.showInformationMessage( - "Language server binary for rust-analyzer was not found. " + - "Do you want to download it now?", - "Download now", "Cancel" - ); - if (userResponse !== "Download now") return null; - - try { - await downloadLatestLanguageServer(langServerSource); - } catch (err) { - await vscode.window.showErrorMessage( - `Failed to download language server from ${langServerSource.repo.name} ` + - `GitHub repository: ${err.message}` - ); - return null; - } - - - assert( - isBinaryAvailable(prebuiltBinaryPath), - "Downloaded language server binary is not functional" - ); + if (isBinaryAvailable(prebuiltBinaryPath)) { + return prebuiltBinaryPath; + } - vscode.window.showInformationMessage( - "Rust analyzer language server was successfully installed 🦀" + const userResponse = await vscode.window.showInformationMessage( + "Language server binary for rust-analyzer was not found. " + + "Do you want to download it now?", + "Download now", "Cancel" + ); + if (userResponse !== "Download now") return null; + + try { + await downloadLatestLanguageServer(langServerSource); + } catch (err) { + await vscode.window.showErrorMessage( + `Failed to download language server from ${langServerSource.repo.name} ` + + `GitHub repository: ${err.message}` ); + return null; } + + + assert( + isBinaryAvailable(prebuiltBinaryPath), + "Downloaded language server binary is not functional" + ); + + vscode.window.showInformationMessage( + "Rust analyzer language server was successfully installed 🦀" + ); + return prebuiltBinaryPath; } } -- cgit v1.2.3 From a63659badb75d22ad834b7524e77505790c10dd0 Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 13:59:27 +0200 Subject: vscode: replaced unwrapNotNil() with ! as per @matklad --- editors/code/src/installation/language_server.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index e571cbc98..a169eae47 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -1,4 +1,3 @@ -import { unwrapNotNil } from "ts-not-nil"; import { spawnSync } from "child_process"; import * as vscode from "vscode"; import * as path from "path"; @@ -12,12 +11,9 @@ import { downloadFile } from "./download_file"; export async function downloadLatestLanguageServer( {file: artifactFileName, dir: installationDir, repo}: BinarySource.GithubRelease ) { - const binaryMetadata = await fetchLatestArtifactMetadata(repo, artifactFileName); - - const { - releaseName, - downloadUrl - } = unwrapNotNil(binaryMetadata, `Latest GitHub release lacks "${artifactFileName}" file`); + const { releaseName, downloadUrl } = (await fetchLatestArtifactMetadata( + repo, artifactFileName + ))!; await fs.mkdir(installationDir).catch(err => assert.strictEqual( err?.code, -- cgit v1.2.3 From f3240e22c6de69b408a83b59e85f40fb913acfab Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 14:18:05 +0200 Subject: vscode: move throtting of download progress to call site --- editors/code/src/installation/language_server.ts | 27 ++++++++++++++---------- 1 file changed, 16 insertions(+), 11 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index a169eae47..c1f37f978 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -1,8 +1,9 @@ -import { spawnSync } from "child_process"; import * as vscode from "vscode"; import * as path from "path"; import { strict as assert } from "assert"; import { promises as fs } from "fs"; +import { spawnSync } from "child_process"; +import { throttle } from "throttle-debounce"; import { BinarySource } from "./interfaces"; import { fetchLatestArtifactMetadata } from "./fetch_latest_artifact_metadata"; @@ -28,19 +29,23 @@ export async function downloadLatestLanguageServer( { location: vscode.ProgressLocation.Notification, cancellable: false, // FIXME: add support for canceling download? - title: `Downloading language server ${releaseName}` + title: `Downloading language server (${releaseName})` }, async (progress, _cancellationToken) => { let lastPrecentage = 0; - await downloadFile(downloadUrl, installationPath, (readBytes, totalBytes) => { - const newPercentage = (readBytes / totalBytes) * 100; - progress.report({ - message: newPercentage.toFixed(0) + "%", - increment: newPercentage - lastPrecentage - }); - - lastPrecentage = newPercentage; - }); + await downloadFile(downloadUrl, installationPath, throttle( + 200, + /* noTrailing: */ true, + (readBytes, totalBytes) => { + const newPercentage = (readBytes / totalBytes) * 100; + progress.report({ + message: newPercentage.toFixed(0) + "%", + increment: newPercentage - lastPrecentage + }); + + lastPrecentage = newPercentage; + }) + ); } ); -- cgit v1.2.3 From 7cba77ed4e4207b2e24b8dd57723368c2717bb2a Mon Sep 17 00:00:00 2001 From: Veetaha Date: Sun, 9 Feb 2020 15:01:00 +0200 Subject: vscode: added logging when donloading binaries --- editors/code/src/installation/language_server.ts | 27 +++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'editors/code/src/installation/language_server.ts') diff --git a/editors/code/src/installation/language_server.ts b/editors/code/src/installation/language_server.ts index c1f37f978..1ce67b8b2 100644 --- a/editors/code/src/installation/language_server.ts +++ b/editors/code/src/installation/language_server.ts @@ -2,6 +2,7 @@ import * as vscode from "vscode"; import * as path from "path"; import { strict as assert } from "assert"; import { promises as fs } from "fs"; +import { promises as dns } from "dns"; import { spawnSync } from "child_process"; import { throttle } from "throttle-debounce"; @@ -25,6 +26,7 @@ export async function downloadLatestLanguageServer( const installationPath = path.join(installationDir, artifactFileName); + console.time("Downloading ra_lsp_server"); await vscode.window.withProgress( { location: vscode.ProgressLocation.Notification, @@ -48,6 +50,7 @@ export async function downloadLatestLanguageServer( ); } ); + console.timeEnd("Downloading ra_lsp_server"); await fs.chmod(installationPath, 0o755); // Set (rwx, r_x, r_x) permissions } @@ -101,15 +104,21 @@ export async function ensureLanguageServerBinary( `Failed to download language server from ${langServerSource.repo.name} ` + `GitHub repository: ${err.message}` ); + + await dns.resolve('www.google.com').catch(err => { + console.error("DNS resolution failed, there might be an issue with Internet availability"); + console.error(err); + }); + return null; } - - assert( - isBinaryAvailable(prebuiltBinaryPath), - "Downloaded language server binary is not functional" + if (!isBinaryAvailable(prebuiltBinaryPath)) assert(false, + `Downloaded language server binary is not functional.` + + `Downloaded from: ${JSON.stringify(langServerSource)}` ); + vscode.window.showInformationMessage( "Rust analyzer language server was successfully installed 🦀" ); @@ -119,6 +128,14 @@ export async function ensureLanguageServerBinary( } function isBinaryAvailable(binaryPath: string) { - return spawnSync(binaryPath, ["--version"]).status === 0; + const res = spawnSync(binaryPath, ["--version"]); + + // ACHTUNG! `res` type declaration is inherently wrong, see + // https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42221 + + console.log("Checked binary availablity via --version", res); + console.log(binaryPath, "--version output:", res.output?.map(String)); + + return res.status === 0; } } -- cgit v1.2.3