about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2021-12-23 12:43:54 +0000
committerGitHub <noreply@github.com>2021-12-23 12:43:54 +0000
commitcb0e270c026987e8863894a96fd19d33d7db1ef1 (patch)
tree49cca357401f52c14ffb733434bf52e4d6af6627
parent4ea1f58bf6b3fd5bb59ed583f2ac432e237e1e1e (diff)
parentaf2bbce8d97ef58de4681493509837de38b8b7fe (diff)
downloadrust-cb0e270c026987e8863894a96fd19d33d7db1ef1.tar.gz
rust-cb0e270c026987e8863894a96fd19d33d7db1ef1.zip
Merge #11106
11106: internal: Remove network access from Code extension r=lnicola a=lnicola



Co-authored-by: Laurențiu Nicola <lnicola@dend.ro>
-rw-r--r--PRIVACY.md2
-rw-r--r--docs/user/manual.adoc4
-rw-r--r--editors/code/package-lock.json115
-rw-r--r--editors/code/package.json20
-rw-r--r--editors/code/src/config.ts22
-rw-r--r--editors/code/src/main.ts292
-rw-r--r--editors/code/src/net.ts228
-rw-r--r--editors/code/src/persistent_state.ts38
8 files changed, 54 insertions, 667 deletions
diff --git a/PRIVACY.md b/PRIVACY.md
index 718fbed1206..89e252be731 100644
--- a/PRIVACY.md
+++ b/PRIVACY.md
@@ -1 +1 @@
-See the [Privacy](https://rust-analyzer.github.io/manual.html#security) section of the user manual.
+See the [Privacy](https://rust-analyzer.github.io/manual.html#privacy) section of the user manual.
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index 1335f8df7c0..13165e8d3f0 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -653,10 +653,12 @@ Here is a **non-exhaustive** list of ways to make rust-analyzer execute arbitrar
 The LSP server performs no network access in itself, but runs `cargo metadata` which will update or download the crate registry and the source code of the project dependencies.
 If enabled (the default), build scripts and procedural macros can do anything.
 
-The Code extension automatically connects to GitHub to download updated LSP binaries and, if the nightly channel is selected, to perform update checks using the GitHub API. For `rust-analyzer` developers, using `cargo xtask release` uses the same API to put together the release notes.
+The Code extension does not access the network.
 
 Any other editor plugins are not under the control of the `rust-analyzer` developers. For any privacy concerns, you should check with their respective developers.
 
+For `rust-analyzer` developers, `cargo xtask release` uses the GitHub API to put together the release notes.
+
 == Features
 
 include::./generated_features.adoc[]
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index 8728654662c..4aa9ac9d430 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -11,8 +11,6 @@
             "dependencies": {
                 "d3": "^7.2.0",
                 "d3-graphviz": "^4.0.0",
-                "https-proxy-agent": "^5.0.0",
-                "node-fetch": "^3.0.3",
                 "vscode-languageclient": "8.0.0-next.2"
             },
             "devDependencies": {
@@ -345,6 +343,7 @@
             "version": "6.0.2",
             "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
             "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "dev": true,
             "dependencies": {
                 "debug": "4"
             },
@@ -1274,18 +1273,11 @@
                 "node": ">=12"
             }
         },
-        "node_modules/data-uri-to-buffer": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-            "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
-            "engines": {
-                "node": ">= 12"
-            }
-        },
         "node_modules/debug": {
             "version": "4.3.3",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
             "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+            "dev": true,
             "dependencies": {
                 "ms": "2.1.2"
             },
@@ -2059,27 +2051,6 @@
                 "pend": "~1.2.0"
             }
         },
-        "node_modules/fetch-blob": {
-            "version": "3.1.3",
-            "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.3.tgz",
-            "integrity": "sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ==",
-            "funding": [
-                {
-                    "type": "github",
-                    "url": "https://github.com/sponsors/jimmywarting"
-                },
-                {
-                    "type": "paypal",
-                    "url": "https://paypal.me/jimmywarting"
-                }
-            ],
-            "dependencies": {
-                "web-streams-polyfill": "^3.0.3"
-            },
-            "engines": {
-                "node": "^12.20 || >= 14.13"
-            }
-        },
         "node_modules/file-entry-cache": {
             "version": "6.0.1",
             "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -2123,17 +2094,6 @@
             "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
             "dev": true
         },
