Remove server download and update checks

This commit is contained in:
Laurențiu Nicola 2021-12-23 08:24:58 +02:00
parent 45d2262963
commit d5b4aa3037
2 changed files with 2 additions and 230 deletions

View file

@ -5,9 +5,8 @@ import * as commands from './commands';
import { activateInlayHints } from './inlay_hints'; import { activateInlayHints } from './inlay_hints';
import { Ctx } from './ctx'; import { Ctx } from './ctx';
import { Config } from './config'; import { Config } from './config';
import { log, assert, isValidExecutable, isRustDocument } from './util'; import { log, isValidExecutable, isRustDocument } from './util';
import { PersistentState } from './persistent_state'; import { PersistentState } from './persistent_state';
import { fetchRelease, download } from './net';
import { activateTaskProvider } from './tasks'; import { activateTaskProvider } from './tasks';
import { setContextValue } from './util'; import { setContextValue } from './util';
import { exec, spawnSync } from 'child_process'; import { exec, spawnSync } from 'child_process';
@ -111,10 +110,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
await activate(context).catch(log.error); await activate(context).catch(log.error);
}); });
ctx.registerCommand('updateGithubToken', ctx => async () => {
await queryForGithubToken(new PersistentState(ctx.globalState));
});
ctx.registerCommand('analyzerStatus', commands.analyzerStatus); ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
ctx.registerCommand('memoryUsage', commands.memoryUsage); ctx.registerCommand('memoryUsage', commands.memoryUsage);
ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph); ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph);
@ -163,95 +158,10 @@ export async function deactivate() {
async function bootstrap(config: Config, state: PersistentState): Promise<string> { async function bootstrap(config: Config, state: PersistentState): Promise<string> {
await vscode.workspace.fs.createDirectory(config.globalStorageUri).then(); await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
if (!config.currentExtensionIsNightly) {
await state.updateNightlyReleaseId(undefined);
}
await bootstrapExtension(config, state);
const path = await bootstrapServer(config, state); const path = await bootstrapServer(config, state);
return path; return path;
} }
async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> {
if (config.package.releaseTag === null) return;
if (config.channel === "stable") {
if (config.currentExtensionIsNightly) {
void vscode.window.showWarningMessage(
`You are running a nightly version of rust-analyzer extension. ` +
`To switch to stable, uninstall the extension and re-install it from the marketplace`
);
}
return;
};
if (serverPath(config)) return;
const now = Date.now();
const isInitialNightlyDownload = state.nightlyReleaseId === undefined;
if (config.currentExtensionIsNightly) {
// Check if we should poll github api for the new nightly version
// if we haven't done it during the past hour
const lastCheck = state.lastCheck;
const anHour = 60 * 60 * 1000;
const shouldCheckForNewNightly = isInitialNightlyDownload || (now - (lastCheck ?? 0)) > anHour;
if (!shouldCheckForNewNightly) return;
}
const latestNightlyRelease = await downloadWithRetryDialog(state, async () => {
return await fetchRelease("nightly", state.githubToken, config.proxySettings);
}).catch(async (e) => {
log.error(e);
if (isInitialNightlyDownload) {
await vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly: ${e}`);
}
return;
});
if (latestNightlyRelease === undefined) {
if (isInitialNightlyDownload) {
await vscode.window.showErrorMessage("Failed to download rust-analyzer nightly: empty release contents returned");
}
return;
}
if (config.currentExtensionIsNightly && latestNightlyRelease.id === state.nightlyReleaseId) return;
const userResponse = await vscode.window.showInformationMessage(
"New version of rust-analyzer (nightly) is available (requires reload).",
"Update"
);
if (userResponse !== "Update") return;
let arch = process.arch;
if (arch === "ia32") {
arch = "x64";
}
let platform = process.platform as string;
if (platform === "linux" && isMusl()) {
platform = "alpine";
}
const artifactName = `rust-analyzer-${platform}-${arch}.vsix`;
const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === artifactName);
assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`);
const dest = vscode.Uri.joinPath(config.globalStorageUri, "rust-analyzer.vsix");
await downloadWithRetryDialog(state, async () => {
await download({
url: artifact.browser_download_url,
dest,
progressTitle: "Downloading rust-analyzer extension",
proxySettings: config.proxySettings,
});
});
await vscode.commands.executeCommand("workbench.extensions.installExtension", dest);
await vscode.workspace.fs.delete(dest);
await state.updateNightlyReleaseId(latestNightlyRelease.id);
await state.updateLastCheck(now);
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
async function bootstrapServer(config: Config, state: PersistentState): Promise<string> { async function bootstrapServer(config: Config, state: PersistentState): Promise<string> {
const path = await getServer(config, state); const path = await getServer(config, state);
if (!path) { if (!path) {
@ -356,56 +266,16 @@ async function getServer(config: Config, state: PersistentState): Promise<string
const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer-${platform}${ext}`); const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer-${platform}${ext}`);
const bundled = vscode.Uri.joinPath(config.installUri, "server", `rust-analyzer${ext}`); const bundled = vscode.Uri.joinPath(config.installUri, "server", `rust-analyzer${ext}`);
const bundledExists = await vscode.workspace.fs.stat(bundled).then(() => true, () => false); const bundledExists = await vscode.workspace.fs.stat(bundled).then(() => true, () => false);
let exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false); const exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false);
if (bundledExists) { if (bundledExists) {
await state.updateServerVersion(config.package.version);
if (!await isNixOs()) { if (!await isNixOs()) {
return bundled.fsPath; return bundled.fsPath;
} }
if (!exists) { if (!exists) {
await vscode.workspace.fs.copy(bundled, dest); await vscode.workspace.fs.copy(bundled, dest);
await patchelf(dest); await patchelf(dest);
exists = true;
} }
} }
if (!exists) {
await state.updateServerVersion(undefined);
}
if (state.serverVersion === config.package.version) return dest.fsPath;
if (config.askBeforeDownload) {
const userResponse = await vscode.window.showInformationMessage(
`Language server version ${config.package.version} for rust-analyzer is not installed.`,
"Download now"
);
if (userResponse !== "Download now") return dest.fsPath;
}
const releaseTag = config.package.releaseTag;
const release = await downloadWithRetryDialog(state, async () => {
return await fetchRelease(releaseTag, state.githubToken, config.proxySettings);
});
const artifact = release.assets.find(artifact => artifact.name === `rust-analyzer-${platform}.gz`);
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
await downloadWithRetryDialog(state, async () => {
await download({
url: artifact.browser_download_url,
dest,
progressTitle: "Downloading rust-analyzer server",
gunzip: true,
mode: 0o755,
proxySettings: config.proxySettings,
});
});
// Patching executable if that's NixOS.
if (await isNixOs()) {
await patchelf(dest);
}
await state.updateServerVersion(config.package.version);
return dest.fsPath; return dest.fsPath;
} }
@ -429,59 +299,6 @@ function isMusl(): boolean {
return res.stderr != null && res.stderr.indexOf("musl libc") >= 0; return res.stderr != null && res.stderr.indexOf("musl libc") >= 0;
} }
async function downloadWithRetryDialog<T>(state: PersistentState, downloadFunc: () => Promise<T>): Promise<T> {
while (true) {
try {
return await downloadFunc();
} catch (e) {
const selected = await vscode.window.showErrorMessage("Failed to download: " + e.message, {}, {
title: "Update Github Auth Token",
updateToken: true,
}, {
title: "Retry download",
retry: true,
}, {
title: "Dismiss",
});
if (selected?.updateToken) {
await queryForGithubToken(state);
continue;
} else if (selected?.retry) {
continue;
}
throw e;
};
}
}
async function queryForGithubToken(state: PersistentState): Promise<void> {
const githubTokenOptions: vscode.InputBoxOptions = {
value: state.githubToken,
password: true,
prompt: `
This dialog allows to store a Github authorization token.
The usage of an authorization token will increase the rate
limit on the use of Github APIs and can thereby prevent getting
throttled.
Auth tokens can be created at https://github.com/settings/tokens`,
};
const newToken = await vscode.window.showInputBox(githubTokenOptions);
if (newToken === undefined) {
// The user aborted the dialog => Do not update the stored token
return;
}
if (newToken === "") {
log.info("Clearing github token");
await state.updateGithubToken(undefined);
} else {
log.info("Storing new github token");
await state.updateGithubToken(newToken);
}
}
function warnAboutExtensionConflicts() { function warnAboutExtensionConflicts() {
const conflicting = [ const conflicting = [
["rust-analyzer", "matklad.rust-analyzer"], ["rust-analyzer", "matklad.rust-analyzer"],

View file

@ -3,50 +3,5 @@ import { log } from './util';
export class PersistentState { export class PersistentState {
constructor(private readonly globalState: vscode.Memento) { constructor(private readonly globalState: vscode.Memento) {
const { lastCheck, nightlyReleaseId, serverVersion } = this;
log.info("PersistentState:", { lastCheck, nightlyReleaseId, serverVersion });
}
/**
* Used to check for *nightly* updates once an hour.
*/
get lastCheck(): number | undefined {
return this.globalState.get("lastCheck");
}
async updateLastCheck(value: number) {
await this.globalState.update("lastCheck", value);
}
/**
* Release id of the *nightly* extension.
* Used to check if we should update.
*/
get nightlyReleaseId(): number | undefined {
return this.globalState.get("releaseId");
}
async updateNightlyReleaseId(value: number | undefined) {
await this.globalState.update("releaseId", value);
}
/**
* Version of the extension that installed the server.
* Used to check if we need to update the server.
*/
get serverVersion(): string | undefined {
return this.globalState.get("serverVersion");
}
async updateServerVersion(value: string | undefined) {
await this.globalState.update("serverVersion", value);
}
/**
* Github authorization token.
* This is used for API requests against the Github API.
*/
get githubToken(): string | undefined {
return this.globalState.get("githubToken");
}
async updateGithubToken(value: string | undefined) {
await this.globalState.update("githubToken", value);
} }
} }