1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
import * as vscode from "vscode";
import * as path from "path";
import { spawnSync } from "child_process";
import { ArtifactSource } from "./interfaces";
import { fetchArtifactReleaseInfo } from "./fetch_artifact_release_info";
import { downloadArtifactWithProgressUi } from "./downloads";
import { log, assert } from "../util";
import { Config, NIGHTLY_TAG } from "../config";
export async function ensureServerBinary(config: Config): Promise<null | string> {
const source = config.serverSource;
if (!source) {
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 (source.type) {
case ArtifactSource.Type.ExplicitPath: {
if (isBinaryAvailable(source.path)) {
return source.path;
}
vscode.window.showErrorMessage(
`Unable to run ${source.path} binary. ` +
`To use the pre-built language server, set "rust-analyzer.serverPath" ` +
"value to `null` or remove it from the settings to use it by default."
);
return null;
}
case ArtifactSource.Type.GithubRelease: {
if (!shouldDownloadServer(source, config)) {
return path.join(source.dir, source.file);
}
if (config.askBeforeDownload) {
const userResponse = await vscode.window.showInformationMessage(
`Language server version ${source.tag} for rust-analyzer is not installed. ` +
"Do you want to download it now?",
"Download now", "Cancel"
);
if (userResponse !== "Download now") return null;
}
return await downloadServer(source, config);
}
}
}
function shouldDownloadServer(
source: ArtifactSource.GithubRelease,
config: Config
): boolean {
if (!isBinaryAvailable(path.join(source.dir, source.file))) return true;
const installed = {
tag: config.serverReleaseTag.get(),
date: config.serverReleaseDate.get()
};
const required = {
tag: source.tag,
date: config.installedNightlyExtensionReleaseDate.get()
};
log.debug("Installed server:", installed, "required:", required);
if (required.tag !== NIGHTLY_TAG || installed.tag !== NIGHTLY_TAG) {
return required.tag !== installed.tag;
}
assert(required.date !== null, "Extension release date should have been saved during its installation");
assert(installed.date !== null, "Server release date should have been saved during its installation");
return installed.date.getTime() !== required.date.getTime();
}
async function downloadServer(
source: ArtifactSource.GithubRelease,
config: Config,
): Promise<null | string> {
try {
const releaseInfo = await fetchArtifactReleaseInfo(source.repo, source.file, source.tag);
await downloadArtifactWithProgressUi(releaseInfo, source.file, source.dir, "language server");
await Promise.all([
config.serverReleaseTag.set(releaseInfo.releaseName),
config.serverReleaseDate.set(releaseInfo.releaseDate)
]);
} catch (err) {
log.downloadError(err, "language server", source.repo.name);
return null;
}
const binaryPath = path.join(source.dir, source.file);
assert(isBinaryAvailable(binaryPath),
`Downloaded language server binary is not functional.` +
`Downloaded from GitHub repo ${source.repo.owner}/${source.repo.name} ` +
`to ${binaryPath}`
);
vscode.window.showInformationMessage(
"Rust analyzer language server was successfully installed 🦀"
);
return binaryPath;
}
function isBinaryAvailable(binaryPath: string): boolean {
const res = spawnSync(binaryPath, ["--version"]);
// ACHTUNG! `res` type declaration is inherently wrong, see
// https://github.com/DefinitelyTyped/DefinitelyTyped/issues/42221
log.debug("Checked binary availablity via --version", res);
log.debug(binaryPath, "--version output:", res.output?.map(String));
return res.status === 0;
}
|