-        "node_modules/formdata-polyfill": {
-            "version": "4.0.10",
-            "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
-            "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
-            "dependencies": {
-                "fetch-blob": "^3.1.2"
-            },
-            "engines": {
-                "node": ">=12.20.0"
-            }
-        },
         "node_modules/fs-constants": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -2403,6 +2363,7 @@
             "version": "5.0.0",
             "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
             "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+            "dev": true,
             "dependencies": {
                 "agent-base": "6",
                 "debug": "4"
@@ -2770,7 +2731,8 @@
         "node_modules/ms": {
             "version": "2.1.2",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+            "dev": true
         },
         "node_modules/mute-stream": {
             "version": "0.0.8",
@@ -2814,23 +2776,6 @@
             "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
             "dev": true
         },
-        "node_modules/node-fetch": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.1.0.tgz",
-            "integrity": "sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==",
-            "dependencies": {
-                "data-uri-to-buffer": "^4.0.0",
-                "fetch-blob": "^3.1.2",
-                "formdata-polyfill": "^4.0.10"
-            },
-            "engines": {
-                "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
-            },
-            "funding": {
-                "type": "opencollective",
-                "url": "https://opencollective.com/node-fetch"
-            }
-        },
         "node_modules/npmlog": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -3866,14 +3811,6 @@
             "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.3.tgz",
             "integrity": "sha512-VQcXnhKYxUW6OiRMhG++SzmZYMJwusXknJGd+FfdOnS1yHAo734OHyR0e2eEHDlv0/oWc8RZPgx/VKSKyondVg=="
         },
-        "node_modules/web-streams-polyfill": {
-            "version": "3.2.0",
-            "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
-            "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==",
-            "engines": {
-                "node": ">= 8"
-            }
-        },
         "node_modules/which": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4170,6 +4107,7 @@
             "version": "6.0.2",
             "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
             "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+            "dev": true,
             "requires": {
                 "debug": "4"
             }
@@ -4874,15 +4812,11 @@
                 "d3-transition": "2 - 3"
             }
         },
-        "data-uri-to-buffer": {
-            "version": "4.0.0",
-            "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
-            "integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
-        },
         "debug": {
             "version": "4.3.3",
             "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz",
             "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==",
+            "dev": true,
             "requires": {
                 "ms": "2.1.2"
             }
@@ -5434,14 +5368,6 @@
                 "pend": "~1.2.0"
             }
         },
-        "fetch-blob": {
-            "version": "3.1.3",
-            "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.3.tgz",
-            "integrity": "sha512-ax1Y5I9w+9+JiM+wdHkhBoxew+zG4AJ2SvAD1v1szpddUIiPERVGBxrMcB2ZqW0Y3PP8bOWYv2zqQq1Jp2kqUQ==",
-            "requires": {
-                "web-streams-polyfill": "^3.0.3"
-            }
-        },
         "file-entry-cache": {
             "version": "6.0.1",
             "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@@ -5476,14 +5402,6 @@
             "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==",
             "dev": true
         },
