diff options
Diffstat (limited to 'editors/code/src/installation')
-rw-r--r-- | editors/code/src/installation/download_artifact.ts | 50 | ||||
-rw-r--r-- | editors/code/src/installation/downloads.ts (renamed from editors/code/src/installation/download_file.ts) | 46 | ||||
-rw-r--r-- | editors/code/src/installation/extension.ts | 144 | ||||
-rw-r--r-- | editors/code/src/installation/fetch_artifact_release_info.ts | 3 | ||||
-rw-r--r-- | editors/code/src/installation/interfaces.ts | 18 | ||||
-rw-r--r-- | editors/code/src/installation/server.ts | 104 |
6 files changed, 250 insertions, 115 deletions
diff --git a/editors/code/src/installation/download_artifact.ts b/editors/code/src/installation/download_artifact.ts deleted file mode 100644 index 97e4d67c2..000000000 --- a/editors/code/src/installation/download_artifact.ts +++ /dev/null | |||
@@ -1,50 +0,0 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | import * as path from "path"; | ||
3 | import { promises as fs } from "fs"; | ||
4 | |||
5 | import { ArtifactReleaseInfo } from "./interfaces"; | ||
6 | import { downloadFile } from "./download_file"; | ||
7 | import { assert } from "../util"; | ||
8 | |||
9 | /** | ||
10 | * Downloads artifact from given `downloadUrl`. | ||
11 | * Creates `installationDir` if it is not yet created and put the artifact under | ||
12 | * `artifactFileName`. | ||
13 | * Displays info about the download progress in an info message printing the name | ||
14 | * of the artifact as `displayName`. | ||
15 | */ | ||
16 | export async function downloadArtifact( | ||
17 | { downloadUrl, releaseName }: ArtifactReleaseInfo, | ||
18 | artifactFileName: string, | ||
19 | installationDir: string, | ||
20 | displayName: string, | ||
21 | ) { | ||
22 | await fs.mkdir(installationDir).catch(err => assert( | ||
23 | err?.code === "EEXIST", | ||
24 | `Couldn't create directory "${installationDir}" to download ` + | ||
25 | `${artifactFileName} artifact: ${err?.message}` | ||
26 | )); | ||
27 | |||
28 | const installationPath = path.join(installationDir, artifactFileName); | ||
29 | |||
30 | await vscode.window.withProgress( | ||
31 | { | ||
32 | location: vscode.ProgressLocation.Notification, | ||
33 | cancellable: false, // FIXME: add support for canceling download? | ||
34 | title: `Downloading ${displayName} (${releaseName})` | ||
35 | }, | ||
36 | async (progress, _cancellationToken) => { | ||
37 | let lastPrecentage = 0; | ||
38 | const filePermissions = 0o755; // (rwx, r_x, r_x) | ||
39 | await downloadFile(downloadUrl, installationPath, filePermissions, (readBytes, totalBytes) => { | ||
40 | const newPercentage = (readBytes / totalBytes) * 100; | ||
41 | progress.report({ | ||
42 | message: newPercentage.toFixed(0) + "%", | ||
43 | increment: newPercentage - lastPrecentage | ||
44 | }); | ||
45 | |||
46 | lastPrecentage = newPercentage; | ||
47 | }); | ||
48 | } | ||
49 | ); | ||
50 | } | ||
diff --git a/editors/code/src/installation/download_file.ts b/editors/code/src/installation/downloads.ts index ee8949d61..7ce2e2960 100644 --- a/editors/code/src/installation/download_file.ts +++ b/editors/code/src/installation/downloads.ts | |||
@@ -1,8 +1,11 @@ | |||
1 | import fetch from "node-fetch"; | 1 | import fetch from "node-fetch"; |
2 | import * as vscode from "vscode"; | ||
3 | import * as path from "path"; | ||
2 | import * as fs from "fs"; | 4 | import * as fs from "fs"; |
3 | import * as stream from "stream"; | 5 | import * as stream from "stream"; |
4 | import * as util from "util"; | 6 | import * as util from "util"; |
5 | import { log, assert } from "../util"; | 7 | import { log, assert } from "../util"; |
8 | import { ArtifactReleaseInfo } from "./interfaces"; | ||
6 | 9 | ||
7 | const pipeline = util.promisify(stream.pipeline); | 10 | const pipeline = util.promisify(stream.pipeline); |
8 | 11 | ||
@@ -49,3 +52,46 @@ export async function downloadFile( | |||
49 | // Issue at nodejs repo: https://github.com/nodejs/node/issues/31776 | 52 | // Issue at nodejs repo: https://github.com/nodejs/node/issues/31776 |
50 | }); | 53 | }); |
51 | } | 54 | } |
55 | |||
56 | /** | ||
57 | * Downloads artifact from given `downloadUrl`. | ||
58 | * Creates `installationDir` if it is not yet created and puts the artifact under | ||
59 | * `artifactFileName`. | ||
60 | * Displays info about the download progress in an info message printing the name | ||
61 | * of the artifact as `displayName`. | ||
62 | */ | ||
63 | export async function downloadArtifactWithProgressUi( | ||
64 | { downloadUrl, releaseName }: ArtifactReleaseInfo, | ||
65 | artifactFileName: string, | ||
66 | installationDir: string, | ||
67 | displayName: string, | ||
68 | ) { | ||
69 | await fs.promises.mkdir(installationDir).catch(err => assert( | ||
70 | err?.code === "EEXIST", | ||
71 | `Couldn't create directory "${installationDir}" to download ` + | ||
72 | `${artifactFileName} artifact: ${err?.message}` | ||
73 | )); | ||
74 | |||
75 | const installationPath = path.join(installationDir, artifactFileName); | ||
76 | |||
77 | await vscode.window.withProgress( | ||
78 | { | ||
79 | location: vscode.ProgressLocation.Notification, | ||
80 | cancellable: false, // FIXME: add support for canceling download? | ||
81 | title: `Downloading rust-analyzer ${displayName} (${releaseName})` | ||
82 | }, | ||
83 | async (progress, _cancellationToken) => { | ||
84 | let lastPrecentage = 0; | ||
85 | const filePermissions = 0o755; // (rwx, r_x, r_x) | ||
86 | await downloadFile(downloadUrl, installationPath, filePermissions, (readBytes, totalBytes) => { | ||
87 | const newPercentage = (readBytes / totalBytes) * 100; | ||
88 | progress.report({ | ||
89 | message: newPercentage.toFixed(0) + "%", | ||
90 | increment: newPercentage - lastPrecentage | ||
91 | }); | ||
92 | |||
93 | lastPrecentage = newPercentage; | ||
94 | }); | ||
95 | } | ||
96 | ); | ||
97 | } | ||
diff --git a/editors/code/src/installation/extension.ts b/editors/code/src/installation/extension.ts new file mode 100644 index 000000000..eea6fded2 --- /dev/null +++ b/editors/code/src/installation/extension.ts | |||
@@ -0,0 +1,144 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | import * as path from "path"; | ||
3 | import { promises as fs } from 'fs'; | ||
4 | |||
5 | import { vscodeReinstallExtension, vscodeReloadWindow, log, vscodeInstallExtensionFromVsix, assert, notReentrant } from "../util"; | ||
6 | import { Config, UpdatesChannel } from "../config"; | ||
7 | import { ArtifactReleaseInfo, ArtifactSource } from "./interfaces"; | ||
8 | import { downloadArtifactWithProgressUi } from "./downloads"; | ||
9 | import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; | ||
10 | |||
11 | const HEURISTIC_NIGHTLY_RELEASE_PERIOD_IN_HOURS = 25; | ||
12 | |||
13 | /** | ||
14 | * Installs `stable` or latest `nightly` version or does nothing if the current | ||
15 | * extension version is what's needed according to `desiredUpdateChannel`. | ||
16 | */ | ||
17 | export async function ensureProperExtensionVersion(config: Config): Promise<never | void> { | ||
18 | // User has built lsp server from sources, she should manage updates manually | ||
19 | if (config.serverSource?.type === ArtifactSource.Type.ExplicitPath) return; | ||
20 | |||
21 | const currentUpdChannel = config.installedExtensionUpdateChannel; | ||
22 | const desiredUpdChannel = config.updatesChannel; | ||
23 | |||
24 | if (currentUpdChannel === UpdatesChannel.Stable) { | ||
25 | // Release date is present only when we are on nightly | ||
26 | await config.installedNightlyExtensionReleaseDate.set(null); | ||
27 | } | ||
28 | |||
29 | if (desiredUpdChannel === UpdatesChannel.Stable) { | ||
30 | // VSCode should handle updates for stable channel | ||
31 | if (currentUpdChannel === UpdatesChannel.Stable) return; | ||
32 | |||
33 | if (!await askToDownloadProperExtensionVersion(config)) return; | ||
34 | |||
35 | await vscodeReinstallExtension(config.extensionId); | ||
36 | await vscodeReloadWindow(); // never returns | ||
37 | } | ||
38 | |||
39 | if (currentUpdChannel === UpdatesChannel.Stable) { | ||
40 | if (!await askToDownloadProperExtensionVersion(config)) return; | ||
41 | |||
42 | return await tryDownloadNightlyExtension(config); | ||
43 | } | ||
44 | |||
45 | const currentExtReleaseDate = config.installedNightlyExtensionReleaseDate.get(); | ||
46 | |||
47 | if (currentExtReleaseDate === null) { | ||
48 | void vscode.window.showErrorMessage( | ||
49 | "Nightly release date must've been set during the installation. " + | ||
50 | "Did you download and install the nightly .vsix package manually?" | ||
51 | ); | ||
52 | throw new Error("Nightly release date was not set in globalStorage"); | ||
53 | } | ||
54 | |||
55 | const dateNow = new Date; | ||
56 | const hoursSinceLastUpdate = diffInHours(currentExtReleaseDate, dateNow); | ||
57 | log.debug( | ||
58 | "Current rust-analyzer nightly was downloaded", hoursSinceLastUpdate, | ||
59 | "hours ago, namely:", currentExtReleaseDate, "and now is", dateNow | ||
60 | ); | ||
61 | |||
62 | if (hoursSinceLastUpdate < HEURISTIC_NIGHTLY_RELEASE_PERIOD_IN_HOURS) { | ||
63 | return; | ||
64 | } | ||
65 | if (!await askToDownloadProperExtensionVersion(config, "The installed nightly version is most likely outdated. ")) { | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | await tryDownloadNightlyExtension(config, releaseInfo => { | ||
70 | assert( | ||
71 | currentExtReleaseDate.getTime() === config.installedNightlyExtensionReleaseDate.get()?.getTime(), | ||
72 | "Other active VSCode instance has reinstalled the extension" | ||
73 | ); | ||
74 | |||
75 | if (releaseInfo.releaseDate.getTime() === currentExtReleaseDate.getTime()) { | ||
76 | vscode.window.showInformationMessage( | ||
77 | "Whoops, it appears that your nightly version is up-to-date. " + | ||
78 | "There might be some problems with the upcomming nightly release " + | ||
79 | "or you traveled too far into the future. Sorry for that 😅! " | ||
80 | ); | ||
81 | return false; | ||
82 | } | ||
83 | return true; | ||
84 | }); | ||
85 | } | ||
86 | |||
87 | async function askToDownloadProperExtensionVersion(config: Config, reason = "") { | ||
88 | if (!config.askBeforeDownload) return true; | ||
89 | |||
90 | const stableOrNightly = config.updatesChannel === UpdatesChannel.Stable ? "stable" : "latest nightly"; | ||
91 | |||
92 | // In case of reentering this function and showing the same info message | ||
93 | // (e.g. after we had shown this message, the user changed the config) | ||
94 | // vscode will dismiss the already shown one (i.e. return undefined). | ||
95 | // This behaviour is what we want, but likely it is not documented | ||
96 | |||
97 | const userResponse = await vscode.window.showInformationMessage( | ||
98 | reason + `Do you want to download the ${stableOrNightly} rust-analyzer extension ` + | ||
99 | `version and reload the window now?`, | ||
100 | "Download now", "Cancel" | ||
101 | ); | ||
102 | return userResponse === "Download now"; | ||
103 | } | ||
104 | |||
105 | /** | ||
106 | * Shutdowns the process in case of success (i.e. reloads the window) or throws an error. | ||
107 | * | ||
108 | * ACHTUNG!: this function has a crazy amount of state transitions, handling errors during | ||
109 | * each of them would result in a ton of code (especially accounting for cross-process | ||
110 | * shared mutable `globalState` access). Enforcing no reentrancy for this is best-effort. | ||
111 | */ | ||
112 | const tryDownloadNightlyExtension = notReentrant(async ( | ||
113 | config: Config, | ||
114 | shouldDownload: (releaseInfo: ArtifactReleaseInfo) => boolean = () => true | ||
115 | ): Promise<never | void> => { | ||
116 | const vsixSource = config.nightlyVsixSource; | ||
117 | try { | ||
118 | const releaseInfo = await fetchArtifactReleaseInfo(vsixSource.repo, vsixSource.file, vsixSource.tag); | ||
119 | |||
120 | if (!shouldDownload(releaseInfo)) return; | ||
121 | |||
122 | await downloadArtifactWithProgressUi(releaseInfo, vsixSource.file, vsixSource.dir, "nightly extension"); | ||
123 | |||
124 | const vsixPath = path.join(vsixSource.dir, vsixSource.file); | ||
125 | |||
126 | await vscodeInstallExtensionFromVsix(vsixPath); | ||
127 | await config.installedNightlyExtensionReleaseDate.set(releaseInfo.releaseDate); | ||
128 | await fs.unlink(vsixPath); | ||
129 | |||
130 | await vscodeReloadWindow(); // never returns | ||
131 | } catch (err) { | ||
132 | log.downloadError(err, "nightly extension", vsixSource.repo.name); | ||
133 | } | ||
134 | }); | ||
135 | |||
136 | function diffInHours(a: Date, b: Date): number { | ||
137 | // Discard the time and time-zone information (to abstract from daylight saving time bugs) | ||
138 | // https://stackoverflow.com/a/15289883/9259330 | ||
139 | |||
140 | const utcA = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate()); | ||
141 | const utcB = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate()); | ||
142 | |||
143 | return (utcA - utcB) / (1000 * 60 * 60); | ||
144 | } | ||
diff --git a/editors/code/src/installation/fetch_artifact_release_info.ts b/editors/code/src/installation/fetch_artifact_release_info.ts index b1b5a3485..1ad3b8338 100644 --- a/editors/code/src/installation/fetch_artifact_release_info.ts +++ b/editors/code/src/installation/fetch_artifact_release_info.ts | |||
@@ -59,12 +59,15 @@ export async function fetchArtifactReleaseInfo( | |||
59 | 59 | ||
60 | return { | 60 | return { |
61 | releaseName: release.name, | 61 | releaseName: release.name, |
62 | releaseDate: new Date(release.published_at), | ||
62 | downloadUrl: artifact.browser_download_url | 63 | downloadUrl: artifact.browser_download_url |
63 | }; | 64 | }; |
64 | 65 | ||
65 | // We omit declaration of tremendous amount of fields that we are not using here | 66 | // We omit declaration of tremendous amount of fields that we are not using here |
66 | interface GithubRelease { | 67 | interface GithubRelease { |
67 | name: string; | 68 | name: string; |
69 | // eslint-disable-next-line camelcase | ||
70 | published_at: string; | ||
68 | assets: Array<{ | 71 | assets: Array<{ |
69 | name: string; | 72 | name: string; |
70 | // eslint-disable-next-line camelcase | 73 | // eslint-disable-next-line camelcase |
diff --git a/editors/code/src/installation/interfaces.ts b/editors/code/src/installation/interfaces.ts index 50b635921..1a8ea0884 100644 --- a/editors/code/src/installation/interfaces.ts +++ b/editors/code/src/installation/interfaces.ts | |||
@@ -1,5 +1,3 @@ | |||
1 | import * as vscode from "vscode"; | ||
2 | |||
3 | export interface GithubRepo { | 1 | export interface GithubRepo { |
4 | name: string; | 2 | name: string; |
5 | owner: string; | 3 | owner: string; |
@@ -9,6 +7,7 @@ export interface GithubRepo { | |||
9 | * Metadata about particular artifact retrieved from GitHub releases. | 7 | * Metadata about particular artifact retrieved from GitHub releases. |
10 | */ | 8 | */ |
11 | export interface ArtifactReleaseInfo { | 9 | export interface ArtifactReleaseInfo { |
10 | releaseDate: Date; | ||
12 | releaseName: string; | 11 | releaseName: string; |
13 | downloadUrl: string; | 12 | downloadUrl: string; |
14 | } | 13 | } |
@@ -42,6 +41,9 @@ export namespace ArtifactSource { | |||
42 | */ | 41 | */ |
43 | repo: GithubRepo; | 42 | repo: GithubRepo; |
44 | 43 | ||
44 | |||
45 | // FIXME: add installationPath: string; | ||
46 | |||
45 | /** | 47 | /** |
46 | * Directory on the filesystem where the bundled binary is stored. | 48 | * Directory on the filesystem where the bundled binary is stored. |
47 | */ | 49 | */ |
@@ -57,17 +59,5 @@ export namespace ArtifactSource { | |||
57 | * Tag of github release that denotes a version required by this extension. | 59 | * Tag of github release that denotes a version required by this extension. |
58 | */ | 60 | */ |
59 | tag: string; | 61 | tag: string; |
60 | |||
61 | /** | ||
62 | * Object that provides `get()/update()` operations to store metadata | ||
63 | * about the actual binary, e.g. its actual version. | ||
64 | */ | ||
65 | storage: vscode.Memento; | ||
66 | |||
67 | /** | ||
68 | * Ask for the user permission before downloading the artifact. | ||
69 | */ | ||
70 | askBeforeDownload: boolean; | ||
71 | } | 62 | } |
72 | |||
73 | } | 63 | } |
diff --git a/editors/code/src/installation/server.ts b/editors/code/src/installation/server.ts index ef1c45ff6..05730a778 100644 --- a/editors/code/src/installation/server.ts +++ b/editors/code/src/installation/server.ts | |||
@@ -1,14 +1,16 @@ | |||
1 | import * as vscode from "vscode"; | 1 | import * as vscode from "vscode"; |
2 | import * as path from "path"; | 2 | import * as path from "path"; |
3 | import { promises as dns } from "dns"; | ||
4 | import { spawnSync } from "child_process"; | 3 | import { spawnSync } from "child_process"; |
5 | 4 | ||
6 | import { ArtifactSource } from "./interfaces"; | 5 | import { ArtifactSource } from "./interfaces"; |
7 | import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; | 6 | import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info"; |
8 | import { downloadArtifact } from "./download_artifact"; | 7 | import { downloadArtifactWithProgressUi } from "./downloads"; |
9 | import { log, assert } from "../util"; | 8 | import { log, assert, notReentrant } from "../util"; |
9 | import { Config, NIGHTLY_TAG } from "../config"; | ||
10 | |||
11 | export async function ensureServerBinary(config: Config): Promise<null | string> { | ||
12 | const source = config.serverSource; | ||
10 | 13 | ||
11 | export async function ensureServerBinary(source: null | ArtifactSource): Promise<null | string> { | ||
12 | if (!source) { | 14 | if (!source) { |
13 | vscode.window.showErrorMessage( | 15 | vscode.window.showErrorMessage( |
14 | "Unfortunately we don't ship binaries for your platform yet. " + | 16 | "Unfortunately we don't ship binaries for your platform yet. " + |
@@ -35,18 +37,11 @@ export async function ensureServerBinary(source: null | ArtifactSource): Promise | |||
35 | return null; | 37 | return null; |
36 | } | 38 | } |
37 | case ArtifactSource.Type.GithubRelease: { | 39 | case ArtifactSource.Type.GithubRelease: { |
38 | const prebuiltBinaryPath = path.join(source.dir, source.file); | 40 | if (!shouldDownloadServer(source, config)) { |
39 | 41 | return path.join(source.dir, source.file); | |
40 | const installedVersion: null | string = getServerVersion(source.storage); | ||
41 | const requiredVersion: string = source.tag; | ||
42 | |||
43 | log.debug("Installed version:", installedVersion, "required:", requiredVersion); | ||
44 | |||
45 | if (isBinaryAvailable(prebuiltBinaryPath) && installedVersion === requiredVersion) { | ||
46 | return prebuiltBinaryPath; | ||
47 | } | 42 | } |
48 | 43 | ||
49 | if (source.askBeforeDownload) { | 44 | if (config.askBeforeDownload) { |
50 | const userResponse = await vscode.window.showInformationMessage( | 45 | const userResponse = await vscode.window.showInformationMessage( |
51 | `Language server version ${source.tag} for rust-analyzer is not installed. ` + | 46 | `Language server version ${source.tag} for rust-analyzer is not installed. ` + |
52 | "Do you want to download it now?", | 47 | "Do you want to download it now?", |
@@ -55,38 +50,56 @@ export async function ensureServerBinary(source: null | ArtifactSource): Promise | |||
55 | if (userResponse !== "Download now") return null; | 50 | if (userResponse !== "Download now") return null; |
56 | } | 51 | } |
57 | 52 | ||
58 | if (!await downloadServer(source)) return null; | 53 | return await downloadServer(source, config); |
59 | |||
60 | return prebuiltBinaryPath; | ||
61 | } | 54 | } |
62 | } | 55 | } |
63 | } | 56 | } |
64 | 57 | ||
65 | async function downloadServer(source: ArtifactSource.GithubRelease): Promise<boolean> { | 58 | function shouldDownloadServer( |
59 | source: ArtifactSource.GithubRelease, | ||
60 | config: Config | ||
61 | ): boolean { | ||
62 | if (!isBinaryAvailable(path.join(source.dir, source.file))) return true; | ||
63 | |||
64 | const installed = { | ||
65 | tag: config.serverReleaseTag.get(), | ||
66 | date: config.serverReleaseDate.get() | ||
67 | }; | ||
68 | const required = { | ||
69 | tag: source.tag, | ||
70 | date: config.installedNightlyExtensionReleaseDate.get() | ||
71 | }; | ||
72 | |||
73 | log.debug("Installed server:", installed, "required:", required); | ||
74 | |||
75 | if (required.tag !== NIGHTLY_TAG || installed.tag !== NIGHTLY_TAG) { | ||
76 | return required.tag !== installed.tag; | ||
77 | } | ||
78 | |||
79 | assert(required.date !== null, "Extension release date should have been saved during its installation"); | ||
80 | assert(installed.date !== null, "Server release date should have been saved during its installation"); | ||
81 | |||
82 | return installed.date.getTime() !== required.date.getTime(); | ||
83 | } | ||
84 | |||
85 | /** | ||
86 | * Enforcing no reentrancy for this is best-effort. | ||
87 | */ | ||
88 | const downloadServer = notReentrant(async ( | ||
89 | source: ArtifactSource.GithubRelease, | ||
90 | config: Config, | ||
91 | ): Promise<null | string> => { | ||
66 | try { | 92 | try { |
67 | const releaseInfo = await fetchArtifactReleaseInfo(source.repo, source.file, source.tag); | 93 | const releaseInfo = await fetchArtifactReleaseInfo(source.repo, source.file, source.tag); |
68 | 94 | ||
69 | await downloadArtifact(releaseInfo, source.file, source.dir, "language server"); | 95 | await downloadArtifactWithProgressUi(releaseInfo, source.file, source.dir, "language server"); |
70 | await setServerVersion(source.storage, releaseInfo.releaseName); | 96 | await Promise.all([ |
97 | config.serverReleaseTag.set(releaseInfo.releaseName), | ||
98 | config.serverReleaseDate.set(releaseInfo.releaseDate) | ||
99 | ]); | ||
71 | } catch (err) { | 100 | } catch (err) { |
72 | vscode.window.showErrorMessage( | 101 | log.downloadError(err, "language server", source.repo.name); |
73 | `Failed to download language server from ${source.repo.name} ` + | 102 | return null; |
74 | `GitHub repository: ${err.message}` | ||
75 | ); | ||
76 | |||
77 | log.error(err); | ||
78 | |||
79 | dns.resolve('example.com').then( | ||
80 | addrs => log.debug("DNS resolution for example.com was successful", addrs), | ||
81 | err => { | ||
82 | log.error( | ||
83 | "DNS resolution for example.com failed, " + | ||
84 | "there might be an issue with Internet availability" | ||
85 | ); | ||
86 | log.error(err); | ||
87 | } | ||
88 | ); | ||
89 | return false; | ||
90 | } | 103 | } |
91 | 104 | ||
92 | const binaryPath = path.join(source.dir, source.file); | 105 | const binaryPath = path.join(source.dir, source.file); |
@@ -101,8 +114,8 @@ async function downloadServer(source: ArtifactSource.GithubRelease): Promise<boo | |||
101 | "Rust analyzer language server was successfully installed 🦀" | 114 | "Rust analyzer language server was successfully installed 🦀" |
102 | ); | 115 | ); |
103 | 116 | ||
104 | return true; | 117 | return binaryPath; |
105 | } | 118 | }); |
106 | 119 | ||
107 | function isBinaryAvailable(binaryPath: string): boolean { | 120 | function isBinaryAvailable(binaryPath: string): boolean { |
108 | const res = spawnSync(binaryPath, ["--version"]); | 121 | const res = spawnSync(binaryPath, ["--version"]); |
@@ -115,14 +128,3 @@ function isBinaryAvailable(binaryPath: string): boolean { | |||
115 | 128 | ||
116 | return res.status === 0; | 129 | return res.status === 0; |
117 | } | 130 | } |
118 | |||
119 | function getServerVersion(storage: vscode.Memento): null | string { | ||
120 | const version = storage.get<null | string>("server-version", null); | ||
121 | log.debug("Get server-version:", version); | ||
122 | return version; | ||
123 | } | ||
124 | |||
125 | async function setServerVersion(storage: vscode.Memento, version: string): Promise<void> { | ||
126 | log.debug("Set server-version:", version); | ||
127 | await storage.update("server-version", version.toString()); | ||
128 | } | ||