aboutsummaryrefslogtreecommitdiff
path: root/editors/code/src/config.ts
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-03-16 10:26:31 +0000
committerGitHub <[email protected]>2020-03-16 10:26:31 +0000
commit200c275c2e9955371e61f6ad7684084655df46fc (patch)
treec4b61de644cec37cffca9010d56afc4136d23ca8 /editors/code/src/config.ts
parenta99cac671c3e6105a0192acbb1a91cb83e453018 (diff)
parent5a0041c5aaeee49be84ce771fb0360ae55cbd8b2 (diff)
Merge #3534
3534: Feature: vscode impl nightlies download and installation r=Veetaha a=Veetaha I need to test things more, but the core shape of the code is quite well-formed. The main problem is that we save the release date only for nightlies and there are no means to get the release date of the stable extension (i.e. for this we would need to consult the github releases via a network request, or we would need to somehow save this info into package.json or any other file accessible from the extension code during the deployment step, but this will be very hard I guess). So there is an invariant that the users can install nightly only from our extension and they can't do it manually, because when installing the nightly `.vsix` we actually save its release date to `globalState` Closes: #3402 TODO: - [x] More manual tests and documentation cc @matklad @lnicola Co-authored-by: Veetaha <[email protected]> Co-authored-by: Veetaha <[email protected]>
Diffstat (limited to 'editors/code/src/config.ts')
-rw-r--r--editors/code/src/config.ts117
1 files changed, 97 insertions, 20 deletions
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 6db073bec..f63e1d20e 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -1,7 +1,7 @@
1import * as os from "os"; 1import * as os from "os";
2import * as vscode from 'vscode'; 2import * as vscode from 'vscode';
3import { ArtifactSource } from "./installation/interfaces"; 3import { ArtifactSource } from "./installation/interfaces";
4import { log } from "./util"; 4import { log, vscodeReloadWindow } from "./util";
5 5
6const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG; 6const RA_LSP_DEBUG = process.env.__RA_LSP_SERVER_DEBUG;
7 7
@@ -23,25 +23,40 @@ export interface CargoFeatures {
23 allFeatures: boolean; 23 allFeatures: boolean;
24 features: string[]; 24 features: string[];
25} 25}
26
27export const enum UpdatesChannel {
28 Stable = "stable",
29 Nightly = "nightly"
30}
31
32export const NIGHTLY_TAG = "nightly";
26export class Config { 33export class Config {
27 private static readonly rootSection = "rust-analyzer"; 34 readonly extensionId = "matklad.rust-analyzer";
28 private static readonly requiresReloadOpts = [ 35
36 private readonly rootSection = "rust-analyzer";
37 private readonly requiresReloadOpts = [
38 "serverPath",
29 "cargoFeatures", 39 "cargoFeatures",
30 "cargo-watch", 40 "cargo-watch",
31 "highlighting.semanticTokens", 41 "highlighting.semanticTokens",
32 "inlayHints", 42 "inlayHints",
33 ] 43 ]
34 .map(opt => `${Config.rootSection}.${opt}`); 44 .map(opt => `${this.rootSection}.${opt}`);
35 45
36 private static readonly extensionVersion: string = (() => { 46 readonly packageJsonVersion = vscode
37 const packageJsonVersion = vscode 47 .extensions
38 .extensions 48 .getExtension(this.extensionId)!
39 .getExtension("matklad.rust-analyzer")! 49 .packageJSON
40 .packageJSON 50 .version as string; // n.n.YYYYMMDD[-nightly]
41 .version as string; // n.n.YYYYMMDD 51
52 /**
53 * Either `nightly` or `YYYY-MM-DD` (i.e. `stable` release)
54 */
55 readonly extensionReleaseTag: string = (() => {
56 if (this.packageJsonVersion.endsWith(NIGHTLY_TAG)) return NIGHTLY_TAG;
42 57
43 const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/; 58 const realVersionRegexp = /^\d+\.\d+\.(\d{4})(\d{2})(\d{2})/;
44 const [, yyyy, mm, dd] = packageJsonVersion.match(realVersionRegexp)!; 59 const [, yyyy, mm, dd] = this.packageJsonVersion.match(realVersionRegexp)!;
45 60
46 return `${yyyy}-${mm}-${dd}`; 61 return `${yyyy}-${mm}-${dd}`;
47 })(); 62 })();
@@ -54,16 +69,19 @@ export class Config {
54 } 69 }
55 70
56 private refreshConfig() { 71 private refreshConfig() {
57 this.cfg = vscode.workspace.getConfiguration(Config.rootSection); 72 this.cfg = vscode.workspace.getConfiguration(this.rootSection);
58 const enableLogging = this.cfg.get("trace.extension") as boolean; 73 const enableLogging = this.cfg.get("trace.extension") as boolean;
59 log.setEnabled(enableLogging); 74 log.setEnabled(enableLogging);
60 log.debug("Using configuration:", this.cfg); 75 log.debug(
76 "Extension version:", this.packageJsonVersion,
77 "using configuration:", this.cfg
78 );
61 } 79 }
62 80
63 private async onConfigChange(event: vscode.ConfigurationChangeEvent) { 81 private async onConfigChange(event: vscode.ConfigurationChangeEvent) {
64 this.refreshConfig(); 82 this.refreshConfig();
65 83
66 const requiresReloadOpt = Config.requiresReloadOpts.find( 84 const requiresReloadOpt = this.requiresReloadOpts.find(
67 opt => event.affectsConfiguration(opt) 85 opt => event.affectsConfiguration(opt)
68 ); 86 );
69 87
@@ -75,7 +93,7 @@ export class Config {
75 ); 93 );
76 94
77 if (userResponse === "Reload now") { 95 if (userResponse === "Reload now") {
78 vscode.commands.executeCommand("workbench.action.reloadWindow"); 96 await vscodeReloadWindow();
79 } 97 }
80 } 98 }
81 99
@@ -121,8 +139,14 @@ export class Config {
121 } 139 }
122 } 140 }
123 141
142 get installedExtensionUpdateChannel(): UpdatesChannel {
143 return this.extensionReleaseTag === NIGHTLY_TAG
144 ? UpdatesChannel.Nightly
145 : UpdatesChannel.Stable;
146 }
147
124 get serverSource(): null | ArtifactSource { 148 get serverSource(): null | ArtifactSource {
125 const serverPath = RA_LSP_DEBUG ?? this.cfg.get<null | string>("serverPath"); 149 const serverPath = RA_LSP_DEBUG ?? this.serverPath;
126 150
127 if (serverPath) { 151 if (serverPath) {
128 return { 152 return {
@@ -135,13 +159,18 @@ export class Config {
135 159
136 if (!prebuiltBinaryName) return null; 160 if (!prebuiltBinaryName) return null;
137 161
162 return this.createGithubReleaseSource(
163 prebuiltBinaryName,
164 this.extensionReleaseTag
165 );
166 }
167
168 private createGithubReleaseSource(file: string, tag: string): ArtifactSource.GithubRelease {
138 return { 169 return {
139 type: ArtifactSource.Type.GithubRelease, 170 type: ArtifactSource.Type.GithubRelease,
171 file,
172 tag,
140 dir: this.ctx.globalStoragePath, 173 dir: this.ctx.globalStoragePath,
141 file: prebuiltBinaryName,
142 storage: this.ctx.globalState,
143 tag: Config.extensionVersion,
144 askBeforeDownload: this.cfg.get("updates.askBeforeDownload") as boolean,
145 repo: { 174 repo: {
146 name: "rust-analyzer", 175 name: "rust-analyzer",
147 owner: "rust-analyzer", 176 owner: "rust-analyzer",
@@ -149,9 +178,23 @@ export class Config {
149 }; 178 };
150 } 179 }
151 180
181 get nightlyVsixSource(): ArtifactSource.GithubRelease {
182 return this.createGithubReleaseSource("rust-analyzer.vsix", NIGHTLY_TAG);
183 }
184
185 readonly installedNightlyExtensionReleaseDate = new DateStorage(
186 "installed-nightly-extension-release-date",
187 this.ctx.globalState
188 );
189 readonly serverReleaseDate = new DateStorage("server-release-date", this.ctx.globalState);
190 readonly serverReleaseTag = new Storage<null | string>("server-release-tag", this.ctx.globalState, null);
191
152 // We don't do runtime config validation here for simplicity. More on stackoverflow: 192 // We don't do runtime config validation here for simplicity. More on stackoverflow:
153 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension 193 // https://stackoverflow.com/questions/60135780/what-is-the-best-way-to-type-check-the-configuration-for-vscode-extension
154 194
195 private get serverPath() { return this.cfg.get("serverPath") as null | string; }
196 get updatesChannel() { return this.cfg.get("updates.channel") as UpdatesChannel; }
197 get askBeforeDownload() { return this.cfg.get("updates.askBeforeDownload") as boolean; }
155 get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; } 198 get highlightingSemanticTokens() { return this.cfg.get("highlighting.semanticTokens") as boolean; }
156 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; } 199 get highlightingOn() { return this.cfg.get("highlightingOn") as boolean; }
157 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; } 200 get rainbowHighlightingOn() { return this.cfg.get("rainbowHighlightingOn") as boolean; }
@@ -189,3 +232,37 @@ export class Config {
189 // for internal use 232 // for internal use
190 get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; } 233 get withSysroot() { return this.cfg.get("withSysroot", true) as boolean; }
191} 234}
235
236export class Storage<T> {
237 constructor(
238 private readonly key: string,
239 private readonly storage: vscode.Memento,
240 private readonly defaultVal: T
241 ) { }
242
243 get(): T {
244 const val = this.storage.get(this.key, this.defaultVal);
245 log.debug(this.key, "==", val);
246 return val;
247 }
248 async set(val: T) {
249 log.debug(this.key, "=", val);
250 await this.storage.update(this.key, val);
251 }
252}
253export class DateStorage {
254 inner: Storage<null | string>;
255
256 constructor(key: string, storage: vscode.Memento) {
257 this.inner = new Storage(key, storage, null);
258 }
259
260 get(): null | Date {
261 const dateStr = this.inner.get();
262 return dateStr ? new Date(dateStr) : null;
263 }
264
265 async set(date: null | Date) {
266 await this.inner.set(date ? date.toString() : null);
267 }
268}