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:
commit
57eedd9066
4 changed files with 38 additions and 20 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Reference in a new issue