8936: fix: Improve nightly downloads with better local state management r=matklad a=SomeoneToIgnore

When any nightly is downloaded, we store its GitHub release id in the local cache and never invalidate that cache.

Due to this, it was possible to do the following sequence:
* have the nightly locally
* downgrade the extension to any stable version
* observe that despite the `"rust-analyzer.updates.channel": "nightly",` setting, no nightly updates are happening
* on the next day, the actual update happens (given the new nightly is released)

Since it's impossible to install nightly version directly through the VSCode marketplace, any fiddling with dev version results in the same situation: one have to wait for the next nightly release to happen in order to restore the nightly.

This PR 
* invalidates the cache eagerly during bootstrap if the current plugin is not nightly
* enforces the release id check for nightly versions only
* fixes the `ctx.globalStoragePath` deprecated API usage

Hopefully, it also helps mysterious non-updated plugins that we encounter from time to time, but hard to tell for sure.

8939: internal: disable debug symbols due to failing windows build r=matklad a=matklad

bors r+
🤖

Co-authored-by: Kirill Bulatov <mail4score@gmail.com>
Co-authored-by: Aleksey Kladov <aleksey.kladov@gmail.com>
This commit is contained in:
bors[bot] 2021-05-23 11:12:45 +00:00 committed by GitHub
commit 57eedd9066
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 38 additions and 20 deletions

View file

@ -4,7 +4,7 @@ import { log } from "./util";
export type UpdatesChannel = "stable" | "nightly";
export const NIGHTLY_TAG = "nightly";
const NIGHTLY_TAG = "nightly";
export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[];
@ -34,7 +34,7 @@ export class Config {
readonly globalStoragePath: string;
constructor(ctx: vscode.ExtensionContext) {
this.globalStoragePath = ctx.globalStoragePath;
this.globalStoragePath = ctx.globalStorageUri.path;
vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions);
this.refreshLogging();
}
@ -170,4 +170,8 @@ export class Config {
gotoTypeDef: this.get<boolean>("hoverActions.gotoTypeDef"),
};
}
get currentExtensionIsNightly() {
return this.package.releaseTag === NIGHTLY_TAG;
}
}

View file

@ -6,7 +6,7 @@ import { promises as fs, PathLike } from "fs";
import * as commands from './commands';
import { activateInlayHints } from './inlay_hints';
import { Ctx } from './ctx';
import { Config, NIGHTLY_TAG } from './config';
import { Config } from './config';
import { log, assert, isValidExecutable } from './util';
import { PersistentState } from './persistent_state';
import { fetchRelease, download } from './net';
@ -156,16 +156,18 @@ export async function deactivate() {
async function bootstrap(config: Config, state: PersistentState): Promise<string> {
await fs.mkdir(config.globalStoragePath, { recursive: true });
if (!config.currentExtensionIsNightly) {
await state.updateNightlyReleaseId(undefined);
}
await bootstrapExtension(config, state);
const path = await bootstrapServer(config, state);
return path;
}
async function bootstrapExtension(config: Config, state: PersistentState): Promise<void> {
if (config.package.releaseTag === null) return;
if (config.channel === "stable") {
if (config.package.releaseTag === NIGHTLY_TAG) {
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`
@ -176,27 +178,34 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
if (serverPath(config)) return;
const now = Date.now();
if (config.package.releaseTag === NIGHTLY_TAG) {
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 = state.releaseId === undefined || (now - (lastCheck ?? 0)) > anHour;
const shouldCheckForNewNightly = isInitialNightlyDownload || (now - (lastCheck ?? 0)) > anHour;
if (!shouldCheckForNewNightly) return;
}
const release = await downloadWithRetryDialog(state, async () => {
const latestNightlyRelease = await downloadWithRetryDialog(state, async () => {
return await fetchRelease("nightly", state.githubToken, config.httpProxy);
}).catch(async (e) => {
log.error(e);
if (state.releaseId === undefined) { // Show error only for the initial download
await vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly ${e}`);
if (isInitialNightlyDownload) {
await vscode.window.showErrorMessage(`Failed to download rust-analyzer nightly: ${e}`);
}
return undefined;
return;
});
if (release === undefined || release.id === state.releaseId) 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).",
@ -204,8 +213,8 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
);
if (userResponse !== "Update") return;
const artifact = release.assets.find(artifact => artifact.name === "rust-analyzer.vsix");
assert(!!artifact, `Bad release: ${JSON.stringify(release)}`);
const artifact = latestNightlyRelease.assets.find(artifact => artifact.name === "rust-analyzer.vsix");
assert(!!artifact, `Bad release: ${JSON.stringify(latestNightlyRelease)}`);
const dest = path.join(config.globalStoragePath, "rust-analyzer.vsix");
@ -221,7 +230,7 @@ async function bootstrapExtension(config: Config, state: PersistentState): Promi
await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(dest));
await fs.unlink(dest);
await state.updateReleaseId(release.id);
await state.updateNightlyReleaseId(latestNightlyRelease.id);
await state.updateLastCheck(now);
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}

View file

@ -3,8 +3,8 @@ import { log } from './util';
export class PersistentState {
constructor(private readonly globalState: vscode.Memento) {
const { lastCheck, releaseId, serverVersion } = this;
log.info("PersistentState:", { lastCheck, releaseId, serverVersion });
const { lastCheck, nightlyReleaseId, serverVersion } = this;
log.info("PersistentState:", { lastCheck, nightlyReleaseId, serverVersion });
}
/**
@ -21,10 +21,10 @@ export class PersistentState {
* Release id of the *nightly* extension.
* Used to check if we should update.
*/
get releaseId(): number | undefined {
get nightlyReleaseId(): number | undefined {
return this.globalState.get("releaseId");
}
async updateReleaseId(value: number) {
async updateNightlyReleaseId(value: number | undefined) {
await this.globalState.update("releaseId", value);
}

View file

@ -67,7 +67,12 @@ fn dist_client(version: &str, release_tag: &str) -> Result<()> {
fn dist_server(release_channel: &str) -> Result<()> {
let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "true");
let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
// We want do enable debug symbols, but this causes our windows CI to fail:
// https://github.com/rust-lang/rust/issues/85598
//
// let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
let target = get_target();
if target.contains("-linux-gnu") || target.contains("-linux-musl") {
env::set_var("CC", "clang");