-        "formdata-polyfill": {
-            "version": "4.0.10",
-            "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
-            "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
-            "requires": {
-                "fetch-blob": "^3.1.2"
-            }
-        },
         "fs-constants": {
             "version": "1.0.0",
             "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
@@ -5696,6 +5614,7 @@
             "version": "5.0.0",
             "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
             "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+            "dev": true,
             "requires": {
                 "agent-base": "6",
                 "debug": "4"
@@ -5978,7 +5897,8 @@
         "ms": {
             "version": "2.1.2",
             "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+            "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
+            "dev": true
         },
         "mute-stream": {
             "version": "0.0.8",
@@ -6021,16 +5941,6 @@
             "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==",
             "dev": true
         },
-        "node-fetch": {
-            "version": "3.1.0",
-            "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.1.0.tgz",
-            "integrity": "sha512-QU0WbIfMUjd5+MUzQOYhenAazakV7Irh1SGkWCsRzBwvm4fAhzEUaHMJ6QLP7gWT6WO9/oH2zhKMMGMuIrDyKw==",
-            "requires": {
-                "data-uri-to-buffer": "^4.0.0",
-                "fetch-blob": "^3.1.2",
-                "formdata-polyfill": "^4.0.10"
-            }
-        },
         "npmlog": {
             "version": "4.1.2",
             "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
@@ -6827,11 +6737,6 @@
             "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.0-next.3.tgz",
             "integrity": "sha512-VQcXnhKYxUW6OiRMhG++SzmZYMJwusXknJGd+FfdOnS1yHAo734OHyR0e2eEHDlv0/oWc8RZPgx/VKSKyondVg=="
         },
-        "web-streams-polyfill": {
-            "version": "3.2.0",
-            "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
-            "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA=="
-        },
         "which": {
             "version": "2.0.2",
             "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/editors/code/package.json b/editors/code/package.json
index 9ab57d7dc5f..550b28e1cdb 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -36,8 +36,6 @@
         "test": "node ./out/tests/runTests.js"
     },
     "dependencies": {
-        "https-proxy-agent": "^5.0.0",
-        "node-fetch": "^3.0.3",
         "vscode-languageclient": "8.0.0-next.2",
         "d3": "^7.2.0",
         "d3-graphviz": "^4.0.0"
@@ -305,24 +303,6 @@
                     "default": true,
                     "description": "Whether inlay hints font size should be smaller than editor's font size."
                 },
-                "rust-analyzer.updates.channel": {
-                    "type": "string",
-                    "enum": [
-                        "stable",
-                        "nightly"
-                    ],
-                    "default": "stable",
-                    "markdownEnumDescriptions": [
-                        "`stable` updates are shipped weekly, they don't contain cutting-edge features from VSCode proposed APIs but have less bugs in general.",
-                        "`nightly` updates are shipped daily (extension updates automatically by downloading artifacts directly from GitHub), they contain cutting-edge features and latest bug fixes. These releases help us get your feedback very quickly and speed up rust-analyzer development **drastically**."
-                    ],
-                    "markdownDescription": "Choose `nightly` updates to get the latest features and bug fixes every day. While `stable` releases occur weekly and don't contain cutting-edge features from VSCode proposed APIs."
-                },
-                "rust-analyzer.updates.askBeforeDownload": {
-                    "type": "boolean",
-                    "default": false,
-                    "description": "Whether to ask for permission before downloading any files from the Internet."
-                },
                 "rust-analyzer.server.path": {
                     "type": [
                         "null",
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index cb0868db597..cdbaa67fe22 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -8,11 +8,6 @@ const NIGHTLY_TAG = "nightly";
 
 export type RunnableEnvCfg = undefined | Record<string, string> | { mask?: string; env: Record<string, string> }[];
 
-export class ProxySettings {
-    proxy?: string = undefined;
-    strictSSL: boolean = true;
-}
-
 export class Config {
     readonly extensionId = "matklad.rust-analyzer";
 
@@ -24,7 +19,6 @@ export class Config {
         "procMacro",
         "files",
         "highlighting",
-        "updates.channel",
         "lens", // works as lens.*
     ]
         .map(opt => `${this.rootSection}.${opt}`);
@@ -36,11 +30,9 @@ export class Config {
     } = vscode.extensions.getExtension(this.extensionId)!.packageJSON;
 
     readonly globalStorageUri: vscode.Uri;
-    readonly installUri: vscode.Uri;
 
     constructor(ctx: vscode.ExtensionContext) {
         this.globalStorageUri = ctx.globalStorageUri;
-        this.installUri = ctx.extensionUri;
         vscode.workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, ctx.subscriptions);
         this.refreshLogging();
     }
@@ -103,21 +95,7 @@ export class Config {
         return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
     }
     get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; }
-    get channel() { return this.get<UpdatesChannel>("updates.channel"); }
-    get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
     get traceExtension() { return this.get<boolean>("trace.extension"); }
-    get proxySettings(): ProxySettings {
-        const proxy = vscode
-            .workspace
-            .getConfiguration('http')
-            .get<null | string>("proxy")! || process.env["https_proxy"] || process.env["HTTPS_PROXY"];
-        const strictSSL = vscode.workspace.getConfiguration("http").get<boolean>("proxyStrictSSL") ?? true;
-
-        return {
-            proxy: proxy,
-            strictSSL: strictSSL,
-        };
-    }
 
     get inlayHints() {
         return {
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index dc0a9a2f872..df7580b9bc5 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -5,12 +5,11 @@ import * as commands from './commands';
 import { activateInlayHints } from './inlay_hints';
 import { Ctx } from './ctx';
 import { Config } from './config';
-import { log, assert, isValidExecutable, isRustDocument } from './util';
+import { log, isValidExecutable, isRustDocument } from './util';
 import { PersistentState } from './persistent_state';
-import { fetchRelease, download } from './net';
 import { activateTaskProvider } from './tasks';
 import { setContextValue } from './util';
-import { exec, spawnSync } from 'child_process';
+import { exec } from 'child_process';
 
 let ctx: Ctx | undefined;
 
@@ -28,14 +27,9 @@ export async function activate(context: vscode.ExtensionContext) {
 async function tryActivate(context: vscode.ExtensionContext) {
     const config = new Config(context);
     const state = new PersistentState(context.globalState);
-    const serverPath = await bootstrap(config, state).catch(err => {
+    const serverPath = await bootstrap(context, config, state).catch(err => {
         let message = "bootstrap error. ";
 
-        if (err.code === "EBUSY" || err.code === "ETXTBSY" || err.code === "EPERM") {
-            message += "Other vscode windows might be using rust-analyzer, ";
-            message += "you should close them and reload this window to retry. ";
-        }
-
         message += 'See the logs in "OUTPUT > Rust Analyzer Client" (should open automatically). ';
         message += 'To enable verbose logs use { "rust-analyzer.trace.extension": true }';
 
@@ -111,10 +105,6 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
         await activate(context).catch(log.error);
     });
 
-    ctx.registerCommand('updateGithubToken', ctx => async () => {
-        await queryForGithubToken(new PersistentState(ctx.globalState));
-    });
-
     ctx.registerCommand('analyzerStatus', commands.analyzerStatus);
     ctx.registerCommand('memoryUsage', commands.memoryUsage);
     ctx.registerCommand('shuffleCrateGraph', commands.shuffleCrateGraph);
@@ -161,99 +151,8 @@ export async function deactivate() {
     ctx = undefined;
 }
 
-async function bootstrap(config: Config, state: PersistentState): Promise<string> {
-    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);
-    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> {
-    const path = await getServer(config, state);
+async function bootstrap(context: vscode.ExtensionContext, config: Config, state: PersistentState): Promise<string> {
+    const path = await getServer(context, config, state);
     if (!path) {
         throw new Error(
             "Rust Analyzer Language Server is not available. " +
@@ -318,7 +217,7 @@ async function patchelf(dest: vscode.Uri): Promise<void> {
     );
 }
 
-async function getServer(config: Config, state: PersistentState): Promise<string | undefined> {
+async function getServer(context: vscode.ExtensionContext, config: Config, state: PersistentState): Promise<string | undefined> {
     const explicitPath = serverPath(config);
     if (explicitPath) {
         if (explicitPath.startsWith("~/")) {
@@ -328,85 +227,39 @@ async function getServer(config: Config, state: PersistentState): Promise<string
     };
     if (config.package.releaseTag === null) return "rust-analyzer";
 
-    const platforms: { [key: string]: string } = {
-        "ia32 win32": "x86_64-pc-windows-msvc",
-        "x64 win32": "x86_64-pc-windows-msvc",
-        "x64 linux": "x86_64-unknown-linux-gnu",
-        "x64 darwin": "x86_64-apple-darwin",
-        "arm64 win32": "aarch64-pc-windows-msvc",
-        "arm64 linux": "aarch64-unknown-linux-gnu",
-        "arm64 darwin": "aarch64-apple-darwin",
-    };
-    let platform = platforms[`${process.arch} ${process.platform}`];
-    if (platform === undefined) {
-        await 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 undefined;
-    }
-    if (platform === "x86_64-unknown-linux-gnu" && isMusl()) {
-        platform = "x86_64-unknown-linux-musl";
-    }
-    const ext = platform.indexOf("-windows-") !== -1 ? ".exe" : "";
-    const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer-${platform}${ext}`);
-    const bundled = vscode.Uri.joinPath(config.installUri, "server", `rust-analyzer${ext}`);
+    const ext = process.platform === "win32" ? ".exe" : "";
+    const bundled = vscode.Uri.joinPath(context.extensionUri, "server", `rust-analyzer${ext}`);
     const bundledExists = await vscode.workspace.fs.stat(bundled).then(() => true, () => false);
-    let exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false);
     if (bundledExists) {
-        await state.updateServerVersion(config.package.version);
-        if (!await isNixOs()) {
-            return bundled.fsPath;
-        }
-        if (!exists) {
-            await vscode.workspace.fs.copy(bundled, dest);
-            await patchelf(dest);
-            exists = true;
+        let server = bundled;
+        if (await isNixOs()) {
+            await vscode.workspace.fs.createDirectory(config.globalStorageUri).then();
+            const dest = vscode.Uri.joinPath(config.globalStorageUri, `rust-analyzer${ext}`);
+            let exists = await vscode.workspace.fs.stat(dest).then(() => true, () => false);
+            if (exists && config.package.version !== state.serverVersion) {
+                await vscode.workspace.fs.delete(dest);
+                exists = false;
+            }
+            if (!exists) {
+                await vscode.workspace.fs.copy(bundled, dest);
+                await patchelf(dest);
+                server = dest;
+            }
         }
-    }
-    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 server.fsPath;
     }
 
-    await state.updateServerVersion(config.package.version);
-    return dest.fsPath;
+    await state.updateServerVersion(undefined);
+    await vscode.window.showErrorMessage(
+        "Unfortunately we don't ship binaries for your platform yet. " +
+        "You need to manually clone the 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 undefined;
 }
 
 function serverPath(config: Config): string | null {
@@ -422,85 +275,14 @@ async function isNixOs(): Promise<boolean> {
     }
 }
 
-function isMusl(): boolean {
-    // We can detect Alpine by checking `/etc/os-release` but not Void Linux musl.
-    // Instead, we run `ldd` since it advertises the libc which it belongs to.
-    const res = spawnSync("ldd", ["--version"]);
-    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() {
-    const conflicting = [
-        ["rust-analyzer", "matklad.rust-analyzer"],
-        ["Rust", "rust-lang.rust"],
-        ["Rust", "kalitaalexey.vscode-rust"],
-    ];
-
-    const found = conflicting.filter(
-        nameId => vscode.extensions.getExtension(nameId[1]) !== undefined);
-
-    if (found.length > 1) {
-        const fst = found[0];
-        const sec = found[1];
+    if (vscode.extensions.getExtension("rust-lang.rust")) {
         vscode.window.showWarningMessage(
-            `You have both the ${fst[0]} (${fst[1]}) and ${sec[0]} (${sec[1]}) ` +
+            `You have both the rust-analyzer (matklad.rust-analyzer) and Rust (rust-lang.rust) ` +
             "plugins enabled. These are known to conflict and cause various functions of " +
             "both plugins to not work correctly. You should disable one of them.", "Got it")
             .then(() => { }, console.error);
-    };
+    }
 }
 
 /**
diff --git a/editors/code/src/net.ts b/editors/code/src/net.ts
deleted file mode 100644
index bd1bb5f8a8a..00000000000
--- a/editors/code/src/net.ts
+++ /dev/null
@@ -1,228 +0,0 @@
-import fetch from "node-fetch";
-var HttpsProxyAgent = require('https-proxy-agent');
-
-import * as vscode from "vscode";
-import * as stream from "stream";
-import * as crypto from "crypto";
-import * as fs from "fs";
-import * as zlib from "zlib";
-import * as util from "util";
-import * as path from "path";
-import { log, assert } from "./util";
-import * as https from "https";
-import { ProxySettings } from "./config";
-
-const pipeline = util.promisify(stream.pipeline);
-
-const GITHUB_API_ENDPOINT_URL = "https://api.github.com";
-const OWNER = "rust-analyzer";
-const REPO = "rust-analyzer";
-
-function makeHttpAgent(proxy: string | null | undefined, options?: https.AgentOptions) {
-    if (proxy) {
-        return new HttpsProxyAgent({ ...options, ...new URL(proxy) });
-    } else {
-        return new https.Agent(options);
-    }
-}
-
-export async function fetchRelease(
-    releaseTag: string,
-    githubToken: string | null | undefined,
-    proxySettings: ProxySettings,
-): Promise<GithubRelease> {
-
-    const apiEndpointPath = `/repos/${OWNER}/${REPO}/releases/tags/${releaseTag}`;
-
-    const requestUrl = GITHUB_API_ENDPOINT_URL + apiEndpointPath;
-
-    log.debug("Issuing request for released artifacts metadata to", requestUrl);
-
-    const headers: Record<string, string> = { Accept: "application/vnd.github.v3+json" };
-    if (githubToken != null) {
-        headers.Authorization = "token " + githubToken;
-    }
-
-    const response = await (() => {
-        if (proxySettings.proxy) {
-            log.debug(`Fetching release metadata via proxy: ${proxySettings.proxy}`);
-        }
-        const options: any = {};
-        if (proxySettings.strictSSL) {
-            options["rejectUnauthorized"] = false;
-        }
-        const agent = makeHttpAgent(proxySettings.proxy, options);
-        return fetch(requestUrl, { headers: headers, agent: agent });
-    })();
-
-    if (!response.ok) {
-        log.error("Error fetching artifact release info", {
-            requestUrl,
-            releaseTag,
-            response: {
-                headers: response.headers,
-                status: response.status,
-                body: await response.text(),
-            }
-        });
-
-        throw new Error(
-            `Got response ${response.status} when trying to fetch ` +
-            `release info for ${releaseTag} release`
-        );
-    }
-
-    // We skip runtime type checks for simplicity (here we cast from `unknown` to `GithubRelease`)
-    const release = await response.json() as GithubRelease;
-    return release;
-}
-
-// We omit declaration of tremendous amount of fields that we are not using here
-export interface GithubRelease {
-    name: string;
-    id: number;
-    // eslint-disable-next-line camelcase
-    published_at: string;
-    assets: Array<{
-        name: string;
-        // eslint-disable-next-line camelcase
-        browser_download_url: vscode.Uri;
-    }>;
-}
-
-interface DownloadOpts {
-    progressTitle: string;
-    url: vscode.Uri;
-    dest: vscode.Uri;
-    mode?: number;
-    gunzip?: boolean;
-    proxySettings: ProxySettings;
-}
-
-export async function download(opts: DownloadOpts) {
-    // Put artifact into a temporary file (in the same dir for simplicity)
-    // to prevent partially downloaded files when user kills vscode
-    // This also avoids overwriting running executables
-    const randomHex = crypto.randomBytes(5).toString("hex");
-    const rawDest = path.parse(opts.dest.fsPath);
-    const oldServerPath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}-stale-${randomHex}${rawDest.ext}`);
-    const tempFilePath = vscode.Uri.joinPath(vscode.Uri.file(rawDest.dir), `${rawDest.name}${randomHex}`);
-
-    await vscode.window.withProgress(
-        {
-            location: vscode.ProgressLocation.Notification,
-            cancellable: false,
-            title: opts.progressTitle
-        },
-        async (progress, _cancellationToken) => {
-            let lastPercentage = 0;
-            await downloadFile(opts.url, tempFilePath, opts.mode, !!opts.gunzip, opts.proxySettings, (readBytes, totalBytes) => {
-                const newPercentage = Math.round((readBytes / totalBytes) * 100);
-                if (newPercentage !== lastPercentage) {
-                    progress.report({
-                        message: `${newPercentage.toFixed(0)}%`,
-                        increment: newPercentage - lastPercentage
-                    });
-
-                    lastPercentage = newPercentage;
-                }
-            });
-        }
-    );
-
-    // Try to rename a running server to avoid EPERM on Windows
-    // NB: this can lead to issues if a running Code instance tries to restart the server.
-    try {
-        await vscode.workspace.fs.rename(opts.dest, oldServerPath, { overwrite: true });
-        log.info(`Renamed old server binary ${opts.dest.fsPath} to ${oldServerPath.fsPath}`);
-    } catch (err) {
-        const fsErr = err as vscode.FileSystemError;
-
-        // This is supposed to return `FileNotFound` (spelled as `EntryNotFound`)
-        // but instead `code` is `Unknown` and `name` is `EntryNotFound (FileSystemError) (FileSystemError)`.
-        // https://github.com/rust-analyzer/rust-analyzer/pull/10222
-        if (!fsErr.code || fsErr.code !== "EntryNotFound" && fsErr.name.indexOf("EntryNotFound") === -1) {
-            log.error(`Cannot rename existing server instance: ${err}"`);
-        }
-    }
-    try {
-        await vscode.workspace.fs.rename(tempFilePath, opts.dest, { overwrite: true });
-    } catch (err) {
-        log.error(`Cannot update server binary: ${err}`);
-    }
-
-    // Now try to remove any stale server binaries
-    const serverDir = vscode.Uri.file(rawDest.dir);
-    try {
-        const entries = await vscode.workspace.fs.readDirectory(serverDir);
-        for (const [entry, _] of entries) {
-            try {
-                if (entry.includes(`${rawDest.name}-stale-`)) {
-                    const uri = vscode.Uri.joinPath(serverDir, entry);
-                    try {
-                        await vscode.workspace.fs.delete(uri);
-                        log.info(`Removed old server binary ${uri.fsPath}`);
-                    } catch (err) {
-                        log.error(`Unable to remove old server binary ${uri.fsPath}`);
-                    }
-                }
-            } catch (err) {
-                log.error(`Unable to parse ${entry}`);
-            }
-        }
-    } catch (err) {
-        log.error(`Unable to enumerate contents of ${serverDir.fsPath}`);
-    }
-}
-
-async function downloadFile(
-    url: vscode.Uri,
-    destFilePath: vscode.Uri,
-    mode: number | undefined,
-    gunzip: boolean,
-    proxySettings: ProxySettings,
-    onProgress: (readBytes: number, totalBytes: number) => void
-): Promise<void> {
-    const urlString = url.toString();
-
-    const res = await (() => {
-        if (proxySettings.proxy) {
-            log.debug(`Downloading ${urlString} via proxy: ${proxySettings.proxy}`);
-        }
-        const options: any = {};
-        if (proxySettings.strictSSL) {
-            options["rejectUnauthorized"] = false;
-        }
-        const agent = makeHttpAgent(proxySettings.proxy, options);
-        return fetch(urlString, { agent: agent });
-    })();
-
-    if (!res.ok) {
-        log.error("Error", res.status, "while downloading file from", urlString);
-        log.error({ body: await res.text(), headers: res.headers });
-
-        throw new Error(`Got response ${res.status} when trying to download a file.`);
-    }
-
-    if (!res.body) {
-        log.error("Empty body while downloading file from", urlString);
-        log.error({ headers: res.headers });
-        throw new Error(`Got empty body when trying to download a file.`);
-    }
-
-    const totalBytes = Number(res.headers.get('content-length'));
-    assert(!Number.isNaN(totalBytes), "Sanity check of content-length protocol");
-
-    log.debug("Downloading file of", totalBytes, "bytes size from", urlString, "to", destFilePath.fsPath);
-
-    let readBytes = 0;
-    res.body.on("data", (chunk: Buffer) => {
-        readBytes += chunk.length;
-        onProgress(readBytes, totalBytes);
-    });
-
-    const destFileStream = fs.createWriteStream(destFilePath.fsPath, { mode });
-    const srcStream = gunzip ? res.body.pipe(zlib.createGunzip()) : res.body;
-
-    await pipeline(srcStream, destFileStream);
-}
diff --git a/editors/code/src/persistent_state.ts b/editors/code/src/persistent_state.ts
index dd2aeecca35..3e86ed1e323 100644
--- a/editors/code/src/persistent_state.ts
+++ b/editors/code/src/persistent_state.ts
@@ -3,34 +3,13 @@ import { log } from './util';
 
 export class PersistentState {
     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);
+        const { serverVersion } = this;
+        log.info("PersistentState:", { serverVersion });
     }
 
     /**
      * Version of the extension that installed the server.
-     * Used to check if we need to update the server.
+     * Used to check if we need to run patchelf again on NixOS.
      */
     get serverVersion(): string | undefined {
         return this.globalState.get("serverVersion");
@@ -38,15 +17,4 @@ export class PersistentState {
     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);
-    }
 }